This source file includes following definitions.
- android_run_select_thread
- android_handle_sigusr1
- android_init_events
- android_pending
- android_wait_event
- android_next_event
- android_check_if_event
- android_write_event
- android_select
- android_run_debug_thread
- android_user_full_name
- android_is_special_directory
- android_url_encode
- android_get_content_name
- android_get_home_directory
- android_proc_name
- android_create_lib_link
- android_init_emacs_service
- android_init_emacs_pixmap
- android_init_graphics_point
- android_init_emacs_drawable
- android_init_emacs_window
- android_init_emacs_cursor
- NATIVE_NAME
- android_alloc_id
- android_destroy_handle
- android_resolve_handle
- android_resolve_handle2
- android_change_window_attributes
- android_create_window
- android_set_window_background
- android_destroy_window
- android_init_android_rect_class
- android_init_emacs_gc_class
- android_create_gc
- android_free_gc
- android_change_gc
- android_set_clip_rectangles
- android_reparent_window
- android_clear_window
- android_map_window
- android_unmap_window
- android_resize_window
- android_move_window
- android_swap_buffers
- android_get_gc_values
- android_set_foreground
- android_fill_rectangle
- android_create_pixmap_from_bitmap_data
- android_set_clip_mask
- android_set_fill_style
- android_neon_mask_line
- android_blit_copy
- android_blit_xor
- android_copy_area
- android_free_pixmap
- android_set_background
- android_fill_polygon
- android_draw_rectangle
- android_draw_point
- android_draw_line
- android_create_pixmap
- android_set_ts_origin
- android_clear_area
- android_create_bitmap_from_data
- android_create_image
- android_destroy_image
- android_put_pixel
- android_get_pixel
- android_get_image
- android_put_image
- android_bell
- android_set_input_focus
- android_raise_window
- android_lower_window
- android_query_tree
- android_get_geometry
- android_move_resize_window
- android_map_raised
- android_translate_coordinates
- android_wc_lookup_string
- android_lock_bitmap
- android_damage_window
- android_get_screen_width
- android_get_screen_height
- android_get_mm_width
- android_get_mm_height
- android_detect_mouse
- android_set_dont_focus_on_map
- android_set_dont_accept_focus
- android_get_keysym_name
- android_toggle_on_screen_keyboard
- emacs_abort
- android_check_string
- android_verify_jni_string
- android_build_string
- android_build_jstring
- android_exception_check
- android_exception_check_1
- android_exception_check_2
- android_exception_check_3
- android_exception_check_4
- android_exception_check_nonnull
- android_exception_check_nonnull_1
- android_transform_coordinates
- android_four_corners_bilinear
- android_fetch_pixel_bilinear
- android_project_image_bilinear
- android_fetch_pixel_nearest_24
- android_fetch_pixel_nearest_1
- android_project_image_nearest
- android_browse_url
- android_restart_emacs
- android_query_battery
- android_request_directory_access
- android_check_query
- android_check_query_urgent
- android_answer_query
- android_answer_query_spin
- android_begin_query
- android_end_query
- android_run_in_emacs_thread
- android_update_ic
- android_reset_ic
- android_update_extracted_text
- android_update_cursor_anchor_info
- android_set_fullscreen
- android_create_font_cursor
- android_define_cursor
- android_free_cursor
- android_rewrite_spawn_argv
- android_create_gc
- android_free_gc
- android_create_image
- android_destroy_image
- android_put_pixel
- android_get_pixel
- android_get_image
- android_put_image
- android_project_image_bilinear
- android_project_image_nearest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21 #include <allocator.h>
22 #include <assert.h>
23 #include <careadlinkat.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <fingerprint.h>
27 #include <intprops.h>
28 #include <libgen.h>
29 #include <limits.h>
30 #include <math.h>
31 #include <pthread.h>
32 #include <semaphore.h>
33 #include <signal.h>
34 #include <stdckdint.h>
35 #include <string.h>
36 #include <sys/param.h>
37 #include <timespec.h>
38 #include <unistd.h>
39
40
41 #include <minmax.h>
42
43 #include "android.h"
44 #include "androidgui.h"
45
46 #include "lisp.h"
47 #include "blockinput.h"
48 #include "coding.h"
49 #include "epaths.h"
50
51
52
53 bool android_init_gui;
54
55 #ifndef ANDROID_STUBIFY
56
57 #include <android/bitmap.h>
58 #include <android/log.h>
59
60 #include <linux/unistd.h>
61
62 #include <sys/syscall.h>
63
64 #ifdef __aarch64__
65 #include <arm_neon.h>
66 #endif
67
68 struct android_emacs_pixmap
69 {
70 jclass class;
71 jmethodID constructor;
72 jmethodID constructor_mutable;
73 };
74
75 struct android_graphics_point
76 {
77 jclass class;
78 jmethodID constructor;
79 };
80
81 struct android_emacs_drawable
82 {
83 jclass class;
84 jmethodID get_bitmap;
85 jmethodID damage_rect;
86 };
87
88 struct android_emacs_window
89 {
90 jclass class;
91 jmethodID swap_buffers;
92 jmethodID toggle_on_screen_keyboard;
93 jmethodID lookup_string;
94 jmethodID set_fullscreen;
95 jmethodID change_window_background;
96 jmethodID reparent_to;
97 jmethodID map_window;
98 jmethodID unmap_window;
99 jmethodID resize_window;
100 jmethodID move_window;
101 jmethodID make_input_focus;
102 jmethodID raise;
103 jmethodID lower;
104 jmethodID get_window_geometry;
105 jmethodID translate_coordinates;
106 jmethodID set_dont_accept_focus;
107 jmethodID set_dont_focus_on_map;
108 jmethodID define_cursor;
109 };
110
111 struct android_emacs_cursor
112 {
113 jclass class;
114 jmethodID constructor;
115 };
116
117
118 static int android_api_level;
119
120
121 char *android_site_load_path;
122
123
124 char *android_lib_dir;
125
126
127 char *android_game_path;
128
129
130 char *android_cache_dir;
131
132
133
134 char *android_class_path;
135
136
137 double android_pixel_density_x, android_pixel_density_y;
138
139
140
141 double android_scaled_pixel_density;
142
143
144 static char *android_files_dir;
145
146
147 JNIEnv *android_java_env;
148
149
150 static jclass emacs_gc_class;
151
152
153 static jfieldID emacs_gc_foreground, emacs_gc_background;
154 static jfieldID emacs_gc_function, emacs_gc_clip_rects;
155 static jfieldID emacs_gc_clip_x_origin, emacs_gc_clip_y_origin;
156 static jfieldID emacs_gc_stipple, emacs_gc_clip_mask;
157 static jfieldID emacs_gc_fill_style, emacs_gc_ts_origin_x;
158 static jfieldID emacs_gc_ts_origin_y;
159
160
161 static jmethodID emacs_gc_constructor, emacs_gc_mark_dirty;
162
163
164 static jclass android_rect_class;
165
166
167 static jmethodID android_rect_constructor;
168
169
170 jobject emacs_service;
171
172
173 struct android_emacs_service service_class;
174
175
176 static struct android_emacs_pixmap pixmap_class;
177
178
179 static struct android_graphics_point point_class;
180
181
182 static struct android_emacs_drawable drawable_class;
183
184
185 static struct android_emacs_window window_class;
186
187
188 static struct android_emacs_cursor cursor_class;
189
190
191
192 unsigned int event_serial;
193
194 #ifdef __i386__
195
196
197 void *unused_pointer;
198
199 #endif
200
201
202
203
204 static bool signal_mask_changed_p;
205
206
207 static sigset_t startup_signal_mask;
208
209
210
211
212
213
214
215
216
217 struct android_event_container
218 {
219
220 struct android_event_container *next, *last;
221
222
223 union android_event event;
224 };
225
226 struct android_event_queue
227 {
228
229 pthread_mutex_t mutex;
230
231
232 pthread_mutex_t select_mutex;
233
234
235 pthread_t select_thread;
236
237
238 pthread_cond_t read_var;
239
240
241
242 int num_events;
243
244
245 struct android_event_container events;
246 };
247
248
249 static int android_pselect_nfds;
250 static fd_set *android_pselect_readfds;
251 static fd_set *android_pselect_writefds;
252 static fd_set *android_pselect_exceptfds;
253 static struct timespec *android_pselect_timeout;
254
255
256 static int android_pselect_rc;
257
258
259 static struct android_event_queue event_queue;
260
261
262 static sem_t android_pselect_sem, android_pselect_start_sem;
263
264 #if __ANDROID_API__ < 16
265
266
267 static int select_pipe[2];
268
269 #else
270
271
272 static volatile sig_atomic_t android_pselect_interrupted;
273
274 #endif
275
276 static void *
277 android_run_select_thread (void *data)
278 {
279
280 JNI_STACK_ALIGNMENT_PROLOGUE;
281
282 int rc;
283 #if __ANDROID_API__ < 16
284 int nfds;
285 fd_set readfds;
286 char byte;
287 #else
288 sigset_t signals, waitset;
289 int sig;
290 #endif
291
292 #if __ANDROID_API__ < 16
293
294
295
296
297
298
299
300 while (true)
301 {
302
303 while (sem_wait (&android_pselect_start_sem) < 0)
304 ;;
305
306
307
308
309
310 pthread_mutex_lock (&event_queue.select_mutex);
311 nfds = android_pselect_nfds;
312
313 if (android_pselect_readfds)
314 readfds = *android_pselect_readfds;
315 else
316 FD_ZERO (&readfds);
317
318 if (nfds < select_pipe[0] + 1)
319 nfds = select_pipe[0] + 1;
320 FD_SET (select_pipe[0], &readfds);
321
322 rc = pselect (nfds, &readfds,
323 android_pselect_writefds,
324 android_pselect_exceptfds,
325 android_pselect_timeout,
326 NULL);
327
328
329
330
331 if (rc != -1 && FD_ISSET (select_pipe[0], &readfds))
332 {
333 rc -= 1;
334 FD_CLR (select_pipe[0], &readfds);
335
336
337
338 if (!rc)
339 rc = -1;
340 }
341
342
343
344 if (android_pselect_readfds)
345 *android_pselect_readfds = readfds;
346
347 android_pselect_rc = rc;
348 pthread_mutex_unlock (&event_queue.select_mutex);
349
350
351
352
353
354
355 pthread_mutex_lock (&event_queue.mutex);
356 pthread_cond_broadcast (&event_queue.read_var);
357 pthread_mutex_unlock (&event_queue.mutex);
358
359
360 read (select_pipe[0], &byte, 1);
361
362
363
364
365 sem_post (&android_pselect_sem);
366 }
367 #else
368 if (pthread_sigmask (SIG_BLOCK, &signals, NULL))
369 __android_log_print (ANDROID_LOG_FATAL, __func__,
370 "pthread_sigmask: %s",
371 strerror (errno));
372
373 sigfillset (&signals);
374 sigdelset (&signals, SIGUSR1);
375 sigemptyset (&waitset);
376 sigaddset (&waitset, SIGUSR1);
377
378 while (true)
379 {
380
381 while (sem_wait (&android_pselect_start_sem) < 0)
382 ;;
383
384
385
386 android_pselect_interrupted = 0;
387
388
389 pthread_mutex_lock (&event_queue.select_mutex);
390 rc = pselect (android_pselect_nfds,
391 android_pselect_readfds,
392 android_pselect_writefds,
393 android_pselect_exceptfds,
394 android_pselect_timeout,
395 &signals);
396 android_pselect_rc = rc;
397 pthread_mutex_unlock (&event_queue.select_mutex);
398
399
400
401
402
403
404 pthread_mutex_lock (&event_queue.mutex);
405 pthread_cond_broadcast (&event_queue.read_var);
406 pthread_mutex_unlock (&event_queue.mutex);
407
408
409
410
411
412
413
414 if (!android_pselect_interrupted)
415
416
417
418
419 sigwait (&waitset, &sig);
420
421
422
423
424 sem_post (&android_pselect_sem);
425 }
426 #endif
427
428 return NULL;
429 }
430
431 #if __ANDROID_API__ >= 16
432
433 static void
434 android_handle_sigusr1 (int sig, siginfo_t *siginfo, void *arg)
435 {
436
437 android_pselect_interrupted = 1;
438 }
439
440 #endif
441
442
443
444 static sem_t android_query_sem;
445
446
447
448
449
450
451
452
453
454 static void
455 android_init_events (void)
456 {
457 struct sigaction sa;
458
459 if (pthread_mutex_init (&event_queue.mutex, NULL))
460 __android_log_print (ANDROID_LOG_FATAL, __func__,
461 "pthread_mutex_init: %s",
462 strerror (errno));
463
464 if (pthread_mutex_init (&event_queue.select_mutex, NULL))
465 __android_log_print (ANDROID_LOG_FATAL, __func__,
466 "pthread_mutex_init: %s",
467 strerror (errno));
468
469 if (pthread_cond_init (&event_queue.read_var, NULL))
470 __android_log_print (ANDROID_LOG_FATAL, __func__,
471 "pthread_cond_init: %s",
472 strerror (errno));
473
474 sem_init (&android_pselect_sem, 0, 0);
475 sem_init (&android_pselect_start_sem, 0, 0);
476 sem_init (&android_query_sem, 0, 0);
477
478 event_queue.events.next = &event_queue.events;
479 event_queue.events.last = &event_queue.events;
480
481 #if __ANDROID_API__ >= 16
482
483
484
485 sigfillset (&sa.sa_mask);
486 sa.sa_sigaction = android_handle_sigusr1;
487 sa.sa_flags = SA_SIGINFO;
488
489 #else
490
491
492 if (pipe2 (select_pipe, O_CLOEXEC) < 0)
493 __android_log_print (ANDROID_LOG_FATAL, __func__,
494 "pipe2: %s", strerror (errno));
495
496
497 if (select_pipe[0] >= FD_SETSIZE)
498 __android_log_print (ANDROID_LOG_FATAL, __func__,
499 "read end of select pipe"
500 " lies outside FD_SETSIZE!");
501
502 #endif
503
504 if (sigaction (SIGUSR1, &sa, NULL))
505 __android_log_print (ANDROID_LOG_FATAL, __func__,
506 "sigaction: %s",
507 strerror (errno));
508
509
510 if (pthread_create (&event_queue.select_thread, NULL,
511 android_run_select_thread, NULL))
512 __android_log_print (ANDROID_LOG_FATAL, __func__,
513 "pthread_create: %s",
514 strerror (errno));
515 }
516
517 int
518 android_pending (void)
519 {
520 int i;
521
522 pthread_mutex_lock (&event_queue.mutex);
523 i = event_queue.num_events;
524 pthread_mutex_unlock (&event_queue.mutex);
525
526 return i;
527 }
528
529
530
531 static void android_check_query (void);
532
533
534
535
536
537 void
538 android_wait_event (void)
539 {
540
541 android_check_query ();
542
543 pthread_mutex_lock (&event_queue.mutex);
544
545
546
547 if (!event_queue.num_events)
548 pthread_cond_wait (&event_queue.read_var,
549 &event_queue.mutex);
550
551 pthread_mutex_unlock (&event_queue.mutex);
552
553
554
555 android_check_query ();
556 }
557
558 void
559 android_next_event (union android_event *event_return)
560 {
561 struct android_event_container *container;
562
563 pthread_mutex_lock (&event_queue.mutex);
564
565
566
567 if (!event_queue.num_events)
568 pthread_cond_wait (&event_queue.read_var,
569 &event_queue.mutex);
570
571
572 container = event_queue.events.last;
573 eassert (container != &event_queue.events);
574
575
576
577 container->last->next = container->next;
578 container->next->last = container->last;
579 *event_return = container->event;
580 event_queue.num_events--;
581
582
583 free (container);
584
585
586 pthread_mutex_unlock (&event_queue.mutex);
587 }
588
589 bool
590 android_check_if_event (union android_event *event_return,
591 bool (*predicate) (union android_event *,
592 void *),
593 void *arg)
594 {
595 struct android_event_container *container;
596
597 pthread_mutex_lock (&event_queue.mutex);
598
599
600 container = event_queue.events.last;
601 for (; container != &event_queue.events; container = container->last)
602 {
603
604 if ((*predicate) (&container->event, arg))
605 {
606
607 *event_return = container->event;
608 --event_queue.num_events;
609
610
611 container->last->next = container->next;
612 container->next->last = container->last;
613 free (container);
614 pthread_mutex_unlock (&event_queue.mutex);
615 return true;
616 }
617 }
618
619 pthread_mutex_unlock (&event_queue.mutex);
620 return false;
621 }
622
623 void
624 android_write_event (union android_event *event)
625 {
626 struct android_event_container *container;
627
628 container = malloc (sizeof *container);
629
630 if (!container)
631 return;
632
633
634 if (!event_queue.events.next)
635 return;
636
637 pthread_mutex_lock (&event_queue.mutex);
638 container->next = event_queue.events.next;
639 container->last = &event_queue.events;
640 container->next->last = container;
641 container->last->next = container;
642 container->event = *event;
643 event_queue.num_events++;
644 pthread_cond_broadcast (&event_queue.read_var);
645 pthread_mutex_unlock (&event_queue.mutex);
646
647
648
649 pending_signals = true;
650
651 switch (event->type)
652 {
653
654
655
656 case ANDROID_KEY_PRESS:
657 case ANDROID_WINDOW_ACTION:
658 kill (getpid (), SIGIO);
659 break;
660
661 default:
662 break;
663 }
664 }
665
666
667
668
669
670
671 static bool android_urgent_query;
672
673 int
674 android_select (int nfds, fd_set *readfds, fd_set *writefds,
675 fd_set *exceptfds, struct timespec *timeout)
676 {
677 int nfds_return;
678 #if __ANDROID_API__ < 16
679 static char byte;
680 #endif
681
682
683
684
685 __atomic_clear (&android_urgent_query, __ATOMIC_RELEASE);
686
687
688
689 android_check_query ();
690
691 pthread_mutex_lock (&event_queue.mutex);
692
693 if (event_queue.num_events)
694 {
695 pthread_mutex_unlock (&event_queue.mutex);
696 return 1;
697 }
698
699 nfds_return = 0;
700
701 pthread_mutex_lock (&event_queue.select_mutex);
702 android_pselect_nfds = nfds;
703 android_pselect_readfds = readfds;
704 android_pselect_writefds = writefds;
705 android_pselect_exceptfds = exceptfds;
706 android_pselect_timeout = timeout;
707 pthread_mutex_unlock (&event_queue.select_mutex);
708
709
710 sem_post (&android_pselect_start_sem);
711
712
713 pthread_cond_wait (&event_queue.read_var, &event_queue.mutex);
714
715 #if __ANDROID_API__ >= 16
716
717
718 pthread_kill (event_queue.select_thread, SIGUSR1);
719 #else
720
721 if (write (select_pipe[1], &byte, 1) != 1)
722 __android_log_print (ANDROID_LOG_FATAL, __func__,
723 "write: %s", strerror (errno));
724 #endif
725
726
727 pthread_mutex_unlock (&event_queue.mutex);
728
729
730
731
732
733 while (sem_wait (&android_pselect_sem) < 0)
734 ;;
735
736
737
738 pthread_mutex_lock (&event_queue.mutex);
739 if (event_queue.num_events)
740 nfds_return = 1;
741 pthread_mutex_unlock (&event_queue.mutex);
742
743
744
745
746 if (android_pselect_rc >= 0)
747 nfds_return += android_pselect_rc;
748 else if (!nfds_return)
749
750
751
752 nfds_return = android_pselect_rc;
753
754 if ((android_pselect_rc < 0) && nfds_return >= 0)
755 {
756
757
758
759
760 if (readfds)
761 FD_ZERO (readfds);
762
763 if (writefds)
764 FD_ZERO (writefds);
765
766 if (exceptfds)
767 FD_ZERO (exceptfds);
768 }
769
770
771 if (nfds_return < 0)
772 errno = EINTR;
773
774
775
776 android_check_query ();
777
778 return nfds_return;
779 }
780
781
782
783 static void *
784 android_run_debug_thread (void *data)
785 {
786 FILE *file;
787 int fd;
788 char *line;
789 size_t n;
790
791 fd = (int) (intptr_t) data;
792 file = fdopen (fd, "r");
793
794 if (!file)
795 return NULL;
796
797 line = NULL;
798
799 while (true)
800 {
801 if (getline (&line, &n, file) < 0)
802 {
803 free (line);
804 break;
805 }
806
807 __android_log_print (ANDROID_LOG_INFO, __func__, "%s", line);
808 }
809
810 fclose (file);
811 return NULL;
812 }
813
814
815
816
817
818
819 char *
820 android_user_full_name (struct passwd *pw)
821 {
822 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
823 if (!pw->pw_gecos)
824 return (char *) "Android user";
825
826 return pw->pw_gecos;
827 #else
828 return "Android user";
829 #endif
830 }
831
832
833
834
835
836
837
838
839
840
841
842 const char *
843 android_is_special_directory (const char *name, const char *dir)
844 {
845 size_t len;
846
847
848
849 len = strlen (dir);
850 if (strncmp (name, dir, len))
851 return NULL;
852
853
854
855
856 name += len;
857 switch (*name)
858 {
859 case '\0':
860
861
862 return name;
863
864 case '/':
865
866
867 return name + 1;
868
869 default:
870
871 return NULL;
872 }
873 }
874
875 #if 0
876
877
878
879
880
881
882
883 static ssize_t
884 android_url_encode (const char *restrict string, size_t length,
885 char *restrict buffer, size_t n)
886 {
887 int len, character;
888 size_t num_encoded;
889 char *end;
890 char format[1 + 25];
891
892
893
894 end = string + length;
895 num_encoded = 0;
896
897 while (string < end)
898 {
899
900
901
902
903
904 len = 1;
905
906
907 if (!len || string + len > end)
908 goto failure;
909
910
911
912 character = *(unsigned char *) string;
913 string += len;
914
915
916
917
918 if (!((character >= 'A'
919 && character <= 'Z')
920 || (character >= 'a'
921 && character <= 'z')
922 || (character >= '0'
923 && character <= '9')
924 || character == '_'
925 || character == '-'
926 || character == '!'
927 || character == '.'
928 || character == '~'
929 || character == '\''
930 || character == '('
931 || character == ')'
932 || character == '*'))
933 {
934 len = sprintf (format, "%%%X", (unsigned int) character);
935 if (len < 0)
936 goto failure;
937
938
939
940
941 if (n < len)
942 goto failure;
943
944 n -= len;
945 num_encoded += len;
946
947
948 memcpy (buffer, format, n);
949 buffer += len;
950 }
951 else
952 {
953
954 if (!n)
955 goto failure;
956
957
958 n--, num_encoded++;
959 *(buffer++) = character;
960 }
961 }
962
963
964
965
966 if (!n || num_encoded > SSIZE_MAX)
967 goto failure;
968
969
970 *buffer = '\0';
971 return num_encoded;
972
973 failure:
974 return -1;
975 }
976
977
978
979
980
981
982 static const char *
983 android_get_content_name (const char *filename)
984 {
985 static char buffer[PATH_MAX + 1];
986 char *head, *token, *next, *saveptr, *copy, *mark, *mark1;
987 ssize_t rc;
988 size_t n, length;
989
990
991
992
993 filename = android_is_special_directory (filename, "/content");
994
995 if (!filename)
996 return NULL;
997
998 if (!*filename)
999 return "content://";
1000
1001
1002
1003
1004 copy = xstrdup (filename);
1005 mark = saveptr = NULL;
1006 head = stpcpy (buffer, "content:/");
1007
1008
1009
1010 token = strtok_r (copy, "/", &saveptr);
1011
1012 while (token)
1013 {
1014
1015
1016 n = PATH_MAX - (head - buffer);
1017
1018
1019
1020
1021 if (!n)
1022 goto failure;
1023
1024 *head++ = '/';
1025 n--;
1026
1027
1028 next = strtok_r (NULL, "/", &saveptr);
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 if (!next)
1047 {
1048
1049
1050 mark1 = strchr (token, '?');
1051
1052 while (mark1)
1053 {
1054 mark = mark1;
1055 mark1 = strchr (mark + 1, '?');
1056 }
1057 }
1058
1059 if (mark)
1060 {
1061
1062
1063
1064 rc = 0;
1065 if (mark > token)
1066 rc = android_url_encode (token, mark - token,
1067 head, n + 1);
1068
1069
1070
1071 if (rc < 0)
1072 goto failure;
1073
1074
1075
1076 n -= rc, head += rc;
1077 length = strlen (mark);
1078
1079 if (n < length)
1080 goto failure;
1081
1082 strcpy (head, mark);
1083
1084
1085
1086 break;
1087 }
1088 else
1089
1090 rc = android_url_encode (token, strlen (token),
1091 head, n + 1);
1092
1093 if (rc < 0)
1094 goto failure;
1095
1096 head += rc;
1097 token = next;
1098 }
1099
1100
1101
1102 xfree (copy);
1103 return buffer;
1104
1105 failure:
1106 xfree (copy);
1107 return NULL;
1108 }
1109
1110 #endif
1111
1112
1113
1114
1115 const char *
1116 android_get_home_directory (void)
1117 {
1118 return android_files_dir;
1119 }
1120
1121
1122
1123
1124
1125 static char *
1126 android_proc_name (int fd)
1127 {
1128 char format[sizeof "/proc/self/fd/"
1129 + INT_STRLEN_BOUND (int)];
1130 static struct allocator allocator = {
1131
1132
1133 malloc, realloc, free, NULL,
1134 };
1135
1136 sprintf (format, "/proc/self/fd/%d", fd);
1137 return careadlinkat (AT_FDCWD, format, NULL, 0,
1138 &allocator, readlinkat);
1139 }
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154 static void
1155 android_create_lib_link (void)
1156 {
1157 char *filename;
1158 char lib_directory[PATH_MAX];
1159 int fd;
1160
1161
1162 filename = dirname (android_files_dir);
1163 if (!filename)
1164 goto failure;
1165
1166
1167
1168 snprintf (lib_directory, PATH_MAX, "%s/lib", filename);
1169
1170
1171 fd = open (lib_directory, O_DIRECTORY);
1172
1173
1174
1175 if (fd >= 0)
1176 goto success;
1177
1178
1179
1180 unlink (lib_directory);
1181
1182
1183
1184
1185 if (symlink (android_lib_dir, lib_directory))
1186
1187 __android_log_print (ANDROID_LOG_WARN, __func__,
1188 "Failed to create symbolic link from"
1189 " application library directory `%s'"
1190 " to its actual location at `%s'",
1191 lib_directory, android_files_dir);
1192
1193 success:
1194 close (fd);
1195 failure:
1196 return;
1197 }
1198
1199
1200
1201
1202
1203 #ifdef __clang__
1204 #pragma clang diagnostic push
1205 #pragma clang diagnostic ignored "-Wmissing-prototypes"
1206 #else
1207 #pragma GCC diagnostic push
1208 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
1209 #endif
1210
1211 JNIEXPORT jint JNICALL
1212 NATIVE_NAME (dup) (JNIEnv *env, jobject object, jint fd)
1213 {
1214 JNI_STACK_ALIGNMENT_PROLOGUE;
1215
1216 return dup (fd);
1217 }
1218
1219 JNIEXPORT jstring JNICALL
1220 NATIVE_NAME (getFingerprint) (JNIEnv *env, jobject object)
1221 {
1222 JNI_STACK_ALIGNMENT_PROLOGUE;
1223
1224 char buffer[sizeof fingerprint * 2 + 1];
1225
1226 memset (buffer, 0, sizeof buffer);
1227 hexbuf_digest (buffer, (char *) fingerprint,
1228 sizeof fingerprint);
1229
1230 return (*env)->NewStringUTF (env, buffer);
1231 }
1232
1233 JNIEXPORT void JNICALL
1234 NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
1235 jobject local_asset_manager,
1236 jobject files_dir, jobject libs_dir,
1237 jobject cache_dir,
1238 jfloat pixel_density_x,
1239 jfloat pixel_density_y,
1240 jfloat scaled_density,
1241 jobject class_path,
1242 jobject emacs_service_object,
1243 jint api_level)
1244 {
1245 JNI_STACK_ALIGNMENT_PROLOGUE;
1246
1247 int pipefd[2];
1248 pthread_t thread;
1249 const char *java_string;
1250
1251
1252
1253 android_api_level = api_level;
1254
1255
1256
1257 android_pixel_density_x = pixel_density_x;
1258 android_pixel_density_y = pixel_density_y;
1259 android_scaled_pixel_density = scaled_density;
1260
1261 __android_log_print (ANDROID_LOG_INFO, __func__,
1262 "Initializing "PACKAGE_STRING"...\nPlease report bugs to "
1263 PACKAGE_BUGREPORT". Thanks.\n");
1264
1265 if (emacs_service_object)
1266 {
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278 if (pipe2 (pipefd, O_CLOEXEC) < 0)
1279 emacs_abort ();
1280
1281 if (dup2 (pipefd[1], 2) < 0)
1282 emacs_abort ();
1283 close (pipefd[1]);
1284
1285 if (pthread_create (&thread, NULL, android_run_debug_thread,
1286 (void *) (intptr_t) pipefd[0]))
1287 emacs_abort ();
1288 }
1289
1290
1291
1292 java_string = (*env)->GetStringUTFChars (env, (jstring) files_dir,
1293 NULL);
1294
1295 if (!java_string)
1296 emacs_abort ();
1297
1298 android_files_dir = strdup ((const char *) java_string);
1299
1300 if (!android_files_dir)
1301 emacs_abort ();
1302
1303 (*env)->ReleaseStringUTFChars (env, (jstring) files_dir,
1304 java_string);
1305
1306 java_string = (*env)->GetStringUTFChars (env, (jstring) libs_dir,
1307 NULL);
1308
1309 if (!java_string)
1310 emacs_abort ();
1311
1312 android_lib_dir = strdup ((const char *) java_string);
1313
1314 if (!android_files_dir)
1315 emacs_abort ();
1316
1317 (*env)->ReleaseStringUTFChars (env, (jstring) libs_dir,
1318 java_string);
1319
1320 java_string = (*env)->GetStringUTFChars (env, (jstring) cache_dir,
1321 NULL);
1322
1323 if (!java_string)
1324 emacs_abort ();
1325
1326 android_cache_dir = strdup ((const char *) java_string);
1327
1328 if (!android_files_dir)
1329 emacs_abort ();
1330
1331 (*env)->ReleaseStringUTFChars (env, (jstring) cache_dir,
1332 java_string);
1333
1334 if (class_path)
1335 {
1336 java_string = (*env)->GetStringUTFChars (env, (jstring) class_path,
1337 NULL);
1338
1339 if (!java_string)
1340 emacs_abort ();
1341
1342 android_class_path = strdup ((const char *) java_string);
1343
1344 if (!android_files_dir)
1345 emacs_abort ();
1346
1347 (*env)->ReleaseStringUTFChars (env, (jstring) class_path,
1348 java_string);
1349 }
1350
1351
1352
1353 android_site_load_path = malloc (PATH_MAX + 1);
1354
1355 if (!android_site_load_path)
1356 emacs_abort ();
1357
1358 android_game_path = malloc (PATH_MAX + 1);
1359
1360 if (!android_game_path)
1361 emacs_abort ();
1362
1363 snprintf (android_site_load_path, PATH_MAX, "%s/site-lisp",
1364 android_files_dir);
1365 snprintf (android_game_path, PATH_MAX, "%s/scores", android_files_dir);
1366
1367 __android_log_print (ANDROID_LOG_INFO, __func__,
1368 "Site-lisp directory: %s\n"
1369 "Files directory: %s\n"
1370 "Native code directory: %s\n"
1371 "Game score path: %s\n"
1372 "Class path: %s\n",
1373 android_site_load_path,
1374 android_files_dir,
1375 android_lib_dir, android_game_path,
1376 (android_class_path
1377 ? android_class_path
1378 : "None"));
1379
1380 if (android_class_path)
1381
1382
1383 setenv ("EMACS_CLASS_PATH", android_class_path, 1);
1384
1385
1386 setenv ("LD_LIBRARY_PATH", android_lib_dir, 1);
1387
1388
1389
1390
1391
1392 setenv ("EMACS_LD_LIBRARY_PATH", android_lib_dir, 1);
1393
1394
1395
1396 if (emacs_service_object)
1397 {
1398 emacs_service = (*env)->NewGlobalRef (env, emacs_service_object);
1399
1400 if (!emacs_service)
1401 emacs_abort ();
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411 android_create_lib_link ();
1412 }
1413
1414
1415 android_init_events ();
1416
1417
1418 android_vfs_init (env, local_asset_manager);
1419
1420
1421
1422 }
1423
1424 JNIEXPORT jobject JNICALL
1425 NATIVE_NAME (getProcName) (JNIEnv *env, jobject object, jint fd)
1426 {
1427 JNI_STACK_ALIGNMENT_PROLOGUE;
1428
1429 char *buffer;
1430 size_t length;
1431 jbyteArray array;
1432
1433 buffer = android_proc_name (fd);
1434 if (!buffer)
1435 return NULL;
1436
1437
1438
1439 length = strlen (buffer);
1440 array = (*env)->NewByteArray (env, length);
1441 if (!array)
1442 goto finish;
1443
1444 (*env)->SetByteArrayRegion (env, array, 0, length,
1445 (jbyte *) buffer);
1446
1447 finish:
1448 free (buffer);
1449 return array;
1450 }
1451
1452
1453
1454 static void
1455 android_init_emacs_service (void)
1456 {
1457 jclass old;
1458
1459 service_class.class
1460 = (*android_java_env)->FindClass (android_java_env,
1461 "org/gnu/emacs/EmacsService");
1462 eassert (service_class.class);
1463
1464 old = service_class.class;
1465 service_class.class
1466 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
1467 (jobject) old);
1468 ANDROID_DELETE_LOCAL_REF (old);
1469
1470 if (!service_class.class)
1471 emacs_abort ();
1472
1473 #define FIND_METHOD(c_name, name, signature) \
1474 service_class.c_name \
1475 = (*android_java_env)->GetMethodID (android_java_env, \
1476 service_class.class, \
1477 name, signature); \
1478 assert (service_class.c_name);
1479
1480 FIND_METHOD (fill_rectangle, "fillRectangle",
1481 "(Lorg/gnu/emacs/EmacsDrawable;"
1482 "Lorg/gnu/emacs/EmacsGC;IIII)V");
1483 FIND_METHOD (fill_polygon, "fillPolygon",
1484 "(Lorg/gnu/emacs/EmacsDrawable;"
1485 "Lorg/gnu/emacs/EmacsGC;"
1486 "[Landroid/graphics/Point;)V");
1487 FIND_METHOD (draw_rectangle, "drawRectangle",
1488 "(Lorg/gnu/emacs/EmacsDrawable;"
1489 "Lorg/gnu/emacs/EmacsGC;IIII)V");
1490 FIND_METHOD (draw_line, "drawLine",
1491 "(Lorg/gnu/emacs/EmacsDrawable;"
1492 "Lorg/gnu/emacs/EmacsGC;IIII)V");
1493 FIND_METHOD (draw_point, "drawPoint",
1494 "(Lorg/gnu/emacs/EmacsDrawable;"
1495 "Lorg/gnu/emacs/EmacsGC;II)V");
1496 FIND_METHOD (clear_window, "clearWindow",
1497 "(Lorg/gnu/emacs/EmacsWindow;)V");
1498 FIND_METHOD (clear_area, "clearArea",
1499 "(Lorg/gnu/emacs/EmacsWindow;IIII)V");
1500 FIND_METHOD (ring_bell, "ringBell", "()V");
1501 FIND_METHOD (query_tree, "queryTree",
1502 "(Lorg/gnu/emacs/EmacsWindow;)[S");
1503 FIND_METHOD (get_screen_width, "getScreenWidth", "(Z)I");
1504 FIND_METHOD (get_screen_height, "getScreenHeight", "(Z)I");
1505 FIND_METHOD (detect_mouse, "detectMouse", "()Z");
1506 FIND_METHOD (name_keysym, "nameKeysym", "(I)Ljava/lang/String;");
1507 FIND_METHOD (browse_url, "browseUrl", "(Ljava/lang/String;Z)"
1508 "Ljava/lang/String;");
1509 FIND_METHOD (restart_emacs, "restartEmacs", "()V");
1510 FIND_METHOD (update_ic, "updateIC",
1511 "(Lorg/gnu/emacs/EmacsWindow;IIII)V");
1512 FIND_METHOD (reset_ic, "resetIC",
1513 "(Lorg/gnu/emacs/EmacsWindow;I)V");
1514 FIND_METHOD (open_content_uri, "openContentUri",
1515 "([BZZZ)I");
1516 FIND_METHOD (check_content_uri, "checkContentUri",
1517 "(Ljava/lang/String;ZZ)Z");
1518 FIND_METHOD (query_battery, "queryBattery", "()[J");
1519 FIND_METHOD (update_extracted_text, "updateExtractedText",
1520 "(Lorg/gnu/emacs/EmacsWindow;"
1521 "Landroid/view/inputmethod/ExtractedText;I)V");
1522 FIND_METHOD (update_cursor_anchor_info, "updateCursorAnchorInfo",
1523 "(Lorg/gnu/emacs/EmacsWindow;FFFF)V");
1524 FIND_METHOD (get_document_authorities, "getDocumentAuthorities",
1525 "()[Ljava/lang/String;");
1526 FIND_METHOD (request_directory_access, "requestDirectoryAccess",
1527 "()I");
1528 FIND_METHOD (get_document_trees, "getDocumentTrees",
1529 "([B)[Ljava/lang/String;");
1530 FIND_METHOD (document_id_from_name, "documentIdFromName",
1531 "(Ljava/lang/String;Ljava/lang/String;"
1532 "[Ljava/lang/String;)I");
1533 FIND_METHOD (get_tree_uri, "getTreeUri",
1534 "(Ljava/lang/String;Ljava/lang/String;)"
1535 "Ljava/lang/String;");
1536 FIND_METHOD (stat_document, "statDocument",
1537 "(Ljava/lang/String;Ljava/lang/String;Z)[J");
1538 FIND_METHOD (access_document, "accessDocument",
1539 "(Ljava/lang/String;Ljava/lang/String;Z)I");
1540 FIND_METHOD (open_document_directory, "openDocumentDirectory",
1541 "(Ljava/lang/String;Ljava/lang/String;)"
1542 "Landroid/database/Cursor;");
1543 FIND_METHOD (read_directory_entry, "readDirectoryEntry",
1544 "(Landroid/database/Cursor;)Lorg/gnu/emacs/"
1545 "EmacsDirectoryEntry;");
1546 FIND_METHOD (open_document, "openDocument",
1547 "(Ljava/lang/String;Ljava/lang/String;ZZZ)"
1548 "Landroid/os/ParcelFileDescriptor;");
1549 FIND_METHOD (create_document, "createDocument",
1550 "(Ljava/lang/String;Ljava/lang/String;"
1551 "Ljava/lang/String;)Ljava/lang/String;");
1552 FIND_METHOD (create_directory, "createDirectory",
1553 "(Ljava/lang/String;Ljava/lang/String;"
1554 "Ljava/lang/String;)Ljava/lang/String;");
1555 FIND_METHOD (delete_document, "deleteDocument",
1556 "(Ljava/lang/String;Ljava/lang/String;"
1557 "Ljava/lang/String;)I");
1558 FIND_METHOD (rename_document, "renameDocument",
1559 "(Ljava/lang/String;Ljava/lang/String;"
1560 "Ljava/lang/String;Ljava/lang/String;)I");
1561 FIND_METHOD (move_document, "moveDocument",
1562 "(Ljava/lang/String;Ljava/lang/String;"
1563 "Ljava/lang/String;Ljava/lang/String;"
1564 "Ljava/lang/String;)Ljava/lang/String;");
1565 FIND_METHOD (valid_authority, "validAuthority",
1566 "(Ljava/lang/String;)Z");
1567 #undef FIND_METHOD
1568 }
1569
1570 static void
1571 android_init_emacs_pixmap (void)
1572 {
1573 jclass old;
1574
1575 pixmap_class.class
1576 = (*android_java_env)->FindClass (android_java_env,
1577 "org/gnu/emacs/EmacsPixmap");
1578 eassert (pixmap_class.class);
1579
1580 old = pixmap_class.class;
1581 pixmap_class.class
1582 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
1583 (jobject) old);
1584 ANDROID_DELETE_LOCAL_REF (old);
1585
1586 if (!pixmap_class.class)
1587 emacs_abort ();
1588
1589 #define FIND_METHOD(c_name, name, signature) \
1590 pixmap_class.c_name \
1591 = (*android_java_env)->GetMethodID (android_java_env, \
1592 pixmap_class.class, \
1593 name, signature); \
1594 assert (pixmap_class.c_name);
1595
1596 FIND_METHOD (constructor, "<init>", "(S[IIII)V");
1597 FIND_METHOD (constructor_mutable, "<init>", "(SIII)V");
1598
1599 #undef FIND_METHOD
1600 }
1601
1602 static void
1603 android_init_graphics_point (void)
1604 {
1605 jclass old;
1606
1607 point_class.class
1608 = (*android_java_env)->FindClass (android_java_env,
1609 "android/graphics/Point");
1610 eassert (point_class.class);
1611
1612 old = point_class.class;
1613 point_class.class
1614 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
1615 (jobject) old);
1616 ANDROID_DELETE_LOCAL_REF (old);
1617
1618 if (!point_class.class)
1619 emacs_abort ();
1620
1621 #define FIND_METHOD(c_name, name, signature) \
1622 point_class.c_name \
1623 = (*android_java_env)->GetMethodID (android_java_env, \
1624 point_class.class, \
1625 name, signature); \
1626 assert (point_class.c_name);
1627
1628 FIND_METHOD (constructor, "<init>", "(II)V");
1629 #undef FIND_METHOD
1630 }
1631
1632 static void
1633 android_init_emacs_drawable (void)
1634 {
1635 jclass old;
1636
1637 drawable_class.class
1638 = (*android_java_env)->FindClass (android_java_env,
1639 "org/gnu/emacs/EmacsDrawable");
1640 eassert (drawable_class.class);
1641
1642 old = drawable_class.class;
1643 drawable_class.class
1644 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
1645 (jobject) old);
1646 ANDROID_DELETE_LOCAL_REF (old);
1647
1648 if (!drawable_class.class)
1649 emacs_abort ();
1650
1651 #define FIND_METHOD(c_name, name, signature) \
1652 drawable_class.c_name \
1653 = (*android_java_env)->GetMethodID (android_java_env, \
1654 drawable_class.class, \
1655 name, signature); \
1656 assert (drawable_class.c_name);
1657
1658 FIND_METHOD (get_bitmap, "getBitmap", "()Landroid/graphics/Bitmap;");
1659 FIND_METHOD (damage_rect, "damageRect", "(Landroid/graphics/Rect;)V");
1660 #undef FIND_METHOD
1661 }
1662
1663 static void
1664 android_init_emacs_window (void)
1665 {
1666 jclass old;
1667
1668 window_class.class
1669 = (*android_java_env)->FindClass (android_java_env,
1670 "org/gnu/emacs/EmacsWindow");
1671 eassert (window_class.class);
1672
1673 old = window_class.class;
1674 window_class.class
1675 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
1676 (jobject) old);
1677 ANDROID_DELETE_LOCAL_REF (old);
1678
1679 if (!window_class.class)
1680 emacs_abort ();
1681
1682 #define FIND_METHOD(c_name, name, signature) \
1683 window_class.c_name \
1684 = (*android_java_env)->GetMethodID (android_java_env, \
1685 window_class.class, \
1686 name, signature); \
1687 assert (window_class.c_name);
1688
1689 FIND_METHOD (swap_buffers, "swapBuffers", "()V");
1690 FIND_METHOD (toggle_on_screen_keyboard,
1691 "toggleOnScreenKeyboard", "(Z)V");
1692 FIND_METHOD (lookup_string, "lookupString", "(I)Ljava/lang/String;");
1693 FIND_METHOD (set_fullscreen, "setFullscreen", "(Z)V");
1694 FIND_METHOD (change_window_background, "changeWindowBackground",
1695 "(I)V");
1696 FIND_METHOD (reparent_to, "reparentTo",
1697 "(Lorg/gnu/emacs/EmacsWindow;II)V");
1698 FIND_METHOD (map_window, "mapWindow", "()V");
1699 FIND_METHOD (unmap_window, "unmapWindow", "()V");
1700 FIND_METHOD (resize_window, "resizeWindow", "(II)V");
1701 FIND_METHOD (move_window, "moveWindow", "(II)V");
1702 FIND_METHOD (make_input_focus, "makeInputFocus", "(J)V");
1703 FIND_METHOD (raise, "raise", "()V");
1704 FIND_METHOD (lower, "lower", "()V");
1705 FIND_METHOD (get_window_geometry, "getWindowGeometry",
1706 "()[I");
1707 FIND_METHOD (translate_coordinates, "translateCoordinates",
1708 "(II)[I");
1709 FIND_METHOD (set_dont_focus_on_map, "setDontFocusOnMap", "(Z)V");
1710 FIND_METHOD (set_dont_accept_focus, "setDontAcceptFocus", "(Z)V");
1711 FIND_METHOD (define_cursor, "defineCursor",
1712 "(Lorg/gnu/emacs/EmacsCursor;)V");
1713 #undef FIND_METHOD
1714 }
1715
1716 static void
1717 android_init_emacs_cursor (void)
1718 {
1719 jclass old;
1720
1721 cursor_class.class
1722 = (*android_java_env)->FindClass (android_java_env,
1723 "org/gnu/emacs/EmacsCursor");
1724 eassert (cursor_class.class);
1725
1726 old = cursor_class.class;
1727 cursor_class.class
1728 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
1729 (jobject) old);
1730 ANDROID_DELETE_LOCAL_REF (old);
1731
1732 if (!cursor_class.class)
1733 emacs_abort ();
1734
1735 #define FIND_METHOD(c_name, name, signature) \
1736 cursor_class.c_name \
1737 = (*android_java_env)->GetMethodID (android_java_env, \
1738 cursor_class.class, \
1739 name, signature); \
1740 assert (cursor_class.c_name);
1741
1742 FIND_METHOD (constructor, "<init>", "(SI)V");
1743 #undef FIND_METHOD
1744 }
1745
1746 JNIEXPORT void JNICALL
1747 NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv,
1748 jobject dump_file_object)
1749 {
1750
1751
1752
1753
1754
1755
1756
1757 JNI_STACK_ALIGNMENT_PROLOGUE;
1758
1759 char **c_argv;
1760 jsize nelements, i;
1761 jobject argument;
1762 const char *c_argument;
1763 char *dump_file;
1764
1765 android_java_env = env;
1766
1767 nelements = (*env)->GetArrayLength (env, argv);
1768 c_argv = alloca (sizeof *c_argv * nelements);
1769
1770 for (i = 0; i < nelements; ++i)
1771 {
1772 argument = (*env)->GetObjectArrayElement (env, argv, i);
1773 c_argument = (*env)->GetStringUTFChars (env, (jstring) argument,
1774 NULL);
1775
1776 if (!c_argument)
1777 emacs_abort ();
1778
1779
1780
1781 c_argv[i] = alloca (strlen (c_argument) + 1);
1782 strcpy (c_argv[i], c_argument);
1783 (*env)->ReleaseStringUTFChars (env, (jstring) argument, c_argument);
1784 }
1785
1786 android_init_emacs_service ();
1787 android_init_emacs_pixmap ();
1788 android_init_graphics_point ();
1789 android_init_emacs_drawable ();
1790 android_init_emacs_window ();
1791 android_init_emacs_cursor ();
1792
1793
1794 setenv ("HOME", android_files_dir, 1);
1795
1796
1797 setenv ("TMPDIR", android_cache_dir, 1);
1798
1799
1800
1801 setenv ("SHELL", "/system/bin/sh", 1);
1802
1803
1804 if (chdir (android_files_dir))
1805 __android_log_print (ANDROID_LOG_WARN, __func__,
1806 "chdir: %s", strerror (errno));
1807
1808
1809
1810
1811 if (emacs_service)
1812 android_init_gui = true;
1813
1814
1815 dump_file = NULL;
1816
1817 if (dump_file_object)
1818 {
1819 c_argument
1820 = (*env)->GetStringUTFChars (env, (jstring) dump_file_object,
1821 NULL);
1822
1823
1824 dump_file = strdup (c_argument);
1825
1826
1827 (*env)->ReleaseStringUTFChars (env, (jstring) dump_file_object,
1828 c_argument);
1829 }
1830
1831
1832 ANDROID_DELETE_LOCAL_REF (argv);
1833 ANDROID_DELETE_LOCAL_REF (dump_file_object);
1834
1835
1836
1837
1838 if (signal_mask_changed_p)
1839 pthread_sigmask (SIG_SETMASK, &startup_signal_mask, NULL);
1840
1841
1842 android_emacs_init (nelements, c_argv, dump_file);
1843
1844
1845 emacs_abort ();
1846 }
1847
1848 JNIEXPORT void JNICALL
1849 NATIVE_NAME (emacsAbort) (JNIEnv *env, jobject object)
1850 {
1851 JNI_STACK_ALIGNMENT_PROLOGUE;
1852
1853 emacs_abort ();
1854 }
1855
1856 JNIEXPORT void JNICALL
1857 NATIVE_NAME (quit) (JNIEnv *env, jobject object)
1858 {
1859 JNI_STACK_ALIGNMENT_PROLOGUE;
1860
1861 __android_log_print (ANDROID_LOG_VERBOSE, __func__,
1862 "Sending SIGIO and setting Vquit_flag");
1863
1864
1865
1866 Vquit_flag = Qt;
1867 kill (getpid (), SIGIO);
1868 }
1869
1870 JNIEXPORT jlong JNICALL
1871 NATIVE_NAME (sendConfigureNotify) (JNIEnv *env, jobject object,
1872 jshort window, jlong time,
1873 jint x, jint y, jint width,
1874 jint height)
1875 {
1876 JNI_STACK_ALIGNMENT_PROLOGUE;
1877
1878 union android_event event;
1879
1880 event.xconfigure.type = ANDROID_CONFIGURE_NOTIFY;
1881 event.xconfigure.serial = ++event_serial;
1882 event.xconfigure.window = window;
1883 event.xconfigure.time = time;
1884 event.xconfigure.x = x;
1885 event.xconfigure.y = y;
1886 event.xconfigure.width = width;
1887 event.xconfigure.height = height;
1888
1889 android_write_event (&event);
1890 return event_serial;
1891 }
1892
1893 JNIEXPORT jlong JNICALL
1894 NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object,
1895 jshort window, jlong time,
1896 jint state, jint keycode,
1897 jint unicode_char)
1898 {
1899 JNI_STACK_ALIGNMENT_PROLOGUE;
1900
1901 union android_event event;
1902
1903 event.xkey.type = ANDROID_KEY_PRESS;
1904 event.xkey.serial = ++event_serial;
1905 event.xkey.window = window;
1906 event.xkey.time = time;
1907 event.xkey.state = state;
1908 event.xkey.keycode = keycode;
1909 event.xkey.unicode_char = unicode_char;
1910 event.xkey.counter = 0;
1911
1912 android_write_event (&event);
1913 return event_serial;
1914 }
1915
1916 JNIEXPORT jlong JNICALL
1917 NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object,
1918 jshort window, jlong time,
1919 jint state, jint keycode,
1920 jint unicode_char)
1921 {
1922 JNI_STACK_ALIGNMENT_PROLOGUE;
1923
1924 union android_event event;
1925
1926 event.xkey.type = ANDROID_KEY_RELEASE;
1927 event.xkey.serial = ++event_serial;
1928 event.xkey.window = window;
1929 event.xkey.time = time;
1930 event.xkey.state = state;
1931 event.xkey.keycode = keycode;
1932 event.xkey.unicode_char = unicode_char;
1933 event.xkey.counter = 0;
1934
1935 android_write_event (&event);
1936 return event_serial;
1937 }
1938
1939 JNIEXPORT jlong JNICALL
1940 NATIVE_NAME (sendFocusIn) (JNIEnv *env, jobject object,
1941 jshort window, jlong time)
1942 {
1943 JNI_STACK_ALIGNMENT_PROLOGUE;
1944
1945 union android_event event;
1946
1947 event.xfocus.type = ANDROID_FOCUS_IN;
1948 event.xfocus.serial = ++event_serial;
1949 event.xfocus.window = window;
1950 event.xfocus.time = time;
1951
1952 android_write_event (&event);
1953 return event_serial;
1954 }
1955
1956 JNIEXPORT jlong JNICALL
1957 NATIVE_NAME (sendFocusOut) (JNIEnv *env, jobject object,
1958 jshort window, jlong time)
1959 {
1960 JNI_STACK_ALIGNMENT_PROLOGUE;
1961
1962 union android_event event;
1963
1964 event.xfocus.type = ANDROID_FOCUS_OUT;
1965 event.xfocus.serial = ++event_serial;
1966 event.xfocus.window = window;
1967 event.xfocus.time = time;
1968
1969 android_write_event (&event);
1970 return ++event_serial;
1971 }
1972
1973 JNIEXPORT jlong JNICALL
1974 NATIVE_NAME (sendWindowAction) (JNIEnv *env, jobject object,
1975 jshort window, jint action)
1976 {
1977 JNI_STACK_ALIGNMENT_PROLOGUE;
1978
1979 union android_event event;
1980
1981 event.xaction.type = ANDROID_WINDOW_ACTION;
1982 event.xaction.serial = ++event_serial;
1983 event.xaction.window = window;
1984 event.xaction.action = action;
1985
1986 android_write_event (&event);
1987 return event_serial;
1988 }
1989
1990 JNIEXPORT jlong JNICALL
1991 NATIVE_NAME (sendEnterNotify) (JNIEnv *env, jobject object,
1992 jshort window, jint x, jint y,
1993 jlong time)
1994 {
1995 JNI_STACK_ALIGNMENT_PROLOGUE;
1996
1997 union android_event event;
1998
1999 event.xcrossing.type = ANDROID_ENTER_NOTIFY;
2000 event.xcrossing.serial = ++event_serial;
2001 event.xcrossing.window = window;
2002 event.xcrossing.x = x;
2003 event.xcrossing.y = y;
2004 event.xcrossing.time = time;
2005
2006 android_write_event (&event);
2007 return event_serial;
2008 }
2009
2010 JNIEXPORT jlong JNICALL
2011 NATIVE_NAME (sendLeaveNotify) (JNIEnv *env, jobject object,
2012 jshort window, jint x, jint y,
2013 jlong time)
2014 {
2015 JNI_STACK_ALIGNMENT_PROLOGUE;
2016
2017 union android_event event;
2018
2019 event.xcrossing.type = ANDROID_LEAVE_NOTIFY;
2020 event.xcrossing.serial = ++event_serial;
2021 event.xcrossing.window = window;
2022 event.xcrossing.x = x;
2023 event.xcrossing.y = y;
2024 event.xcrossing.time = time;
2025
2026 android_write_event (&event);
2027 return event_serial;
2028 }
2029
2030 JNIEXPORT jlong JNICALL
2031 NATIVE_NAME (sendMotionNotify) (JNIEnv *env, jobject object,
2032 jshort window, jint x, jint y,
2033 jlong time)
2034 {
2035 JNI_STACK_ALIGNMENT_PROLOGUE;
2036
2037 union android_event event;
2038
2039 event.xmotion.type = ANDROID_MOTION_NOTIFY;
2040 event.xmotion.serial = ++event_serial;
2041 event.xmotion.window = window;
2042 event.xmotion.x = x;
2043 event.xmotion.y = y;
2044 event.xmotion.time = time;
2045
2046 android_write_event (&event);
2047 return event_serial;
2048 }
2049
2050 JNIEXPORT jlong JNICALL
2051 NATIVE_NAME (sendButtonPress) (JNIEnv *env, jobject object,
2052 jshort window, jint x, jint y,
2053 jlong time, jint state,
2054 jint button)
2055 {
2056 JNI_STACK_ALIGNMENT_PROLOGUE;
2057
2058 union android_event event;
2059
2060 event.xbutton.type = ANDROID_BUTTON_PRESS;
2061 event.xbutton.serial = ++event_serial;
2062 event.xbutton.window = window;
2063 event.xbutton.x = x;
2064 event.xbutton.y = y;
2065 event.xbutton.time = time;
2066 event.xbutton.state = state;
2067 event.xbutton.button = button;
2068
2069 android_write_event (&event);
2070 return event_serial;
2071 }
2072
2073 JNIEXPORT jlong JNICALL
2074 NATIVE_NAME (sendButtonRelease) (JNIEnv *env, jobject object,
2075 jshort window, jint x, jint y,
2076 jlong time, jint state,
2077 jint button)
2078 {
2079 JNI_STACK_ALIGNMENT_PROLOGUE;
2080
2081 union android_event event;
2082
2083 event.xbutton.type = ANDROID_BUTTON_RELEASE;
2084 event.xbutton.serial = ++event_serial;
2085 event.xbutton.window = window;
2086 event.xbutton.x = x;
2087 event.xbutton.y = y;
2088 event.xbutton.time = time;
2089 event.xbutton.state = state;
2090 event.xbutton.button = button;
2091
2092 android_write_event (&event);
2093 return event_serial;
2094 }
2095
2096 JNIEXPORT jlong JNICALL
2097 NATIVE_NAME (sendTouchDown) (JNIEnv *env, jobject object,
2098 jshort window, jint x, jint y,
2099 jlong time, jint pointer_id,
2100 jint flags)
2101 {
2102 JNI_STACK_ALIGNMENT_PROLOGUE;
2103
2104 union android_event event;
2105
2106 event.touch.type = ANDROID_TOUCH_DOWN;
2107 event.touch.serial = ++event_serial;
2108 event.touch.window = window;
2109 event.touch.x = x;
2110 event.touch.y = y;
2111 event.touch.time = time;
2112 event.touch.pointer_id = pointer_id;
2113 event.touch.flags = flags;
2114
2115 android_write_event (&event);
2116 return event_serial;
2117 }
2118
2119 JNIEXPORT jlong JNICALL
2120 NATIVE_NAME (sendTouchUp) (JNIEnv *env, jobject object,
2121 jshort window, jint x, jint y,
2122 jlong time, jint pointer_id,
2123 jint flags)
2124 {
2125 JNI_STACK_ALIGNMENT_PROLOGUE;
2126
2127 union android_event event;
2128
2129 event.touch.type = ANDROID_TOUCH_UP;
2130 event.touch.serial = ++event_serial;
2131 event.touch.window = window;
2132 event.touch.x = x;
2133 event.touch.y = y;
2134 event.touch.time = time;
2135 event.touch.pointer_id = pointer_id;
2136 event.touch.flags = flags;
2137
2138 android_write_event (&event);
2139 return event_serial;
2140 }
2141
2142 JNIEXPORT jlong JNICALL
2143 NATIVE_NAME (sendTouchMove) (JNIEnv *env, jobject object,
2144 jshort window, jint x, jint y,
2145 jlong time, jint pointer_id,
2146 jint flags)
2147 {
2148 JNI_STACK_ALIGNMENT_PROLOGUE;
2149
2150 union android_event event;
2151
2152 event.touch.type = ANDROID_TOUCH_MOVE;
2153 event.touch.serial = ++event_serial;
2154 event.touch.window = window;
2155 event.touch.x = x;
2156 event.touch.y = y;
2157 event.touch.time = time;
2158 event.touch.pointer_id = pointer_id;
2159 event.touch.flags = flags;
2160
2161 android_write_event (&event);
2162 return event_serial;
2163 }
2164
2165 JNIEXPORT jlong JNICALL
2166 NATIVE_NAME (sendWheel) (JNIEnv *env, jobject object,
2167 jshort window, jint x, jint y,
2168 jlong time, jint state,
2169 jfloat x_delta, jfloat y_delta)
2170 {
2171 JNI_STACK_ALIGNMENT_PROLOGUE;
2172
2173 union android_event event;
2174
2175 event.wheel.type = ANDROID_WHEEL;
2176 event.wheel.serial = ++event_serial;
2177 event.wheel.window = window;
2178 event.wheel.x = x;
2179 event.wheel.y = y;
2180 event.wheel.time = time;
2181 event.wheel.state = state;
2182 event.wheel.x_delta = x_delta;
2183 event.wheel.y_delta = y_delta;
2184
2185 android_write_event (&event);
2186 return event_serial;
2187 }
2188
2189 JNIEXPORT jlong JNICALL
2190 NATIVE_NAME (sendIconified) (JNIEnv *env, jobject object,
2191 jshort window)
2192 {
2193 JNI_STACK_ALIGNMENT_PROLOGUE;
2194
2195 union android_event event;
2196
2197 event.iconified.type = ANDROID_ICONIFIED;
2198 event.iconified.serial = ++event_serial;
2199 event.iconified.window = window;
2200
2201 android_write_event (&event);
2202 return event_serial;
2203 }
2204
2205 JNIEXPORT jlong JNICALL
2206 NATIVE_NAME (sendDeiconified) (JNIEnv *env, jobject object,
2207 jshort window)
2208 {
2209 JNI_STACK_ALIGNMENT_PROLOGUE;
2210
2211 union android_event event;
2212
2213 event.iconified.type = ANDROID_DEICONIFIED;
2214 event.iconified.serial = ++event_serial;
2215 event.iconified.window = window;
2216
2217 android_write_event (&event);
2218 return event_serial;
2219 }
2220
2221 JNIEXPORT jlong JNICALL
2222 NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object,
2223 jshort window, jint menu_event_id,
2224 jint menu_event_serial)
2225 {
2226 JNI_STACK_ALIGNMENT_PROLOGUE;
2227
2228 union android_event event;
2229
2230 event.menu.type = ANDROID_CONTEXT_MENU;
2231 event.menu.serial = ++event_serial;
2232 event.menu.window = window;
2233 event.menu.menu_event_id = menu_event_id;
2234 event.menu.menu_event_serial = menu_event_serial;
2235
2236 android_write_event (&event);
2237 return event_serial;
2238 }
2239
2240 JNIEXPORT jlong JNICALL
2241 NATIVE_NAME (sendExpose) (JNIEnv *env, jobject object,
2242 jshort window, jint x, jint y,
2243 jint width, jint height)
2244 {
2245 JNI_STACK_ALIGNMENT_PROLOGUE;
2246
2247 union android_event event;
2248
2249 event.xexpose.type = ANDROID_EXPOSE;
2250 event.xexpose.serial = ++event_serial;
2251 event.xexpose.window = window;
2252 event.xexpose.x = x;
2253 event.xexpose.y = y;
2254 event.xexpose.width = width;
2255 event.xexpose.height = height;
2256
2257 android_write_event (&event);
2258 return event_serial;
2259 }
2260
2261 JNIEXPORT jboolean JNICALL
2262 NATIVE_NAME (shouldForwardMultimediaButtons) (JNIEnv *env,
2263 jobject object)
2264 {
2265
2266
2267 return !android_pass_multimedia_buttons_to_system;
2268 }
2269
2270 JNIEXPORT void JNICALL
2271 NATIVE_NAME (blitRect) (JNIEnv *env, jobject object,
2272 jobject src, jobject dest,
2273 jint x1, jint y1, jint x2, jint y2)
2274 {
2275 AndroidBitmapInfo src_info, dest_info;
2276 unsigned char *src_data_1, *dest_data_1;
2277 void *src_data, *dest_data;
2278
2279
2280
2281
2282
2283 memset (&src_info, 0, sizeof src_info);
2284 memset (&dest_info, 0, sizeof dest_info);
2285 AndroidBitmap_getInfo (env, src, &src_info);
2286 AndroidBitmap_getInfo (env, dest, &dest_info);
2287
2288
2289
2290
2291 if (!src_info.stride || !dest_info.stride)
2292 return;
2293
2294
2295 eassert (src_info.format == dest_info.format
2296 && src_info.format == ANDROID_BITMAP_FORMAT_RGBA_8888);
2297
2298
2299 src_data = NULL;
2300 AndroidBitmap_lockPixels (env, src, &src_data);
2301
2302 if (!src_data)
2303 return;
2304
2305 dest_data = NULL;
2306 AndroidBitmap_lockPixels (env, dest, &dest_data);
2307
2308 if (!dest_data)
2309 goto fail1;
2310
2311
2312
2313
2314 x1 = MAX (x1, 0);
2315 y1 = MAX (y1, 0);
2316 x2 = MAX (x2, 0);
2317 y2 = MAX (y2, 0);
2318
2319
2320 if (x1 >= src_info.width
2321 || x1 >= dest_info.width)
2322 x1 = MIN (dest_info.width - 1, src_info.width - 1);
2323
2324 if (x2 > src_info.width
2325 || x2 > dest_info.width)
2326 x2 = MIN (src_info.width, dest_info.width);
2327
2328 if (y1 >= src_info.height
2329 || y1 >= dest_info.height)
2330 y1 = MIN (dest_info.height - 1, src_info.height - 1);
2331
2332 if (y2 > src_info.height
2333 || y2 > dest_info.height)
2334 y2 = MIN (src_info.height, dest_info.height);
2335
2336 if (x1 >= x2 || y1 >= y2)
2337 goto fail2;
2338
2339
2340
2341 src_data_1 = src_data;
2342 dest_data_1 = dest_data;
2343 src_data_1 += x1 * 4;
2344 src_data_1 += y1 * src_info.stride;
2345 dest_data_1 += x1 * 4;
2346 dest_data_1 += y1 * dest_info.stride;
2347
2348
2349
2350 while (y1 != y2)
2351 {
2352 memcpy (dest_data_1, src_data_1, (x2 - x1) * 4);
2353 src_data_1 += src_info.stride;
2354 dest_data_1 += dest_info.stride;
2355 y1++;
2356 }
2357
2358
2359
2360 fail2:
2361 AndroidBitmap_unlockPixels (env, dest);
2362 fail1:
2363 AndroidBitmap_unlockPixels (env, src);
2364 }
2365
2366 JNIEXPORT void JNICALL
2367 NATIVE_NAME (notifyPixelsChanged) (JNIEnv *env, jobject object,
2368 jobject bitmap)
2369 {
2370 void *data;
2371
2372
2373
2374
2375 if (AndroidBitmap_lockPixels (env, bitmap, &data) < 0)
2376
2377
2378 return;
2379
2380 AndroidBitmap_unlockPixels (env, bitmap);
2381 }
2382
2383
2384
2385 static void android_begin_query (void);
2386 static void android_end_query (void);
2387 static void android_answer_query_spin (void);
2388
2389 JNIEXPORT void JNICALL
2390 NATIVE_NAME (beginSynchronous) (JNIEnv *env, jobject object)
2391 {
2392 JNI_STACK_ALIGNMENT_PROLOGUE;
2393
2394 android_begin_query ();
2395 }
2396
2397 JNIEXPORT void JNICALL
2398 NATIVE_NAME (endSynchronous) (JNIEnv *env, jobject object)
2399 {
2400 JNI_STACK_ALIGNMENT_PROLOGUE;
2401
2402 android_end_query ();
2403 }
2404
2405 JNIEXPORT void JNICALL
2406 NATIVE_NAME (answerQuerySpin) (JNIEnv *env, jobject object)
2407 {
2408 JNI_STACK_ALIGNMENT_PROLOGUE;
2409
2410 android_answer_query_spin ();
2411 }
2412
2413
2414
2415
2416
2417
2418
2419
2420 JNIEXPORT void JNICALL
2421 NATIVE_NAME (setupSystemThread) (void)
2422 {
2423 sigset_t sigset;
2424
2425
2426
2427
2428 sigfillset (&sigset);
2429 sigdelset (&sigset, SIGSEGV);
2430 sigdelset (&sigset, SIGBUS);
2431
2432
2433
2434
2435 if (pthread_sigmask (SIG_BLOCK, &sigset, &startup_signal_mask))
2436 __android_log_print (ANDROID_LOG_WARN, __func__,
2437 "pthread_sigmask: %s", strerror (errno));
2438 else
2439 signal_mask_changed_p = true;
2440 }
2441
2442 #ifdef __clang__
2443 #pragma clang diagnostic pop
2444 #else
2445 #pragma GCC diagnostic pop
2446 #endif
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458 struct android_handle_entry
2459 {
2460
2461 enum android_handle_type type;
2462
2463
2464 jobject handle;
2465 };
2466
2467
2468 struct android_handle_entry android_handles[USHRT_MAX];
2469
2470
2471
2472 static android_handle max_handle;
2473
2474
2475
2476
2477 static android_handle
2478 android_alloc_id (void)
2479 {
2480 android_handle handle;
2481
2482
2483
2484 if (!max_handle)
2485 max_handle++;
2486
2487
2488
2489 if (android_handles[max_handle].handle)
2490 {
2491
2492
2493 handle = max_handle;
2494 max_handle++;
2495
2496 while (handle != max_handle)
2497 {
2498 ++max_handle;
2499
2500
2501 if (!max_handle)
2502 ++max_handle;
2503
2504 if (!android_handles[max_handle].handle)
2505 return max_handle++;
2506 }
2507
2508 return ANDROID_NONE;
2509 }
2510
2511 return max_handle++;
2512 }
2513
2514
2515
2516
2517 static void
2518 android_destroy_handle (android_handle handle)
2519 {
2520 static jclass old, class;
2521 static jmethodID method;
2522
2523 if (!android_handles[handle].handle)
2524 {
2525 __android_log_print (ANDROID_LOG_ERROR, __func__,
2526 "Trying to destroy free handle!");
2527 emacs_abort ();
2528 }
2529
2530 if (!class)
2531 {
2532 class
2533 = (*android_java_env)->FindClass (android_java_env,
2534 "org/gnu/emacs/EmacsHandleObject");
2535 assert (class != NULL);
2536
2537 method
2538 = (*android_java_env)->GetMethodID (android_java_env, class,
2539 "destroyHandle", "()V");
2540 assert (method != NULL);
2541
2542 old = class;
2543 class
2544 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
2545 (jobject) class);
2546 android_exception_check_1 (old);
2547 ANDROID_DELETE_LOCAL_REF (old);
2548 }
2549
2550 (*android_java_env)->CallVoidMethod (android_java_env,
2551 android_handles[handle].handle,
2552 method);
2553
2554
2555
2556
2557 (*android_java_env)->ExceptionClear (android_java_env);
2558
2559
2560 (*android_java_env)->DeleteGlobalRef (android_java_env,
2561 android_handles[handle].handle);
2562 android_handles[handle].handle = NULL;
2563 }
2564
2565 jobject
2566 android_resolve_handle (android_handle handle,
2567 enum android_handle_type type)
2568 {
2569 if (!handle)
2570
2571 return NULL;
2572
2573
2574
2575
2576
2577 #ifdef ENABLE_CHECKING
2578
2579 if (!android_handles[handle].handle)
2580 {
2581 __android_log_print (ANDROID_LOG_ERROR, __func__,
2582 "Trying to resolve free handle!");
2583 emacs_abort ();
2584 }
2585
2586 if (android_handles[handle].type != type)
2587 {
2588 __android_log_print (ANDROID_LOG_ERROR, __func__,
2589 "Handle has wrong type!");
2590 emacs_abort ();
2591 }
2592
2593 #endif
2594
2595 return android_handles[handle].handle;
2596 }
2597
2598 static jobject
2599 android_resolve_handle2 (android_handle handle,
2600 enum android_handle_type type,
2601 enum android_handle_type type2)
2602 {
2603 if (!handle)
2604 return NULL;
2605
2606
2607
2608
2609
2610 #ifdef ENABLE_CHECKING
2611
2612 if (!android_handles[handle].handle)
2613 {
2614 __android_log_print (ANDROID_LOG_ERROR, __func__,
2615 "Trying to resolve free handle!");
2616 emacs_abort ();
2617 }
2618
2619 if (android_handles[handle].type != type
2620 && android_handles[handle].type != type2)
2621 {
2622 __android_log_print (ANDROID_LOG_ERROR, __func__,
2623 "Handle has wrong type!");
2624 emacs_abort ();
2625 }
2626
2627 #endif
2628
2629 return android_handles[handle].handle;
2630 }
2631
2632 void
2633 android_change_window_attributes (android_window handle,
2634 enum android_window_value_mask value_mask,
2635 struct android_set_window_attributes *attrs)
2636 {
2637 jmethodID method;
2638 jobject window;
2639 jint pixel;
2640
2641 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
2642
2643 if (value_mask & ANDROID_CW_BACK_PIXEL)
2644 {
2645 method = window_class.change_window_background;
2646 pixel = (jint) attrs->background_pixel;
2647 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
2648 window,
2649 window_class.class,
2650 method, pixel);
2651 android_exception_check ();
2652 }
2653 }
2654
2655
2656
2657
2658 android_window
2659 android_create_window (android_window parent, int x, int y,
2660 int width, int height,
2661 enum android_window_value_mask value_mask,
2662 struct android_set_window_attributes *attrs)
2663 {
2664 static jclass class;
2665 static jmethodID constructor;
2666 jobject object, parent_object, old;
2667 android_window window;
2668 android_handle prev_max_handle;
2669 bool override_redirect;
2670
2671 parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW);
2672
2673 prev_max_handle = max_handle;
2674 window = android_alloc_id ();
2675
2676 if (!window)
2677 error ("Out of window handles!");
2678
2679 if (!class)
2680 {
2681 class = (*android_java_env)->FindClass (android_java_env,
2682 "org/gnu/emacs/EmacsWindow");
2683 assert (class != NULL);
2684
2685 constructor
2686 = (*android_java_env)->GetMethodID (android_java_env, class, "<init>",
2687 "(SLorg/gnu/emacs/EmacsWindow;"
2688 "IIIIZ)V");
2689 assert (constructor != NULL);
2690
2691 old = class;
2692 class = (*android_java_env)->NewGlobalRef (android_java_env, class);
2693 android_exception_check_1 (old);
2694 ANDROID_DELETE_LOCAL_REF (old);
2695 }
2696
2697
2698
2699 override_redirect = ((value_mask
2700 & ANDROID_CW_OVERRIDE_REDIRECT)
2701 && attrs->override_redirect);
2702
2703 object = (*android_java_env)->NewObject (android_java_env, class,
2704 constructor, (jshort) window,
2705 parent_object, (jint) x, (jint) y,
2706 (jint) width, (jint) height,
2707 (jboolean) override_redirect);
2708 if (!object)
2709 {
2710 (*android_java_env)->ExceptionClear (android_java_env);
2711
2712 max_handle = prev_max_handle;
2713 memory_full (0);
2714 }
2715
2716 android_handles[window].type = ANDROID_HANDLE_WINDOW;
2717 android_handles[window].handle
2718 = (*android_java_env)->NewGlobalRef (android_java_env,
2719 object);
2720 (*android_java_env)->ExceptionClear (android_java_env);
2721 ANDROID_DELETE_LOCAL_REF (object);
2722
2723 if (!android_handles[window].handle)
2724 memory_full (0);
2725
2726 android_change_window_attributes (window, value_mask, attrs);
2727 return window;
2728 }
2729
2730 void
2731 android_set_window_background (android_window window, unsigned long pixel)
2732 {
2733 struct android_set_window_attributes attrs;
2734
2735 attrs.background_pixel = pixel;
2736 android_change_window_attributes (window, ANDROID_CW_BACK_PIXEL,
2737 &attrs);
2738 }
2739
2740 void
2741 android_destroy_window (android_window window)
2742 {
2743 if (android_handles[window].type != ANDROID_HANDLE_WINDOW)
2744 {
2745 __android_log_print (ANDROID_LOG_ERROR, __func__,
2746 "Trying to destroy something not a window!");
2747 emacs_abort ();
2748 }
2749
2750 android_destroy_handle (window);
2751 }
2752
2753 static void
2754 android_init_android_rect_class (void)
2755 {
2756 jclass old;
2757
2758 if (android_rect_class)
2759
2760 return;
2761
2762 android_rect_class
2763 = (*android_java_env)->FindClass (android_java_env,
2764 "android/graphics/Rect");
2765 assert (android_rect_class);
2766
2767 android_rect_constructor
2768 = (*android_java_env)->GetMethodID (android_java_env, android_rect_class,
2769 "<init>", "(IIII)V");
2770 assert (emacs_gc_constructor);
2771
2772 old = android_rect_class;
2773 android_rect_class
2774 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
2775 (jobject) android_rect_class);
2776 android_exception_check_1 (old);
2777 ANDROID_DELETE_LOCAL_REF (old);
2778 }
2779
2780 static void
2781 android_init_emacs_gc_class (void)
2782 {
2783 jclass old;
2784
2785 if (emacs_gc_class)
2786
2787 return;
2788
2789 emacs_gc_class
2790 = (*android_java_env)->FindClass (android_java_env,
2791 "org/gnu/emacs/EmacsGC");
2792 assert (emacs_gc_class);
2793
2794 emacs_gc_constructor
2795 = (*android_java_env)->GetMethodID (android_java_env,
2796 emacs_gc_class,
2797 "<init>", "(S)V");
2798 assert (emacs_gc_constructor);
2799
2800 emacs_gc_mark_dirty
2801 = (*android_java_env)->GetMethodID (android_java_env,
2802 emacs_gc_class,
2803 "markDirty", "(Z)V");
2804 assert (emacs_gc_mark_dirty);
2805
2806 old = emacs_gc_class;
2807 emacs_gc_class
2808 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
2809 (jobject) emacs_gc_class);
2810 android_exception_check_1 (old);
2811 ANDROID_DELETE_LOCAL_REF (old);
2812
2813 emacs_gc_foreground
2814 = (*android_java_env)->GetFieldID (android_java_env,
2815 emacs_gc_class,
2816 "foreground", "I");
2817 emacs_gc_background
2818 = (*android_java_env)->GetFieldID (android_java_env,
2819 emacs_gc_class,
2820 "background", "I");
2821 emacs_gc_function
2822 = (*android_java_env)->GetFieldID (android_java_env,
2823 emacs_gc_class,
2824 "function", "I");
2825 emacs_gc_clip_rects
2826 = (*android_java_env)->GetFieldID (android_java_env,
2827 emacs_gc_class,
2828 "clip_rects",
2829 "[Landroid/graphics/Rect;");
2830 emacs_gc_clip_x_origin
2831 = (*android_java_env)->GetFieldID (android_java_env,
2832 emacs_gc_class,
2833 "clip_x_origin", "I");
2834 emacs_gc_clip_y_origin
2835 = (*android_java_env)->GetFieldID (android_java_env,
2836 emacs_gc_class,
2837 "clip_y_origin", "I");
2838 emacs_gc_stipple
2839 = (*android_java_env)->GetFieldID (android_java_env,
2840 emacs_gc_class,
2841 "stipple",
2842 "Lorg/gnu/emacs/EmacsPixmap;");
2843 emacs_gc_clip_mask
2844 = (*android_java_env)->GetFieldID (android_java_env,
2845 emacs_gc_class,
2846 "clip_mask",
2847 "Lorg/gnu/emacs/EmacsPixmap;");
2848 emacs_gc_fill_style
2849 = (*android_java_env)->GetFieldID (android_java_env,
2850 emacs_gc_class,
2851 "fill_style", "I");
2852 emacs_gc_ts_origin_x
2853 = (*android_java_env)->GetFieldID (android_java_env,
2854 emacs_gc_class,
2855 "ts_origin_x", "I");
2856 emacs_gc_ts_origin_y
2857 = (*android_java_env)->GetFieldID (android_java_env,
2858 emacs_gc_class,
2859 "ts_origin_y", "I");
2860 }
2861
2862 struct android_gc *
2863 android_create_gc (enum android_gc_value_mask mask,
2864 struct android_gc_values *values)
2865 {
2866 struct android_gc *gc;
2867 android_handle prev_max_handle;
2868 jobject object;
2869
2870 android_init_emacs_gc_class ();
2871
2872 gc = xmalloc (sizeof *gc);
2873 prev_max_handle = max_handle;
2874 gc->gcontext = android_alloc_id ();
2875 gc->foreground = 0;
2876 gc->background = 0xffffff;
2877 gc->clip_rects = NULL;
2878
2879
2880 gc->num_clip_rects = -1;
2881
2882
2883 gc->function = ANDROID_GC_COPY;
2884 gc->fill_style = ANDROID_FILL_SOLID;
2885 gc->clip_x_origin = 0;
2886 gc->clip_y_origin = 0;
2887 gc->clip_mask = ANDROID_NONE;
2888 gc->stipple = ANDROID_NONE;
2889 gc->ts_x_origin = 0;
2890 gc->ts_y_origin = 0;
2891
2892 if (!gc->gcontext)
2893 {
2894 xfree (gc);
2895 error ("Out of GContext handles!");
2896 }
2897
2898 object = (*android_java_env)->NewObject (android_java_env,
2899 emacs_gc_class,
2900 emacs_gc_constructor,
2901 (jshort) gc->gcontext);
2902
2903 if (!object)
2904 {
2905 (*android_java_env)->ExceptionClear (android_java_env);
2906
2907 max_handle = prev_max_handle;
2908 memory_full (0);
2909 }
2910
2911 android_handles[gc->gcontext].type = ANDROID_HANDLE_GCONTEXT;
2912 android_handles[gc->gcontext].handle
2913 = (*android_java_env)->NewGlobalRef (android_java_env, object);
2914 (*android_java_env)->ExceptionClear (android_java_env);
2915 ANDROID_DELETE_LOCAL_REF (object);
2916
2917 if (!android_handles[gc->gcontext].handle)
2918 memory_full (0);
2919
2920 android_change_gc (gc, mask, values);
2921 return gc;
2922 }
2923
2924 void
2925 android_free_gc (struct android_gc *gc)
2926 {
2927 android_destroy_handle (gc->gcontext);
2928
2929 xfree (gc->clip_rects);
2930 xfree (gc);
2931 }
2932
2933 void
2934 android_change_gc (struct android_gc *gc,
2935 enum android_gc_value_mask mask,
2936 struct android_gc_values *values)
2937 {
2938 jobject what, gcontext;
2939 jboolean clip_changed;
2940
2941 clip_changed = false;
2942
2943 android_init_emacs_gc_class ();
2944 gcontext = android_resolve_handle (gc->gcontext,
2945 ANDROID_HANDLE_GCONTEXT);
2946
2947 if (mask & ANDROID_GC_FOREGROUND)
2948 {
2949 (*android_java_env)->SetIntField (android_java_env,
2950 gcontext,
2951 emacs_gc_foreground,
2952 values->foreground);
2953 gc->foreground = values->foreground;
2954 }
2955
2956 if (mask & ANDROID_GC_BACKGROUND)
2957 {
2958 (*android_java_env)->SetIntField (android_java_env,
2959 gcontext,
2960 emacs_gc_background,
2961 values->background);
2962 gc->background = values->background;
2963 }
2964
2965 if (mask & ANDROID_GC_FUNCTION)
2966 {
2967 (*android_java_env)->SetIntField (android_java_env,
2968 gcontext,
2969 emacs_gc_function,
2970 values->function);
2971 gc->function = values->function;
2972 }
2973
2974 if (mask & ANDROID_GC_CLIP_X_ORIGIN)
2975 {
2976 (*android_java_env)->SetIntField (android_java_env,
2977 gcontext,
2978 emacs_gc_clip_x_origin,
2979 values->clip_x_origin);
2980 gc->clip_x_origin = values->clip_x_origin;
2981 clip_changed = true;
2982 }
2983
2984 if (mask & ANDROID_GC_CLIP_Y_ORIGIN)
2985 {
2986 (*android_java_env)->SetIntField (android_java_env,
2987 gcontext,
2988 emacs_gc_clip_y_origin,
2989 values->clip_y_origin);
2990 gc->clip_y_origin = values->clip_y_origin;
2991 clip_changed = true;
2992 }
2993
2994 if (mask & ANDROID_GC_CLIP_MASK)
2995 {
2996 what = android_resolve_handle (values->clip_mask,
2997 ANDROID_HANDLE_PIXMAP);
2998 (*android_java_env)->SetObjectField (android_java_env,
2999 gcontext,
3000 emacs_gc_clip_mask,
3001 what);
3002 gc->clip_mask = values->clip_mask;
3003
3004
3005 (*android_java_env)->SetObjectField (android_java_env,
3006 gcontext,
3007 emacs_gc_clip_rects,
3008 NULL);
3009
3010 xfree (gc->clip_rects);
3011 gc->clip_rects = NULL;
3012 gc->num_clip_rects = -1;
3013 clip_changed = true;
3014 }
3015
3016 if (mask & ANDROID_GC_STIPPLE)
3017 {
3018 what = android_resolve_handle (values->stipple,
3019 ANDROID_HANDLE_PIXMAP);
3020 (*android_java_env)->SetObjectField (android_java_env,
3021 gcontext,
3022 emacs_gc_stipple,
3023 what);
3024 gc->stipple = values->stipple;
3025 }
3026
3027 if (mask & ANDROID_GC_FILL_STYLE)
3028 {
3029 (*android_java_env)->SetIntField (android_java_env,
3030 gcontext,
3031 emacs_gc_fill_style,
3032 values->fill_style);
3033 gc->fill_style = values->fill_style;
3034 }
3035
3036 if (mask & ANDROID_GC_TILE_STIP_X_ORIGIN)
3037 {
3038 (*android_java_env)->SetIntField (android_java_env,
3039 gcontext,
3040 emacs_gc_ts_origin_x,
3041 values->ts_x_origin);
3042 gc->ts_x_origin = values->ts_x_origin;
3043 }
3044
3045 if (mask & ANDROID_GC_TILE_STIP_Y_ORIGIN)
3046 {
3047 (*android_java_env)->SetIntField (android_java_env,
3048 gcontext,
3049 emacs_gc_ts_origin_y,
3050 values->ts_y_origin);
3051 gc->ts_y_origin = values->ts_y_origin;
3052 }
3053
3054 if (mask)
3055 {
3056 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3057 gcontext,
3058 emacs_gc_class,
3059 emacs_gc_mark_dirty,
3060 (jboolean) clip_changed);
3061 android_exception_check ();
3062 }
3063 }
3064
3065 void
3066 android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin,
3067 int clip_y_origin,
3068 struct android_rectangle *clip_rects,
3069 int n_clip_rects)
3070 {
3071 jobjectArray array;
3072 jobject rect, gcontext;
3073 int i;
3074
3075 android_init_android_rect_class ();
3076 android_init_emacs_gc_class ();
3077
3078 gcontext = android_resolve_handle (gc->gcontext,
3079 ANDROID_HANDLE_GCONTEXT);
3080
3081 array = (*android_java_env)->NewObjectArray (android_java_env,
3082 n_clip_rects,
3083 android_rect_class,
3084 NULL);
3085 android_exception_check ();
3086
3087 for (i = 0; i < n_clip_rects; ++i)
3088 {
3089 rect = (*android_java_env)->NewObject (android_java_env,
3090 android_rect_class,
3091 android_rect_constructor,
3092 (jint) clip_rects[i].x,
3093 (jint) clip_rects[i].y,
3094 (jint) (clip_rects[i].x
3095 + clip_rects[i].width),
3096 (jint) (clip_rects[i].y
3097 + clip_rects[i].height));
3098
3099
3100
3101
3102 android_exception_check_1 (array);
3103
3104 (*android_java_env)->SetObjectArrayElement (android_java_env,
3105 array, i, rect);
3106 ANDROID_DELETE_LOCAL_REF (rect);
3107 }
3108
3109 (*android_java_env)->SetObjectField (android_java_env,
3110 gcontext,
3111 emacs_gc_clip_rects,
3112 (jobject) array);
3113 ANDROID_DELETE_LOCAL_REF (array);
3114
3115 (*android_java_env)->SetIntField (android_java_env,
3116 gcontext,
3117 emacs_gc_clip_x_origin,
3118 clip_x_origin);
3119 (*android_java_env)->SetIntField (android_java_env,
3120 gcontext,
3121 emacs_gc_clip_y_origin,
3122 clip_y_origin);
3123
3124 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3125 gcontext,
3126 emacs_gc_class,
3127 emacs_gc_mark_dirty,
3128 (jboolean) true);
3129 android_exception_check ();
3130
3131
3132
3133 if (gc->clip_rects)
3134 xfree (gc->clip_rects);
3135
3136
3137
3138 gc->clip_rects = xmalloc (sizeof *gc->clip_rects
3139 * n_clip_rects);
3140 gc->num_clip_rects = n_clip_rects;
3141 memcpy (gc->clip_rects, clip_rects,
3142 n_clip_rects * sizeof *gc->clip_rects);
3143 }
3144
3145 void
3146 android_reparent_window (android_window w, android_window parent_handle,
3147 int x, int y)
3148 {
3149 jobject window, parent;
3150 jmethodID method;
3151
3152 window = android_resolve_handle (w, ANDROID_HANDLE_WINDOW);
3153 parent = android_resolve_handle (parent_handle,
3154 ANDROID_HANDLE_WINDOW);
3155
3156 method = window_class.reparent_to;
3157 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, window,
3158 window_class.class, method,
3159 parent, (jint) x, (jint) y);
3160 android_exception_check ();
3161 }
3162
3163 void
3164 android_clear_window (android_window handle)
3165 {
3166 jobject window;
3167
3168 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
3169
3170 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3171 emacs_service,
3172 service_class.class,
3173 service_class.clear_window,
3174 window);
3175 android_exception_check ();
3176 }
3177
3178 void
3179 android_map_window (android_window handle)
3180 {
3181 jobject window;
3182 jmethodID map_window;
3183
3184 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
3185 map_window = window_class.map_window;
3186
3187 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3188 window,
3189 window_class.class,
3190 map_window);
3191 android_exception_check ();
3192 }
3193
3194 void
3195 android_unmap_window (android_window handle)
3196 {
3197 jobject window;
3198 jmethodID unmap_window;
3199
3200 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
3201 unmap_window = window_class.unmap_window;
3202
3203 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3204 window,
3205 window_class.class,
3206 unmap_window);
3207 android_exception_check ();
3208 }
3209
3210 void
3211 android_resize_window (android_window handle, unsigned int width,
3212 unsigned int height)
3213 {
3214 jobject window;
3215 jmethodID resize_window;
3216
3217 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
3218 resize_window = window_class.resize_window;
3219
3220 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3221 window,
3222 window_class.class,
3223 resize_window,
3224 (jint) width,
3225 (jint) height);
3226 android_exception_check ();
3227 }
3228
3229 void
3230 android_move_window (android_window handle, int x, int y)
3231 {
3232 jobject window;
3233 jmethodID move_window;
3234
3235 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
3236 move_window = window_class.move_window;
3237
3238 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3239 window,
3240 window_class.class,
3241 move_window,
3242 (jint) x, (jint) y);
3243 android_exception_check ();
3244 }
3245
3246 void
3247 android_swap_buffers (struct android_swap_info *swap_info,
3248 int num_windows)
3249 {
3250 jobject window;
3251 int i;
3252
3253 for (i = 0; i < num_windows; ++i)
3254 {
3255 window = android_resolve_handle (swap_info[i].swap_window,
3256 ANDROID_HANDLE_WINDOW);
3257 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3258 window,
3259 window_class.class,
3260 window_class.swap_buffers);
3261 android_exception_check ();
3262 }
3263 }
3264
3265 void
3266 android_get_gc_values (struct android_gc *gc,
3267 enum android_gc_value_mask mask,
3268 struct android_gc_values *values)
3269 {
3270 if (mask & ANDROID_GC_FOREGROUND)
3271
3272
3273 values->foreground = gc->foreground;
3274
3275 if (mask & ANDROID_GC_BACKGROUND)
3276 values->background = gc->background;
3277
3278 if (mask & ANDROID_GC_FUNCTION)
3279 values->function = gc->function;
3280
3281 if (mask & ANDROID_GC_CLIP_X_ORIGIN)
3282 values->clip_x_origin = gc->clip_x_origin;
3283
3284 if (mask & ANDROID_GC_CLIP_Y_ORIGIN)
3285 values->clip_y_origin = gc->clip_y_origin;
3286
3287 if (mask & ANDROID_GC_FILL_STYLE)
3288 values->fill_style = gc->fill_style;
3289
3290 if (mask & ANDROID_GC_TILE_STIP_X_ORIGIN)
3291 values->ts_x_origin = gc->ts_x_origin;
3292
3293 if (mask & ANDROID_GC_TILE_STIP_Y_ORIGIN)
3294 values->ts_y_origin = gc->ts_y_origin;
3295
3296
3297
3298 }
3299
3300 void
3301 android_set_foreground (struct android_gc *gc, unsigned long foreground)
3302 {
3303 struct android_gc_values gcv;
3304
3305 gcv.foreground = foreground;
3306 android_change_gc (gc, ANDROID_GC_FOREGROUND, &gcv);
3307 }
3308
3309 void
3310 android_fill_rectangle (android_drawable handle, struct android_gc *gc,
3311 int x, int y, unsigned int width,
3312 unsigned int height)
3313 {
3314 jobject drawable, gcontext;
3315
3316 drawable = android_resolve_handle2 (handle,
3317 ANDROID_HANDLE_WINDOW,
3318 ANDROID_HANDLE_PIXMAP);
3319 gcontext = android_resolve_handle (gc->gcontext,
3320 ANDROID_HANDLE_GCONTEXT);
3321
3322 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
3323 emacs_service,
3324 service_class.class,
3325 service_class.fill_rectangle,
3326 drawable,
3327 gcontext,
3328 (jint) x, (jint) y,
3329 (jint) width,
3330 (jint) height);
3331 }
3332
3333 android_pixmap
3334 android_create_pixmap_from_bitmap_data (char *data, unsigned int width,
3335 unsigned int height,
3336 unsigned long foreground,
3337 unsigned long background,
3338 unsigned int depth)
3339 {
3340 android_handle prev_max_handle;
3341 jobject object;
3342 jintArray colors;
3343 android_pixmap pixmap;
3344 unsigned int x, y;
3345 jint *region;
3346
3347 USE_SAFE_ALLOCA;
3348
3349
3350 colors = (*android_java_env)->NewIntArray (android_java_env,
3351 width * height);
3352 android_exception_check ();
3353
3354 SAFE_NALLOCA (region, sizeof *region, width);
3355
3356 for (y = 0; y < height; ++y)
3357 {
3358 for (x = 0; x < width; ++x)
3359 {
3360 if (depth == 24)
3361 {
3362
3363
3364
3365 if (data[x / 8] & (1 << (x % 8)))
3366 region[x] = foreground | 0xff000000;
3367 else
3368 region[x] = background | 0xff000000;
3369 }
3370 else
3371 {
3372 if (data[x / 8] & (1 << (x % 8)))
3373 region[x] = foreground;
3374 else
3375 region[x] = background;
3376 }
3377 }
3378
3379 (*android_java_env)->SetIntArrayRegion (android_java_env,
3380 colors,
3381 width * y, width,
3382 region);
3383 data += width / 8;
3384 }
3385
3386
3387 prev_max_handle = max_handle;
3388 pixmap = android_alloc_id ();
3389
3390 if (!pixmap)
3391 {
3392 ANDROID_DELETE_LOCAL_REF ((jobject) colors);
3393 error ("Out of pixmap handles!");
3394 }
3395
3396 object = (*android_java_env)->NewObject (android_java_env,
3397 pixmap_class.class,
3398 pixmap_class.constructor,
3399 (jshort) pixmap, colors,
3400 (jint) width, (jint) height,
3401 (jint) depth);
3402 (*android_java_env)->ExceptionClear (android_java_env);
3403 ANDROID_DELETE_LOCAL_REF ((jobject) colors);
3404
3405 if (!object)
3406 {
3407 max_handle = prev_max_handle;
3408 memory_full (0);
3409 }
3410
3411 android_handles[pixmap].type = ANDROID_HANDLE_PIXMAP;
3412 android_handles[pixmap].handle
3413 = (*android_java_env)->NewGlobalRef (android_java_env, object);
3414 ANDROID_DELETE_LOCAL_REF (object);
3415
3416 if (!android_handles[pixmap].handle)
3417 memory_full (0);
3418
3419 SAFE_FREE ();
3420 return pixmap;
3421 }
3422
3423 void
3424 android_set_clip_mask (struct android_gc *gc, android_pixmap pixmap)
3425 {
3426 struct android_gc_values gcv;
3427
3428 gcv.clip_mask = pixmap;
3429 android_change_gc (gc, ANDROID_GC_CLIP_MASK, &gcv);
3430 }
3431
3432 void
3433 android_set_fill_style (struct android_gc *gc,
3434 enum android_fill_style fill_style)
3435 {
3436 struct android_gc_values gcv;
3437
3438 gcv.fill_style = fill_style;
3439 android_change_gc (gc, ANDROID_GC_FILL_STYLE, &gcv);
3440 }
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450 typedef void (*android_blit_func) (int, int, int, int, int, int,
3451 struct android_gc *,
3452 unsigned char *, AndroidBitmapInfo *,
3453 unsigned char *, AndroidBitmapInfo *,
3454 unsigned char *, AndroidBitmapInfo *);
3455
3456
3457
3458 #ifdef __aarch64__
3459
3460
3461
3462
3463 static void
3464 android_neon_mask_line (unsigned int *src, unsigned int *dst,
3465 unsigned char *mask, int n)
3466 {
3467 uint32x4_t src_low, src_high, dst_low, dst_high;
3468 int16x8_t vmask;
3469 int32x4_t ext_mask_low, ext_mask_high, low, high;
3470 int rem, i;
3471
3472
3473 rem = n & 7, n &= ~7;
3474
3475
3476
3477 if (n)
3478 {
3479 again:
3480
3481 src_low = vld1q_u32 (src);
3482 src_high = vld1q_u32 (src + 4);
3483
3484
3485 dst_low = vld1q_u32 (dst);
3486 dst_high = vld1q_u32 (dst + 4);
3487
3488
3489 vmask = vmovl_s8 (vld1_u8 (mask));
3490 ext_mask_low = vmovl_s16 (vget_low_s16 (vmask));
3491 ext_mask_high = vmovl_s16 (vget_high_s16 (vmask));
3492
3493
3494 low = vreinterpretq_u32_s32 (ext_mask_low);
3495 high = vreinterpretq_u32_s32 (ext_mask_high);
3496
3497
3498 dst_low = vbicq_u32 (dst_low, low);
3499 src_low = vandq_u32 (src_low, low);
3500 dst_high = vbicq_u32 (dst_high, high);
3501 src_high = vandq_u32 (src_high, high);
3502
3503
3504 vst1q_u32 (dst, vorrq_u32 (dst_low, src_low));
3505 vst1q_u32 (dst + 4, vorrq_u32 (dst_high, src_high));
3506
3507
3508 dst += 8;
3509 src += 8;
3510 mask += 8;
3511
3512
3513 n -= 8;
3514 if (n > 0)
3515 goto again;
3516 }
3517
3518
3519
3520 for (i = 0; i < rem; ++i)
3521 {
3522
3523 n = ((signed char *) mask)[i];
3524
3525
3526 dst[i] = ((src[i] & n) | (dst[i] & ~n));
3527 }
3528 }
3529
3530 #endif
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544 static void
3545 android_blit_copy (int src_x, int src_y, int width, int height,
3546 int dst_x, int dst_y, struct android_gc *gc,
3547 unsigned char *src, AndroidBitmapInfo *src_info,
3548 unsigned char *dst, AndroidBitmapInfo *dst_info,
3549 unsigned char *mask, AndroidBitmapInfo *mask_info)
3550 {
3551 uintptr_t start, end;
3552 int mask_offset;
3553 size_t pixel, offset, offset1;
3554 unsigned char *src_current, *dst_current;
3555 unsigned char *mask_current;
3556 int overflow, temp, i;
3557 #ifndef __aarch64__
3558 int j;
3559 #endif
3560 bool backwards;
3561 unsigned int *long_src, *long_dst;
3562
3563
3564 eassert (src_x >= 0 && src_y >= 0
3565 && dst_x >= 0 && dst_y >= 0);
3566 eassert (src_x + width <= src_info->width);
3567 eassert (src_y + height <= src_info->height);
3568 eassert (dst_x + width <= dst_info->width);
3569 eassert (dst_y + height <= dst_info->height);
3570
3571
3572 eassert (src_info->format == dst_info->format
3573 && src_info->format == ANDROID_BITMAP_FORMAT_RGBA_8888);
3574 pixel = sizeof (unsigned int);
3575
3576
3577
3578 eassert (!mask || mask_info->format == ANDROID_BITMAP_FORMAT_A_8);
3579
3580
3581
3582
3583
3584 overflow = ckd_mul (&start, src_y, src_info->stride);
3585 overflow |= ckd_mul (&end, src_x, pixel);
3586 overflow |= ckd_add (&start, end, start);
3587 overflow |= ckd_add (&start, (uintptr_t) src, start);
3588
3589 if (overflow)
3590 return;
3591
3592 src_current = (unsigned char *) start;
3593
3594 overflow = ckd_mul (&start, dst_y, dst_info->stride);
3595 overflow |= ckd_mul (&end, dst_x, pixel);
3596 overflow |= ckd_add (&start, end, start);
3597 overflow |= ckd_add (&start, (uintptr_t) dst, start);
3598
3599 if (overflow)
3600 return;
3601
3602 dst_current = (unsigned char *) start;
3603 backwards = false;
3604
3605
3606
3607 if (src == dst && dst_current >= src_current)
3608 {
3609 backwards = true;
3610
3611
3612
3613
3614
3615 overflow = ckd_mul (&start, src_y + height - 1,
3616 src_info->stride);
3617
3618 if (mask)
3619
3620
3621 overflow |= ckd_mul (&end, src_x + width - 1, pixel);
3622 else
3623 end = src_x * pixel;
3624
3625 overflow |= ckd_add (&start, start, end);
3626 overflow |= ckd_add (&start, (uintptr_t) src, start);
3627
3628 if (overflow)
3629 return;
3630
3631 src_current = (unsigned char *) start;
3632
3633 overflow = ckd_mul (&start, dst_y + height - 1,
3634 dst_info->stride);
3635
3636 if (mask)
3637
3638
3639 overflow |= ckd_mul (&end, dst_x + width - 1, pixel);
3640 else
3641 end = dst_x * pixel;
3642
3643 overflow |= ckd_add (&start, start, end);
3644 overflow |= ckd_add (&start, (uintptr_t) dst, start);
3645
3646 if (overflow)
3647 return;
3648
3649 dst_current = (unsigned char *) start;
3650 }
3651
3652 if (!mask)
3653 {
3654
3655
3656
3657 for (i = 0; i < height; ++i)
3658 {
3659 memmove (dst_current, src_current,
3660 width * pixel);
3661
3662 if (backwards)
3663 {
3664
3665 src_current -= src_info->stride;
3666 dst_current -= dst_info->stride;
3667 }
3668 else
3669 {
3670
3671 src_current += src_info->stride;
3672 dst_current += dst_info->stride;
3673 }
3674 }
3675 }
3676 else
3677 {
3678
3679
3680
3681
3682 temp = dst_y;
3683 dst_y = MAX (dst_y, gc->clip_y_origin);
3684 src_y += dst_y - temp;
3685 height -= dst_y - temp;
3686
3687
3688 eassert (dst_y + height
3689 <= gc->clip_y_origin + mask_info->height);
3690 eassert (dst_y >= gc->clip_y_origin);
3691
3692
3693
3694 if (backwards)
3695 {
3696
3697
3698
3699 mask_offset = dst_x + width;
3700 mask_offset -= mask_info->width + gc->clip_x_origin;
3701
3702 if (mask_offset < 0)
3703 mask_offset = 0;
3704
3705
3706
3707
3708 temp = dst_x - gc->clip_x_origin;
3709 temp += MIN (mask_info->width - temp,
3710 width - mask_offset);
3711
3712 if (temp < 0)
3713 return;
3714
3715
3716
3717 i = dst_y - gc->clip_y_origin + height;
3718
3719
3720
3721 if (INT_MULTIPLY_WRAPV (temp, pixel, &offset)
3722 || INT_MULTIPLY_WRAPV (i, mask_info->stride, &offset1)
3723 || INT_ADD_WRAPV (offset, offset1, &offset)
3724 || INT_ADD_WRAPV ((uintptr_t) mask, offset, &start))
3725 return;
3726
3727 if (height <= 0)
3728 return;
3729
3730 mask = mask_current = (unsigned char *) start;
3731
3732 while (height--)
3733 {
3734
3735
3736 long_src = (unsigned int *) (src_current - mask_offset * pixel);
3737 long_dst = (unsigned int *) (dst_current - mask_offset * pixel);
3738 mask = mask_current;
3739
3740
3741 temp = MIN (mask_info->width - temp, width - mask_offset);
3742 while (temp--)
3743 {
3744
3745
3746
3747
3748 i = *(signed char *) mask--;
3749
3750
3751 *long_dst = ((*long_src & i) | (*long_dst & ~i));
3752
3753 long_dst--;
3754 long_src--;
3755 }
3756
3757
3758 src_current -= src_info->stride;
3759 dst_current -= dst_info->stride;
3760 mask_current -= mask_info->stride;
3761 }
3762 }
3763 else
3764 {
3765
3766
3767
3768 mask_offset = dst_x - gc->clip_x_origin;
3769
3770
3771
3772 if (mask_offset > 0)
3773 mask += mask_offset;
3774 else
3775 {
3776
3777 src_current += -mask_offset * pixel;
3778 dst_current += -mask_offset * pixel;
3779 width += mask_offset;
3780 }
3781
3782
3783
3784 eassert (dst_y - gc->clip_y_origin >= 0);
3785 if ((dst_y - gc->clip_y_origin) + height > mask_info->height
3786 || width <= 0)
3787 return;
3788
3789
3790
3791 mask += ((dst_y - gc->clip_y_origin)
3792 * mask_info->stride);
3793
3794
3795
3796 if (mask_offset > 0)
3797 temp = MIN (mask_info->width - mask_offset, width);
3798 else
3799 temp = MIN (mask_info->width, width);
3800
3801 if (temp <= 0 || height <= 0)
3802 return;
3803
3804
3805
3806 while (height--)
3807 {
3808 long_src = (unsigned int *) src_current;
3809 long_dst = (unsigned int *) dst_current;
3810 mask_current = mask;
3811
3812 #ifndef __aarch64__
3813 for (j = 0; j < temp; ++j)
3814 {
3815
3816 i = *(signed char *) mask_current++;
3817
3818
3819 *long_dst = ((*long_src & i) | (*long_dst & ~i));
3820 long_dst++;
3821 long_src++;
3822 }
3823 #else
3824 android_neon_mask_line (long_src, long_dst, mask, temp);
3825 #endif
3826
3827 src_current += src_info->stride;
3828 dst_current += dst_info->stride;
3829 mask += mask_info->stride;
3830 }
3831 }
3832 }
3833 }
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849 static void
3850 android_blit_xor (int src_x, int src_y, int width, int height,
3851 int dst_x, int dst_y, struct android_gc *gc,
3852 unsigned char *src, AndroidBitmapInfo *src_info,
3853 unsigned char *dst, AndroidBitmapInfo *dst_info,
3854 unsigned char *mask, AndroidBitmapInfo *mask_info)
3855 {
3856 #if 0
3857 uintptr_t start, end;
3858 int mask_offset;
3859 size_t pixel, offset, offset1;
3860 unsigned char *src_current, *dst_current;
3861 unsigned char *mask_current;
3862 int overflow, temp, i;
3863 bool backwards;
3864 unsigned int *long_src, *long_dst;
3865 #endif
3866
3867
3868
3869 emacs_abort ();
3870
3871 #if 0
3872
3873 eassert (src_x >= 0 && src_y >= 0
3874 && dst_x >= 0 && dst_y >= 0);
3875 eassert (src_x + width <= src_info->width);
3876 eassert (src_y + height <= src_info->height);
3877 eassert (dst_x + width <= dst_info->width);
3878 eassert (dst_y + height <= dst_info->height);
3879
3880
3881 eassert (src_info->format == dst_info->format
3882 && src_info->format == ANDROID_BITMAP_FORMAT_RGBA_8888);
3883 pixel = sizeof (unsigned int);
3884
3885
3886
3887 eassert (!mask || mask_info->format == ANDROID_BITMAP_FORMAT_A_8);
3888
3889
3890
3891
3892
3893 overflow = ckd_mul (&start, src_y, src_info->stride);
3894 overflow |= ckd_mul (&end, src_x, pixel);
3895 overflow |= ckd_add (&start, (uintptr_t) src, start);
3896
3897 if (overflow)
3898 return;
3899
3900 src_current = (unsigned char *) start;
3901
3902 overflow = ckd_mul (&start, dst_y, src_info->stride);
3903 overflow |= ckd_mul (&end, dst_x, pixel);
3904 overflow |= ckd_add (&start, (uintptr_t) dst, start);
3905
3906 if (overflow)
3907 return;
3908
3909 dst_current = (unsigned char *) start;
3910 backwards = false;
3911
3912
3913
3914 if (src == dst && dst_current >= src_current)
3915 {
3916 backwards = true;
3917
3918
3919
3920
3921
3922 overflow = ckd_mul (&start, src_y + height - 1,
3923 src_info->stride);
3924 if (mask)
3925
3926 overflow |= ckd_mul (&end, src_x + width - 1, pixel);
3927 else
3928 overflow |= ckd_mul (&end, src_x, pixel);
3929 overflow |= ckd_add (&start, start, end);
3930 overflow |= ckd_add (&start, (uintptr_t) src, start);
3931
3932 if (overflow)
3933 return;
3934
3935 src_current = (unsigned char *) start;
3936
3937 overflow = ckd_mul (&start, dst_y + height - 1,
3938 dst_info->stride);
3939 if (mask)
3940
3941 overflow |= ckd_mul (&end, dst_x + width - 1, pixel);
3942 else
3943 overflow |= ckd_mul (&end, dst_x, pixel);
3944 overflow |= ckd_add (&start, start, end);
3945 overflow |= ckd_add (&start, (uintptr_t) dst, start);
3946
3947 if (overflow)
3948 return;
3949
3950 dst_current = (unsigned char *) start;
3951 }
3952
3953 if (!mask)
3954 {
3955
3956
3957
3958 for (i = 0; i < height; ++i)
3959 {
3960 if (backwards)
3961 {
3962 for (i = width - 1; i <= 0; --i)
3963 (((unsigned int *) dst_current)[i])
3964
3965 ^= (((unsigned int *) src_current)[i]) & 0xffffff;
3966
3967
3968 src_current -= src_info->stride;
3969 dst_current -= dst_info->stride;
3970 }
3971 else
3972 {
3973 for (i = 0; i < width; ++i)
3974 (((unsigned int *) dst_current)[i])
3975
3976 ^= (((unsigned int *) src_current)[i]) & 0xffffff;
3977
3978
3979 src_current += src_info->stride;
3980 dst_current += dst_info->stride;
3981 }
3982 }
3983 }
3984 else
3985 {
3986
3987
3988
3989
3990 temp = dst_y;
3991 dst_y = MAX (dst_y, gc->clip_y_origin);
3992 src_y += dst_y - temp;
3993 height -= dst_y - temp;
3994
3995
3996 eassert (dst_y + height
3997 <= gc->clip_y_origin + mask_info->height);
3998 eassert (dst_y >= gc->clip_y_origin);
3999
4000
4001
4002 if (backwards)
4003 {
4004
4005
4006
4007 mask_offset = dst_x + width;
4008 mask_offset -= mask_info->width + gc->clip_x_origin;
4009
4010 if (mask_info < 0)
4011 mask_info = 0;
4012
4013
4014
4015
4016 temp = dst_x - gc->clip_x_origin;
4017 temp += MIN (mask_info->width - temp,
4018 width - mask_offset);
4019
4020 if (temp < 0)
4021 return;
4022
4023
4024
4025 i = dst_y - gc->clip_y_origin + height;
4026
4027
4028
4029 if (INT_MULTIPLY_WRAPV (temp, pixel, &offset)
4030 || INT_MULTIPLY_WRAPV (i, mask_info->stride, &offset1)
4031 || INT_ADD_WRAPV (offset, offset1, &offset)
4032 || INT_ADD_WRAPV ((uintptr_t) mask, offset, &start))
4033 return;
4034
4035 mask = mask_current = (unsigned char *) start;
4036
4037 for (i = 0; i < height; ++i)
4038 {
4039
4040
4041 long_src = (unsigned int *) (src_current - mask_offset * pixel);
4042 long_dst = (unsigned int *) (dst_current - mask_offset * pixel);
4043 mask = mask_current;
4044
4045
4046 temp = MIN (mask_info->width - temp, width - mask_offset);
4047 while (temp--)
4048
4049
4050 *long_dst-- ^= ((*(long_src--) & (0u - (*(mask--) & 1)))
4051 & 0xffffff);
4052
4053
4054 src_current -= src_info->stride;
4055 dst_current -= dst_info->stride;
4056 mask_current -= mask_info->stride;
4057 }
4058 }
4059 else
4060 {
4061
4062
4063
4064 mask_offset = dst_x - gc->clip_x_origin;
4065
4066
4067
4068 if (mask_offset > 0)
4069 mask += mask_offset;
4070 else
4071 {
4072
4073 src_current += -mask_offset * pixel;
4074 dst_current += -mask_offset * pixel;
4075 width -= mask_offset;
4076 }
4077
4078
4079
4080 mask += gc->clip_y_origin * mask_info->stride;
4081
4082 for (i = 0; i < height; ++i)
4083 {
4084 long_src = (unsigned int *) src_current;
4085 long_dst = (unsigned int *) dst_current;
4086 mask_current = mask;
4087
4088 if (mask_offset > 0)
4089 {
4090
4091 temp = MIN (mask_info->width - mask_offset, width);
4092 while (temp--)
4093 *long_dst++ ^= ((*(long_src++)
4094 & (0u - (*(mask_current++) & 1)))
4095 & 0xffffff);
4096 }
4097 else
4098 {
4099
4100 temp = MIN (mask_info->width, width);
4101 while (temp--)
4102 *long_dst++ = ((*(long_src++)
4103 & (0u - (*(mask_current++) & 1)))
4104 & 0xffffff);
4105 }
4106
4107 src_current += src_info->stride;
4108 dst_current += dst_info->stride;
4109 mask += mask_info->stride;
4110 }
4111 }
4112 }
4113 #endif
4114 }
4115
4116 void
4117 android_copy_area (android_drawable src, android_drawable dest,
4118 struct android_gc *gc, int src_x, int src_y,
4119 unsigned int width, unsigned int height,
4120 int dest_x, int dest_y)
4121 {
4122 jobject src_object, dest_object, mask;
4123 android_blit_func do_blit;
4124 AndroidBitmapInfo src_info, dest_info, mask_info;
4125 void *src_data, *dest_data, *mask_data;
4126 int n_clip_rects, i;
4127 bool flag;
4128 struct android_rectangle bounds, rect, temp, *clip_rectangles;
4129
4130
4131
4132
4133
4134 src_data = android_lock_bitmap (src, &src_info, &src_object);
4135 if (!src_data)
4136 return;
4137
4138 mask_data = mask = NULL;
4139
4140 if (src != dest)
4141 {
4142 dest_data = android_lock_bitmap (dest, &dest_info, &dest_object);
4143 if (!dest_data)
4144 goto fail;
4145 }
4146 else
4147 {
4148 dest_data = src_data;
4149 dest_info = src_info;
4150 }
4151
4152
4153
4154 if (gc->clip_mask)
4155 {
4156 mask_data = android_lock_bitmap (gc->clip_mask,
4157 &mask_info, &mask);
4158 if (!mask_data)
4159 goto fail1;
4160 }
4161
4162
4163 n_clip_rects = gc->num_clip_rects;
4164
4165
4166
4167
4168 flag = n_clip_rects == -1;
4169 if (flag)
4170 {
4171 n_clip_rects = 1;
4172 clip_rectangles = ▭
4173 }
4174 else if (!n_clip_rects)
4175 goto fail2;
4176 else
4177 clip_rectangles = gc->clip_rects;
4178
4179
4180
4181 rect.x = 0;
4182 rect.y = 0;
4183 rect.width = dest_info.width;
4184 rect.height = dest_info.height;
4185
4186 if (mask_data)
4187 {
4188
4189
4190 if (src_x + width > mask_info.width)
4191 width = mask_info.width - src_x;
4192
4193 if (src_y + height > mask_info.height)
4194 height = mask_info.height - src_y;
4195 }
4196
4197
4198
4199 if (src_x + width > src_info.width)
4200 width = src_info.width - src_x;
4201
4202 if (src_y + height > src_info.height)
4203 height = src_info.height - src_y;
4204
4205
4206
4207 if (width <= 0 || height <= 0)
4208 goto fail2;
4209
4210
4211
4212 switch (gc->function)
4213 {
4214 case ANDROID_GC_COPY:
4215 do_blit = android_blit_copy;
4216 break;
4217
4218 case ANDROID_GC_XOR:
4219 do_blit = android_blit_xor;
4220 break;
4221
4222 default:
4223 emacs_abort ();
4224 }
4225
4226
4227 bounds.x = dest_x;
4228 bounds.y = dest_y;
4229 bounds.width = width;
4230 bounds.height = height;
4231
4232
4233 for (i = 0; i < n_clip_rects; ++i)
4234 {
4235
4236
4237
4238 if (!gui_intersect_rectangles (&clip_rectangles[i], &bounds,
4239 &temp))
4240 continue;
4241
4242
4243
4244 if (!flag && !gui_intersect_rectangles (&temp, &rect, &temp))
4245 continue;
4246
4247
4248 (*do_blit) (src_x + temp.x - dest_x,
4249 src_y + temp.y - dest_y,
4250 temp.width,
4251 temp.height,
4252 temp.x, temp.y,
4253 gc,
4254 src_data, &src_info,
4255 dest_data, &dest_info,
4256 mask_data, &mask_info);
4257 }
4258
4259
4260
4261
4262 if (android_handles[dest].type == ANDROID_HANDLE_WINDOW)
4263 android_damage_window (dest, &bounds);
4264
4265 fail2:
4266 if (mask)
4267 {
4268 AndroidBitmap_unlockPixels (android_java_env, mask);
4269 ANDROID_DELETE_LOCAL_REF (mask);
4270 }
4271 fail1:
4272 if (src != dest)
4273 {
4274 AndroidBitmap_unlockPixels (android_java_env, dest_object);
4275 ANDROID_DELETE_LOCAL_REF (dest_object);
4276 }
4277 fail:
4278 AndroidBitmap_unlockPixels (android_java_env, src_object);
4279 ANDROID_DELETE_LOCAL_REF (src_object);
4280 }
4281
4282
4283
4284 void
4285 android_free_pixmap (android_pixmap pixmap)
4286 {
4287 android_destroy_handle (pixmap);
4288 }
4289
4290 void
4291 android_set_background (struct android_gc *gc, unsigned long background)
4292 {
4293 struct android_gc_values gcv;
4294
4295 gcv.background = background;
4296 android_change_gc (gc, ANDROID_GC_BACKGROUND, &gcv);
4297 }
4298
4299 void
4300 android_fill_polygon (android_drawable drawable, struct android_gc *gc,
4301 struct android_point *points, int npoints,
4302 enum android_shape shape, enum android_coord_mode mode)
4303 {
4304 jobjectArray array;
4305 jobject point, drawable_object, gcontext;
4306 int i;
4307
4308 drawable_object = android_resolve_handle2 (drawable,
4309 ANDROID_HANDLE_WINDOW,
4310 ANDROID_HANDLE_PIXMAP);
4311 gcontext = android_resolve_handle (gc->gcontext,
4312 ANDROID_HANDLE_GCONTEXT);
4313
4314 array = (*android_java_env)->NewObjectArray (android_java_env,
4315 npoints,
4316 point_class.class,
4317 NULL);
4318 android_exception_check ();
4319
4320 for (i = 0; i < npoints; ++i)
4321 {
4322 point = (*android_java_env)->NewObject (android_java_env,
4323 point_class.class,
4324 point_class.constructor,
4325 (jint) points[i].x,
4326 (jint) points[i].y);
4327 android_exception_check_1 (array);
4328
4329 (*android_java_env)->SetObjectArrayElement (android_java_env,
4330 array, i, point);
4331 ANDROID_DELETE_LOCAL_REF (point);
4332 }
4333
4334 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4335 emacs_service,
4336 service_class.class,
4337 service_class.fill_polygon,
4338 drawable_object,
4339 gcontext, array);
4340 ANDROID_DELETE_LOCAL_REF (array);
4341 }
4342
4343 void
4344 android_draw_rectangle (android_drawable handle, struct android_gc *gc,
4345 int x, int y, unsigned int width, unsigned int height)
4346 {
4347 jobject drawable, gcontext;
4348
4349 drawable = android_resolve_handle2 (handle,
4350 ANDROID_HANDLE_WINDOW,
4351 ANDROID_HANDLE_PIXMAP);
4352 gcontext = android_resolve_handle (gc->gcontext,
4353 ANDROID_HANDLE_GCONTEXT);
4354
4355 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4356 emacs_service,
4357 service_class.class,
4358 service_class.draw_rectangle,
4359 drawable, gcontext,
4360 (jint) x, (jint) y,
4361 (jint) width, (jint) height);
4362 }
4363
4364 void
4365 android_draw_point (android_drawable handle, struct android_gc *gc,
4366 int x, int y)
4367 {
4368 jobject drawable, gcontext;
4369
4370 drawable = android_resolve_handle2 (handle,
4371 ANDROID_HANDLE_WINDOW,
4372 ANDROID_HANDLE_PIXMAP);
4373 gcontext = android_resolve_handle (gc->gcontext,
4374 ANDROID_HANDLE_GCONTEXT);
4375
4376 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4377 emacs_service,
4378 service_class.class,
4379 service_class.draw_point,
4380 drawable, gcontext,
4381 (jint) x, (jint) y);
4382 }
4383
4384 void
4385 android_draw_line (android_drawable handle, struct android_gc *gc,
4386 int x, int y, int x2, int y2)
4387 {
4388 jobject drawable, gcontext;
4389
4390 drawable = android_resolve_handle2 (handle,
4391 ANDROID_HANDLE_WINDOW,
4392 ANDROID_HANDLE_PIXMAP);
4393 gcontext = android_resolve_handle (gc->gcontext,
4394 ANDROID_HANDLE_GCONTEXT);
4395
4396 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4397 emacs_service,
4398 service_class.class,
4399 service_class.draw_line,
4400 drawable, gcontext,
4401 (jint) x, (jint) y,
4402 (jint) x2, (jint) y2);
4403 }
4404
4405 android_pixmap
4406 android_create_pixmap (unsigned int width, unsigned int height,
4407 int depth)
4408 {
4409 android_handle prev_max_handle;
4410 jobject object;
4411 android_pixmap pixmap;
4412
4413
4414 prev_max_handle = max_handle;
4415 pixmap = android_alloc_id ();
4416
4417 if (!pixmap)
4418 error ("Out of pixmap handles!");
4419
4420 object = (*android_java_env)->NewObject (android_java_env,
4421 pixmap_class.class,
4422 pixmap_class.constructor_mutable,
4423 (jshort) pixmap,
4424 (jint) width, (jint) height,
4425 (jint) depth);
4426
4427 if (!object)
4428 {
4429 (*android_java_env)->ExceptionClear (android_java_env);
4430 max_handle = prev_max_handle;
4431 memory_full (0);
4432 }
4433
4434 android_handles[pixmap].type = ANDROID_HANDLE_PIXMAP;
4435 android_handles[pixmap].handle
4436 = (*android_java_env)->NewGlobalRef (android_java_env, object);
4437 (*android_java_env)->ExceptionClear (android_java_env);
4438 ANDROID_DELETE_LOCAL_REF (object);
4439
4440 if (!android_handles[pixmap].handle)
4441 memory_full (0);
4442
4443 return pixmap;
4444 }
4445
4446 void
4447 android_set_ts_origin (struct android_gc *gc, int x, int y)
4448 {
4449 struct android_gc_values gcv;
4450
4451 gcv.ts_x_origin = x;
4452 gcv.ts_y_origin = y;
4453 android_change_gc (gc, (ANDROID_GC_TILE_STIP_X_ORIGIN
4454 | ANDROID_GC_TILE_STIP_Y_ORIGIN),
4455 &gcv);
4456 }
4457
4458 void
4459 android_clear_area (android_window handle, int x, int y,
4460 unsigned int width, unsigned int height)
4461 {
4462 jobject window;
4463
4464 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
4465
4466 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4467 emacs_service,
4468 service_class.class,
4469 service_class.clear_area,
4470 window, (jint) x, (jint) y,
4471 (jint) width, (jint) height);
4472 }
4473
4474 android_pixmap
4475 android_create_bitmap_from_data (char *bits, unsigned int width,
4476 unsigned int height)
4477 {
4478 return android_create_pixmap_from_bitmap_data (bits, 1, 0,
4479 width, height, 1);
4480 }
4481
4482 struct android_image *
4483 android_create_image (unsigned int depth, enum android_image_format format,
4484 char *data, unsigned int width, unsigned int height)
4485 {
4486 struct android_image *image;
4487
4488 image = xmalloc (sizeof *image);
4489
4490
4491
4492
4493 image->width = width;
4494 image->height = height;
4495 image->data = data;
4496 image->depth = depth;
4497 image->format = format;
4498
4499
4500
4501
4502 if (depth == 1)
4503 {
4504 image->bytes_per_line = (width + 7) / 8;
4505 image->bits_per_pixel = 1;
4506 }
4507 else if (depth == 24)
4508 {
4509 image->bytes_per_line = width * 4;
4510 image->bits_per_pixel = 32;
4511 }
4512 else
4513 emacs_abort ();
4514
4515 return image;
4516 }
4517
4518 void
4519 android_destroy_image (struct android_image *ximg)
4520 {
4521
4522
4523
4524 if (ximg->data)
4525 xfree (ximg->data);
4526 xfree (ximg);
4527 }
4528
4529 void
4530 android_put_pixel (struct android_image *ximg, int x, int y,
4531 unsigned long pixel)
4532 {
4533 char *byte, *word;
4534 unsigned int r, g, b;
4535 unsigned int pixel_int;
4536
4537
4538
4539 if (x >= ximg->width || y >= ximg->height || x < 0 || y < 0)
4540 return;
4541
4542 switch (ximg->depth)
4543 {
4544 case 1:
4545 byte = ximg->data + y * ximg->bytes_per_line + x / 8;
4546
4547 if (pixel)
4548 *byte |= (1 << x % 8);
4549 else
4550 *byte &= ~(1 << x % 8);
4551 break;
4552
4553 case 24:
4554
4555 word = ximg->data + y * ximg->bytes_per_line + x * 4;
4556
4557
4558
4559
4560
4561 r = pixel & 0x00ff0000;
4562 g = pixel & 0x0000ff00;
4563 b = pixel & 0x000000ff;
4564 pixel = (r >> 16) | g | (b << 16) | 0xff000000;
4565
4566 pixel_int = pixel;
4567 memcpy (word, &pixel_int, sizeof pixel_int);
4568 break;
4569 }
4570 }
4571
4572 unsigned long
4573 android_get_pixel (struct android_image *ximg, int x, int y)
4574 {
4575 char *byte, *word;
4576 unsigned int pixel, r, g, b;
4577
4578 if (x >= ximg->width || y >= ximg->height
4579 || x < 0 || y < 0)
4580 return 0;
4581
4582 switch (ximg->depth)
4583 {
4584 case 1:
4585 byte = ximg->data + y * ximg->bytes_per_line + x / 8;
4586 return (*byte & (1 << x % 8)) ? 1 : 0;
4587
4588 case 24:
4589 word = ximg->data + y * ximg->bytes_per_line + x * 4;
4590 memcpy (&pixel, word, sizeof pixel);
4591
4592
4593 b = pixel & 0x00ff0000;
4594 g = pixel & 0x0000ff00;
4595 r = pixel & 0x000000ff;
4596 pixel = ((r << 16) | g | (b >> 16)) & ~0xff000000;
4597
4598 return pixel;
4599 }
4600
4601 emacs_abort ();
4602 }
4603
4604 struct android_image *
4605 android_get_image (android_drawable handle,
4606 enum android_image_format format)
4607 {
4608 jobject drawable, bitmap;
4609 AndroidBitmapInfo bitmap_info;
4610 size_t byte_size;
4611 void *data;
4612 struct android_image *image;
4613 unsigned char *data1, *data2;
4614 int i, x;
4615
4616 drawable = android_resolve_handle2 (handle, ANDROID_HANDLE_WINDOW,
4617 ANDROID_HANDLE_PIXMAP);
4618
4619
4620
4621 bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
4622 drawable,
4623 drawable_class.get_bitmap);
4624 android_exception_check ();
4625
4626
4627 memset (&bitmap_info, 0, sizeof bitmap_info);
4628
4629
4630
4631 AndroidBitmap_getInfo (android_java_env, bitmap, &bitmap_info);
4632
4633 if (!bitmap_info.stride)
4634 {
4635 ANDROID_DELETE_LOCAL_REF (bitmap);
4636 memory_full (0);
4637 }
4638
4639
4640
4641
4642 if (bitmap_info.format != ANDROID_BITMAP_FORMAT_A_8)
4643 {
4644 if (INT_MULTIPLY_WRAPV ((size_t) bitmap_info.stride,
4645 (size_t) bitmap_info.height,
4646 &byte_size))
4647 {
4648 ANDROID_DELETE_LOCAL_REF (bitmap);
4649 memory_full (0);
4650 }
4651 }
4652 else
4653
4654 byte_size = (bitmap_info.width + 7) / 8;
4655
4656
4657
4658
4659 data = NULL;
4660 AndroidBitmap_lockPixels (android_java_env, bitmap, &data);
4661
4662 if (!data)
4663 {
4664
4665
4666 ANDROID_DELETE_LOCAL_REF (bitmap);
4667 memory_full (0);
4668 }
4669
4670
4671 image = xmalloc (sizeof *image);
4672 image->width = bitmap_info.width;
4673 image->height = bitmap_info.height;
4674 image->data = malloc (byte_size);
4675
4676 if (!image->data)
4677 {
4678 ANDROID_DELETE_LOCAL_REF (bitmap);
4679 xfree (image);
4680 memory_full (byte_size);
4681 }
4682
4683
4684 switch (bitmap_info.format)
4685 {
4686 case ANDROID_BITMAP_FORMAT_RGBA_8888:
4687 image->depth = 24;
4688 image->bits_per_pixel = 32;
4689 break;
4690
4691
4692
4693 case ANDROID_BITMAP_FORMAT_A_8:
4694 image->depth = 1;
4695 image->bits_per_pixel = 1;
4696 break;
4697
4698
4699 default:
4700 emacs_abort ();
4701 }
4702
4703 image->format = format;
4704
4705 if (image->depth == 24)
4706 {
4707 image->bytes_per_line = bitmap_info.stride;
4708
4709
4710 memcpy (image->data, data, byte_size);
4711 }
4712 else
4713 {
4714
4715 image->bytes_per_line = (image->width + 7) / 8;
4716
4717 data1 = (unsigned char *) image->data;
4718 data2 = data;
4719
4720 for (i = 0; i < image->height; ++i)
4721 {
4722 for (x = 0; x < image->width; ++x)
4723
4724
4725 data1[x / 8] = (data2[x]
4726 ? (data1[x / 8] | (1 << (x % 8)))
4727 : (data1[x / 8] & ~(1 << (x % 8))));
4728
4729 data1 += image->bytes_per_line;
4730 data2 += bitmap_info.stride;
4731 }
4732 }
4733
4734
4735 AndroidBitmap_unlockPixels (android_java_env, bitmap);
4736
4737
4738 ANDROID_DELETE_LOCAL_REF (bitmap);
4739 return image;
4740 }
4741
4742 void
4743 android_put_image (android_pixmap handle, struct android_image *image)
4744 {
4745 jobject drawable, bitmap;
4746 AndroidBitmapInfo bitmap_info;
4747 void *data;
4748 unsigned char *data_1, *data_2;
4749 int i, x;
4750
4751 drawable = android_resolve_handle (handle, ANDROID_HANDLE_PIXMAP);
4752
4753
4754
4755 bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
4756 drawable,
4757 drawable_class.get_bitmap);
4758 android_exception_check ();
4759
4760
4761 memset (&bitmap_info, 0, sizeof bitmap_info);
4762
4763
4764
4765 AndroidBitmap_getInfo (android_java_env, bitmap, &bitmap_info);
4766
4767 if (!bitmap_info.stride)
4768 {
4769 ANDROID_DELETE_LOCAL_REF (bitmap);
4770 memory_full (0);
4771 }
4772
4773 if (bitmap_info.width != image->width
4774 || bitmap_info.height != image->height)
4775
4776 emacs_abort ();
4777
4778
4779
4780 if ((image->depth == 24
4781 && bitmap_info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
4782 || (image->depth == 1
4783 && bitmap_info.format != ANDROID_BITMAP_FORMAT_A_8))
4784 emacs_abort ();
4785
4786
4787
4788
4789 data = NULL;
4790 AndroidBitmap_lockPixels (android_java_env, bitmap, &data);
4791
4792 if (!data)
4793 {
4794
4795
4796 ANDROID_DELETE_LOCAL_REF (bitmap);
4797 memory_full (0);
4798 }
4799
4800 data_1 = data;
4801 data_2 = (unsigned char *) image->data;
4802
4803
4804 for (i = 0; i < image->height; ++i)
4805 {
4806 if (image->depth != 1)
4807 memcpy (data_1, data_2,
4808 image->width * (image->bits_per_pixel / 8));
4809 else
4810 {
4811
4812
4813
4814
4815 for (x = 0; x < image->width; ++x)
4816 data_1[x] = (data_2[x / 8] & (1 << x % 8)) ? 0xff : 0;
4817 }
4818
4819 data_1 += bitmap_info.stride;
4820 data_2 += image->bytes_per_line;
4821 }
4822
4823
4824 AndroidBitmap_unlockPixels (android_java_env, bitmap);
4825
4826
4827 ANDROID_DELETE_LOCAL_REF (bitmap);
4828 }
4829
4830 void
4831 android_bell (void)
4832 {
4833 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4834 emacs_service,
4835 service_class.class,
4836 service_class.ring_bell);
4837 android_exception_check ();
4838 }
4839
4840 void
4841 android_set_input_focus (android_window handle, unsigned long time)
4842 {
4843 jobject window;
4844 jmethodID make_input_focus;
4845
4846 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
4847 make_input_focus = window_class.make_input_focus;
4848
4849 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4850 window,
4851 window_class.class,
4852 make_input_focus,
4853 (jlong) time);
4854 android_exception_check ();
4855 }
4856
4857 void
4858 android_raise_window (android_window handle)
4859 {
4860 jobject window;
4861 jmethodID raise;
4862
4863 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
4864 raise = window_class.raise;
4865
4866 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4867 window,
4868 window_class.class,
4869 raise);
4870 android_exception_check ();
4871 }
4872
4873 void
4874 android_lower_window (android_window handle)
4875 {
4876 jobject window;
4877 jmethodID lower;
4878
4879 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
4880 lower = window_class.lower;
4881
4882 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
4883 window,
4884 window_class.class,
4885 lower);
4886 android_exception_check ();
4887 }
4888
4889 int
4890 android_query_tree (android_window handle, android_window *root_return,
4891 android_window *parent_return,
4892 android_window **children_return,
4893 unsigned int *nchildren_return)
4894 {
4895 jobject window, array;
4896 jsize nelements, i;
4897 android_window *children;
4898 jshort *shorts;
4899
4900 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
4901
4902
4903 array
4904 = (*android_java_env)->CallObjectMethod (android_java_env,
4905 emacs_service,
4906 service_class.query_tree,
4907 window);
4908 android_exception_check ();
4909
4910
4911
4912 nelements = (*android_java_env)->GetArrayLength (android_java_env,
4913 array);
4914 eassert (nelements);
4915
4916
4917 children = xnmalloc (nelements - 1, sizeof *children);
4918
4919 shorts
4920 = (*android_java_env)->GetShortArrayElements (android_java_env, array,
4921 NULL);
4922 android_exception_check_nonnull (shorts, array);
4923
4924 for (i = 1; i < nelements; ++i)
4925
4926
4927 children[i - 1] = shorts[i];
4928
4929
4930 *root_return = 0;
4931 *parent_return = shorts[0];
4932 *children_return = children;
4933 *nchildren_return = nelements - 1;
4934
4935
4936 (*android_java_env)->ReleaseShortArrayElements (android_java_env, array,
4937 shorts, JNI_ABORT);
4938
4939 ANDROID_DELETE_LOCAL_REF (array);
4940 return 1;
4941 }
4942
4943 void
4944 android_get_geometry (android_window handle,
4945 android_window *root_return,
4946 int *x_return, int *y_return,
4947 unsigned int *width_return,
4948 unsigned int *height_return,
4949 unsigned int *border_width_return)
4950 {
4951 jobject window;
4952 jarray window_geometry;
4953 jmethodID get_geometry;
4954 jint *ints;
4955
4956 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
4957 get_geometry = window_class.get_window_geometry;
4958
4959 window_geometry
4960 = (*android_java_env)->CallObjectMethod (android_java_env,
4961 window,
4962 get_geometry);
4963 android_exception_check ();
4964
4965
4966
4967 eassert ((*android_java_env)->GetArrayLength (android_java_env,
4968 window_geometry)
4969 == 4);
4970
4971 *root_return = 0;
4972 *border_width_return = 0;
4973
4974 ints
4975 = (*android_java_env)->GetIntArrayElements (android_java_env,
4976 window_geometry,
4977 NULL);
4978 android_exception_check_nonnull (ints, window_geometry);
4979
4980 *x_return = ints[0];
4981 *y_return = ints[1];
4982 *width_return = ints[2];
4983 *height_return = ints[3];
4984
4985 (*android_java_env)->ReleaseIntArrayElements (android_java_env,
4986 window_geometry,
4987 ints, JNI_ABORT);
4988
4989
4990 ANDROID_DELETE_LOCAL_REF (window_geometry);
4991 }
4992
4993 void
4994 android_move_resize_window (android_window window, int x, int y,
4995 unsigned int width, unsigned int height)
4996 {
4997 android_move_window (window, x, y);
4998 android_resize_window (window, width, height);
4999 }
5000
5001 void
5002 android_map_raised (android_window window)
5003 {
5004 android_raise_window (window);
5005 android_map_window (window);
5006 }
5007
5008 void
5009 android_translate_coordinates (android_window src, int x,
5010 int y, int *root_x, int *root_y)
5011 {
5012 jobject window;
5013 jarray coordinates;
5014 jmethodID method;
5015 jint *ints;
5016
5017 window = android_resolve_handle (src, ANDROID_HANDLE_WINDOW);
5018 method = window_class.translate_coordinates;
5019 coordinates
5020 = (*android_java_env)->CallObjectMethod (android_java_env,
5021 window, method,
5022 (jint) x, (jint) y);
5023 android_exception_check ();
5024
5025
5026
5027 eassert ((*android_java_env)->GetArrayLength (android_java_env,
5028 coordinates)
5029 == 2);
5030
5031
5032 ints = (*android_java_env)->GetIntArrayElements (android_java_env,
5033 coordinates, NULL);
5034 android_exception_check_nonnull (ints, coordinates);
5035
5036 *root_x = ints[0];
5037 *root_y = ints[1];
5038
5039
5040 (*android_java_env)->ReleaseIntArrayElements (android_java_env,
5041 coordinates, ints,
5042 JNI_ABORT);
5043
5044
5045 ANDROID_DELETE_LOCAL_REF (coordinates);
5046 }
5047
5048 int
5049 android_wc_lookup_string (android_key_pressed_event *event,
5050 wchar_t *buffer_return, int wchars_buffer,
5051 int *keysym_return,
5052 enum android_lookup_status *status_return)
5053 {
5054 enum android_lookup_status status;
5055 int rc;
5056 jobject window, string;
5057 const jchar *characters;
5058 jsize size;
5059 size_t i;
5060
5061 status = ANDROID_LOOKUP_NONE;
5062 rc = 0;
5063
5064
5065
5066
5067
5068 if (event->unicode_char != (uint32_t) -1)
5069 {
5070 if (event->unicode_char)
5071 {
5072 if (wchars_buffer < 1)
5073 {
5074 *status_return = ANDROID_BUFFER_OVERFLOW;
5075 return 0;
5076 }
5077 else
5078 {
5079 buffer_return[0] = event->unicode_char;
5080 status = ANDROID_LOOKUP_CHARS;
5081 rc = 1;
5082 }
5083 }
5084
5085 *keysym_return = event->keycode;
5086
5087 if (status == ANDROID_LOOKUP_CHARS)
5088 status = ANDROID_LOOKUP_BOTH;
5089 else
5090 {
5091 status = ANDROID_LOOKUP_KEYSYM;
5092 rc = 0;
5093 }
5094
5095 *status_return = status;
5096
5097 return rc;
5098 }
5099
5100
5101 rc = 0;
5102
5103 if (!android_handles[event->window].handle
5104 || (android_handles[event->window].type
5105 != ANDROID_HANDLE_WINDOW))
5106 status = ANDROID_LOOKUP_NONE;
5107 else
5108 {
5109 window = android_handles[event->window].handle;
5110 string
5111 = (*android_java_env)->CallObjectMethod (android_java_env, window,
5112 window_class.lookup_string,
5113 (jint) event->serial);
5114 android_exception_check ();
5115
5116 if (!string)
5117 status = ANDROID_LOOKUP_NONE;
5118 else
5119 {
5120
5121 characters = (*android_java_env)->GetStringChars (android_java_env,
5122 string, NULL);
5123 android_exception_check_nonnull ((void *) characters, string);
5124
5125
5126 size = (*android_java_env)->GetStringLength (android_java_env,
5127 string);
5128
5129
5130 for (i = 0; i < MIN ((unsigned int) wchars_buffer, size); ++i)
5131 buffer_return[i] = characters[i];
5132
5133 if (i < size)
5134 status = ANDROID_BUFFER_OVERFLOW;
5135 else
5136 status = ANDROID_LOOKUP_CHARS;
5137
5138
5139
5140
5141 if (size > INT_MAX)
5142 rc = INT_MAX;
5143 else
5144 rc = size;
5145
5146 (*android_java_env)->ReleaseStringChars (android_java_env, string,
5147 characters);
5148 ANDROID_DELETE_LOCAL_REF (string);
5149 }
5150 }
5151
5152 *status_return = status;
5153 return rc;
5154 }
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166 unsigned char *
5167 android_lock_bitmap (android_window drawable,
5168 AndroidBitmapInfo *bitmap_info,
5169 jobject *bitmap_return)
5170 {
5171 jobject object, bitmap;
5172 void *data;
5173
5174 object = android_resolve_handle2 (drawable, ANDROID_HANDLE_WINDOW,
5175 ANDROID_HANDLE_PIXMAP);
5176
5177
5178
5179 bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
5180 object,
5181 drawable_class.get_bitmap);
5182 if (!bitmap)
5183
5184
5185 return NULL;
5186
5187 memset (bitmap_info, 0, sizeof *bitmap_info);
5188
5189
5190 AndroidBitmap_getInfo (android_java_env, bitmap, bitmap_info);
5191
5192 if (!bitmap_info->stride)
5193 {
5194 ANDROID_DELETE_LOCAL_REF (bitmap);
5195 return NULL;
5196 }
5197
5198
5199 data = NULL;
5200 AndroidBitmap_lockPixels (android_java_env, bitmap, &data);
5201
5202 if (!data)
5203 {
5204 ANDROID_DELETE_LOCAL_REF (bitmap);
5205 return NULL;
5206 }
5207
5208
5209 *bitmap_return = bitmap;
5210
5211
5212 return data;
5213 }
5214
5215
5216
5217 void
5218 android_damage_window (android_drawable handle,
5219 struct android_rectangle *damage)
5220 {
5221 jobject drawable, rect;
5222
5223 drawable = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
5224
5225
5226 rect = (*android_java_env)->NewObject (android_java_env,
5227 android_rect_class,
5228 android_rect_constructor,
5229 (jint) damage->x,
5230 (jint) damage->y,
5231 (jint) (damage->x
5232 + damage->width),
5233 (jint) (damage->y
5234 + damage->height));
5235 android_exception_check ();
5236
5237
5238 (*android_java_env)->CallVoidMethod (android_java_env,
5239 drawable,
5240 drawable_class.damage_rect,
5241 rect);
5242 android_exception_check_1 (rect);
5243 ANDROID_DELETE_LOCAL_REF (rect);
5244 }
5245
5246
5247
5248
5249
5250 int
5251 android_get_screen_width (void)
5252 {
5253 int rc;
5254 jmethodID method;
5255
5256 method = service_class.get_screen_width;
5257 rc = (*android_java_env)->CallNonvirtualIntMethod (android_java_env,
5258 emacs_service,
5259 service_class.class,
5260 method,
5261 (jboolean) false);
5262 android_exception_check ();
5263 return rc;
5264 }
5265
5266 int
5267 android_get_screen_height (void)
5268 {
5269 int rc;
5270 jmethodID method;
5271
5272 method = service_class.get_screen_height;
5273 rc = (*android_java_env)->CallNonvirtualIntMethod (android_java_env,
5274 emacs_service,
5275 service_class.class,
5276 method,
5277 (jboolean) false);
5278 android_exception_check ();
5279 return rc;
5280 }
5281
5282 int
5283 android_get_mm_width (void)
5284 {
5285 int rc;
5286 jmethodID method;
5287
5288 method = service_class.get_screen_width;
5289 rc = (*android_java_env)->CallNonvirtualIntMethod (android_java_env,
5290 emacs_service,
5291 service_class.class,
5292 method,
5293 (jboolean) true);
5294 android_exception_check ();
5295 return rc;
5296 }
5297
5298 int
5299 android_get_mm_height (void)
5300 {
5301 int rc;
5302 jmethodID method;
5303
5304 method = service_class.get_screen_height;
5305 rc = (*android_java_env)->CallNonvirtualIntMethod (android_java_env,
5306 emacs_service,
5307 service_class.class,
5308 method,
5309 (jboolean) true);
5310 android_exception_check ();
5311 return rc;
5312 }
5313
5314 bool
5315 android_detect_mouse (void)
5316 {
5317 bool rc;
5318 jmethodID method;
5319
5320 method = service_class.detect_mouse;
5321 rc = (*android_java_env)->CallNonvirtualBooleanMethod (android_java_env,
5322 emacs_service,
5323 service_class.class,
5324 method);
5325 android_exception_check ();
5326 return rc;
5327 }
5328
5329 void
5330 android_set_dont_focus_on_map (android_window handle,
5331 bool no_focus_on_map)
5332 {
5333 jmethodID method;
5334 jobject window;
5335
5336 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
5337 method = window_class.set_dont_focus_on_map;
5338
5339 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, window,
5340 window_class.class,
5341 method,
5342 (jboolean) no_focus_on_map);
5343 android_exception_check ();
5344 }
5345
5346 void
5347 android_set_dont_accept_focus (android_window handle,
5348 bool no_accept_focus)
5349 {
5350 jmethodID method;
5351 jobject window;
5352
5353 window = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
5354 method = window_class.set_dont_accept_focus;
5355
5356 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, window,
5357 window_class.class,
5358 method,
5359 (jboolean) no_accept_focus);
5360 android_exception_check ();
5361 }
5362
5363 void
5364 android_get_keysym_name (int keysym, char *name_return, size_t size)
5365 {
5366 jobject string;
5367 const char *buffer;
5368
5369 string = (*android_java_env)->CallObjectMethod (android_java_env,
5370 emacs_service,
5371 service_class.name_keysym,
5372 (jint) keysym);
5373 android_exception_check ();
5374
5375 buffer = (*android_java_env)->GetStringUTFChars (android_java_env,
5376 (jstring) string,
5377 NULL);
5378 android_exception_check_nonnull ((void *) buffer, string);
5379 strncpy (name_return, buffer, size - 1);
5380 name_return[size] = '\0';
5381
5382 (*android_java_env)->ReleaseStringUTFChars (android_java_env,
5383 (jstring) string,
5384 buffer);
5385 ANDROID_DELETE_LOCAL_REF (string);
5386 }
5387
5388
5389
5390
5391
5392
5393
5394 void
5395 android_toggle_on_screen_keyboard (android_window window, bool show)
5396 {
5397 jobject object;
5398 jmethodID method;
5399
5400 object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
5401 method = window_class.toggle_on_screen_keyboard;
5402
5403
5404 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, object,
5405 window_class.class,
5406 method, (jboolean) show);
5407
5408
5409 android_exception_check ();
5410 }
5411
5412
5413
5414
5415
5416
5417 void
5418 emacs_abort (void)
5419 {
5420 volatile char *foo;
5421
5422 __android_log_print (ANDROID_LOG_FATAL, __func__,
5423 "emacs_abort called, please review the ensuing"
5424 " stack trace");
5425
5426
5427
5428 foo = NULL;
5429 *foo = '\0';
5430
5431 abort ();
5432 }
5433
5434
5435
5436
5437
5438
5439 static bool
5440 android_check_string (Lisp_Object text)
5441 {
5442 ptrdiff_t i;
5443
5444 for (i = 0; i < SBYTES (text); ++i)
5445 {
5446 if (SREF (text, i) & 128)
5447 return false;
5448 }
5449
5450 return true;
5451 }
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467 int
5468 android_verify_jni_string (const char *name)
5469 {
5470 const unsigned char *chars;
5471
5472 chars = (unsigned char *) name;
5473 while (*chars)
5474 {
5475
5476
5477 switch (*chars++ >> 4)
5478 {
5479 case 0 ... 7:
5480
5481
5482 break;
5483
5484 case 8 ... 0xb:
5485
5486 return 1;
5487
5488 case 0xf:
5489
5490
5491 return 1;
5492
5493 case 0xe:
5494
5495
5496
5497 if ((*chars++ & 0xc0) != 0x80)
5498 return 1;
5499
5500 FALLTHROUGH;
5501
5502 case 0xc ... 0xd:
5503
5504
5505
5506 if ((*chars++ & 0xc0) != 0x80)
5507 return 1;
5508
5509 break;
5510 }
5511 }
5512
5513 return 0;
5514 }
5515
5516
5517
5518
5519 jstring
5520 android_build_string (Lisp_Object text)
5521 {
5522 Lisp_Object encoded;
5523 jstring string;
5524 size_t nchars;
5525 jchar *characters;
5526 USE_SAFE_ALLOCA;
5527
5528
5529
5530
5531
5532
5533 if ((SBYTES (text) == SCHARS (text)
5534 && android_check_string (text))
5535
5536
5537
5538 || (STRING_MULTIBYTE (text)
5539 && !android_verify_jni_string (SSDATA (text))))
5540 {
5541 string = (*android_java_env)->NewStringUTF (android_java_env,
5542 SSDATA (text));
5543 android_exception_check ();
5544 SAFE_FREE ();
5545
5546 return string;
5547 }
5548
5549 encoded = code_convert_string_norecord (text, Qutf_16le,
5550 true);
5551 nchars = (SBYTES (encoded) / sizeof (jchar));
5552
5553
5554
5555
5556
5557 characters = SAFE_ALLOCA (SBYTES (encoded));
5558 memcpy (characters, SDATA (encoded), SBYTES (encoded));
5559
5560
5561 string
5562 = (*android_java_env)->NewString (android_java_env,
5563 characters, nchars);
5564 android_exception_check ();
5565
5566 SAFE_FREE ();
5567 return string;
5568 }
5569
5570
5571
5572
5573
5574 jstring
5575 android_build_jstring (const char *text)
5576 {
5577 jstring string;
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587 string = (*android_java_env)->NewStringUTF (android_java_env,
5588 text);
5589 android_exception_check ();
5590
5591 return string;
5592 }
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628 #if __GNUC__ >= 3
5629 #define likely(cond) __builtin_expect ((cond), 1)
5630 #else
5631 #define likely(cond) (cond)
5632 #endif
5633
5634
5635
5636
5637 void
5638 android_exception_check (void)
5639 {
5640 if (likely (!(*android_java_env)->ExceptionCheck (android_java_env)))
5641 return;
5642
5643 __android_log_print (ANDROID_LOG_WARN, __func__,
5644 "Possible out of memory error. "
5645 " The Java exception follows: ");
5646
5647 (*android_java_env)->ExceptionDescribe (android_java_env);
5648 (*android_java_env)->ExceptionClear (android_java_env);
5649 memory_full (0);
5650 }
5651
5652
5653
5654
5655
5656 void
5657 android_exception_check_1 (jobject object)
5658 {
5659 if (likely (!(*android_java_env)->ExceptionCheck (android_java_env)))
5660 return;
5661
5662 __android_log_print (ANDROID_LOG_WARN, __func__,
5663 "Possible out of memory error. "
5664 " The Java exception follows: ");
5665
5666 (*android_java_env)->ExceptionDescribe (android_java_env);
5667 (*android_java_env)->ExceptionClear (android_java_env);
5668 ANDROID_DELETE_LOCAL_REF (object);
5669 memory_full (0);
5670 }
5671
5672
5673
5674
5675 void
5676 android_exception_check_2 (jobject object, jobject object1)
5677 {
5678 if (likely (!(*android_java_env)->ExceptionCheck (android_java_env)))
5679 return;
5680
5681 __android_log_print (ANDROID_LOG_WARN, __func__,
5682 "Possible out of memory error. "
5683 " The Java exception follows: ");
5684
5685 (*android_java_env)->ExceptionDescribe (android_java_env);
5686 (*android_java_env)->ExceptionClear (android_java_env);
5687 ANDROID_DELETE_LOCAL_REF (object);
5688 ANDROID_DELETE_LOCAL_REF (object1);
5689 memory_full (0);
5690 }
5691
5692
5693
5694
5695 void
5696 android_exception_check_3 (jobject object, jobject object1,
5697 jobject object2)
5698 {
5699 if (likely (!(*android_java_env)->ExceptionCheck (android_java_env)))
5700 return;
5701
5702 __android_log_print (ANDROID_LOG_WARN, __func__,
5703 "Possible out of memory error. "
5704 " The Java exception follows: ");
5705
5706 (*android_java_env)->ExceptionDescribe (android_java_env);
5707 (*android_java_env)->ExceptionClear (android_java_env);
5708 ANDROID_DELETE_LOCAL_REF (object);
5709 ANDROID_DELETE_LOCAL_REF (object1);
5710 ANDROID_DELETE_LOCAL_REF (object2);
5711 memory_full (0);
5712 }
5713
5714
5715
5716
5717 void
5718 android_exception_check_4 (jobject object, jobject object1,
5719 jobject object2, jobject object3)
5720 {
5721 if (likely (!(*android_java_env)->ExceptionCheck (android_java_env)))
5722 return;
5723
5724 __android_log_print (ANDROID_LOG_WARN, __func__,
5725 "Possible out of memory error. "
5726 " The Java exception follows: ");
5727
5728 (*android_java_env)->ExceptionDescribe (android_java_env);
5729 (*android_java_env)->ExceptionClear (android_java_env);
5730 ANDROID_DELETE_LOCAL_REF (object);
5731 ANDROID_DELETE_LOCAL_REF (object1);
5732 ANDROID_DELETE_LOCAL_REF (object2);
5733 ANDROID_DELETE_LOCAL_REF (object3);
5734 memory_full (0);
5735 }
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746 void
5747 android_exception_check_nonnull (void *object, jobject object1)
5748 {
5749 if (likely (object != NULL))
5750 return;
5751
5752 if (object1)
5753 ANDROID_DELETE_LOCAL_REF (object1);
5754
5755 memory_full (0);
5756 }
5757
5758
5759
5760
5761
5762
5763 void
5764 android_exception_check_nonnull_1 (void *object, jobject object1,
5765 jobject object2)
5766 {
5767 if (likely (object != NULL))
5768 return;
5769
5770 if (object1)
5771 ANDROID_DELETE_LOCAL_REF (object1);
5772
5773 if (object2)
5774 ANDROID_DELETE_LOCAL_REF (object2);
5775
5776 memory_full (0);
5777 }
5778
5779
5780
5781
5782
5783
5784
5785
5786 static void
5787 android_transform_coordinates (int x, int y,
5788 struct android_transform *transform,
5789 float *xout, float *yout)
5790 {
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808 *xout = transform->m1 * x + transform->m2 * y + transform->m3;
5809 *yout = transform->m4 * x + transform->m5 * y + transform->m6;
5810 }
5811
5812
5813
5814
5815 static unsigned int
5816 android_four_corners_bilinear (unsigned int tl, unsigned int tr,
5817 unsigned int bl, unsigned int br,
5818 int distx, int disty)
5819 {
5820 int distxy, distxiy, distixy, distixiy;
5821 uint32_t f, r;
5822
5823 distxy = distx * disty;
5824 distxiy = (distx << 8) - distxy;
5825 distixy = (disty << 8) - distxy;
5826 distixiy = (256 * 256 - (disty << 8)
5827 - (distx << 8) + distxy);
5828
5829
5830 r = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
5831 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
5832
5833
5834 f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
5835 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
5836 r |= f & 0xff000000;
5837
5838
5839 tl >>= 16;
5840 tr >>= 16;
5841 bl >>= 16;
5842 br >>= 16;
5843 r >>= 16;
5844
5845
5846 f = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
5847 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
5848 r |= f & 0x00ff0000;
5849
5850
5851 f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
5852 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
5853 r |= f & 0xff000000;
5854
5855 return r;
5856 }
5857
5858
5859
5860
5861
5862 static unsigned int
5863 android_fetch_pixel_bilinear (struct android_image *image,
5864 float x, float y)
5865 {
5866 int x1, y1, x2, y2;
5867 float distx, disty;
5868 unsigned int top_left, top_right;
5869 unsigned int bottom_left, bottom_right;
5870 char *word;
5871
5872
5873 x1 = (int) x;
5874 x2 = x1 + 1;
5875 y1 = (int) y;
5876 y2 = y1 + 1;
5877
5878
5879 x1 = MAX (0, MIN (image->width - 1, x1));
5880 y1 = MAX (0, MIN (image->height - 1, y1));
5881 x2 = MAX (0, MIN (image->width - 1, x2));
5882 y2 = MAX (0, MIN (image->height - 1, y2));
5883
5884
5885
5886 distx = x - x1;
5887 disty = y - y1;
5888
5889
5890 word = image->data + y1 * image->bytes_per_line + x1 * 4;
5891 memcpy (&top_left, word, sizeof top_left);
5892 word = image->data + y1 * image->bytes_per_line + x2 * 4;
5893 memcpy (&top_right, word, sizeof top_right);
5894 word = image->data + y2 * image->bytes_per_line + x1 * 4;
5895 memcpy (&bottom_left, word, sizeof bottom_left);
5896 word = image->data + y2 * image->bytes_per_line + x2 * 4;
5897 memcpy (&bottom_right, word, sizeof bottom_right);
5898
5899
5900 return android_four_corners_bilinear (top_left, top_right, bottom_left,
5901 bottom_right, distx * 256,
5902 disty * 256);
5903 }
5904
5905
5906
5907
5908
5909
5910 void
5911 android_project_image_bilinear (struct android_image *image,
5912 struct android_image *out,
5913 struct android_transform *transform)
5914 {
5915 int x, y;
5916 unsigned int pixel;
5917 float xout, yout;
5918 char *word;
5919
5920
5921
5922
5923 for (y = 0; y < out->height; ++y)
5924 {
5925 for (x = 0; x < out->width; ++x)
5926 {
5927
5928 android_transform_coordinates (x, y, transform,
5929 &xout, &yout);
5930
5931
5932 pixel = android_fetch_pixel_bilinear (image, xout, yout);
5933
5934
5935 word = out->data + y * out->bytes_per_line + x * 4;
5936 memcpy (word, &pixel, sizeof pixel);
5937 }
5938 }
5939 }
5940
5941
5942
5943 static unsigned int
5944 android_fetch_pixel_nearest_24 (struct android_image *image, float x,
5945 float y)
5946 {
5947 int x1, y1;
5948 char *word;
5949 unsigned int pixel;
5950
5951 x1 = MAX (0, MIN (image->width - 1, (int) roundf (x)));
5952 y1 = MAX (0, MIN (image->height - 1, (int) roundf (y)));
5953
5954 word = image->data + y1 * image->bytes_per_line + x1 * 4;
5955 memcpy (&pixel, word, sizeof pixel);
5956
5957 return pixel;
5958 }
5959
5960
5961
5962 static unsigned int
5963 android_fetch_pixel_nearest_1 (struct android_image *image, float x,
5964 float y)
5965 {
5966 int x1, y1;
5967 char *byte;
5968
5969 x1 = MAX (0, MIN (image->width - 1, (int) roundf (x)));
5970 y1 = MAX (0, MIN (image->height - 1, (int) roundf (y)));
5971
5972 byte = image->data + y1 * image->bytes_per_line;
5973 return (byte[x1 / 8] & (1 << x1 % 8)) ? 1 : 0;
5974 }
5975
5976
5977
5978
5979
5980
5981 void
5982 android_project_image_nearest (struct android_image *image,
5983 struct android_image *out,
5984 struct android_transform *transform)
5985 {
5986 int x, y;
5987 unsigned int pixel;
5988 float xout, yout;
5989 char *word, *byte;
5990
5991 if (image->depth == 1)
5992 {
5993 for (y = 0; y < out->height; ++y)
5994 {
5995 for (x = 0; x < out->width; ++x)
5996 {
5997
5998 android_transform_coordinates (x, y, transform,
5999 &xout, &yout);
6000
6001
6002 pixel = android_fetch_pixel_nearest_1 (image, xout, yout);
6003
6004
6005 byte = out->data + y * out->bytes_per_line + x / 8;
6006
6007 if (pixel)
6008 *byte |= (1 << x % 8);
6009 else
6010 *byte &= ~(1 << x % 8);
6011 }
6012 }
6013
6014 return;
6015 }
6016
6017 for (y = 0; y < out->height; ++y)
6018 {
6019 for (x = 0; x < out->width; ++x)
6020 {
6021
6022 android_transform_coordinates (x, y, transform,
6023 &xout, &yout);
6024
6025
6026 pixel = android_fetch_pixel_nearest_24 (image, xout, yout);
6027
6028
6029 word = out->data + y * out->bytes_per_line + x * 4;
6030 memcpy (word, &pixel, sizeof pixel);
6031 }
6032 }
6033 }
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046 Lisp_Object
6047 android_browse_url (Lisp_Object url, Lisp_Object send)
6048 {
6049 jobject value, string;
6050 Lisp_Object tem;
6051 const char *buffer;
6052
6053 string = android_build_string (url);
6054 value = (*android_java_env)->CallObjectMethod (android_java_env,
6055 emacs_service,
6056 service_class.browse_url,
6057 string,
6058 (jboolean) !NILP (send));
6059 android_exception_check ();
6060
6061 ANDROID_DELETE_LOCAL_REF (string);
6062
6063
6064 if (!value)
6065 return Qnil;
6066
6067 buffer = (*android_java_env)->GetStringUTFChars (android_java_env,
6068 (jstring) value,
6069 NULL);
6070 android_exception_check_1 (string);
6071
6072
6073 tem = build_string_from_utf8 (buffer);
6074
6075 (*android_java_env)->ReleaseStringUTFChars (android_java_env,
6076 (jstring) value,
6077 buffer);
6078
6079
6080 ANDROID_DELETE_LOCAL_REF (value);
6081 return tem;
6082 }
6083
6084
6085
6086
6087
6088 _Noreturn void
6089 android_restart_emacs (void)
6090 {
6091
6092
6093 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
6094 emacs_service,
6095 service_class.class,
6096 service_class.restart_emacs);
6097
6098
6099 exit (0);
6100 }
6101
6102
6103
6104
6105
6106
6107
6108
6109 int
6110 (android_get_current_api_level) (void)
6111 {
6112 return android_api_level;
6113 }
6114
6115
6116
6117
6118 int
6119 android_query_battery (struct android_battery_state *status)
6120 {
6121 jlongArray array;
6122 jlong *longs;
6123
6124 array = (*android_java_env)->CallObjectMethod (android_java_env,
6125 emacs_service,
6126 service_class.query_battery);
6127 android_exception_check ();
6128
6129
6130
6131
6132 if (!array)
6133 return 1;
6134
6135 longs = (*android_java_env)->GetLongArrayElements (android_java_env,
6136 array, NULL);
6137 android_exception_check_nonnull (longs, array);
6138
6139 status->capacity = longs[0];
6140 status->charge_counter = longs[1];
6141 status->current_average = longs[2];
6142 status->current_now = longs[3];
6143 status->remaining = longs[4];
6144 status->status = longs[5];
6145 status->plugged = longs[6];
6146 status->temperature = longs[7];
6147
6148 (*android_java_env)->ReleaseLongArrayElements (android_java_env,
6149 array, longs,
6150 JNI_ABORT);
6151 ANDROID_DELETE_LOCAL_REF (array);
6152
6153 return 0;
6154 }
6155
6156
6157
6158
6159
6160
6161 int
6162 android_request_directory_access (void)
6163 {
6164 jint rc;
6165 jmethodID method;
6166
6167 method = service_class.request_directory_access;
6168 rc = (*android_java_env)->CallNonvirtualIntMethod (android_java_env,
6169 emacs_service,
6170 service_class.class,
6171 method);
6172 android_exception_check ();
6173
6174 return rc;
6175 }
6176
6177
6178
6179
6180
6181
6182
6183 static char android_servicing_query;
6184
6185
6186 static void (*android_query_function) (void *);
6187
6188
6189 static void *android_query_context;
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221 static void
6222 android_check_query (void)
6223 {
6224 void (*proc) (void *);
6225 void *closure;
6226
6227 if (!__atomic_load_n (&android_servicing_query, __ATOMIC_ACQUIRE))
6228 return;
6229
6230
6231 closure = android_query_context;
6232 proc = android_query_function;
6233
6234 if (!proc)
6235 return;
6236
6237 proc (closure);
6238
6239
6240 android_query_context = NULL;
6241 android_query_function = NULL;
6242 __atomic_store_n (&android_servicing_query, 0, __ATOMIC_RELEASE);
6243 __atomic_clear (&android_urgent_query, __ATOMIC_RELEASE);
6244
6245
6246 sem_post (&android_query_sem);
6247 }
6248
6249
6250
6251
6252
6253
6254
6255
6256 void
6257 android_check_query_urgent (void)
6258 {
6259 void (*proc) (void *);
6260 void *closure;
6261
6262 if (!__atomic_load_n (&android_urgent_query, __ATOMIC_ACQUIRE))
6263 return;
6264
6265 __android_log_print (ANDROID_LOG_VERBOSE, __func__,
6266 "Responding to urgent query...");
6267
6268 if (!__atomic_load_n (&android_servicing_query, __ATOMIC_ACQUIRE))
6269 return;
6270
6271
6272 closure = android_query_context;
6273 proc = android_query_function;
6274
6275 if (!proc)
6276 return;
6277
6278 proc (closure);
6279
6280
6281
6282
6283 android_query_context = NULL;
6284 android_query_function = NULL;
6285 __atomic_store_n (&android_servicing_query, 0, __ATOMIC_RELEASE);
6286
6287
6288 sem_post (&android_query_sem);
6289 }
6290
6291
6292
6293
6294
6295 static void
6296 android_answer_query (void)
6297 {
6298 void (*proc) (void *);
6299 void *closure;
6300
6301 eassert (__atomic_load_n (&android_servicing_query,
6302 __ATOMIC_ACQUIRE)
6303 == 1);
6304
6305
6306 closure = android_query_context;
6307 proc = android_query_function;
6308
6309 if (!proc)
6310 return;
6311
6312 proc (closure);
6313
6314
6315 android_query_context = NULL;
6316 android_query_function = NULL;
6317 __atomic_clear (&android_urgent_query, __ATOMIC_RELEASE);
6318
6319
6320 sem_post (&android_query_sem);
6321 }
6322
6323
6324
6325
6326 static void
6327 android_answer_query_spin (void)
6328 {
6329 int n;
6330
6331 while (!(n = __atomic_load_n (&android_servicing_query,
6332 __ATOMIC_ACQUIRE)))
6333 eassert (!n);
6334
6335
6336
6337 android_check_query ();
6338 }
6339
6340
6341
6342
6343
6344
6345
6346 static void
6347 android_begin_query (void)
6348 {
6349 char old;
6350
6351
6352
6353
6354 old = __atomic_exchange_n (&android_servicing_query,
6355 2, __ATOMIC_ACQ_REL);
6356
6357
6358 if (old == 1)
6359 {
6360
6361 assert (android_query_function != NULL);
6362 android_answer_query ();
6363 }
6364
6365
6366 }
6367
6368
6369
6370
6371 static void
6372 android_end_query (void)
6373 {
6374 __atomic_store_n (&android_servicing_query, 0, __ATOMIC_RELEASE);
6375 __atomic_clear (&android_urgent_query, __ATOMIC_RELEASE);
6376 }
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389 int
6390 android_run_in_emacs_thread (void (*proc) (void *), void *closure)
6391 {
6392 union android_event event;
6393 char old;
6394 int rc;
6395 struct timespec timeout;
6396
6397 event.xaction.type = ANDROID_WINDOW_ACTION;
6398 event.xaction.serial = ++event_serial;
6399 event.xaction.window = 0;
6400 event.xaction.action = 0;
6401
6402
6403 android_query_context = closure;
6404 android_query_function = proc;
6405
6406
6407
6408
6409
6410 old = 0;
6411 if (!__atomic_compare_exchange_n (&android_servicing_query, &old,
6412 1, false, __ATOMIC_ACQ_REL,
6413 __ATOMIC_ACQUIRE))
6414 {
6415 android_query_context = NULL;
6416 android_query_function = NULL;
6417
6418
6419
6420
6421
6422 return 1;
6423 }
6424
6425
6426
6427
6428
6429
6430 android_write_event (&event);
6431
6432
6433
6434
6435 timeout.tv_sec = 2;
6436 timeout.tv_nsec = 0;
6437 timeout = timespec_add (current_timespec (), timeout);
6438
6439
6440
6441
6442
6443 if (__atomic_load_n (&android_urgent_query, __ATOMIC_ACQUIRE))
6444 kill (getpid (), SIGIO);
6445
6446 again:
6447 rc = sem_timedwait (&android_query_sem, &timeout);
6448
6449 if (rc < 0)
6450 {
6451 if (errno == EINTR)
6452 goto again;
6453
6454 eassert (errno == ETIMEDOUT);
6455
6456 __android_log_print (ANDROID_LOG_VERBOSE, __func__,
6457 "Timed out waiting for response"
6458 " from main thread...");
6459
6460
6461
6462 __atomic_store_n (&android_urgent_query, true,
6463 __ATOMIC_RELEASE);
6464
6465 kill_again:
6466
6467
6468
6469
6470
6471
6472
6473 kill (getpid (), SIGIO);
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484 timeout.tv_sec = 4;
6485 timeout.tv_nsec = 0;
6486 timeout = timespec_add (current_timespec (), timeout);
6487
6488 while (sem_timedwait (&android_query_sem, &timeout) < 0)
6489 {
6490
6491
6492
6493 if (errno == ETIMEDOUT)
6494 goto kill_again;
6495
6496
6497 eassert (errno == EINTR);
6498 }
6499 }
6500
6501
6502
6503
6504
6505 eassert (!__atomic_load_n (&android_servicing_query,
6506 __ATOMIC_ACQUIRE)
6507 || (__atomic_load_n (&android_servicing_query,
6508 __ATOMIC_ACQUIRE) == 2));
6509
6510 return 0;
6511 }
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526 void
6527 android_update_ic (android_window window, ptrdiff_t selection_start,
6528 ptrdiff_t selection_end, ptrdiff_t composing_region_start,
6529 ptrdiff_t composing_region_end)
6530 {
6531 jobject object;
6532
6533 object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
6534
6535 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
6536 emacs_service,
6537 service_class.class,
6538 service_class.update_ic,
6539 object,
6540 (jint) selection_start,
6541 (jint) selection_end,
6542 (jint) composing_region_start,
6543 (jint) composing_region_end);
6544 android_exception_check ();
6545 }
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565 void
6566 android_reset_ic (android_window window, enum android_ic_mode mode)
6567 {
6568 jobject object;
6569
6570 object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
6571
6572 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
6573 emacs_service,
6574 service_class.class,
6575 service_class.reset_ic,
6576 object, (jint) mode);
6577 android_exception_check ();
6578 }
6579
6580
6581
6582
6583
6584
6585 void
6586 android_update_extracted_text (android_window window, void *text,
6587 int token)
6588 {
6589 jobject object;
6590 jmethodID method;
6591
6592 object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
6593 method = service_class.update_extracted_text;
6594
6595 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
6596 emacs_service,
6597 service_class.class,
6598 method, object,
6599
6600
6601
6602
6603
6604
6605 (jobject) text,
6606 (jint) token);
6607 android_exception_check_1 (text);
6608 }
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618 void
6619 android_update_cursor_anchor_info (android_window window, float x,
6620 float y, float y_baseline,
6621 float y_bottom)
6622 {
6623 jobject object;
6624 jmethodID method;
6625
6626 object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
6627 method = service_class.update_cursor_anchor_info;
6628
6629 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
6630 emacs_service,
6631 service_class.class,
6632 method,
6633 object,
6634 (jfloat) x,
6635 (jfloat) y,
6636 (jfloat) y_baseline,
6637 (jfloat) y_bottom);
6638 android_exception_check ();
6639 }
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651 int
6652 android_set_fullscreen (android_window window, bool fullscreen)
6653 {
6654 jobject object;
6655
6656
6657
6658 if (android_api_level < 16)
6659 return 1;
6660
6661 object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
6662
6663 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
6664 object,
6665 window_class.class,
6666 window_class.set_fullscreen,
6667 (jboolean) fullscreen);
6668 android_exception_check ();
6669 return 0;
6670 }
6671
6672
6673
6674
6675
6676 android_cursor
6677 android_create_font_cursor (enum android_cursor_shape shape)
6678 {
6679 android_cursor id;
6680 short prev_max_handle;
6681 jobject object;
6682
6683
6684 prev_max_handle = max_handle;
6685 id = android_alloc_id ();
6686
6687 if (!id)
6688 error ("Out of cursor handles!");
6689
6690
6691 object = (*android_java_env)->NewObject (android_java_env,
6692 cursor_class.class,
6693 cursor_class.constructor,
6694 (jshort) id,
6695 (jint) shape);
6696 if (!object)
6697 {
6698 (*android_java_env)->ExceptionClear (android_java_env);
6699 max_handle = prev_max_handle;
6700 memory_full (0);
6701 }
6702
6703 android_handles[id].type = ANDROID_HANDLE_CURSOR;
6704 android_handles[id].handle
6705 = (*android_java_env)->NewGlobalRef (android_java_env, object);
6706 (*android_java_env)->ExceptionClear (android_java_env);
6707 ANDROID_DELETE_LOCAL_REF (object);
6708
6709 if (!android_handles[id].handle)
6710 memory_full (0);
6711
6712 return id;
6713 }
6714
6715 void
6716 android_define_cursor (android_window window, android_cursor cursor)
6717 {
6718 jobject window1, cursor1;
6719 jmethodID method;
6720
6721 window1 = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
6722 cursor1 = android_resolve_handle (cursor, ANDROID_HANDLE_CURSOR);
6723 method = window_class.define_cursor;
6724
6725 (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
6726 window1,
6727 window_class.class,
6728 method, cursor1);
6729 android_exception_check ();
6730 }
6731
6732 void
6733 android_free_cursor (android_cursor cursor)
6734 {
6735 if (android_handles[cursor].type != ANDROID_HANDLE_CURSOR)
6736 {
6737 __android_log_print (ANDROID_LOG_ERROR, __func__,
6738 "Trying to destroy something not a CURSOR!");
6739 emacs_abort ();
6740 }
6741
6742 android_destroy_handle (cursor);
6743 }
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755 enum
6756 {
6757
6758 MAXARGS = 1024,
6759 };
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769 int
6770 android_rewrite_spawn_argv (const char ***argv)
6771 {
6772 static const char *new_args[MAXARGS];
6773 static char exec1_name[PATH_MAX], loader_name[PATH_MAX];
6774 size_t i, nargs;
6775
6776
6777
6778 if (android_api_level < 29 || !android_use_exec_loader)
6779 return 0;
6780
6781
6782
6783
6784 eassert (**argv);
6785 if (access (**argv, R_OK | X_OK))
6786 return 1;
6787
6788
6789
6790 nargs = 0;
6791 while ((*argv)[nargs])
6792 ++nargs;
6793
6794
6795
6796
6797 if (nargs + 2 > MAXARGS)
6798 {
6799 errno = E2BIG;
6800 return 1;
6801 }
6802
6803
6804 snprintf (exec1_name, PATH_MAX, "%s/libexec1.so",
6805 android_lib_dir);
6806
6807
6808 snprintf (loader_name, PATH_MAX, "%s/libloader.so",
6809 android_lib_dir);
6810
6811
6812 new_args[0] = exec1_name;
6813 new_args[1] = loader_name;
6814
6815
6816 for (i = 0; i < nargs + 1; ++i)
6817 new_args[i + 2] = (*argv)[i];
6818
6819
6820 *argv = new_args;
6821
6822
6823 return 0;
6824 }
6825
6826
6827
6828 #else
6829
6830
6831
6832 struct android_gc *
6833 android_create_gc (enum android_gc_value_mask mask,
6834 struct android_gc_values *values)
6835 {
6836
6837 emacs_abort ();
6838 }
6839
6840 void
6841 android_free_gc (struct android_gc *gc)
6842 {
6843
6844 emacs_abort ();
6845 }
6846
6847 struct android_image *
6848 android_create_image (unsigned int depth, enum android_image_format format,
6849 char *data, unsigned int width, unsigned int height)
6850 {
6851 emacs_abort ();
6852 }
6853
6854 void
6855 android_destroy_image (struct android_image *ximg)
6856 {
6857 emacs_abort ();
6858 }
6859
6860 void
6861 android_put_pixel (struct android_image *ximg, int x, int y,
6862 unsigned long pixel)
6863 {
6864 emacs_abort ();
6865 }
6866
6867 unsigned long
6868 android_get_pixel (struct android_image *ximg, int x, int y)
6869 {
6870 emacs_abort ();
6871 }
6872
6873 struct android_image *
6874 android_get_image (android_drawable drawable,
6875 enum android_image_format format)
6876 {
6877 emacs_abort ();
6878 }
6879
6880 void
6881 android_put_image (android_pixmap pixmap,
6882 struct android_image *image)
6883 {
6884 emacs_abort ();
6885 }
6886
6887 void
6888 android_project_image_bilinear (struct android_image *image,
6889 struct android_image *out,
6890 struct android_transform *transform)
6891 {
6892 emacs_abort ();
6893 }
6894
6895 void
6896 android_project_image_nearest (struct android_image *image,
6897 struct android_image *out,
6898 struct android_transform *transform)
6899 {
6900 emacs_abort ();
6901 }
6902
6903 #endif