aboutsummaryrefslogtreecommitdiffstats
path: root/src/androidfns.c
diff options
context:
space:
mode:
authorPo Lu2023-01-14 22:12:16 +0800
committerPo Lu2023-01-14 22:12:16 +0800
commit2b87ab7b27163fbd7b6b64c5a44e26b0e692c00a (patch)
tree3ab31df90bd435009d2d42b636ce3baf33bd2b28 /src/androidfns.c
parent28a9baccd4c8e997895d3adb3cfce4a11fa29896 (diff)
downloademacs-2b87ab7b27163fbd7b6b64c5a44e26b0e692c00a.tar.gz
emacs-2b87ab7b27163fbd7b6b64c5a44e26b0e692c00a.zip
Update Android port
* java/Makefile.in (clean): Fix distclean and bootstrap-clean rules. * java/debug.sh (jdb_port): (attach_existing): (num_pids): (line): Add new options to upload a gdbserver binary to the device. * java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): Make focusedActivities public. * java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu): New class. * java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Fix bounds computation. * java/org/gnu/emacs/EmacsGC.java (markDirty): Set stroke width explicitly. * java/org/gnu/emacs/EmacsService.java (EmacsService) (getLocationOnScreen, nameKeysym): New functions. * java/org/gnu/emacs/EmacsView.java (EmacsView): Disable focus highlight. (onCreateContextMenu, popupMenu, cancelPopupMenu): New functions. * java/org/gnu/emacs/EmacsWindow.java (EmacsWindow): Implement a kind of ``override redirect'' window for tooltips. * src/android.c (struct android_emacs_service): New method `name_keysym'. (android_run_select_thread, android_init_events): (android_select): Release select thread on semaphores instead of signals to avoid one nasty race on SIGUSR2 delivery. (android_init_emacs_service): Initialize new method. (android_create_window): Handle CW_OVERRIDE_REDIRECT. (android_move_resize_window, android_map_raised) (android_translate_coordinates, android_get_keysym_name) (android_build_string, android_exception_check): New functions. * src/android.h: Update prototypes. * src/androidfns.c (android_set_parent_frame, Fx_create_frame) (unwind_create_tip_frame, android_create_tip_frame) (android_hide_tip, compute_tip_xy, Fx_show_tip, Fx_hide_tip) (syms_of_androidfns): Implement tooltips and iconification reporting. * src/androidgui.h (enum android_window_value_mask): Add CWOverrideRedirect. (struct android_set_window_attributes): Add `override_redirect'. (ANDROID_IS_MODIFIER_KEY): Recognize Caps Lock. * src/androidmenu.c (struct android_emacs_context_menu): New struct. (android_init_emacs_context_menu, android_unwind_local_frame) (android_push_local_frame, android_menu_show, init_androidmenu): New functions. * src/androidterm.c (handle_one_android_event): Fix NULL pointer dereference. (android_fullscreen_hook): Handle fullscreen correctly. (android_draw_box_rect): Fix top line. (get_keysym_name): Implement function. (android_create_terminal): Remove scroll bar stubs and add menu hook. * src/androidterm.h: Update prototypes. * src/emacs.c (android_emacs_init): Initialize androidmenu.c. * xcompile/Makefile.in: Fix clean rules.
Diffstat (limited to 'src/androidfns.c')
-rw-r--r--src/androidfns.c677
1 files changed, 664 insertions, 13 deletions
diff --git a/src/androidfns.c b/src/androidfns.c
index 459e407b901..ab136bc2722 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -25,12 +25,36 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
25#include "androidterm.h" 25#include "androidterm.h"
26#include "blockinput.h" 26#include "blockinput.h"
27#include "keyboard.h" 27#include "keyboard.h"
28#include "buffer.h"
28 29
29#ifndef ANDROID_STUBIFY 30#ifndef ANDROID_STUBIFY
30 31
31/* Some kind of reference count for the image cache. */ 32/* Some kind of reference count for the image cache. */
32static ptrdiff_t image_cache_refcount; 33static ptrdiff_t image_cache_refcount;
33 34
35/* The frame of the currently visible tooltip, or nil if none. */
36static Lisp_Object tip_frame;
37
38/* The window-system window corresponding to the frame of the
39 currently visible tooltip. */
40static android_window tip_window;
41
42/* The X and Y deltas of the last call to `x-show-tip'. */
43static Lisp_Object tip_dx, tip_dy;
44
45/* A timer that hides or deletes the currently visible tooltip when it
46 fires. */
47static Lisp_Object tip_timer;
48
49/* STRING argument of last `x-show-tip' call. */
50static Lisp_Object tip_last_string;
51
52/* Normalized FRAME argument of last `x-show-tip' call. */
53static Lisp_Object tip_last_frame;
54
55/* PARMS argument of last `x-show-tip' call. */
56static Lisp_Object tip_last_parms;
57
34#endif 58#endif
35 59
36static struct android_display_info * 60static struct android_display_info *
@@ -180,6 +204,9 @@ android_set_parent_frame (struct frame *f, Lisp_Object new_value,
180 204
181 fset_parent_frame (f, new_value); 205 fset_parent_frame (f, new_value);
182 } 206 }
207
208 /* Update the fullscreen frame parameter as well. */
209 FRAME_TERMINAL (f)->fullscreen_hook (f);
183} 210}
184 211
185void 212void
@@ -858,13 +885,13 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
858 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0), 885 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
859 NULL, NULL, RES_TYPE_NUMBER); 886 NULL, NULL, RES_TYPE_NUMBER);
860 887
861 /* gui_default_parameter (f, parms, Qvertical_scroll_bars, */ 888 gui_default_parameter (f, parms, Qvertical_scroll_bars,
862 /* Qleft, */ 889 Qleft,
863 /* "verticalScrollBars", "ScrollBars", */ 890 "verticalScrollBars", "ScrollBars",
864 /* RES_TYPE_SYMBOL); */ 891 RES_TYPE_SYMBOL);
865 /* gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil, */ 892 gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
866 /* "horizontalScrollBars", "ScrollBars", */ 893 "horizontalScrollBars", "ScrollBars",
867 /* RES_TYPE_SYMBOL); TODO */ 894 RES_TYPE_SYMBOL);
868 895
869 /* Also do the stuff which must be set before the window exists. */ 896 /* Also do the stuff which must be set before the window exists. */
870 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"), 897 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
@@ -893,7 +920,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
893 android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background, 920 android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
894 "scrollBarBackground", 921 "scrollBarBackground",
895 "ScrollBarBackground", false); 922 "ScrollBarBackground", false);
896#endif /* TODO */ 923#endif
897 924
898 /* Init faces before gui_default_parameter is called for the 925 /* Init faces before gui_default_parameter is called for the
899 scroll-bar-width parameter because otherwise we end up in 926 scroll-bar-width parameter because otherwise we end up in
@@ -974,12 +1001,16 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
974 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN); 1001 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
975 gui_default_parameter (f, parms, Qcursor_type, Qbox, 1002 gui_default_parameter (f, parms, Qcursor_type, Qbox,
976 "cursorType", "CursorType", RES_TYPE_SYMBOL); 1003 "cursorType", "CursorType", RES_TYPE_SYMBOL);
1004 /* Scroll bars are not supported on Android, as they are near
1005 useless. */
1006#if 0
977 gui_default_parameter (f, parms, Qscroll_bar_width, Qnil, 1007 gui_default_parameter (f, parms, Qscroll_bar_width, Qnil,
978 "scrollBarWidth", "ScrollBarWidth", 1008 "scrollBarWidth", "ScrollBarWidth",
979 RES_TYPE_NUMBER); 1009 RES_TYPE_NUMBER);
980 gui_default_parameter (f, parms, Qscroll_bar_height, Qnil, 1010 gui_default_parameter (f, parms, Qscroll_bar_height, Qnil,
981 "scrollBarHeight", "ScrollBarHeight", 1011 "scrollBarHeight", "ScrollBarHeight",
982 RES_TYPE_NUMBER); 1012 RES_TYPE_NUMBER);
1013#endif
983 gui_default_parameter (f, parms, Qalpha, Qnil, 1014 gui_default_parameter (f, parms, Qalpha, Qnil,
984 "alpha", "Alpha", RES_TYPE_NUMBER); 1015 "alpha", "Alpha", RES_TYPE_NUMBER);
985 gui_default_parameter (f, parms, Qalpha_background, Qnil, 1016 gui_default_parameter (f, parms, Qalpha_background, Qnil,
@@ -1009,8 +1040,9 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1009 1040
1010 /* Process fullscreen parameter here in the hope that normalizing a 1041 /* Process fullscreen parameter here in the hope that normalizing a
1011 fullheight/fullwidth frame will produce the size set by the last 1042 fullheight/fullwidth frame will produce the size set by the last
1012 adjust_frame_size call. */ 1043 adjust_frame_size call. Note that Android only supports the
1013 gui_default_parameter (f, parms, Qfullscreen, Qnil, 1044 `maximized' state. */
1045 gui_default_parameter (f, parms, Qfullscreen, Qmaximized,
1014 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); 1046 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
1015 1047
1016 /* When called from `x-create-frame-with-faces' visibility is 1048 /* When called from `x-create-frame-with-faces' visibility is
@@ -1661,6 +1693,391 @@ DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
1661 return result; 1693 return result;
1662} 1694}
1663 1695
1696#ifndef ANDROID_STUBIFY
1697
1698static void
1699unwind_create_tip_frame (Lisp_Object frame)
1700{
1701 Lisp_Object deleted;
1702
1703 deleted = unwind_create_frame (frame);
1704 if (EQ (deleted, Qt))
1705 {
1706 tip_window = ANDROID_NONE;
1707 tip_frame = Qnil;
1708 }
1709}
1710
1711static Lisp_Object
1712android_create_tip_frame (struct android_display_info *dpyinfo,
1713 Lisp_Object parms)
1714{
1715 struct frame *f;
1716 Lisp_Object frame;
1717 Lisp_Object name;
1718 specpdl_ref count = SPECPDL_INDEX ();
1719 bool face_change_before = face_change;
1720
1721 if (!dpyinfo->terminal->name)
1722 error ("Terminal is not live, can't create new frames on it");
1723
1724 parms = Fcopy_alist (parms);
1725
1726 /* Get the name of the frame to use for resource lookup. */
1727 name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
1728 RES_TYPE_STRING);
1729 if (!STRINGP (name)
1730 && !BASE_EQ (name, Qunbound)
1731 && !NILP (name))
1732 error ("Invalid frame name--not a string or nil");
1733
1734 frame = Qnil;
1735 f = make_frame (false);
1736 f->wants_modeline = false;
1737 XSETFRAME (frame, f);
1738 record_unwind_protect (unwind_create_tip_frame, frame);
1739
1740 f->terminal = dpyinfo->terminal;
1741
1742 /* By setting the output method, we're essentially saying that
1743 the frame is live, as per FRAME_LIVE_P. If we get a signal
1744 from this point on, x_destroy_window might screw up reference
1745 counts etc. */
1746 f->output_method = output_android;
1747 f->output_data.android = xzalloc (sizeof *f->output_data.android);
1748 FRAME_FONTSET (f) = -1;
1749 f->output_data.android->white_relief.pixel = -1;
1750 f->output_data.android->black_relief.pixel = -1;
1751
1752 f->tooltip = true;
1753 fset_icon_name (f, Qnil);
1754 FRAME_DISPLAY_INFO (f) = dpyinfo;
1755 f->output_data.android->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
1756
1757 /* These colors will be set anyway later, but it's important
1758 to get the color reference counts right, so initialize them! */
1759 {
1760 Lisp_Object black;
1761
1762 /* Function android_decode_color can signal an error. Make sure
1763 to initialize color slots so that we won't try to free colors
1764 we haven't allocated. */
1765 FRAME_FOREGROUND_PIXEL (f) = -1;
1766 FRAME_BACKGROUND_PIXEL (f) = -1;
1767 f->output_data.android->cursor_pixel = -1;
1768 f->output_data.android->cursor_foreground_pixel = -1;
1769
1770 black = build_string ("black");
1771 FRAME_FOREGROUND_PIXEL (f)
1772 = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
1773 FRAME_BACKGROUND_PIXEL (f)
1774 = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
1775 f->output_data.android->cursor_pixel
1776 = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
1777 f->output_data.android->cursor_foreground_pixel
1778 = android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
1779 }
1780
1781 /* Set the name; the functions to which we pass f expect the name to
1782 be set. */
1783 if (BASE_EQ (name, Qunbound) || NILP (name))
1784 f->explicit_name = false;
1785 else
1786 {
1787 fset_name (f, name);
1788 f->explicit_name = true;
1789 /* use the frame's title when getting resources for this frame. */
1790 specbind (Qx_resource_name, name);
1791 }
1792
1793 register_font_driver (&androidfont_driver, f);
1794 register_font_driver (&android_sfntfont_driver, f);
1795
1796 image_cache_refcount
1797 = FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
1798#ifdef GLYPH_DEBUG
1799 dpyinfo_refcount = dpyinfo->reference_count;
1800#endif /* GLYPH_DEBUG */
1801
1802 gui_default_parameter (f, parms, Qfont_backend, Qnil,
1803 "fontBackend", "FontBackend", RES_TYPE_STRING);
1804
1805 /* Extract the window parameters from the supplied values that are
1806 needed to determine window geometry. */
1807 android_default_font_parameter (f, parms);
1808
1809 gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
1810 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
1811
1812 /* This defaults to 1 in order to match xterm. We recognize either
1813 internalBorderWidth or internalBorder (which is what xterm calls
1814 it). */
1815 if (NILP (Fassq (Qinternal_border_width, parms)))
1816 {
1817 Lisp_Object value;
1818
1819 value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
1820 "internalBorder", "internalBorder",
1821 RES_TYPE_NUMBER);
1822 if (! BASE_EQ (value, Qunbound))
1823 parms = Fcons (Fcons (Qinternal_border_width, value),
1824 parms);
1825 }
1826
1827 gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (1),
1828 "internalBorderWidth", "internalBorderWidth",
1829 RES_TYPE_NUMBER);
1830 gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
1831 NULL, NULL, RES_TYPE_NUMBER);
1832 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
1833 NULL, NULL, RES_TYPE_NUMBER);
1834
1835 /* Also do the stuff which must be set before the window exists. */
1836 gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
1837 "foreground", "Foreground", RES_TYPE_STRING);
1838 gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
1839 "background", "Background", RES_TYPE_STRING);
1840 gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
1841 "pointerColor", "Foreground", RES_TYPE_STRING);
1842 gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
1843 "cursorColor", "Foreground", RES_TYPE_STRING);
1844 gui_default_parameter (f, parms, Qborder_color, build_string ("black"),
1845 "borderColor", "BorderColor", RES_TYPE_STRING);
1846 gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
1847 NULL, NULL, RES_TYPE_BOOLEAN);
1848
1849 {
1850 struct android_set_window_attributes attrs;
1851 unsigned long mask;
1852
1853 block_input ();
1854 mask = ANDROID_CW_OVERRIDE_REDIRECT;
1855
1856 attrs.override_redirect = true;
1857 tip_window
1858 = FRAME_ANDROID_WINDOW (f)
1859 = android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
1860 /* x, y, width, height, value-mask,
1861 attrs. */
1862 0, 0, 1, 1, mask, &attrs);
1863 unblock_input ();
1864 }
1865
1866 /* Init faces before gui_default_parameter is called for the
1867 scroll-bar-width parameter because otherwise we end up in
1868 init_iterator with a null face cache, which should not happen. */
1869 init_frame_faces (f);
1870
1871 gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
1872 "inhibitDoubleBuffering", "InhibitDoubleBuffering",
1873 RES_TYPE_BOOLEAN);
1874
1875 gui_figure_window_size (f, parms, false, false);
1876
1877 f->output_data.android->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
1878
1879 android_make_gc (f);
1880
1881 gui_default_parameter (f, parms, Qauto_raise, Qnil,
1882 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
1883 gui_default_parameter (f, parms, Qauto_lower, Qnil,
1884 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
1885 gui_default_parameter (f, parms, Qcursor_type, Qbox,
1886 "cursorType", "CursorType", RES_TYPE_SYMBOL);
1887 gui_default_parameter (f, parms, Qalpha, Qnil,
1888 "alpha", "Alpha", RES_TYPE_NUMBER);
1889 gui_default_parameter (f, parms, Qalpha_background, Qnil,
1890 "alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
1891
1892 /* Add `tooltip' frame parameter's default value. */
1893 if (NILP (Fframe_parameter (frame, Qtooltip)))
1894 {
1895 AUTO_FRAME_ARG (arg, Qtooltip, Qt);
1896 Fmodify_frame_parameters (frame, arg);
1897 }
1898
1899 /* FIXME - can this be done in a similar way to normal frames?
1900 https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
1901
1902 /* Set the `display-type' frame parameter before setting up faces. */
1903 {
1904 Lisp_Object disptype;
1905
1906 disptype = Qcolor;
1907
1908 if (NILP (Fframe_parameter (frame, Qdisplay_type)))
1909 {
1910 AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
1911 Fmodify_frame_parameters (frame, arg);
1912 }
1913 }
1914
1915 /* Set up faces after all frame parameters are known. This call
1916 also merges in face attributes specified for new frames. */
1917 {
1918 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
1919
1920 call2 (Qface_set_after_frame_default, frame, Qnil);
1921
1922 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
1923 {
1924 AUTO_FRAME_ARG (arg, Qbackground_color, bg);
1925 Fmodify_frame_parameters (frame, arg);
1926 }
1927 }
1928
1929 f->no_split = true;
1930
1931 /* Now that the frame will be official, it counts as a reference to
1932 its display and terminal. */
1933 f->terminal->reference_count++;
1934
1935 /* It is now ok to make the frame official even if we get an error
1936 below. And the frame needs to be on Vframe_list or making it
1937 visible won't work. */
1938 Vframe_list = Fcons (frame, Vframe_list);
1939 f->can_set_window_size = true;
1940 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
1941 0, true, Qtip_frame);
1942
1943 /* Setting attributes of faces of the tooltip frame from resources
1944 and similar will set face_change, which leads to the clearing of
1945 all current matrices. Since this isn't necessary here, avoid it
1946 by resetting face_change to the value it had before we created
1947 the tip frame. */
1948 face_change = face_change_before;
1949
1950 /* Discard the unwind_protect. */
1951 return unbind_to (count, frame);
1952}
1953
1954static Lisp_Object
1955android_hide_tip (bool delete)
1956{
1957 if (!NILP (tip_timer))
1958 {
1959 call1 (Qcancel_timer, tip_timer);
1960 tip_timer = Qnil;
1961 }
1962
1963 if (NILP (tip_frame)
1964 || (!delete
1965 && !NILP (tip_frame)
1966 && FRAME_LIVE_P (XFRAME (tip_frame))
1967 && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
1968 return Qnil;
1969 else
1970 {
1971 Lisp_Object was_open = Qnil;
1972
1973 specpdl_ref count = SPECPDL_INDEX ();
1974 specbind (Qinhibit_redisplay, Qt);
1975 specbind (Qinhibit_quit, Qt);
1976
1977 if (!NILP (tip_frame))
1978 {
1979 struct frame *f = XFRAME (tip_frame);
1980
1981 if (FRAME_LIVE_P (f))
1982 {
1983 if (delete)
1984 {
1985 delete_frame (tip_frame, Qnil);
1986 tip_frame = Qnil;
1987 }
1988 else
1989 android_make_frame_invisible (XFRAME (tip_frame));
1990
1991 was_open = Qt;
1992 }
1993 else
1994 tip_frame = Qnil;
1995 }
1996 else
1997 tip_frame = Qnil;
1998
1999 return unbind_to (count, was_open);
2000 }
2001}
2002
2003static void
2004compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
2005 Lisp_Object dy, int width, int height, int *root_x,
2006 int *root_y)
2007{
2008 Lisp_Object left, top, right, bottom;
2009 int min_x, min_y, max_x, max_y = -1;
2010 android_window window;
2011 struct frame *mouse_frame;
2012
2013 /* Initialize these values in case there is no mouse frame. */
2014 *root_x = 0;
2015 *root_y = 0;
2016
2017 /* User-specified position? */
2018 left = CDR (Fassq (Qleft, parms));
2019 top = CDR (Fassq (Qtop, parms));
2020 right = CDR (Fassq (Qright, parms));
2021 bottom = CDR (Fassq (Qbottom, parms));
2022
2023 /* Move the tooltip window where the mouse pointer was last seen.
2024 Resize and show it. */
2025 if ((!FIXNUMP (left) && !FIXNUMP (right))
2026 || (!FIXNUMP (top) && !FIXNUMP (bottom)))
2027 {
2028 if (x_display_list->last_mouse_motion_frame)
2029 {
2030 *root_x = x_display_list->last_mouse_motion_x;
2031 *root_y = x_display_list->last_mouse_motion_y;
2032 mouse_frame = x_display_list->last_mouse_motion_frame;
2033 window = FRAME_ANDROID_WINDOW (mouse_frame);
2034
2035 /* Translate the coordinates to the screen. */
2036 android_translate_coordinates (window, *root_x, *root_y,
2037 root_x, root_y);
2038 }
2039 }
2040
2041 min_x = 0;
2042 min_y = 0;
2043 max_x = android_get_screen_width ();
2044 max_y = android_get_screen_height ();
2045
2046 if (FIXNUMP (top))
2047 *root_y = XFIXNUM (top);
2048 else if (FIXNUMP (bottom))
2049 *root_y = XFIXNUM (bottom) - height;
2050 else if (*root_y + XFIXNUM (dy) <= min_y)
2051 *root_y = min_y; /* Can happen for negative dy */
2052 else if (*root_y + XFIXNUM (dy) + height <= max_y)
2053 /* It fits below the pointer */
2054 *root_y += XFIXNUM (dy);
2055 else if (height + XFIXNUM (dy) + min_y <= *root_y)
2056 /* It fits above the pointer. */
2057 *root_y -= height + XFIXNUM (dy);
2058 else
2059 /* Put it on the top. */
2060 *root_y = min_y;
2061
2062 if (FIXNUMP (left))
2063 *root_x = XFIXNUM (left);
2064 else if (FIXNUMP (right))
2065 *root_x = XFIXNUM (right) - width;
2066 else if (*root_x + XFIXNUM (dx) <= min_x)
2067 *root_x = 0; /* Can happen for negative dx */
2068 else if (*root_x + XFIXNUM (dx) + width <= max_x)
2069 /* It fits to the right of the pointer. */
2070 *root_x += XFIXNUM (dx);
2071 else if (width + XFIXNUM (dx) + min_x <= *root_x)
2072 /* It fits to the left of the pointer. */
2073 *root_x -= width + XFIXNUM (dx);
2074 else
2075 /* Put it left justified on the screen -- it ought to fit that way. */
2076 *root_x = min_x;
2077}
2078
2079#endif
2080
1664DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, 2081DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
1665 doc: /* SKIP: real doc in xfns.c. */) 2082 doc: /* SKIP: real doc in xfns.c. */)
1666 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, 2083 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms,
@@ -1670,8 +2087,214 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
1670 error ("Android cross-compilation stub called!"); 2087 error ("Android cross-compilation stub called!");
1671 return Qnil; 2088 return Qnil;
1672#else 2089#else
1673 /* TODO tooltips */ 2090 struct frame *f, *tip_f;
1674 return Qnil; 2091 struct window *w;
2092 int root_x, root_y;
2093 struct buffer *old_buffer;
2094 struct text_pos pos;
2095 int width, height;
2096 int old_windows_or_buffers_changed = windows_or_buffers_changed;
2097 specpdl_ref count = SPECPDL_INDEX ();
2098 Lisp_Object window, size, tip_buf;
2099 bool displayed;
2100#ifdef ENABLE_CHECKING
2101 struct glyph_row *row, *end;
2102#endif
2103 AUTO_STRING (tip, " *tip*");
2104
2105 specbind (Qinhibit_redisplay, Qt);
2106
2107 CHECK_STRING (string);
2108 if (SCHARS (string) == 0)
2109 string = make_unibyte_string (" ", 1);
2110
2111 if (NILP (frame))
2112 frame = selected_frame;
2113 f = decode_window_system_frame (frame);
2114
2115 if (NILP (timeout))
2116 timeout = Vx_show_tooltip_timeout;
2117 CHECK_FIXNAT (timeout);
2118
2119 if (NILP (dx))
2120 dx = make_fixnum (5);
2121 else
2122 CHECK_FIXNUM (dx);
2123
2124 if (NILP (dy))
2125 dy = make_fixnum (-10);
2126 else
2127 CHECK_FIXNUM (dy);
2128
2129 tip_dx = dx;
2130 tip_dy = dy;
2131
2132 if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
2133 {
2134 if (FRAME_VISIBLE_P (XFRAME (tip_frame))
2135 && !NILP (Fequal_including_properties (tip_last_string,
2136 string))
2137 && !NILP (Fequal (tip_last_parms, parms)))
2138 {
2139 /* Only DX and DY have changed. */
2140 tip_f = XFRAME (tip_frame);
2141 if (!NILP (tip_timer))
2142 {
2143 call1 (Qcancel_timer, tip_timer);
2144 tip_timer = Qnil;
2145 }
2146
2147 block_input ();
2148 compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
2149 FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
2150 android_move_window (FRAME_ANDROID_WINDOW (tip_f),
2151 root_x, root_y);
2152 unblock_input ();
2153
2154 goto start_timer;
2155 }
2156 else
2157 android_hide_tip (true);
2158 }
2159 else
2160 android_hide_tip (true);
2161
2162 tip_last_frame = frame;
2163 tip_last_string = string;
2164 tip_last_parms = parms;
2165
2166 if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
2167 {
2168 /* Add default values to frame parameters. */
2169 if (NILP (Fassq (Qname, parms)))
2170 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
2171 if (NILP (Fassq (Qinternal_border_width, parms)))
2172 parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)),
2173 parms);
2174 if (NILP (Fassq (Qborder_width, parms)))
2175 parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
2176 if (NILP (Fassq (Qborder_color, parms)))
2177 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")),
2178 parms);
2179 if (NILP (Fassq (Qbackground_color, parms)))
2180 parms = Fcons (Fcons (Qbackground_color,
2181 build_string ("lightyellow")),
2182 parms);
2183
2184 /* Create a frame for the tooltip, and record it in the global
2185 variable tip_frame. */
2186 if (NILP (tip_frame = android_create_tip_frame (FRAME_DISPLAY_INFO (f),
2187 parms)))
2188 /* Creating the tip frame failed. */
2189 return unbind_to (count, Qnil);
2190 }
2191
2192 tip_f = XFRAME (tip_frame);
2193 window = FRAME_ROOT_WINDOW (tip_f);
2194 tip_buf = Fget_buffer_create (tip, Qnil);
2195 /* We will mark the tip window a "pseudo-window" below, and such
2196 windows cannot have display margins. */
2197 bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
2198 bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
2199 set_window_buffer (window, tip_buf, false, false);
2200 w = XWINDOW (window);
2201 w->pseudo_window_p = true;
2202 /* Try to avoid that `other-window' select us (Bug#47207). */
2203 Fset_window_parameter (window, Qno_other_window, Qt);
2204
2205 /* Set up the frame's root window. Note: The following code does not
2206 try to size the window or its frame correctly. Its only purpose is
2207 to make the subsequent text size calculations work. The right
2208 sizes should get installed when the toolkit gets back to us. */
2209 w->left_col = 0;
2210 w->top_line = 0;
2211 w->pixel_left = 0;
2212 w->pixel_top = 0;
2213
2214 if (CONSP (Vx_max_tooltip_size)
2215 && RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
2216 && RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
2217 {
2218 w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
2219 w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
2220 }
2221 else
2222 {
2223 w->total_cols = 80;
2224 w->total_lines = 40;
2225 }
2226
2227 w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
2228 w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
2229 FRAME_TOTAL_COLS (tip_f) = w->total_cols;
2230 adjust_frame_glyphs (tip_f);
2231
2232 /* Insert STRING into root window's buffer and fit the frame to the
2233 buffer. */
2234 specpdl_ref count_1 = SPECPDL_INDEX ();
2235 old_buffer = current_buffer;
2236 set_buffer_internal_1 (XBUFFER (w->contents));
2237 bset_truncate_lines (current_buffer, Qnil);
2238 specbind (Qinhibit_read_only, Qt);
2239 specbind (Qinhibit_modification_hooks, Qt);
2240 specbind (Qinhibit_point_motion_hooks, Qt);
2241 Ferase_buffer ();
2242 Finsert (1, &string);
2243 clear_glyph_matrix (w->desired_matrix);
2244 clear_glyph_matrix (w->current_matrix);
2245 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
2246 displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
2247
2248 if (!displayed && NILP (Vx_max_tooltip_size))
2249 {
2250#ifdef ENABLE_CHECKING
2251 row = w->desired_matrix->rows;
2252 end = w->desired_matrix->rows + w->desired_matrix->nrows;
2253
2254 while (row < end)
2255 {
2256 if (!row->displays_text_p
2257 || row->ends_at_zv_p)
2258 break;
2259 ++row;
2260 }
2261
2262 eassert (row < end && row->ends_at_zv_p);
2263#endif
2264 }
2265
2266 /* Calculate size of tooltip window. */
2267 size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
2268 make_fixnum (w->pixel_height), Qnil,
2269 Qnil);
2270 /* Add the frame's internal border to calculated size. */
2271 width = XFIXNUM (CAR (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
2272 height = XFIXNUM (CDR (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
2273
2274 /* Calculate position of tooltip frame. */
2275 compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
2276
2277 /* Show tooltip frame. */
2278 block_input ();
2279 android_move_resize_window (FRAME_ANDROID_WINDOW (tip_f),
2280 root_x, root_y, width,
2281 height);
2282 android_map_raised (FRAME_ANDROID_WINDOW (tip_f));
2283 unblock_input ();
2284
2285 w->must_be_updated_p = true;
2286 update_single_window (w);
2287 flush_frame (tip_f);
2288 set_buffer_internal_1 (old_buffer);
2289 unbind_to (count_1, Qnil);
2290 windows_or_buffers_changed = old_windows_or_buffers_changed;
2291
2292 start_timer:
2293 /* Let the tip disappear after timeout seconds. */
2294 tip_timer = call3 (Qrun_at_time, timeout, Qnil,
2295 Qx_hide_tip);
2296
2297 return unbind_to (count, Qnil);
1675#endif 2298#endif
1676} 2299}
1677 2300
@@ -1683,7 +2306,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
1683 error ("Android cross-compilation stub called!"); 2306 error ("Android cross-compilation stub called!");
1684 return Qnil; 2307 return Qnil;
1685#else 2308#else
1686 return Qnil; 2309 return android_hide_tip (true);
1687#endif 2310#endif
1688} 2311}
1689 2312
@@ -2112,6 +2735,17 @@ syms_of_androidfns (void)
2112 doc: /* SKIP: real doc in xfns.c. */); 2735 doc: /* SKIP: real doc in xfns.c. */);
2113 Vx_cursor_fore_pixel = Qnil; 2736 Vx_cursor_fore_pixel = Qnil;
2114 2737
2738 /* Used by Fx_show_tip. */
2739 DEFSYM (Qrun_at_time, "run-at-time");
2740 DEFSYM (Qx_hide_tip, "x-hide-tip");
2741 DEFSYM (Qcancel_timer, "cancel-timer");
2742 DEFSYM (Qassq_delete_all, "assq-delete-all");
2743 DEFSYM (Qcolor, "color");
2744
2745 DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
2746 doc: /* SKIP: real doc in xfns.c. */);
2747 Vx_max_tooltip_size = Qnil;
2748
2115 /* Functions defined. */ 2749 /* Functions defined. */
2116 defsubr (&Sx_create_frame); 2750 defsubr (&Sx_create_frame);
2117 defsubr (&Sxw_color_defined_p); 2751 defsubr (&Sxw_color_defined_p);
@@ -2139,4 +2773,21 @@ syms_of_androidfns (void)
2139 defsubr (&Sx_show_tip); 2773 defsubr (&Sx_show_tip);
2140 defsubr (&Sx_hide_tip); 2774 defsubr (&Sx_hide_tip);
2141 defsubr (&Sandroid_detect_mouse); 2775 defsubr (&Sandroid_detect_mouse);
2776
2777#ifndef ANDROID_STUBIFY
2778 tip_timer = Qnil;
2779 staticpro (&tip_timer);
2780 tip_frame = Qnil;
2781 staticpro (&tip_frame);
2782 tip_last_frame = Qnil;
2783 staticpro (&tip_last_frame);
2784 tip_last_string = Qnil;
2785 staticpro (&tip_last_string);
2786 tip_last_parms = Qnil;
2787 staticpro (&tip_last_parms);
2788 tip_dx = Qnil;
2789 staticpro (&tip_dx);
2790 tip_dy = Qnil;
2791 staticpro (&tip_dy);
2792#endif
2142} 2793}