aboutsummaryrefslogtreecommitdiffstats
path: root/src/androidterm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/androidterm.c')
-rw-r--r--src/androidterm.c443
1 files changed, 435 insertions, 8 deletions
diff --git a/src/androidterm.c b/src/androidterm.c
index 0279da4f58d..05fe7f01bf9 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -41,6 +41,11 @@ struct android_display_info *x_display_list;
41 41
42#include <android/log.h> 42#include <android/log.h>
43 43
44/* Non-zero means that a HELP_EVENT has been generated since Emacs
45 start. */
46
47static bool any_help_event_p;
48
44enum 49enum
45 { 50 {
46 ANDROID_EVENT_NORMAL, 51 ANDROID_EVENT_NORMAL,
@@ -261,6 +266,94 @@ android_detect_focus_change (struct android_display_info *dpyinfo,
261 } 266 }
262} 267}
263 268
269static bool
270android_note_mouse_movement (struct frame *frame,
271 struct android_motion_event *event)
272{
273 struct android_display_info *dpyinfo;
274 Emacs_Rectangle *r;
275
276 if (!FRAME_ANDROID_OUTPUT (frame))
277 return false;
278
279 dpyinfo = FRAME_DISPLAY_INFO (frame);
280 dpyinfo->last_mouse_motion_frame = frame;
281 dpyinfo->last_mouse_motion_x = event->x;
282 dpyinfo->last_mouse_motion_y = event->y;
283 dpyinfo->last_mouse_movement_time = event->time;
284
285 /* Has the mouse moved off the glyph it was on at the last sighting? */
286 r = &dpyinfo->last_mouse_glyph;
287 if (frame != dpyinfo->last_mouse_glyph_frame
288 || event->x < r->x || event->x >= r->x + r->width
289 || event->y < r->y || event->y >= r->y + r->height)
290 {
291 frame->mouse_moved = true;
292 /* TODO
293 dpyinfo->last_mouse_scroll_bar = NULL; */
294 note_mouse_highlight (frame, event->x, event->y);
295 /* Remember which glyph we're now on. */
296 remember_mouse_glyph (frame, event->x, event->y, r);
297 dpyinfo->last_mouse_glyph_frame = frame;
298 return true;
299 }
300
301 return false;
302}
303
304static struct frame *
305mouse_or_wdesc_frame (struct android_display_info *dpyinfo, int wdesc)
306{
307 struct frame *lm_f = (gui_mouse_grabbed (dpyinfo)
308 ? dpyinfo->last_mouse_frame
309 : NULL);
310
311 if (lm_f && !EQ (track_mouse, Qdropping)
312 && !EQ (track_mouse, Qdrag_source))
313 return lm_f;
314 else
315 {
316 struct frame *w_f = android_window_to_frame (dpyinfo, wdesc);
317
318 /* Do not return a tooltip frame. */
319 if (!w_f || FRAME_TOOLTIP_P (w_f))
320 return EQ (track_mouse, Qdropping) ? lm_f : NULL;
321 else
322 /* When dropping it would be probably nice to raise w_f
323 here. */
324 return w_f;
325 }
326}
327
328static Lisp_Object
329android_construct_mouse_click (struct input_event *result,
330 struct android_button_event *event,
331 struct frame *f)
332{
333 struct android_display_info *dpyinfo;
334 int x, y;
335
336 dpyinfo = FRAME_DISPLAY_INFO (f);
337 x = event->x;
338 y = event->y;
339
340 /* Make the event type NO_EVENT; we'll change that when we decide
341 otherwise. */
342 result->kind = MOUSE_CLICK_EVENT;
343 result->code = event->button - 1;
344 result->timestamp = event->time;
345 result->modifiers = (android_android_to_emacs_modifiers (dpyinfo,
346 event->state)
347 | (event->type == ANDROID_BUTTON_RELEASE
348 ? up_modifier : down_modifier));
349
350 XSETINT (result->x, x);
351 XSETINT (result->y, y);
352 XSETFRAME (result->frame_or_window, f);
353 result->arg = Qnil;
354 return Qnil;
355}
356
264static int 357static int
265handle_one_android_event (struct android_display_info *dpyinfo, 358handle_one_android_event (struct android_display_info *dpyinfo,
266 union android_event *event, int *finish, 359 union android_event *event, int *finish,
@@ -270,17 +363,20 @@ handle_one_android_event (struct android_display_info *dpyinfo,
270 struct frame *f, *any, *mouse_frame; 363 struct frame *f, *any, *mouse_frame;
271 Mouse_HLInfo *hlinfo; 364 Mouse_HLInfo *hlinfo;
272 union buffered_input_event inev; 365 union buffered_input_event inev;
273 int modifiers, count; 366 int modifiers, count, do_help;
274 367
275 /* It is okay for this to not resemble handle_one_xevent so much. 368 /* It is okay for this to not resemble handle_one_xevent so much.
276 Differences in event handling code are much less nasty than 369 Differences in event handling code are much less nasty than
277 stuble differences in the graphics code. */ 370 stuble differences in the graphics code. */
278 371
279 count = 0; 372 do_help = count = 0;
280 hlinfo = &dpyinfo->mouse_highlight; 373 hlinfo = &dpyinfo->mouse_highlight;
281 *finish = ANDROID_EVENT_NORMAL; 374 *finish = ANDROID_EVENT_NORMAL;
282 any = android_window_to_frame (dpyinfo, event->xany.window); 375 any = android_window_to_frame (dpyinfo, event->xany.window);
283 376
377 if (any && any->wait_event_type == event->type)
378 any->wait_event_type = 0; /* Indicates we got it. */
379
284 EVENT_INIT (inev.ie); 380 EVENT_INIT (inev.ie);
285 381
286 switch (event->type) 382 switch (event->type)
@@ -410,6 +506,213 @@ handle_one_android_event (struct android_display_info *dpyinfo,
410 /* A new frame must be created. */; 506 /* A new frame must be created. */;
411 } 507 }
412 508
509 case ANDROID_ENTER_NOTIFY:
510 f = any;
511
512 if (f)
513 android_note_mouse_movement (f, &event->xmotion);
514 goto OTHER;
515
516 case ANDROID_MOTION_NOTIFY:
517 f = any;
518
519 if (f)
520 {
521 /* Maybe generate a SELECT_WINDOW_EVENT for
522 `mouse-autoselect-window' but don't let popup menus
523 interfere with this (Bug#1261). */
524 if (!NILP (Vmouse_autoselect_window)
525 && !popup_activated ()
526 /* Don't switch if we're currently in the minibuffer.
527 This tries to work around problems where the
528 minibuffer gets unselected unexpectedly, and where
529 you then have to move your mouse all the way down to
530 the minibuffer to select it. */
531 && !MINI_WINDOW_P (XWINDOW (selected_window))
532 /* With `focus-follows-mouse' non-nil create an event
533 also when the target window is on another frame. */
534 && (f == XFRAME (selected_frame)
535 || !NILP (focus_follows_mouse)))
536 {
537 static Lisp_Object last_mouse_window;
538 Lisp_Object window
539 = window_from_coordinates (f, event->xmotion.x,
540 event->xmotion.y, 0,
541 false, false);
542
543 /* A window will be autoselected only when it is not
544 selected now and the last mouse movement event was
545 not in it. The remainder of the code is a bit vague
546 wrt what a "window" is. For immediate autoselection,
547 the window is usually the entire window but for GTK
548 where the scroll bars don't count. For delayed
549 autoselection the window is usually the window's text
550 area including the margins. */
551 if (WINDOWP (window)
552 && !EQ (window, last_mouse_window)
553 && !EQ (window, selected_window))
554 {
555 inev.ie.kind = SELECT_WINDOW_EVENT;
556 inev.ie.frame_or_window = window;
557 }
558
559 /* Remember the last window where we saw the mouse. */
560 last_mouse_window = window;
561 }
562
563 if (!android_note_mouse_movement (f, &event->xmotion))
564 help_echo_string = previous_help_echo_string;
565 }
566
567 /* If the contents of the global variable help_echo_string
568 has changed, generate a HELP_EVENT. */
569 if (!NILP (help_echo_string)
570 || !NILP (previous_help_echo_string))
571 do_help = 1;
572
573 if (f)
574 android_flush_dirty_back_buffer_on (f);
575
576 goto OTHER;
577
578 case ANDROID_LEAVE_NOTIFY:
579 f = any;
580
581 if (f)
582 {
583 /* Now clear dpyinfo->last_mouse_motion_frame, or
584 gui_redo_mouse_highlight will end up highlighting the
585 last known position of the mouse if a tooltip frame is
586 later unmapped. */
587
588 if (f == dpyinfo->last_mouse_motion_frame)
589 dpyinfo->last_mouse_motion_frame = NULL;
590
591 /* Something similar applies to
592 dpyinfo->last_mouse_glyph_frame. */
593 if (f == dpyinfo->last_mouse_glyph_frame)
594 dpyinfo->last_mouse_glyph_frame = NULL;
595
596 if (f == hlinfo->mouse_face_mouse_frame)
597 {
598 /* If we move outside the frame, then we're
599 certainly no longer on any text in the frame. */
600 clear_mouse_face (hlinfo);
601 hlinfo->mouse_face_mouse_frame = 0;
602 android_flush_dirty_back_buffer_on (f);
603 }
604
605 /* Generate a nil HELP_EVENT to cancel a help-echo.
606 Do it only if there's something to cancel.
607 Otherwise, the startup message is cleared when
608 the mouse leaves the frame. */
609 if (any_help_event_p
610 /* But never if `mouse-drag-and-drop-region' is in
611 progress, since that results in the tooltip being
612 dismissed when the mouse moves on top. */
613 && !((EQ (track_mouse, Qdrag_source)
614 || EQ (track_mouse, Qdropping))
615 && gui_mouse_grabbed (dpyinfo)))
616 do_help = -1;
617 }
618
619 goto OTHER;
620
621 case ANDROID_BUTTON_PRESS:
622 case ANDROID_BUTTON_RELEASE:
623 /* If we decide we want to generate an event to be seen
624 by the rest of Emacs, we put it here. */
625
626 f = any;
627
628 Lisp_Object tab_bar_arg = Qnil;
629 bool tab_bar_p = false;
630 bool tool_bar_p = false;
631
632 dpyinfo->last_mouse_glyph_frame = NULL;
633
634 f = mouse_or_wdesc_frame (dpyinfo, event->xbutton.window);
635
636 if (f)
637 {
638 /* Is this in the tab-bar? */
639 if (WINDOWP (f->tab_bar_window)
640 && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
641 {
642 Lisp_Object window;
643 int x = event->xbutton.x;
644 int y = event->xbutton.y;
645
646 window = window_from_coordinates (f, x, y, 0, true, true);
647 tab_bar_p = EQ (window, f->tab_bar_window);
648
649 if (tab_bar_p)
650 {
651 tab_bar_arg = handle_tab_bar_click
652 (f, x, y, (event->xbutton.type
653 == ANDROID_BUTTON_PRESS),
654 android_android_to_emacs_modifiers (dpyinfo,
655 event->xbutton.state));
656 android_flush_dirty_back_buffer_on (f);
657 }
658 }
659
660 /* Is this in the tool-bar? */
661 if (WINDOWP (f->tool_bar_window)
662 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
663 {
664 Lisp_Object window;
665 int x = event->xbutton.x;
666 int y = event->xbutton.y;
667
668 window = window_from_coordinates (f, x, y, 0, true, true);
669 tool_bar_p = (EQ (window, f->tool_bar_window)
670 && ((event->xbutton.type
671 != ANDROID_BUTTON_RELEASE)
672 || f->last_tool_bar_item != -1));
673
674 if (tool_bar_p && event->xbutton.button < 4)
675 {
676 handle_tool_bar_click
677 (f, x, y, (event->xbutton.type
678 == ANDROID_BUTTON_PRESS),
679 android_android_to_emacs_modifiers (dpyinfo,
680 event->xbutton.state));
681 android_flush_dirty_back_buffer_on (f);
682 }
683 }
684
685 if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
686 {
687 android_construct_mouse_click (&inev.ie, &event->xbutton, f);
688
689 if (!NILP (tab_bar_arg))
690 inev.ie.arg = tab_bar_arg;
691 }
692 }
693 else
694 {
695 /* TODO: scroll bars */
696 }
697
698 if (event->type == ANDROID_BUTTON_PRESS)
699 {
700 dpyinfo->grabbed |= (1 << event->xbutton.button);
701 dpyinfo->last_mouse_frame = f;
702 if (f && !tab_bar_p)
703 f->last_tab_bar_item = -1;
704 if (f && !tool_bar_p)
705 f->last_tool_bar_item = -1;
706 }
707 else
708 dpyinfo->grabbed &= ~(1 << event->xbutton.button);
709
710 /* Ignore any mouse motion that happened before this event;
711 any subsequent mouse-movement Emacs events should reflect
712 only motion after the ButtonPress/Release. */
713 if (f != 0)
714 f->mouse_moved = false;
715
413 goto OTHER; 716 goto OTHER;
414 717
415 default: 718 default:
@@ -423,6 +726,30 @@ handle_one_android_event (struct android_display_info *dpyinfo,
423 count++; 726 count++;
424 } 727 }
425 728
729 if (do_help
730 && !(hold_quit && hold_quit->kind != NO_EVENT))
731 {
732 Lisp_Object frame;
733
734 if (f)
735 XSETFRAME (frame, f);
736 else
737 frame = Qnil;
738
739 if (do_help > 0)
740 {
741 any_help_event_p = true;
742 gen_help_event (help_echo_string, frame, help_echo_window,
743 help_echo_object, help_echo_pos);
744 }
745 else
746 {
747 help_echo_string = Qnil;
748 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
749 }
750 count++;
751 }
752
426 return count; 753 return count;
427} 754}
428 755
@@ -562,7 +889,32 @@ android_mouse_position (struct frame **fp, int insist,
562 enum scroll_bar_part *part, Lisp_Object *x, 889 enum scroll_bar_part *part, Lisp_Object *x,
563 Lisp_Object *y, Time *timestamp) 890 Lisp_Object *y, Time *timestamp)
564{ 891{
565 /* TODO */ 892 Lisp_Object tail, frame;
893 struct android_display_info *dpyinfo;
894
895 dpyinfo = FRAME_DISPLAY_INFO (*fp);
896
897 /* This is the best implementation possible on Android, where the
898 system doesn't let Emacs obtain any information about the mouse
899 pointer at all. */
900
901 if (dpyinfo->last_mouse_motion_frame)
902 {
903 *fp = dpyinfo->last_mouse_motion_frame;
904 *timestamp = dpyinfo->last_mouse_movement_time;
905 *x = make_fixnum (dpyinfo->last_mouse_motion_x);
906 *y = make_fixnum (dpyinfo->last_mouse_motion_y);
907 *bar_window = Qnil;
908 *part = scroll_bar_nowhere;
909
910 FOR_EACH_FRAME (tail, frame)
911 {
912 if (FRAME_ANDROID_P (XFRAME (frame)))
913 XFRAME (frame)->mouse_moved = false;
914 }
915
916 dpyinfo->last_mouse_motion_frame->mouse_moved = false;
917 }
566} 918}
567 919
568static Lisp_Object 920static Lisp_Object
@@ -679,6 +1031,45 @@ android_iconify_frame (struct frame *f)
679} 1031}
680 1032
681static void 1033static void
1034android_wait_for_event (struct frame *f, int eventtype)
1035{
1036 if (!FLOATP (Vandroid_wait_for_event_timeout))
1037 return;
1038
1039 int level = interrupt_input_blocked;
1040 struct timespec tmo, tmo_at, time_now;
1041
1042 f->wait_event_type = eventtype;
1043
1044 /* Default timeout is 0.1 second. Hopefully not noticeable. */
1045 double timeout = XFLOAT_DATA (Vandroid_wait_for_event_timeout);
1046 time_t timeout_seconds = (time_t) timeout;
1047 tmo = make_timespec (timeout_seconds,
1048 (long int) ((timeout - timeout_seconds)
1049 * 1000 * 1000 * 1000));
1050 tmo_at = timespec_add (current_timespec (), tmo);
1051
1052 while (f->wait_event_type)
1053 {
1054 pending_signals = true;
1055 totally_unblock_input ();
1056 /* XTread_socket is called after unblock. */
1057 block_input ();
1058 interrupt_input_blocked = level;
1059
1060 time_now = current_timespec ();
1061 if (timespec_cmp (tmo_at, time_now) < 0)
1062 break;
1063
1064 tmo = timespec_sub (tmo_at, time_now);
1065 if (android_select (0, NULL, NULL, NULL, &tmo, NULL) == 0)
1066 break; /* Timeout */
1067 }
1068
1069 f->wait_event_type = 0;
1070}
1071
1072static void
682android_set_window_size_1 (struct frame *f, bool change_gravity, 1073android_set_window_size_1 (struct frame *f, bool change_gravity,
683 int width, int height) 1074 int width, int height)
684{ 1075{
@@ -688,11 +1079,29 @@ android_set_window_size_1 (struct frame *f, bool change_gravity,
688 android_resize_window (FRAME_ANDROID_WINDOW (f), width, 1079 android_resize_window (FRAME_ANDROID_WINDOW (f), width,
689 height); 1080 height);
690 1081
691 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
692 receive in the ConfigureNotify event; if we get what we asked
693 for, then the event won't cause the screen to become garbaged, so
694 we have to make sure to do it here. */
695 SET_FRAME_GARBAGED (f); 1082 SET_FRAME_GARBAGED (f);
1083
1084 if (FRAME_VISIBLE_P (f))
1085 {
1086 android_wait_for_event (f, ANDROID_CONFIGURE_NOTIFY);
1087
1088 if (CONSP (frame_size_history))
1089 frame_size_history_extra (f, build_string ("set_window_size_1 visible"),
1090 FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f),
1091 width, height, f->new_width, f->new_height);
1092 }
1093 else
1094 {
1095 if (CONSP (frame_size_history))
1096 frame_size_history_extra (f, build_string ("set_window_size_1 "
1097 "invisible"),
1098 FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f),
1099 width, height, f->new_width, f->new_height);
1100
1101 adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width),
1102 FRAME_PIXEL_TO_TEXT_HEIGHT (f, height),
1103 5, 0, Qx_set_window_size_1);
1104 }
696} 1105}
697 1106
698void 1107void
@@ -792,7 +1201,6 @@ android_new_font (struct frame *f, Lisp_Object font_object, int fontset)
792static bool 1201static bool
793android_bitmap_icon (struct frame *f, Lisp_Object file) 1202android_bitmap_icon (struct frame *f, Lisp_Object file)
794{ 1203{
795 /* TODO */
796 return false; 1204 return false;
797} 1205}
798 1206
@@ -841,6 +1249,13 @@ android_free_frame_resources (struct frame *f)
841 if (f == hlinfo->mouse_face_mouse_frame) 1249 if (f == hlinfo->mouse_face_mouse_frame)
842 reset_mouse_highlight (hlinfo); 1250 reset_mouse_highlight (hlinfo);
843 1251
1252 /* These two need to be freed now that they are used to compute the
1253 mouse position, I think. */
1254 if (f == dpyinfo->last_mouse_motion_frame)
1255 dpyinfo->last_mouse_motion_frame = NULL;
1256 if (f == dpyinfo->last_mouse_frame)
1257 dpyinfo->last_mouse_frame = NULL;
1258
844 unblock_input (); 1259 unblock_input ();
845} 1260}
846 1261
@@ -3233,6 +3648,18 @@ syms_of_androidterm (void)
3233{ 3648{
3234 Fprovide (Qandroid, Qnil); 3649 Fprovide (Qandroid, Qnil);
3235 3650
3651 DEFVAR_LISP ("android-wait-for-event-timeout",
3652 Vandroid_wait_for_event_timeout,
3653 doc: /* How long to wait for Android events.
3654
3655Emacs will wait up to this many seconds to receive events after
3656making changes which affect the state of the graphical interface.
3657Under some situations this can take an indefinite amount of time,
3658so it is important to limit the wait.
3659
3660If set to a non-float value, there will be no wait at all. */);
3661 Vandroid_wait_for_event_timeout = make_float (0.1);
3662
3236 DEFVAR_BOOL ("x-use-underline-position-properties", 3663 DEFVAR_BOOL ("x-use-underline-position-properties",
3237 x_use_underline_position_properties, 3664 x_use_underline_position_properties,
3238 doc: /* SKIP: real doc in xterm.c. */); 3665 doc: /* SKIP: real doc in xterm.c. */);