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