1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

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.
This commit is contained in:
Po Lu 2023-01-14 22:12:16 +08:00
parent 28a9baccd4
commit 2b87ab7b27
18 changed files with 1683 additions and 110 deletions

View file

@ -25,12 +25,36 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "androidterm.h"
#include "blockinput.h"
#include "keyboard.h"
#include "buffer.h"
#ifndef ANDROID_STUBIFY
/* Some kind of reference count for the image cache. */
static ptrdiff_t image_cache_refcount;
/* The frame of the currently visible tooltip, or nil if none. */
static Lisp_Object tip_frame;
/* The window-system window corresponding to the frame of the
currently visible tooltip. */
static android_window tip_window;
/* The X and Y deltas of the last call to `x-show-tip'. */
static Lisp_Object tip_dx, tip_dy;
/* A timer that hides or deletes the currently visible tooltip when it
fires. */
static Lisp_Object tip_timer;
/* STRING argument of last `x-show-tip' call. */
static Lisp_Object tip_last_string;
/* Normalized FRAME argument of last `x-show-tip' call. */
static Lisp_Object tip_last_frame;
/* PARMS argument of last `x-show-tip' call. */
static Lisp_Object tip_last_parms;
#endif
static struct android_display_info *
@ -180,6 +204,9 @@ android_set_parent_frame (struct frame *f, Lisp_Object new_value,
fset_parent_frame (f, new_value);
}
/* Update the fullscreen frame parameter as well. */
FRAME_TERMINAL (f)->fullscreen_hook (f);
}
void
@ -858,13 +885,13 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
NULL, NULL, RES_TYPE_NUMBER);
/* gui_default_parameter (f, parms, Qvertical_scroll_bars, */
/* Qleft, */
/* "verticalScrollBars", "ScrollBars", */
/* RES_TYPE_SYMBOL); */
/* gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil, */
/* "horizontalScrollBars", "ScrollBars", */
/* RES_TYPE_SYMBOL); TODO */
gui_default_parameter (f, parms, Qvertical_scroll_bars,
Qleft,
"verticalScrollBars", "ScrollBars",
RES_TYPE_SYMBOL);
gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
"horizontalScrollBars", "ScrollBars",
RES_TYPE_SYMBOL);
/* Also do the stuff which must be set before the window exists. */
gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
@ -893,7 +920,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
"scrollBarBackground",
"ScrollBarBackground", false);
#endif /* TODO */
#endif
/* Init faces before gui_default_parameter is called for the
scroll-bar-width parameter because otherwise we end up in
@ -974,12 +1001,16 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
"autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
gui_default_parameter (f, parms, Qcursor_type, Qbox,
"cursorType", "CursorType", RES_TYPE_SYMBOL);
/* Scroll bars are not supported on Android, as they are near
useless. */
#if 0
gui_default_parameter (f, parms, Qscroll_bar_width, Qnil,
"scrollBarWidth", "ScrollBarWidth",
RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qscroll_bar_height, Qnil,
"scrollBarHeight", "ScrollBarHeight",
RES_TYPE_NUMBER);
#endif
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
@ -1009,8 +1040,9 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
/* Process fullscreen parameter here in the hope that normalizing a
fullheight/fullwidth frame will produce the size set by the last
adjust_frame_size call. */
gui_default_parameter (f, parms, Qfullscreen, Qnil,
adjust_frame_size call. Note that Android only supports the
`maximized' state. */
gui_default_parameter (f, parms, Qfullscreen, Qmaximized,
"fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
/* 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,
return result;
}
#ifndef ANDROID_STUBIFY
static void
unwind_create_tip_frame (Lisp_Object frame)
{
Lisp_Object deleted;
deleted = unwind_create_frame (frame);
if (EQ (deleted, Qt))
{
tip_window = ANDROID_NONE;
tip_frame = Qnil;
}
}
static Lisp_Object
android_create_tip_frame (struct android_display_info *dpyinfo,
Lisp_Object parms)
{
struct frame *f;
Lisp_Object frame;
Lisp_Object name;
specpdl_ref count = SPECPDL_INDEX ();
bool face_change_before = face_change;
if (!dpyinfo->terminal->name)
error ("Terminal is not live, can't create new frames on it");
parms = Fcopy_alist (parms);
/* Get the name of the frame to use for resource lookup. */
name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
RES_TYPE_STRING);
if (!STRINGP (name)
&& !BASE_EQ (name, Qunbound)
&& !NILP (name))
error ("Invalid frame name--not a string or nil");
frame = Qnil;
f = make_frame (false);
f->wants_modeline = false;
XSETFRAME (frame, f);
record_unwind_protect (unwind_create_tip_frame, frame);
f->terminal = dpyinfo->terminal;
/* By setting the output method, we're essentially saying that
the frame is live, as per FRAME_LIVE_P. If we get a signal
from this point on, x_destroy_window might screw up reference
counts etc. */
f->output_method = output_android;
f->output_data.android = xzalloc (sizeof *f->output_data.android);
FRAME_FONTSET (f) = -1;
f->output_data.android->white_relief.pixel = -1;
f->output_data.android->black_relief.pixel = -1;
f->tooltip = true;
fset_icon_name (f, Qnil);
FRAME_DISPLAY_INFO (f) = dpyinfo;
f->output_data.android->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
/* These colors will be set anyway later, but it's important
to get the color reference counts right, so initialize them! */
{
Lisp_Object black;
/* Function android_decode_color can signal an error. Make sure
to initialize color slots so that we won't try to free colors
we haven't allocated. */
FRAME_FOREGROUND_PIXEL (f) = -1;
FRAME_BACKGROUND_PIXEL (f) = -1;
f->output_data.android->cursor_pixel = -1;
f->output_data.android->cursor_foreground_pixel = -1;
black = build_string ("black");
FRAME_FOREGROUND_PIXEL (f)
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
FRAME_BACKGROUND_PIXEL (f)
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
f->output_data.android->cursor_pixel
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
f->output_data.android->cursor_foreground_pixel
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
}
/* Set the name; the functions to which we pass f expect the name to
be set. */
if (BASE_EQ (name, Qunbound) || NILP (name))
f->explicit_name = false;
else
{
fset_name (f, name);
f->explicit_name = true;
/* use the frame's title when getting resources for this frame. */
specbind (Qx_resource_name, name);
}
register_font_driver (&androidfont_driver, f);
register_font_driver (&android_sfntfont_driver, f);
image_cache_refcount
= FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
#ifdef GLYPH_DEBUG
dpyinfo_refcount = dpyinfo->reference_count;
#endif /* GLYPH_DEBUG */
gui_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);
/* Extract the window parameters from the supplied values that are
needed to determine window geometry. */
android_default_font_parameter (f, parms);
gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
"borderWidth", "BorderWidth", RES_TYPE_NUMBER);
/* This defaults to 1 in order to match xterm. We recognize either
internalBorderWidth or internalBorder (which is what xterm calls
it). */
if (NILP (Fassq (Qinternal_border_width, parms)))
{
Lisp_Object value;
value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
"internalBorder", "internalBorder",
RES_TYPE_NUMBER);
if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qinternal_border_width, value),
parms);
}
gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (1),
"internalBorderWidth", "internalBorderWidth",
RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
NULL, NULL, RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
NULL, NULL, RES_TYPE_NUMBER);
/* Also do the stuff which must be set before the window exists. */
gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
"foreground", "Foreground", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
"background", "Background", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
"pointerColor", "Foreground", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
"cursorColor", "Foreground", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qborder_color, build_string ("black"),
"borderColor", "BorderColor", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
NULL, NULL, RES_TYPE_BOOLEAN);
{
struct android_set_window_attributes attrs;
unsigned long mask;
block_input ();
mask = ANDROID_CW_OVERRIDE_REDIRECT;
attrs.override_redirect = true;
tip_window
= FRAME_ANDROID_WINDOW (f)
= android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
/* x, y, width, height, value-mask,
attrs. */
0, 0, 1, 1, mask, &attrs);
unblock_input ();
}
/* Init faces before gui_default_parameter is called for the
scroll-bar-width parameter because otherwise we end up in
init_iterator with a null face cache, which should not happen. */
init_frame_faces (f);
gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
"inhibitDoubleBuffering", "InhibitDoubleBuffering",
RES_TYPE_BOOLEAN);
gui_figure_window_size (f, parms, false, false);
f->output_data.android->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
android_make_gc (f);
gui_default_parameter (f, parms, Qauto_raise, Qnil,
"autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
gui_default_parameter (f, parms, Qauto_lower, Qnil,
"autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
gui_default_parameter (f, parms, Qcursor_type, Qbox,
"cursorType", "CursorType", RES_TYPE_SYMBOL);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
/* Add `tooltip' frame parameter's default value. */
if (NILP (Fframe_parameter (frame, Qtooltip)))
{
AUTO_FRAME_ARG (arg, Qtooltip, Qt);
Fmodify_frame_parameters (frame, arg);
}
/* FIXME - can this be done in a similar way to normal frames?
https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
/* Set the `display-type' frame parameter before setting up faces. */
{
Lisp_Object disptype;
disptype = Qcolor;
if (NILP (Fframe_parameter (frame, Qdisplay_type)))
{
AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
Fmodify_frame_parameters (frame, arg);
}
}
/* Set up faces after all frame parameters are known. This call
also merges in face attributes specified for new frames. */
{
Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
call2 (Qface_set_after_frame_default, frame, Qnil);
if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
{
AUTO_FRAME_ARG (arg, Qbackground_color, bg);
Fmodify_frame_parameters (frame, arg);
}
}
f->no_split = true;
/* Now that the frame will be official, it counts as a reference to
its display and terminal. */
f->terminal->reference_count++;
/* It is now ok to make the frame official even if we get an error
below. And the frame needs to be on Vframe_list or making it
visible won't work. */
Vframe_list = Fcons (frame, Vframe_list);
f->can_set_window_size = true;
adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
0, true, Qtip_frame);
/* Setting attributes of faces of the tooltip frame from resources
and similar will set face_change, which leads to the clearing of
all current matrices. Since this isn't necessary here, avoid it
by resetting face_change to the value it had before we created
the tip frame. */
face_change = face_change_before;
/* Discard the unwind_protect. */
return unbind_to (count, frame);
}
static Lisp_Object
android_hide_tip (bool delete)
{
if (!NILP (tip_timer))
{
call1 (Qcancel_timer, tip_timer);
tip_timer = Qnil;
}
if (NILP (tip_frame)
|| (!delete
&& !NILP (tip_frame)
&& FRAME_LIVE_P (XFRAME (tip_frame))
&& !FRAME_VISIBLE_P (XFRAME (tip_frame))))
return Qnil;
else
{
Lisp_Object was_open = Qnil;
specpdl_ref count = SPECPDL_INDEX ();
specbind (Qinhibit_redisplay, Qt);
specbind (Qinhibit_quit, Qt);
if (!NILP (tip_frame))
{
struct frame *f = XFRAME (tip_frame);
if (FRAME_LIVE_P (f))
{
if (delete)
{
delete_frame (tip_frame, Qnil);
tip_frame = Qnil;
}
else
android_make_frame_invisible (XFRAME (tip_frame));
was_open = Qt;
}
else
tip_frame = Qnil;
}
else
tip_frame = Qnil;
return unbind_to (count, was_open);
}
}
static void
compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
Lisp_Object dy, int width, int height, int *root_x,
int *root_y)
{
Lisp_Object left, top, right, bottom;
int min_x, min_y, max_x, max_y = -1;
android_window window;
struct frame *mouse_frame;
/* Initialize these values in case there is no mouse frame. */
*root_x = 0;
*root_y = 0;
/* User-specified position? */
left = CDR (Fassq (Qleft, parms));
top = CDR (Fassq (Qtop, parms));
right = CDR (Fassq (Qright, parms));
bottom = CDR (Fassq (Qbottom, parms));
/* Move the tooltip window where the mouse pointer was last seen.
Resize and show it. */
if ((!FIXNUMP (left) && !FIXNUMP (right))
|| (!FIXNUMP (top) && !FIXNUMP (bottom)))
{
if (x_display_list->last_mouse_motion_frame)
{
*root_x = x_display_list->last_mouse_motion_x;
*root_y = x_display_list->last_mouse_motion_y;
mouse_frame = x_display_list->last_mouse_motion_frame;
window = FRAME_ANDROID_WINDOW (mouse_frame);
/* Translate the coordinates to the screen. */
android_translate_coordinates (window, *root_x, *root_y,
root_x, root_y);
}
}
min_x = 0;
min_y = 0;
max_x = android_get_screen_width ();
max_y = android_get_screen_height ();
if (FIXNUMP (top))
*root_y = XFIXNUM (top);
else if (FIXNUMP (bottom))
*root_y = XFIXNUM (bottom) - height;
else if (*root_y + XFIXNUM (dy) <= min_y)
*root_y = min_y; /* Can happen for negative dy */
else if (*root_y + XFIXNUM (dy) + height <= max_y)
/* It fits below the pointer */
*root_y += XFIXNUM (dy);
else if (height + XFIXNUM (dy) + min_y <= *root_y)
/* It fits above the pointer. */
*root_y -= height + XFIXNUM (dy);
else
/* Put it on the top. */
*root_y = min_y;
if (FIXNUMP (left))
*root_x = XFIXNUM (left);
else if (FIXNUMP (right))
*root_x = XFIXNUM (right) - width;
else if (*root_x + XFIXNUM (dx) <= min_x)
*root_x = 0; /* Can happen for negative dx */
else if (*root_x + XFIXNUM (dx) + width <= max_x)
/* It fits to the right of the pointer. */
*root_x += XFIXNUM (dx);
else if (width + XFIXNUM (dx) + min_x <= *root_x)
/* It fits to the left of the pointer. */
*root_x -= width + XFIXNUM (dx);
else
/* Put it left justified on the screen -- it ought to fit that way. */
*root_x = min_x;
}
#endif
DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
doc: /* SKIP: real doc in xfns.c. */)
(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,
error ("Android cross-compilation stub called!");
return Qnil;
#else
/* TODO tooltips */
return Qnil;
struct frame *f, *tip_f;
struct window *w;
int root_x, root_y;
struct buffer *old_buffer;
struct text_pos pos;
int width, height;
int old_windows_or_buffers_changed = windows_or_buffers_changed;
specpdl_ref count = SPECPDL_INDEX ();
Lisp_Object window, size, tip_buf;
bool displayed;
#ifdef ENABLE_CHECKING
struct glyph_row *row, *end;
#endif
AUTO_STRING (tip, " *tip*");
specbind (Qinhibit_redisplay, Qt);
CHECK_STRING (string);
if (SCHARS (string) == 0)
string = make_unibyte_string (" ", 1);
if (NILP (frame))
frame = selected_frame;
f = decode_window_system_frame (frame);
if (NILP (timeout))
timeout = Vx_show_tooltip_timeout;
CHECK_FIXNAT (timeout);
if (NILP (dx))
dx = make_fixnum (5);
else
CHECK_FIXNUM (dx);
if (NILP (dy))
dy = make_fixnum (-10);
else
CHECK_FIXNUM (dy);
tip_dx = dx;
tip_dy = dy;
if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
{
if (FRAME_VISIBLE_P (XFRAME (tip_frame))
&& !NILP (Fequal_including_properties (tip_last_string,
string))
&& !NILP (Fequal (tip_last_parms, parms)))
{
/* Only DX and DY have changed. */
tip_f = XFRAME (tip_frame);
if (!NILP (tip_timer))
{
call1 (Qcancel_timer, tip_timer);
tip_timer = Qnil;
}
block_input ();
compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
android_move_window (FRAME_ANDROID_WINDOW (tip_f),
root_x, root_y);
unblock_input ();
goto start_timer;
}
else
android_hide_tip (true);
}
else
android_hide_tip (true);
tip_last_frame = frame;
tip_last_string = string;
tip_last_parms = parms;
if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
{
/* Add default values to frame parameters. */
if (NILP (Fassq (Qname, parms)))
parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
if (NILP (Fassq (Qinternal_border_width, parms)))
parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)),
parms);
if (NILP (Fassq (Qborder_width, parms)))
parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
if (NILP (Fassq (Qborder_color, parms)))
parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")),
parms);
if (NILP (Fassq (Qbackground_color, parms)))
parms = Fcons (Fcons (Qbackground_color,
build_string ("lightyellow")),
parms);
/* Create a frame for the tooltip, and record it in the global
variable tip_frame. */
if (NILP (tip_frame = android_create_tip_frame (FRAME_DISPLAY_INFO (f),
parms)))
/* Creating the tip frame failed. */
return unbind_to (count, Qnil);
}
tip_f = XFRAME (tip_frame);
window = FRAME_ROOT_WINDOW (tip_f);
tip_buf = Fget_buffer_create (tip, Qnil);
/* We will mark the tip window a "pseudo-window" below, and such
windows cannot have display margins. */
bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
set_window_buffer (window, tip_buf, false, false);
w = XWINDOW (window);
w->pseudo_window_p = true;
/* Try to avoid that `other-window' select us (Bug#47207). */
Fset_window_parameter (window, Qno_other_window, Qt);
/* Set up the frame's root window. Note: The following code does not
try to size the window or its frame correctly. Its only purpose is
to make the subsequent text size calculations work. The right
sizes should get installed when the toolkit gets back to us. */
w->left_col = 0;
w->top_line = 0;
w->pixel_left = 0;
w->pixel_top = 0;
if (CONSP (Vx_max_tooltip_size)
&& RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
&& RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
{
w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
}
else
{
w->total_cols = 80;
w->total_lines = 40;
}
w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
FRAME_TOTAL_COLS (tip_f) = w->total_cols;
adjust_frame_glyphs (tip_f);
/* Insert STRING into root window's buffer and fit the frame to the
buffer. */
specpdl_ref count_1 = SPECPDL_INDEX ();
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (w->contents));
bset_truncate_lines (current_buffer, Qnil);
specbind (Qinhibit_read_only, Qt);
specbind (Qinhibit_modification_hooks, Qt);
specbind (Qinhibit_point_motion_hooks, Qt);
Ferase_buffer ();
Finsert (1, &string);
clear_glyph_matrix (w->desired_matrix);
clear_glyph_matrix (w->current_matrix);
SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
if (!displayed && NILP (Vx_max_tooltip_size))
{
#ifdef ENABLE_CHECKING
row = w->desired_matrix->rows;
end = w->desired_matrix->rows + w->desired_matrix->nrows;
while (row < end)
{
if (!row->displays_text_p
|| row->ends_at_zv_p)
break;
++row;
}
eassert (row < end && row->ends_at_zv_p);
#endif
}
/* Calculate size of tooltip window. */
size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
make_fixnum (w->pixel_height), Qnil,
Qnil);
/* Add the frame's internal border to calculated size. */
width = XFIXNUM (CAR (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
height = XFIXNUM (CDR (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
/* Calculate position of tooltip frame. */
compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
/* Show tooltip frame. */
block_input ();
android_move_resize_window (FRAME_ANDROID_WINDOW (tip_f),
root_x, root_y, width,
height);
android_map_raised (FRAME_ANDROID_WINDOW (tip_f));
unblock_input ();
w->must_be_updated_p = true;
update_single_window (w);
flush_frame (tip_f);
set_buffer_internal_1 (old_buffer);
unbind_to (count_1, Qnil);
windows_or_buffers_changed = old_windows_or_buffers_changed;
start_timer:
/* Let the tip disappear after timeout seconds. */
tip_timer = call3 (Qrun_at_time, timeout, Qnil,
Qx_hide_tip);
return unbind_to (count, Qnil);
#endif
}
@ -1683,7 +2306,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
error ("Android cross-compilation stub called!");
return Qnil;
#else
return Qnil;
return android_hide_tip (true);
#endif
}
@ -2112,6 +2735,17 @@ syms_of_androidfns (void)
doc: /* SKIP: real doc in xfns.c. */);
Vx_cursor_fore_pixel = Qnil;
/* Used by Fx_show_tip. */
DEFSYM (Qrun_at_time, "run-at-time");
DEFSYM (Qx_hide_tip, "x-hide-tip");
DEFSYM (Qcancel_timer, "cancel-timer");
DEFSYM (Qassq_delete_all, "assq-delete-all");
DEFSYM (Qcolor, "color");
DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
doc: /* SKIP: real doc in xfns.c. */);
Vx_max_tooltip_size = Qnil;
/* Functions defined. */
defsubr (&Sx_create_frame);
defsubr (&Sxw_color_defined_p);
@ -2139,4 +2773,21 @@ syms_of_androidfns (void)
defsubr (&Sx_show_tip);
defsubr (&Sx_hide_tip);
defsubr (&Sandroid_detect_mouse);
#ifndef ANDROID_STUBIFY
tip_timer = Qnil;
staticpro (&tip_timer);
tip_frame = Qnil;
staticpro (&tip_frame);
tip_last_frame = Qnil;
staticpro (&tip_last_frame);
tip_last_string = Qnil;
staticpro (&tip_last_string);
tip_last_parms = Qnil;
staticpro (&tip_last_parms);
tip_dx = Qnil;
staticpro (&tip_dx);
tip_dy = Qnil;
staticpro (&tip_dy);
#endif
}