emacs/src/androidfns.c

3792 lines
113 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Communication module for Android terminals.
Copyright (C) 2023-2024 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
#include <math.h>
#include <stdlib.h>
#include "lisp.h"
#include "android.h"
#include "androidterm.h"
#include "blockinput.h"
#include "keyboard.h"
#include "buffer.h"
#include "androidgui.h"
#include "pdumper.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 *
android_display_info_for_name (Lisp_Object name)
{
struct android_display_info *dpyinfo;
CHECK_STRING (name);
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
{
if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element),
name)))
return dpyinfo;
}
error ("Cannot connect to Android if it was not initialized"
" at startup");
}
static struct android_display_info *
check_android_display_info (Lisp_Object object)
{
struct android_display_info *dpyinfo;
struct frame *sf, *f;
struct terminal *t;
if (NILP (object))
{
sf = XFRAME (selected_frame);
if (FRAME_ANDROID_P (sf) && FRAME_LIVE_P (sf))
dpyinfo = FRAME_DISPLAY_INFO (sf);
else if (x_display_list)
dpyinfo = x_display_list;
else
error ("Android windows are not in use or not initialized");
}
else if (TERMINALP (object))
{
t = decode_live_terminal (object);
if (t->type != output_android)
error ("Terminal %d is not an Android display", t->id);
dpyinfo = t->display_info.android;
}
else if (STRINGP (object))
dpyinfo = android_display_info_for_name (object);
else
{
f = decode_window_system_frame (object);
dpyinfo = FRAME_DISPLAY_INFO (f);
}
return dpyinfo;
}
Display_Info *
check_x_display_info (Lisp_Object object)
{
return check_android_display_info (object);
}
#ifndef ANDROID_STUBIFY
void
gamma_correct (struct frame *f, Emacs_Color *color)
{
if (f->gamma)
{
color->red = pow (color->red / 65535.0, f->gamma) * 65535.0 + 0.5;
color->green = pow (color->green / 65535.0, f->gamma) * 65535.0 + 0.5;
color->blue = pow (color->blue / 65535.0, f->gamma) * 65535.0 + 0.5;
}
}
/* Decide if color named COLOR_NAME is valid for use on frame F. If
so, return the RGB values in COLOR. If ALLOC_P, allocate the
color. Value is false if COLOR_NAME is invalid, or no color could
be allocated. MAKE_INDEX is some mysterious argument used on
NS. */
bool
android_defined_color (struct frame *f, const char *color_name,
Emacs_Color *color, bool alloc_p,
bool make_index)
{
bool success_p;
success_p = false;
block_input ();
success_p = android_parse_color (f, color_name, color);
if (success_p && alloc_p)
success_p = android_alloc_nearest_color (f, color);
unblock_input ();
return success_p;
}
/* Return the pixel color value for color COLOR_NAME on frame F. If F
is a monochrome frame, return MONO_COLOR regardless of what ARG
says. Signal an error if color can't be allocated. */
static unsigned long
android_decode_color (struct frame *f, Lisp_Object color_name, int mono_color)
{
Emacs_Color cdef;
CHECK_STRING (color_name);
if (android_defined_color (f, SSDATA (color_name), &cdef,
true, false))
return cdef.pixel;
signal_error ("Undefined color", color_name);
}
static void
android_set_parent_frame (struct frame *f, Lisp_Object new_value,
Lisp_Object old_value)
{
struct frame *p;
p = NULL;
if (!NILP (new_value)
&& (!FRAMEP (new_value)
|| !FRAME_LIVE_P (p = XFRAME (new_value))
|| !FRAME_ANDROID_P (p)))
{
store_frame_param (f, Qparent_frame, old_value);
error ("Invalid specification of `parent-frame'");
}
if (p != FRAME_PARENT_FRAME (f))
{
block_input ();
android_reparent_window (FRAME_ANDROID_WINDOW (f),
(p ? FRAME_ANDROID_WINDOW (p)
: FRAME_DISPLAY_INFO (f)->root_window),
f->left_pos, f->top_pos);
unblock_input ();
fset_parent_frame (f, new_value);
}
/* Update the fullscreen frame parameter as well. */
FRAME_TERMINAL (f)->fullscreen_hook (f);
}
/* Set the WM name to NAME for frame F. Also set the icon name.
If the frame already has an icon name, use that, otherwise set the
icon name to NAME. */
static void
android_set_name_internal (struct frame *f, Lisp_Object name)
{
jstring java_name;
if (FRAME_ANDROID_WINDOW (f))
{
java_name = android_build_string (name, NULL);
android_set_wm_name (FRAME_ANDROID_WINDOW (f), java_name);
ANDROID_DELETE_LOCAL_REF (java_name);
}
}
/* Change the name of frame F to NAME. If NAME is nil, set F's name to
x_id_name.
If EXPLICIT is true, that indicates that lisp code is setting the
name; if NAME is a string, set F's name to NAME and set
F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
If EXPLICIT is false, that indicates that Emacs redisplay code is
suggesting a new name, which lisp code should override; if
F->explicit_name is set, ignore the new name; otherwise, set it. */
static void
android_set_name (struct frame *f, Lisp_Object name, bool explicit)
{
/* Make sure that requests from lisp code override requests from
Emacs redisplay code. */
if (explicit)
{
/* If we're switching from explicit to implicit, we had better
update the mode lines and thereby update the title. */
if (f->explicit_name && NILP (name))
update_mode_lines = 37;
f->explicit_name = ! NILP (name);
}
else if (f->explicit_name)
return;
/* If NAME is nil, set the name to the x_id_name. */
if (NILP (name))
{
/* Check for no change needed in this very common case
before we do any consing. */
if (!strcmp (FRAME_DISPLAY_INFO (f)->x_id_name,
SSDATA (f->name)))
return;
name = build_string (FRAME_DISPLAY_INFO (f)->x_id_name);
}
else
CHECK_STRING (name);
/* Don't change the name if it's already NAME. */
if (! NILP (Fstring_equal (name, f->name)))
return;
fset_name (f, name);
/* For setting the frame title, the title parameter should override
the name parameter. */
if (! NILP (f->title))
name = f->title;
android_set_name_internal (f, name);
}
void
android_implicitly_set_name (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
android_set_name (f, arg, false);
}
void
android_explicitly_set_name (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
android_set_name (f, arg, true);
}
/* Set the number of lines used for the tool bar of frame F to VALUE.
VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
is the old number of tool bar lines. This function changes the
height of all windows on frame F to match the new tool bar height.
The frame's height doesn't change. */
static void
android_set_tool_bar_lines (struct frame *f, Lisp_Object value,
Lisp_Object oldval)
{
int nlines;
/* Treat tool bars like menu bars. */
if (FRAME_MINIBUF_ONLY_P (f))
return;
/* Use VALUE only if an int >= 0. */
if (RANGED_FIXNUMP (0, value, INT_MAX))
nlines = XFIXNAT (value);
else
nlines = 0;
android_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
}
static void
android_set_tool_bar_position (struct frame *f,
Lisp_Object new_value,
Lisp_Object old_value)
{
if (!EQ (new_value, Qtop) && !EQ (new_value, Qbottom))
error ("Tool bar position must be either `top' or `bottom'");
if (EQ (new_value, old_value))
return;
/* Set the tool bar position. */
fset_tool_bar_position (f, new_value);
/* Now reconfigure frame glyphs to place the tool bar at the
bottom. While the inner height has not changed, call
`resize_frame_windows' to place each of the windows at its
new position. */
adjust_frame_size (f, -1, -1, 3, false, Qtool_bar_position);
adjust_frame_glyphs (f);
SET_FRAME_GARBAGED (f);
if (FRAME_ANDROID_WINDOW (f))
android_clear_under_internal_border (f);
}
void
android_change_tool_bar_height (struct frame *f, int height)
{
int unit = FRAME_LINE_HEIGHT (f);
int old_height = FRAME_TOOL_BAR_HEIGHT (f);
int lines = (height + unit - 1) / unit;
Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
/* Make sure we redisplay all windows in this frame. */
fset_redisplay (f);
FRAME_TOOL_BAR_HEIGHT (f) = height;
FRAME_TOOL_BAR_LINES (f) = lines;
store_frame_param (f, Qtool_bar_lines, make_fixnum (lines));
if (FRAME_ANDROID_WINDOW (f) && FRAME_TOOL_BAR_HEIGHT (f) == 0)
{
clear_frame (f);
clear_current_matrices (f);
}
if ((height < old_height) && WINDOWP (f->tool_bar_window))
clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
if (!f->tool_bar_resized)
{
/* As long as tool_bar_resized is false, effectively try to change
F's native height. */
if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
1, false, Qtool_bar_lines);
else
adjust_frame_size (f, -1, -1, 4, false, Qtool_bar_lines);
f->tool_bar_resized = f->tool_bar_redisplayed;
}
else
/* Any other change may leave the native size of F alone. */
adjust_frame_size (f, -1, -1, 3, false, Qtool_bar_lines);
/* adjust_frame_size might not have done anything, garbage frame
here. */
adjust_frame_glyphs (f);
SET_FRAME_GARBAGED (f);
}
/* Set the number of lines used for the tab bar of frame F to VALUE.
VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
is the old number of tab bar lines. This function may change the
height of all windows on frame F to match the new tab bar height.
The frame's height may change if frame_inhibit_implied_resize was
set accordingly. */
static void
android_set_tab_bar_lines (struct frame *f, Lisp_Object value,
Lisp_Object oldval)
{
int olines;
int nlines;
olines = FRAME_TAB_BAR_LINES (f);
/* Treat tab bars like menu bars. */
if (FRAME_MINIBUF_ONLY_P (f))
return;
/* Use VALUE only if an int >= 0. */
if (RANGED_FIXNUMP (0, value, INT_MAX))
nlines = XFIXNAT (value);
else
nlines = 0;
if (nlines != olines && (olines == 0 || nlines == 0))
android_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
}
void
android_change_tab_bar_height (struct frame *f, int height)
{
int unit, old_height, lines;
Lisp_Object fullscreen;
unit = FRAME_LINE_HEIGHT (f);
old_height = FRAME_TAB_BAR_HEIGHT (f);
fullscreen = get_frame_param (f, Qfullscreen);
/* This differs from the tool bar code in that the tab bar height is
not rounded up. Otherwise, if redisplay_tab_bar decides to grow
the tab bar by even 1 pixel, FRAME_TAB_BAR_LINES will be changed,
leading to the tab bar height being incorrectly set upon the next
call to android_set_font. (bug#59285) */
lines = height / unit;
/* Even so, HEIGHT might be less than unit if the tab bar face is
not so tall as the frame's font height; which if true lines will
be set to 0 and the tab bar will thus vanish. */
if (lines == 0 && height != 0)
lines = 1;
/* Make sure we redisplay all windows in this frame. */
fset_redisplay (f);
/* Recalculate tab bar and frame text sizes. */
FRAME_TAB_BAR_HEIGHT (f) = height;
FRAME_TAB_BAR_LINES (f) = lines;
store_frame_param (f, Qtab_bar_lines, make_fixnum (lines));
if (FRAME_ANDROID_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0)
{
clear_frame (f);
clear_current_matrices (f);
}
if ((height < old_height) && WINDOWP (f->tab_bar_window))
clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
if (!f->tab_bar_resized)
{
/* As long as tab_bar_resized is false, effectively try to change
F's native height. */
if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
1, false, Qtab_bar_lines);
else
adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines);
f->tab_bar_resized = f->tab_bar_redisplayed;
}
else
/* Any other change may leave the native size of F alone. */
adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines);
/* adjust_frame_size might not have done anything, garbage frame
here. */
adjust_frame_glyphs (f);
SET_FRAME_GARBAGED (f);
}
void
android_set_scroll_bar_default_height (struct frame *f)
{
int height;
height = FRAME_LINE_HEIGHT (f);
/* The height of a non-toolkit scrollbar is 14 pixels. */
FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
/* Use all of that space (aside from required margins) for the
scroll bar. */
FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = 14;
}
void
android_set_scroll_bar_default_width (struct frame *f)
{
int unit;
unit = FRAME_COLUMN_WIDTH (f);
FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit;
FRAME_CONFIG_SCROLL_BAR_WIDTH (f)
= FRAME_CONFIG_SCROLL_BAR_COLS (f) * unit;
}
/* Verify that the icon position args for this window are valid. */
static void
android_icon_verify (struct frame *f, Lisp_Object parms)
{
Lisp_Object icon_x, icon_y;
/* Set the position of the icon. Note that twm groups all
icons in an icon window. */
icon_x = gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0,
RES_TYPE_NUMBER);
icon_y = gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0,
RES_TYPE_NUMBER);
if (!BASE_EQ (icon_x, Qunbound) && !BASE_EQ (icon_y, Qunbound))
{
CHECK_FIXNUM (icon_x);
CHECK_FIXNUM (icon_y);
}
else if (!BASE_EQ (icon_x, Qunbound) || !BASE_EQ (icon_y, Qunbound))
error ("Both left and top icon corners of icon must be specified");
}
/* Handle the icon stuff for this window. Perhaps later we might
want an x_set_icon_position which can be called interactively as
well. */
static void
android_icon (struct frame *f, Lisp_Object parms)
{
/* Set the position of the icon. Note that twm groups all
icons in an icon window. */
Lisp_Object icon_x
= gui_frame_get_and_record_arg (f, parms, Qicon_left, 0, 0,
RES_TYPE_NUMBER);
Lisp_Object icon_y
= gui_frame_get_and_record_arg (f, parms, Qicon_top, 0, 0,
RES_TYPE_NUMBER);
bool xgiven = !BASE_EQ (icon_x, Qunbound);
bool ygiven = !BASE_EQ (icon_y, Qunbound);
if (xgiven != ygiven)
error ("Both left and top icon corners of icon must be specified");
if (xgiven)
{
check_integer_range (icon_x, INT_MIN, INT_MAX);
check_integer_range (icon_y, INT_MIN, INT_MAX);
}
/* Now return as this is not supported on Android. */
}
/* Make the GCs needed for this window, setting the background
color. */
static void
android_make_gc (struct frame *f)
{
struct android_gc_values gc_values;
block_input ();
/* Create the GCs of this frame.
Note that many default values are used. */
gc_values.foreground = FRAME_FOREGROUND_PIXEL (f);
gc_values.background = FRAME_BACKGROUND_PIXEL (f);
f->output_data.android->normal_gc
= android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND,
&gc_values);
/* Reverse video style. */
gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
gc_values.background = FRAME_FOREGROUND_PIXEL (f);
f->output_data.android->reverse_gc
= android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND,
&gc_values);
/* Cursor has cursor-color background, background-color foreground. */
gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
gc_values.background = f->output_data.android->cursor_pixel;
f->output_data.android->cursor_gc
= android_create_gc (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND,
&gc_values);
unblock_input ();
}
/* Free what was allocated in android_make_gc. */
void
android_free_gcs (struct frame *f)
{
block_input ();
if (f->output_data.android->normal_gc)
{
android_free_gc (f->output_data.android->normal_gc);
f->output_data.android->normal_gc = 0;
}
if (f->output_data.android->reverse_gc)
{
android_free_gc (f->output_data.android->reverse_gc);
f->output_data.android->reverse_gc = 0;
}
if (f->output_data.android->cursor_gc)
{
android_free_gc (f->output_data.android->cursor_gc);
f->output_data.android->cursor_gc = 0;
}
unblock_input ();
}
/* Handler for signals raised during x_create_frame and
Fx_create_tip_frame. FRAME is the frame which is partially
constructed. */
static Lisp_Object
unwind_create_frame (Lisp_Object frame)
{
struct frame *f = XFRAME (frame);
/* If frame is already dead, nothing to do. This can happen if the
display is disconnected after the frame has become official, but
before Fx_create_frame removes the unwind protect. */
if (!FRAME_LIVE_P (f))
return Qnil;
/* If frame is ``official'', nothing to do. */
if (NILP (Fmemq (frame, Vframe_list)))
{
/* If the frame's image cache refcount is still the same as our
private shadow variable, it means we are unwinding a frame
for which we didn't yet call init_frame_faces, where the
refcount is incremented. Therefore, we increment it here, so
that free_frame_faces, called in x_free_frame_resources
below, will not mistakenly decrement the counter that was not
incremented yet to account for this new frame. */
if (FRAME_IMAGE_CACHE (f) != NULL
&& FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
FRAME_IMAGE_CACHE (f)->refcount++;
android_free_frame_resources (f);
free_glyphs (f);
return Qt;
}
return Qnil;
}
static void
do_unwind_create_frame (Lisp_Object frame)
{
unwind_create_frame (frame);
}
void
android_default_font_parameter (struct frame *f, Lisp_Object parms)
{
struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
Lisp_Object font_param = gui_display_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
RES_TYPE_STRING);
Lisp_Object font = Qnil;
if (BASE_EQ (font_param, Qunbound))
font_param = Qnil;
if (NILP (font))
font = (!NILP (font_param)
? font_param
: gui_display_get_arg (dpyinfo, parms,
Qfont, "font", "Font",
RES_TYPE_STRING));
if (! FONTP (font) && ! STRINGP (font))
{
const char *names[] = {
"Droid Sans Mono-12",
"Monospace-12",
"DroidSansMono-12",
NULL
};
int i;
for (i = 0; names[i]; i++)
{
font = font_open_by_name (f, build_unibyte_string (names[i]));
if (! NILP (font))
break;
}
if (NILP (font))
error ("No suitable font was found");
}
gui_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING);
}
static void
android_create_frame_window (struct frame *f)
{
struct android_set_window_attributes attributes;
enum android_window_value_mask attribute_mask;
attributes.background_pixel = FRAME_BACKGROUND_PIXEL (f);
attribute_mask = ANDROID_CW_BACK_PIXEL;
block_input ();
FRAME_ANDROID_WINDOW (f)
= android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
f->left_pos,
f->top_pos,
FRAME_PIXEL_WIDTH (f),
FRAME_PIXEL_HEIGHT (f),
attribute_mask, &attributes);
unblock_input ();
}
#endif /* ANDROID_STUBIFY */
DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object parms)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
struct frame *f;
Lisp_Object frame, tem;
Lisp_Object name;
bool minibuffer_only;
bool undecorated, override_redirect;
long window_prompting;
specpdl_ref count;
Lisp_Object display;
struct android_display_info *dpyinfo;
Lisp_Object parent, parent_frame;
struct kboard *kb;
minibuffer_only = false;
undecorated = false;
override_redirect = false;
window_prompting = 0;
count = SPECPDL_INDEX ();
dpyinfo = NULL;
/* Not actually used, but be consistent with X. */
((void) window_prompting);
parms = Fcopy_alist (parms);
/* Use this general default value to start with
until we know if this frame has a specified name. */
Vx_resource_name = Vinvocation_name;
display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0,
RES_TYPE_NUMBER);
if (BASE_EQ (display, Qunbound))
display = gui_display_get_arg (dpyinfo, parms, Qdisplay, 0, 0,
RES_TYPE_STRING);
if (BASE_EQ (display, Qunbound))
display = Qnil;
dpyinfo = check_android_display_info (display);
kb = dpyinfo->terminal->kboard;
if (!dpyinfo->terminal->name)
error ("Terminal is not live, can't create new frames on it");
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");
if (STRINGP (name))
Vx_resource_name = name;
/* See if parent window is specified. */
parent = gui_display_get_arg (dpyinfo, parms, Qparent_id, NULL, NULL,
RES_TYPE_NUMBER);
if (BASE_EQ (parent, Qunbound))
parent = Qnil;
if (! NILP (parent))
CHECK_FIXNUM (parent);
frame = Qnil;
tem = gui_display_get_arg (dpyinfo,
parms, Qminibuffer, "minibuffer", "Minibuffer",
RES_TYPE_SYMBOL);
if (EQ (tem, Qnone) || NILP (tem))
f = make_frame_without_minibuffer (Qnil, kb, display);
else if (EQ (tem, Qonly))
{
f = make_minibuffer_frame ();
minibuffer_only = true;
}
else if (WINDOWP (tem))
f = make_frame_without_minibuffer (tem, kb, display);
else
f = make_frame (true);
parent_frame = gui_display_get_arg (dpyinfo,
parms,
Qparent_frame,
NULL,
NULL,
RES_TYPE_SYMBOL);
/* Accept parent-frame iff parent-id was not specified. */
if (!NILP (parent)
|| BASE_EQ (parent_frame, Qunbound)
|| NILP (parent_frame)
|| !FRAMEP (parent_frame)
|| !FRAME_LIVE_P (XFRAME (parent_frame))
|| !FRAME_ANDROID_P (XFRAME (parent_frame)))
parent_frame = Qnil;
fset_parent_frame (f, parent_frame);
store_frame_param (f, Qparent_frame, parent_frame);
if (!NILP (tem = (gui_display_get_arg (dpyinfo,
parms,
Qundecorated,
NULL,
NULL,
RES_TYPE_BOOLEAN)))
&& !(BASE_EQ (tem, Qunbound)))
undecorated = true;
FRAME_UNDECORATED (f) = undecorated;
store_frame_param (f, Qundecorated, undecorated ? Qt : Qnil);
if (!NILP (tem = (gui_display_get_arg (dpyinfo,
parms,
Qoverride_redirect,
NULL,
NULL,
RES_TYPE_BOOLEAN)))
&& !(BASE_EQ (tem, Qunbound)))
override_redirect = true;
FRAME_OVERRIDE_REDIRECT (f) = override_redirect;
store_frame_param (f, Qoverride_redirect, override_redirect ? Qt : Qnil);
XSETFRAME (frame, f);
f->terminal = dpyinfo->terminal;
f->output_method = output_android;
f->output_data.android = xzalloc (sizeof *f->output_data.android);
FRAME_FONTSET (f) = -1;
f->output_data.android->scroll_bar_foreground_pixel = -1;
f->output_data.android->scroll_bar_background_pixel = -1;
f->output_data.android->white_relief.pixel = -1;
f->output_data.android->black_relief.pixel = -1;
fset_icon_name (f, gui_display_get_arg (dpyinfo,
parms,
Qicon_name,
"iconName",
"Title",
RES_TYPE_STRING));
if (! STRINGP (f->icon_name))
fset_icon_name (f, Qnil);
FRAME_DISPLAY_INFO (f) = dpyinfo;
/* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */
record_unwind_protect (do_unwind_create_frame, frame);
/* These colors will be set anyway later, but it's important
to get the color reference counts right, so initialize them!
(Not really on Android, but it's best to be consistent with
X.) */
{
Lisp_Object black;
/* Function x_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;
f->output_data.android->mouse_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));
f->output_data.android->mouse_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))
{
fset_name (f, build_string ("GNU Emacs"));
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);
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);
if (!FRAME_FONT (f))
{
delete_frame (frame, Qnoelisp);
error ("Invalid frame font");
}
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 (0),
"internalBorderWidth", "internalBorderWidth",
RES_TYPE_NUMBER);
/* Same for child frames. */
if (NILP (Fassq (Qchild_frame_border_width, parms)))
{
Lisp_Object value;
value = gui_display_get_arg (dpyinfo, parms, Qchild_frame_border_width,
"childFrameBorder", "childFrameBorder",
RES_TYPE_NUMBER);
if (! BASE_EQ (value, Qunbound))
parms = Fcons (Fcons (Qchild_frame_border_width, value),
parms);
}
gui_default_parameter (f, parms, Qchild_frame_border_width, Qnil,
"childFrameBorderWidth", "childFrameBorderWidth",
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);
/* `vertical-scroll-bars' defaults to nil on Android as a
consequence of scroll bars not being supported at all. */
gui_default_parameter (f, parms, Qvertical_scroll_bars, Qnil,
"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"),
"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, Qborder_color, build_string ("black"),
"borderColor", "BorderColor", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qscreen_gamma, Qnil,
"screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
gui_default_parameter (f, parms, Qline_spacing, Qnil,
"lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qleft_fringe, Qnil,
"leftFringe", "LeftFringe", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qright_fringe, Qnil,
"rightFringe", "RightFringe", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
NULL, NULL, RES_TYPE_BOOLEAN);
#if 0
android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
"scrollBarForeground",
"ScrollBarForeground", true);
android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
"scrollBarBackground",
"ScrollBarBackground", false);
#endif
/* 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);
tem = gui_display_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL,
RES_TYPE_NUMBER);
if (FIXNUMP (tem))
store_frame_param (f, Qmin_width, tem);
tem = gui_display_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL,
RES_TYPE_NUMBER);
if (FIXNUMP (tem))
store_frame_param (f, Qmin_height, tem);
adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, true,
Qx_create_frame_1);
/* Set the menu-bar-lines and tool-bar-lines parameters. We don't
look up the X resources controlling the menu-bar and tool-bar
here; they are processed specially at startup, and reflected in
the values of the mode variables. */
gui_default_parameter (f, parms, Qmenu_bar_lines,
NILP (Vmenu_bar_mode)
? make_fixnum (0) : make_fixnum (1),
NULL, NULL, RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qtab_bar_lines,
NILP (Vtab_bar_mode)
? make_fixnum (0) : make_fixnum (1),
NULL, NULL, RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qtool_bar_lines,
NILP (Vtool_bar_mode)
? make_fixnum (0) : make_fixnum (1),
NULL, NULL, RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qbuffer_predicate, Qnil,
"bufferPredicate", "BufferPredicate",
RES_TYPE_SYMBOL);
gui_default_parameter (f, parms, Qtitle, Qnil,
"title", "Title", RES_TYPE_STRING);
gui_default_parameter (f, parms, Qwait_for_wm, Qt,
"waitForWM", "WaitForWM", RES_TYPE_BOOLEAN);
gui_default_parameter (f, parms, Qtool_bar_position,
FRAME_TOOL_BAR_POSITION (f), 0, 0, RES_TYPE_SYMBOL);
gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
"inhibitDoubleBuffering", "InhibitDoubleBuffering",
RES_TYPE_BOOLEAN);
/* Compute the size of the X window. */
window_prompting = gui_figure_window_size (f, parms, true, true);
tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0,
RES_TYPE_BOOLEAN);
f->no_split = minibuffer_only || EQ (tem, Qt);
android_icon_verify (f, parms);
android_create_frame_window (f);
android_icon (f, parms);
android_make_gc (f);
/* Now consider the frame official. */
f->terminal->reference_count++;
Vframe_list = Fcons (frame, Vframe_list);
/* We need to do this after creating the window, so that the
icon-creation functions can say whose icon they're
describing. */
gui_default_parameter (f, parms, Qicon_type, Qt,
"bitmapIcon", "BitmapIcon", RES_TYPE_BOOLEAN);
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);
/* Scroll bars are not supported on Android, as they are near
useless. */
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);
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);
if (!NILP (parent_frame))
{
struct frame *p = XFRAME (parent_frame);
block_input ();
android_reparent_window (FRAME_ANDROID_WINDOW (f),
FRAME_ANDROID_WINDOW (p),
f->left_pos, f->top_pos);
unblock_input ();
}
gui_default_parameter (f, parms, Qno_focus_on_map, Qnil,
NULL, NULL, RES_TYPE_BOOLEAN);
gui_default_parameter (f, parms, Qno_accept_focus, Qnil,
NULL, NULL, RES_TYPE_BOOLEAN);
/* Consider frame official, now. */
f->can_set_window_size = true;
adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
0, true, Qx_create_frame_2);
/* 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. 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
always explicitly nil. */
Lisp_Object visibility
= gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
RES_TYPE_SYMBOL);
Lisp_Object height
= gui_display_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
Lisp_Object width
= gui_display_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
if (EQ (visibility, Qicon))
{
f->was_invisible = true;
android_iconify_frame (f);
}
else
{
if (BASE_EQ (visibility, Qunbound))
visibility = Qt;
if (!NILP (visibility))
android_make_frame_visible (f);
else
f->was_invisible = true;
}
/* Leave f->was_invisible true only if height or width were
specified too. This takes effect only when we are not called
from `x-create-frame-with-faces' (see above comment). */
f->was_invisible
= (f->was_invisible
&& (!BASE_EQ (height, Qunbound) || !BASE_EQ (width, Qunbound)));
store_frame_param (f, Qvisibility, visibility);
/* Set whether or not frame synchronization is enabled. */
gui_default_parameter (f, parms, Quse_frame_synchronization, Qt,
NULL, NULL, RES_TYPE_BOOLEAN);
/* Works iff frame has been already mapped. */
gui_default_parameter (f, parms, Qskip_taskbar, Qnil,
NULL, NULL, RES_TYPE_BOOLEAN);
/* The `z-group' parameter works only for visible frames. */
gui_default_parameter (f, parms, Qz_group, Qnil,
NULL, NULL, RES_TYPE_SYMBOL);
/* Initialize `default-minibuffer-frame' in case this is the first
frame on this terminal. */
if (FRAME_HAS_MINIBUF_P (f)
&& (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame))
|| !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
kset_default_minibuffer_frame (kb, frame);
/* All remaining specified parameters, which have not been "used" by
gui_display_get_arg and friends, now go in the misc. alist of the
frame. */
for (tem = parms; CONSP (tem); tem = XCDR (tem))
if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
/* Make sure windows on this frame appear in calls to next-window
and similar functions. */
Vwindow_list = Qnil;
return unbind_to (count, frame);
#endif
}
DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p,
1, 2, 0, doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object color, Lisp_Object frame)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
Emacs_Color foo;
struct frame *f;
f = decode_window_system_frame (frame);
CHECK_STRING (color);
if (android_defined_color (f, SSDATA (color), &foo, false, false))
return Qt;
else
return Qnil;
#endif
}
DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2,
0, doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object color, Lisp_Object frame)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
Emacs_Color foo;
struct frame *f;
f = decode_window_system_frame (frame);
CHECK_STRING (color);
if (android_defined_color (f, SSDATA (color), &foo, false, false))
return list3i (foo.red, foo.green, foo.blue);
else
return Qnil;
#endif
}
DEFUN ("xw-display-color-p", Fxw_display_color_p,
Sxw_display_color_p, 0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
struct android_display_info *dpyinfo;
dpyinfo = check_android_display_info (terminal);
return dpyinfo->n_planes > 8 ? Qt : Qnil;
}
DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
Sx_display_grayscale_p, 0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
struct android_display_info *dpyinfo;
dpyinfo = check_android_display_info (terminal);
return (dpyinfo->n_planes > 1 && dpyinfo->n_planes <= 8
? Qt : Qnil);
}
DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
Sx_display_pixel_width, 0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
return make_fixnum (android_get_screen_width ());
#endif
}
DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
Sx_display_pixel_height, 0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
return make_fixnum (android_get_screen_height ());
#endif
}
DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
struct android_display_info *dpyinfo;
dpyinfo = check_android_display_info (terminal);
return make_fixnum (dpyinfo->n_planes);
}
DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
struct android_display_info *dpyinfo;
int nr_planes;
dpyinfo = check_android_display_info (terminal);
nr_planes = dpyinfo->n_planes;
/* Truncate nr_planes to 24 to avoid integer overflow. */
if (nr_planes > 24)
nr_planes = 24;
return make_fixnum (1 << nr_planes);
}
DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
check_android_display_info (terminal);
return Vandroid_build_manufacturer;
#endif
}
DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
check_android_display_info (terminal);
return list3i (android_get_current_api_level (), 0, 0);
#endif
}
DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens,
0, 1, 0, doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
check_android_display_info (terminal);
return make_fixnum (1);
}
DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width,
0, 1, 0, doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
return make_fixnum (android_get_mm_width ());
#endif
}
DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height,
0, 1, 0, doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
return make_fixnum (android_get_mm_height ());
#endif
}
DEFUN ("x-display-backing-store", Fx_display_backing_store,
Sx_display_backing_store, 0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
check_android_display_info (terminal);
/* Window contents are preserved insofar as they remain mapped, in a
fashion tantamount to WhenMapped. */
return Qwhen_mapped;
}
DEFUN ("x-display-visual-class", Fx_display_visual_class,
Sx_display_visual_class, 0, 1, 0,
doc: /* SKIP: real doc in xfns.c. */)
(Lisp_Object terminal)
{
struct android_display_info *dpyinfo;
dpyinfo = check_android_display_info (terminal);
if (dpyinfo->n_planes < 24)
return Qstatic_gray;
return Qtrue_color;
}
#ifndef ANDROID_STUBIFY
static Lisp_Object
android_make_monitor_attribute_list (struct MonitorInfo *monitors,
int n_monitors,
int primary_monitor)
{
Lisp_Object monitor_frames;
Lisp_Object frame, rest;
struct frame *f;
monitor_frames = make_nil_vector (n_monitors);
FOR_EACH_FRAME (rest, frame)
{
f = XFRAME (frame);
/* Associate all frames with the primary monitor. */
if (FRAME_WINDOW_P (f)
&& !FRAME_TOOLTIP_P (f))
ASET (monitor_frames, primary_monitor,
Fcons (frame, AREF (monitor_frames,
primary_monitor)));
}
return make_monitor_attribute_list (monitors, n_monitors,
primary_monitor,
monitor_frames, NULL);
}
#endif
DEFUN ("android-display-monitor-attributes-list",
Fandroid_display_monitor_attributes_list,
Sandroid_display_monitor_attributes_list,
0, 1, 0,
doc: /* Return a list of physical monitor attributes on the X display TERMINAL.
The optional argument TERMINAL specifies which display to ask about.
TERMINAL should be a terminal object, a frame or a display name (a string).
If omitted or nil, that stands for the selected frame's display.
Internal use only, use `display-monitor-attributes-list' instead. */)
(Lisp_Object terminal)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
struct MonitorInfo monitor;
memset (&monitor, 0, sizeof monitor);
monitor.geom.width = android_get_screen_width ();
monitor.geom.height = android_get_screen_height ();
monitor.mm_width = android_get_mm_width ();
monitor.mm_height = android_get_mm_height ();
monitor.work = monitor.geom;
monitor.name = (char *) "Android device monitor";
return android_make_monitor_attribute_list (&monitor, 1, 0);
#endif
}
#ifndef ANDROID_STUBIFY
static Lisp_Object
frame_geometry (Lisp_Object frame, Lisp_Object attribute)
{
struct frame *f = decode_live_frame (frame);
android_window rootw;
unsigned int native_width, native_height, x_border_width = 0;
int x_native = 0, y_native = 0, xptr = 0, yptr = 0;
int left_off = 0, right_off = 0, top_off = 0, bottom_off = 0;
int outer_left, outer_top, outer_right, outer_bottom;
int native_left, native_top, native_right, native_bottom;
int inner_left, inner_top, inner_right, inner_bottom;
int internal_border_width;
bool menu_bar_external = false, tool_bar_external = false;
int menu_bar_height = 0, menu_bar_width = 0;
int tab_bar_height = 0, tab_bar_width = 0;
int tool_bar_height = 0, tool_bar_width = 0;
if (FRAME_INITIAL_P (f) || !FRAME_ANDROID_P (f)
|| !FRAME_ANDROID_WINDOW (f))
return Qnil;
block_input ();
android_get_geometry (FRAME_ANDROID_WINDOW (f),
&rootw, &x_native, &y_native,
&native_width, &native_height, &x_border_width);
unblock_input ();
if (FRAME_PARENT_FRAME (f))
{
Lisp_Object parent, edges;
XSETFRAME (parent, FRAME_PARENT_FRAME (f));
edges = Fandroid_frame_edges (parent, Qnative_edges);
if (!NILP (edges))
{
x_native += XFIXNUM (Fnth (make_fixnum (0), edges));
y_native += XFIXNUM (Fnth (make_fixnum (1), edges));
}
outer_left = x_native;
outer_top = y_native;
outer_right = outer_left + native_width + 2 * x_border_width;
outer_bottom = outer_top + native_height + 2 * x_border_width;
native_left = x_native + x_border_width;
native_top = y_native + x_border_width;
native_right = native_left + native_width;
native_bottom = native_top + native_height;
}
else
{
outer_left = xptr;
outer_top = yptr;
outer_right = outer_left + left_off + native_width + right_off;
outer_bottom = outer_top + top_off + native_height + bottom_off;
native_left = outer_left + left_off;
native_top = outer_top + top_off;
native_right = native_left + native_width;
native_bottom = native_top + native_height;
}
internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
inner_left = native_left + internal_border_width;
inner_top = native_top + internal_border_width;
inner_right = native_right - internal_border_width;
inner_bottom = native_bottom - internal_border_width;
menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
inner_top += menu_bar_height;
menu_bar_width = menu_bar_height ? native_width : 0;
tab_bar_height = FRAME_TAB_BAR_HEIGHT (f);
tab_bar_width = (tab_bar_height
? native_width - 2 * internal_border_width
: 0);
inner_top += tab_bar_height;
tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f);
tool_bar_width = (tool_bar_height
? native_width - 2 * internal_border_width
: 0);
/* Subtract or add to the inner dimensions based on the tool bar
position. */
if (EQ (FRAME_TOOL_BAR_POSITION (f), Qtop))
inner_top += tool_bar_height;
else
inner_bottom -= tool_bar_height;
/* Construct list. */
if (EQ (attribute, Qouter_edges))
return list4i (outer_left, outer_top, outer_right, outer_bottom);
else if (EQ (attribute, Qnative_edges))
return list4i (native_left, native_top, native_right, native_bottom);
else if (EQ (attribute, Qinner_edges))
return list4i (inner_left, inner_top, inner_right, inner_bottom);
else
return
list (Fcons (Qouter_position,
Fcons (make_fixnum (outer_left),
make_fixnum (outer_top))),
Fcons (Qouter_size,
Fcons (make_fixnum (outer_right - outer_left),
make_fixnum (outer_bottom - outer_top))),
/* Approximate. */
Fcons (Qexternal_border_size,
Fcons (make_fixnum (right_off),
make_fixnum (bottom_off))),
Fcons (Qouter_border_width, make_fixnum (x_border_width)),
/* Approximate. */
Fcons (Qtitle_bar_size,
Fcons (make_fixnum (0),
make_fixnum (top_off - bottom_off))),
Fcons (Qmenu_bar_external, menu_bar_external ? Qt : Qnil),
Fcons (Qmenu_bar_size,
Fcons (make_fixnum (menu_bar_width),
make_fixnum (menu_bar_height))),
Fcons (Qtab_bar_size,
Fcons (make_fixnum (tab_bar_width),
make_fixnum (tab_bar_height))),
Fcons (Qtool_bar_external, tool_bar_external ? Qt : Qnil),
Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)),
Fcons (Qtool_bar_size,
Fcons (make_fixnum (tool_bar_width),
make_fixnum (tool_bar_height))),
Fcons (Qinternal_border_width,
make_fixnum (internal_border_width)));
}
#endif
DEFUN ("android-frame-geometry", Fandroid_frame_geometry,
Sandroid_frame_geometry,
0, 1, 0,
doc: /* Return geometric attributes of FRAME.
FRAME must be a live frame and defaults to the selected one. The return
value is an association list of the attributes listed below. All height
and width values are in pixels.
`outer-position' is a cons of the outer left and top edges of FRAME
relative to the origin - the position (0, 0) - of FRAME's display.
`outer-size' is a cons of the outer width and height of FRAME. The
outer size includes the title bar and the external borders as well as
any menu and/or tool bar of frame.
`external-border-size' is a cons of the horizontal and vertical width of
FRAME's external borders as supplied by the window manager.
`title-bar-size' is a cons of the width and height of the title bar of
FRAME as supplied by the window manager. If both of them are zero,
FRAME has no title bar. If only the width is zero, Emacs was not
able to retrieve the width information.
`menu-bar-external', if non-nil, means the menu bar is external (never
included in the inner edges of FRAME).
`menu-bar-size' is a cons of the width and height of the menu bar of
FRAME.
`tool-bar-external', if non-nil, means the tool bar is external (never
included in the inner edges of FRAME).
`tool-bar-position' tells on which side the tool bar on FRAME is and can
be one of `left', `top', `right' or `bottom'. If this is nil, FRAME
has no tool bar.
`tool-bar-size' is a cons of the width and height of the tool bar of
FRAME.
`internal-border-width' is the width of the internal border of
FRAME. */)
(Lisp_Object frame)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
return frame_geometry (frame, Qnil);
#endif
}
DEFUN ("android-frame-edges", Fandroid_frame_edges,
Sandroid_frame_edges, 0, 2, 0,
doc: /* Return edge coordinates of FRAME.
FRAME must be a live frame and defaults to the selected one. The return
value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are
in pixels relative to the origin - the position (0, 0) - of FRAME's
display.
If optional argument TYPE is the symbol `outer-edges', return the outer
edges of FRAME. The outer edges comprise the decorations of the window
manager (like the title bar or external borders) as well as any external
menu or tool bar of FRAME. If optional argument TYPE is the symbol
`native-edges' or nil, return the native edges of FRAME. The native
edges exclude the decorations of the window manager and any external
menu or tool bar of FRAME. If TYPE is the symbol `inner-edges', return
the inner edges of FRAME. These edges exclude title bar, any borders,
menu bar or tool bar of FRAME. */)
(Lisp_Object frame, Lisp_Object type)
{
#ifndef ANDROID_STUBIFY
return frame_geometry (frame, ((EQ (type, Qouter_edges)
|| EQ (type, Qinner_edges))
? type
: Qnative_edges));
#else
return Qnil;
#endif
}
#ifndef ANDROID_STUBIFY
static Lisp_Object
android_frame_list_z_order (struct android_display_info *dpyinfo,
android_window window)
{
android_window root, parent, *children;
unsigned int nchildren;
unsigned long i;
Lisp_Object frames;
frames = Qnil;
if (android_query_tree (window, &root, &parent,
&children, &nchildren))
{
for (i = 0; i < nchildren; i++)
{
Lisp_Object frame, tail;
FOR_EACH_FRAME (tail, frame)
{
struct frame *cf = XFRAME (frame);
if (FRAME_ANDROID_P (cf)
&& (FRAME_ANDROID_WINDOW (cf) == children[i]))
frames = Fcons (frame, frames);
}
}
if (children)
xfree (children);
}
return frames;
}
#endif
DEFUN ("android-frame-list-z-order", Fandroid_frame_list_z_order,
Sandroid_frame_list_z_order, 0, 1, 0,
doc: /* Return list of Emacs' frames, in Z (stacking) order.
The optional argument TERMINAL specifies which display to ask about.
TERMINAL should be either a frame or a display name (a string). If
omitted or nil, that stands for the selected frame's display. Return
nil if TERMINAL contains no Emacs frame.
As a special case, if TERMINAL is non-nil and specifies a live frame,
return the child frames of that frame in Z (stacking) order.
Frames are listed from topmost (first) to bottommost (last).
On Android, the order of the frames returned is undefined unless
TERMINAL is a frame. */)
(Lisp_Object terminal)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
struct android_display_info *dpyinfo;
android_window window;
dpyinfo = check_android_display_info (terminal);
if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal)))
window = FRAME_ANDROID_WINDOW (XFRAME (terminal));
else
window = dpyinfo->root_window;
return android_frame_list_z_order (dpyinfo, window);
#endif
}
#ifndef ANDROID_STUBIFY
static void
android_frame_restack (struct frame *f1, struct frame *f2,
bool above_flag)
{
android_window window1;
struct android_window_changes wc;
unsigned long mask;
window1 = FRAME_ANDROID_WINDOW (f1);
wc.sibling = FRAME_ANDROID_WINDOW (f2);
wc.stack_mode = above_flag ? ANDROID_ABOVE : ANDROID_BELOW;
mask = ANDROID_CW_SIBLING | ANDROID_CW_STACK_MODE;
block_input ();
android_reconfigure_wm_window (window1, mask, &wc);
unblock_input ();
}
#endif /* !ANDROID_STUBIFY */
DEFUN ("android-frame-restack", Fandroid_frame_restack,
Sandroid_frame_restack, 2, 3, 0,
doc: /* Restack FRAME1 below FRAME2.
This means that if both frames are visible and the display areas of
these frames overlap, FRAME2 (partially) obscures FRAME1. If optional
third argument ABOVE is non-nil, restack FRAME1 above FRAME2. This
means that if both frames are visible and the display areas of these
frames overlap, FRAME1 (partially) obscures FRAME2.
This may be thought of as an atomic action performed in two steps: The
first step removes FRAME1's window-step window from the display. The
second step reinserts FRAME1's window below (above if ABOVE is true)
that of FRAME2. Hence the position of FRAME2 in its display's Z
\(stacking) order relative to all other frames excluding FRAME1 remains
unaltered.
Android does not facilitate restacking top-level windows managed by
its own window manager; nor is it possible to restack frames that are
children of different parents. Consequently, this function only
functions when FRAME1 and FRAME2 are both child frames subordinate to
the same parent frame. */)
(Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else /* !ANDROID_STUBIFY */
struct frame *f1 = decode_live_frame (frame1);
struct frame *f2 = decode_live_frame (frame2);
if (!(FRAME_ANDROID_WINDOW (f1) && FRAME_ANDROID_WINDOW (f2)))
error ("Cannot restack frames");
android_frame_restack (f1, f2, !NILP (above));
return Qt;
#endif /* ANDROID_STUBIFY */
}
DEFUN ("android-mouse-absolute-pixel-position",
Fandroid_mouse_absolute_pixel_position,
Sandroid_mouse_absolute_pixel_position, 0, 0, 0,
doc: /* Return absolute position of mouse cursor in pixels.
The position is returned as a cons cell (X . Y) of the coordinates of
the mouse cursor position in pixels relative to a position (0, 0) of the
selected frame's display. This does not work on Android. */)
(void)
{
/* This cannot be implemented on Android. */
return Qnil;
}
DEFUN ("android-set-mouse-absolute-pixel-position",
Fandroid_set_mouse_absolute_pixel_position,
Sandroid_set_mouse_absolute_pixel_position, 2, 2, 0,
doc: /* Move mouse pointer to a pixel position at (X, Y). The
coordinates X and Y are interpreted to start from the top-left corner
of the screen. This does not work on Android. */)
(Lisp_Object x, Lisp_Object y)
{
/* This cannot be implemented on Android. */
return Qnil;
}
DEFUN ("android-get-connection", Fandroid_get_connection,
Sandroid_get_connection, 0, 0, 0,
doc: /* Get the connection to the display server.
Return the terminal if it exists, else nil.
Emacs cannot open a connection to the display server itself under
Android, so there is no equivalent of `x-open-connection'. */)
(void)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
Lisp_Object terminal;
terminal = Qnil;
if (x_display_list)
{
XSETTERMINAL (terminal, x_display_list->terminal);
/* Update the display's bit depth from
`android_display_planes'. */
x_display_list->n_planes
= (android_display_planes > 8
? 24 : (android_display_planes > 1
? android_display_planes : 1));
}
return terminal;
#endif
}
DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
doc: /* SKIP: real doc in xfns.c. */)
(void)
{
Lisp_Object result;
result = Qnil;
if (x_display_list)
result = Fcons (XCAR (x_display_list->name_list_element),
result);
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;
f->output_data.android->mouse_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));
f->output_data.android->mouse_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;
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 | ANDROID_CW_BACK_PIXEL;
attrs.override_redirect = true;
attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
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,
Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
{
#ifdef ANDROID_STUBIFY
error ("Android cross-compilation stub called!");
return Qnil;
#else
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 if (tooltip_reuse_hidden_frame && BASE_EQ (frame, tip_last_frame))
{
bool delete = false;
Lisp_Object tail, elt, parm, last;
/* Check if every parameter in PARMS has the same value in
tip_last_parms. This may destruct tip_last_parms which,
however, will be recreated below. */
for (tail = parms; CONSP (tail); tail = XCDR (tail))
{
elt = XCAR (tail);
parm = CAR (elt);
/* The left, top, right and bottom parameters are handled
by compute_tip_xy so they can be ignored here. */
if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
&& !EQ (parm, Qright) && !EQ (parm, Qbottom))
{
last = Fassq (parm, tip_last_parms);
if (NILP (Fequal (CDR (elt), CDR (last))))
{
/* We lost, delete the old tooltip. */
delete = true;
break;
}
else
tip_last_parms
= call2 (Qassq_delete_all, parm, tip_last_parms);
}
else
tip_last_parms
= call2 (Qassq_delete_all, parm, tip_last_parms);
}
/* Now check if every parameter in what is left of
tip_last_parms with a non-nil value has an association in
PARMS. */
for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail))
{
elt = XCAR (tail);
parm = CAR (elt);
if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
&& !EQ (parm, Qbottom) && !NILP (CDR (elt)))
{
/* We lost, delete the old tooltip. */
delete = true;
break;
}
}
android_hide_tip (delete);
}
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 ();
/* Garbage the tip frame too. */
SET_FRAME_GARBAGED (tip_f);
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;
/* MapNotify events are not sent on Android, so make the frame
visible. */
SET_FRAME_VISIBLE (tip_f, true);
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
}
DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
doc: /* SKIP: real doc in xfns.c. */)
(void)
{
#ifdef ANDROID_STUBIFY
/* Fx_hide_tip is called from pre-command-hook (in turn called from
the tests.) Since signaling here prevents any tests from being
run, refrain from protesting if this stub is called. */
#if 0
error ("Android cross-compilation stub called!");
#endif /* 0 */
return Qnil;
#else /* !ANDROID_STUBIFY */
return android_hide_tip (!tooltip_reuse_hidden_frame);
#endif /* ANDROID_STUBIFY */
}
DEFUN ("android-detect-mouse", Fandroid_detect_mouse,
Sandroid_detect_mouse, 0, 0, 0,
doc: /* Figure out whether or not there is a mouse.
Return non-nil if a mouse is connected to this computer, and nil if
there is no mouse. */)
(void)
{
#ifndef ANDROID_STUBIFY
/* If no display connection is present, just return nil. */
if (!android_init_gui)
return Qnil;
return android_detect_mouse () ? Qt : Qnil;
#else
return Qnil;
#endif
}
DEFUN ("android-detect-keyboard", Fandroid_detect_keyboard,
Sandroid_detect_keyboard, 0, 0, 0,
doc: /* Return whether a keyboard is connected.
Return non-nil if a key is connected to this computer, or nil
if there is no keyboard. */)
(void)
{
#ifndef ANDROID_STUBIFY
/* If no display connection is present, just return nil. */
if (!android_init_gui)
return Qnil;
return android_detect_keyboard () ? Qt : Qnil;
#else /* ANDROID_STUBIFY */
return Qt;
#endif /* ANDROID_STUBIFY */
}
DEFUN ("android-toggle-on-screen-keyboard",
Fandroid_toggle_on_screen_keyboard,
Sandroid_toggle_on_screen_keyboard, 2, 2, 0,
doc: /* Display or hide the on-screen keyboard.
If HIDE is non-nil, hide the on screen keyboard if it is currently
being displayed. Else, request that the system display it on behalf
of FRAME. This request may be rejected if FRAME does not have the
input focus. */)
(Lisp_Object frame, Lisp_Object hide)
{
#ifndef ANDROID_STUBIFY
struct frame *f;
f = decode_window_system_frame (frame);
block_input ();
android_toggle_on_screen_keyboard (FRAME_ANDROID_WINDOW (f),
NILP (hide));
unblock_input ();
#endif
return Qnil;
}
#ifndef ANDROID_STUBIFY
static void
android_set_background_color (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
struct android_output *x;
unsigned long bg;
x = f->output_data.android;
bg = android_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
FRAME_BACKGROUND_PIXEL (f) = bg;
if (FRAME_ANDROID_WINDOW (f) != 0)
{
block_input ();
android_set_background (x->normal_gc, bg);
android_set_foreground (x->reverse_gc, bg);
android_set_window_background (FRAME_ANDROID_WINDOW (f), bg);
android_set_foreground (x->cursor_gc, bg);
unblock_input ();
update_face_from_frame_parameter (f, Qbackground_color, arg);
if (FRAME_VISIBLE_P (f))
redraw_frame (f);
}
}
static void
android_set_border_color (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
/* Left unimplemented because Android has no window borders. */
CHECK_STRING (arg);
android_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
update_face_from_frame_parameter (f, Qborder_color, arg);
}
static void
android_set_cursor_color (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
unsigned long fore_pixel, pixel;
struct android_output *x;
x = f->output_data.android;
if (!NILP (Vx_cursor_fore_pixel))
fore_pixel = android_decode_color (f, Vx_cursor_fore_pixel,
WHITE_PIX_DEFAULT (f));
else
fore_pixel = FRAME_BACKGROUND_PIXEL (f);
pixel = android_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
/* Make sure that the cursor color differs from the background color. */
if (pixel == FRAME_BACKGROUND_PIXEL (f))
{
pixel = FRAME_FOREGROUND_PIXEL (f);
if (pixel == fore_pixel)
fore_pixel = FRAME_BACKGROUND_PIXEL (f);
}
x->cursor_foreground_pixel = fore_pixel;
x->cursor_pixel = pixel;
if (FRAME_ANDROID_WINDOW (f) != 0)
{
block_input ();
android_set_background (x->cursor_gc, x->cursor_pixel);
android_set_foreground (x->cursor_gc, fore_pixel);
unblock_input ();
if (FRAME_VISIBLE_P (f))
{
gui_update_cursor (f, false);
gui_update_cursor (f, true);
}
}
update_face_from_frame_parameter (f, Qcursor_color, arg);
}
static void
android_set_cursor_type (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
set_frame_cursor_types (f, arg);
}
static void
android_set_foreground_color (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
struct android_output *x;
unsigned long fg, old_fg;
x = f->output_data.android;
fg = android_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
old_fg = FRAME_FOREGROUND_PIXEL (f);
FRAME_FOREGROUND_PIXEL (f) = fg;
if (FRAME_ANDROID_WINDOW (f) != 0)
{
block_input ();
android_set_foreground (x->normal_gc, fg);
android_set_background (x->reverse_gc, fg);
if (x->cursor_pixel == old_fg)
{
x->cursor_pixel = fg;
android_set_background (x->cursor_gc, x->cursor_pixel);
}
unblock_input ();
update_face_from_frame_parameter (f, Qforeground_color, arg);
if (FRAME_VISIBLE_P (f))
redraw_frame (f);
}
}
static void
android_set_child_frame_border_width (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
int border;
if (NILP (arg))
border = -1;
else if (RANGED_FIXNUMP (0, arg, INT_MAX))
border = XFIXNAT (arg);
else
signal_error ("Invalid child frame border width", arg);
if (border != FRAME_CHILD_FRAME_BORDER_WIDTH (f))
{
f->child_frame_border_width = border;
if (FRAME_ANDROID_WINDOW (f))
{
adjust_frame_size (f, -1, -1, 3, false, Qchild_frame_border_width);
android_clear_under_internal_border (f);
}
}
}
static void
android_set_internal_border_width (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
int border = check_int_nonnegative (arg);
if (border != FRAME_INTERNAL_BORDER_WIDTH (f))
{
f->internal_border_width = border;
if (FRAME_ANDROID_WINDOW (f))
{
adjust_frame_size (f, -1, -1, 3, false, Qinternal_border_width);
android_clear_under_internal_border (f);
}
}
}
static void
android_set_menu_bar_lines (struct frame *f, Lisp_Object value,
Lisp_Object oldval)
{
int nlines;
int olines = FRAME_MENU_BAR_LINES (f);
/* Right now, menu bars don't work properly in minibuf-only frames;
most of the commands try to apply themselves to the minibuffer
frame itself, and get an error because you can't switch buffers
in or split the minibuffer window. */
if (FRAME_MINIBUF_ONLY_P (f) || FRAME_PARENT_FRAME (f))
return;
if (TYPE_RANGED_FIXNUMP (int, value))
nlines = XFIXNUM (value);
else
nlines = 0;
/* Make sure we redisplay all windows in this frame. */
fset_redisplay (f);
FRAME_MENU_BAR_LINES (f) = nlines;
FRAME_MENU_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f);
if (FRAME_ANDROID_WINDOW (f))
android_clear_under_internal_border (f);
/* If the menu bar height gets changed, the internal border below
the top margin has to be cleared. Also, if the menu bar gets
larger, the area for the added lines has to be cleared except for
the first menu bar line that is to be drawn later. */
if (nlines != olines)
{
int height = FRAME_INTERNAL_BORDER_WIDTH (f);
int width = FRAME_PIXEL_WIDTH (f);
int y;
adjust_frame_size (f, -1, -1, 3, true, Qmenu_bar_lines);
/* height can be zero here. */
if (FRAME_ANDROID_WINDOW (f) && height > 0 && width > 0)
{
y = FRAME_TOP_MARGIN_HEIGHT (f);
block_input ();
android_clear_area (FRAME_ANDROID_DRAWABLE (f),
0, y, width, height);
unblock_input ();
}
if (nlines > 1 && nlines > olines)
{
y = (olines == 0 ? 1 : olines) * FRAME_LINE_HEIGHT (f);
height = nlines * FRAME_LINE_HEIGHT (f) - y;
block_input ();
android_clear_area (FRAME_ANDROID_DRAWABLE (f), 0, y,
width, height);
unblock_input ();
}
if (nlines == 0 && WINDOWP (f->menu_bar_window))
clear_glyph_matrix (XWINDOW (f->menu_bar_window)->current_matrix);
}
adjust_frame_glyphs (f);
}
/* These enums must stay in sync with the mouse_cursor_types array
below! */
enum mouse_cursor
{
mouse_cursor_text,
mouse_cursor_nontext,
mouse_cursor_hourglass,
mouse_cursor_mode,
mouse_cursor_hand,
mouse_cursor_horizontal_drag,
mouse_cursor_vertical_drag,
mouse_cursor_left_edge,
mouse_cursor_top_left_corner,
mouse_cursor_top_edge,
mouse_cursor_top_right_corner,
mouse_cursor_right_edge,
mouse_cursor_bottom_right_corner,
mouse_cursor_bottom_edge,
mouse_cursor_bottom_left_corner,
mouse_cursor_max
};
struct mouse_cursor_types
{
/* Printable name for error messages (optional). */
const char *name;
/* Lisp variable controlling the cursor shape. */
/* FIXME: A couple of these variables are defined in the C code but
are not actually accessible from Lisp. They should probably be
made accessible or removed. */
Lisp_Object *shape_var_ptr;
/* The default shape. */
int default_shape;
};
/* This array must stay in sync with enum mouse_cursor above! */
static const struct mouse_cursor_types mouse_cursor_types[] =
{
{"text", &Vx_pointer_shape, ANDROID_XC_XTERM, },
{"nontext", &Vx_nontext_pointer_shape, ANDROID_XC_LEFT_PTR, },
{"hourglass", &Vx_hourglass_pointer_shape, ANDROID_XC_WATCH, },
{"modeline", &Vx_mode_pointer_shape, ANDROID_XC_XTERM, },
{NULL, &Vx_sensitive_text_pointer_shape, ANDROID_XC_HAND2, },
{NULL, &Vx_window_horizontal_drag_shape, ANDROID_XC_SB_H_DOUBLE_ARROW, },
{NULL, &Vx_window_vertical_drag_shape, ANDROID_XC_SB_V_DOUBLE_ARROW, },
{NULL, &Vx_window_left_edge_shape, ANDROID_XC_LEFT_SIDE, },
{NULL, &Vx_window_top_left_corner_shape, ANDROID_XC_TOP_LEFT_CORNER, },
{NULL, &Vx_window_top_edge_shape, ANDROID_XC_TOP_SIDE, },
{NULL, &Vx_window_top_right_corner_shape, ANDROID_XC_TOP_RIGHT_CORNER, },
{NULL, &Vx_window_right_edge_shape, ANDROID_XC_RIGHT_SIDE, },
{NULL, &Vx_window_bottom_right_corner_shape,
ANDROID_XC_BOTTOM_RIGHT_CORNER, },
{NULL, &Vx_window_bottom_edge_shape, ANDROID_XC_BOTTOM_SIDE, },
{NULL, &Vx_window_bottom_left_corner_shape,
ANDROID_XC_BOTTOM_LEFT_CORNER, },
};
struct mouse_cursor_data
{
/* Cursor numbers chosen. */
unsigned int cursor_num[mouse_cursor_max];
/* Allocated Cursor values, or zero for failed attempts. */
android_cursor cursor[mouse_cursor_max];
};
static void
android_set_mouse_color (struct frame *f, Lisp_Object arg,
Lisp_Object oldval)
{
struct android_output *x = f->output_data.android;
struct mouse_cursor_data cursor_data = { -1, -1 };
unsigned long pixel = android_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
unsigned long mask_color = FRAME_BACKGROUND_PIXEL (f);
int i;
/* Don't let pointers be invisible. */
if (mask_color == pixel)
pixel = FRAME_FOREGROUND_PIXEL (f);
x->mouse_pixel = pixel;
for (i = 0; i < mouse_cursor_max; i++)
{
Lisp_Object shape_var = *mouse_cursor_types[i].shape_var_ptr;
cursor_data.cursor_num[i]
= (!NILP (shape_var)
? check_uinteger_max (shape_var, UINT_MAX)
: mouse_cursor_types[i].default_shape);
}
block_input ();
for (i = 0; i < mouse_cursor_max; i++)
cursor_data.cursor[i]
= android_create_font_cursor (cursor_data.cursor_num[i]);
if (FRAME_ANDROID_WINDOW (f))
{
f->output_data.android->current_cursor
= cursor_data.cursor[mouse_cursor_text];
android_define_cursor (FRAME_ANDROID_WINDOW (f),
f->output_data.android->current_cursor);
}
#define INSTALL_CURSOR(FIELD, SHORT_INDEX) \
eassert (x->FIELD \
!= cursor_data.cursor[mouse_cursor_ ## SHORT_INDEX]); \
if (x->FIELD != 0) \
android_free_cursor (x->FIELD); \
x->FIELD = cursor_data.cursor[mouse_cursor_ ## SHORT_INDEX];
INSTALL_CURSOR (text_cursor, text);
INSTALL_CURSOR (nontext_cursor, nontext);
INSTALL_CURSOR (hourglass_cursor, hourglass);
INSTALL_CURSOR (modeline_cursor, mode);
INSTALL_CURSOR (hand_cursor, hand);
INSTALL_CURSOR (horizontal_drag_cursor, horizontal_drag);
INSTALL_CURSOR (vertical_drag_cursor, vertical_drag);
INSTALL_CURSOR (left_edge_cursor, left_edge);
INSTALL_CURSOR (top_left_corner_cursor, top_left_corner);
INSTALL_CURSOR (top_edge_cursor, top_edge);
INSTALL_CURSOR (top_right_corner_cursor, top_right_corner);
INSTALL_CURSOR (right_edge_cursor, right_edge);
INSTALL_CURSOR (bottom_right_corner_cursor, bottom_right_corner);
INSTALL_CURSOR (bottom_edge_cursor, bottom_edge);
INSTALL_CURSOR (bottom_left_corner_cursor, bottom_left_corner);
#undef INSTALL_CURSOR
unblock_input ();
update_face_from_frame_parameter (f, Qmouse_color, arg);
}
static void
android_set_title (struct frame *f, Lisp_Object name,
Lisp_Object old_name)
{
/* Don't change the title if it's already NAME. */
if (EQ (name, f->title))
return;
update_mode_lines = 38;
fset_title (f, name);
if (NILP (name))
name = f->name;
else
CHECK_STRING (name);
android_set_name_internal (f, name);
}
static void
android_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
double alpha = 1.0;
double newval[2];
int i;
Lisp_Object item;
/* N.B. that setting the window alpha is actually unsupported under
Android. */
for (i = 0; i < 2; i++)
{
newval[i] = 1.0;
if (CONSP (arg))
{
item = CAR (arg);
arg = CDR (arg);
}
else
item = arg;
if (NILP (item))
alpha = - 1.0;
else if (FLOATP (item))
{
alpha = XFLOAT_DATA (item);
if (! (0 <= alpha && alpha <= 1.0))
args_out_of_range (make_float (0.0), make_float (1.0));
}
else if (FIXNUMP (item))
{
EMACS_INT ialpha = XFIXNUM (item);
if (! (0 <= ialpha && ialpha <= 100))
args_out_of_range (make_fixnum (0), make_fixnum (100));
alpha = ialpha / 100.0;
}
else
wrong_type_argument (Qnumberp, item);
newval[i] = alpha;
}
for (i = 0; i < 2; i++)
f->alpha[i] = newval[i];
if (FRAME_TERMINAL (f)->set_frame_alpha_hook)
{
block_input ();
FRAME_TERMINAL (f)->set_frame_alpha_hook (f);
unblock_input ();
}
}
static void
android_set_no_focus_on_map (struct frame *f, Lisp_Object new_value,
Lisp_Object old_value)
{
if (!EQ (new_value, old_value))
{
android_set_dont_focus_on_map (FRAME_ANDROID_WINDOW (f),
!NILP (new_value));
FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
}
}
static void
android_set_no_accept_focus (struct frame *f, Lisp_Object new_value,
Lisp_Object old_value)
{
if (!EQ (new_value, old_value))
{
android_set_dont_accept_focus (FRAME_ANDROID_WINDOW (f),
!NILP (new_value));
FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
}
}
frame_parm_handler android_frame_parm_handlers[] =
{
gui_set_autoraise,
gui_set_autolower,
android_set_background_color,
android_set_border_color,
gui_set_border_width,
android_set_cursor_color,
android_set_cursor_type,
gui_set_font,
android_set_foreground_color,
NULL,
NULL,
android_set_child_frame_border_width,
android_set_internal_border_width,
gui_set_right_divider_width,
gui_set_bottom_divider_width,
android_set_menu_bar_lines,
android_set_mouse_color,
android_explicitly_set_name,
gui_set_scroll_bar_width,
gui_set_scroll_bar_height,
android_set_title,
gui_set_unsplittable,
gui_set_vertical_scroll_bars,
gui_set_horizontal_scroll_bars,
gui_set_visibility,
android_set_tab_bar_lines,
android_set_tool_bar_lines,
NULL,
NULL,
gui_set_screen_gamma,
gui_set_line_spacing,
gui_set_left_fringe,
gui_set_right_fringe,
NULL,
gui_set_fullscreen,
gui_set_font_backend,
android_set_alpha,
NULL,
android_set_tool_bar_position,
NULL,
NULL,
android_set_parent_frame,
NULL,
android_set_no_focus_on_map,
android_set_no_accept_focus,
NULL,
NULL,
gui_set_no_special_glyphs,
NULL,
NULL,
};
/* Battery information support. */
DEFUN ("android-query-battery", Fandroid_query_battery,
Sandroid_query_battery, 0, 0, 0,
doc: /* Perform a query for battery information.
Value is nil upon failure, or a list of the form:
(CAPACITY CHARGE-COUNTER CURRENT-AVERAGE CURRENT-NOW STATUS
REMAINING PLUGGED TEMP)
where REMAINING, CURRENT-AVERAGE, and CURRENT-NOW are undefined prior
to Android 5.0.
See the documentation at
https://developer.android.com/reference/android/os/BatteryManager
for more details about these values. */)
(void)
{
struct android_battery_state state;
/* Make sure the Android libraries have been initialized. */
if (!android_init_gui)
return Qnil;
/* Perform the query. */
if (android_query_battery (&state))
return Qnil;
return listn (8, make_int (state.capacity),
make_fixnum (state.charge_counter),
make_int (state.current_average),
make_int (state.current_now),
make_fixnum (state.status),
make_int (state.remaining),
make_fixnum (state.plugged),
make_fixnum (state.temperature));
}
/* SAF directory access management. */
DEFUN ("android-request-directory-access", Fandroid_request_directory_access,
Sandroid_request_directory_access, 0, 0, "",
doc: /* Request access to a directory within external storage.
On Android 5.0 and later, prompt for a directory within external or
application storage, and grant access to it; some of these directories
cannot be accessed through the regular `/sdcard' filesystem.
If access to the directory is granted, it will eventually appear
within the directory `/content/storage'. */)
(void)
{
if (android_get_current_api_level () < 21)
error ("Emacs can only access application storage on"
" Android 5.0 and later");
if (!android_init_gui)
return Qnil;
android_request_directory_access ();
return Qnil;
}
/* Functions concerning storage permissions. */
DEFUN ("android-external-storage-available-p",
Fandroid_external_storage_available_p,
Sandroid_external_storage_available_p, 0, 0, 0,
doc: /* Return non-nil if Emacs is entitled to access external storage.
Return nil if the requisite permissions for external storage access
have not been granted to Emacs, t otherwise. Such permissions can be
requested by means of the `android-request-storage-access'
command.
External storage on Android encompasses the `/sdcard' and
`/storage/emulated' directories, access to which is denied to programs
absent these permissions. */)
(void)
{
return android_external_storage_available_p () ? Qt : Qnil;
}
DEFUN ("android-request-storage-access", Fandroid_request_storage_access,
Sandroid_request_storage_access, 0, 0, "",
doc: /* Request permissions to access external storage.
Return nil regardless of whether access permissions are granted or not,
immediately after displaying the permissions request dialog.
Use `android-external-storage-available-p' (which see) to verify
whether Emacs has actually received such access permissions. */)
(void)
{
android_request_storage_access ();
return Qnil;
}
/* Miscellaneous input method related stuff. */
/* Report X, Y, by the phys cursor width and height as the cursor
anchor rectangle for W's frame. */
void
android_set_preeditarea (struct window *w, int x, int y)
{
struct frame *f;
f = WINDOW_XFRAME (w);
/* Convert the window coordinates to the frame's coordinate
space. */
x = (WINDOW_TO_FRAME_PIXEL_X (w, x)
+ WINDOW_LEFT_FRINGE_WIDTH (w)
+ WINDOW_LEFT_MARGIN_WIDTH (w));
y = WINDOW_TO_FRAME_PIXEL_Y (w, y);
/* Note that calculating the baseline is too hard, so the bottom of
the cursor is used instead. */
android_update_cursor_anchor_info (FRAME_ANDROID_WINDOW (f), x,
y, y + w->phys_cursor_height,
y + w->phys_cursor_height);
}
/* Debugging. */
DEFUN ("android-recreate-activity", Fandroid_recreate_activity,
Sandroid_recreate_activity, 0, 0, "",
doc: /* Recreate the activity attached to the current frame.
This function exists for debugging purposes and is of no interest to
users. */)
(void)
{
struct frame *f;
f = decode_window_system_frame (Qnil);
android_recreate_activity (FRAME_ANDROID_WINDOW (f));
return Qnil;
}
#endif /* !ANDROID_STUBIFY */
#ifndef ANDROID_STUBIFY
static void
syms_of_androidfns_for_pdumper (void)
{
jclass locale;
jmethodID method;
jobject object;
jstring string;
Lisp_Object language, country, script, variant;
const char *data;
FILE *fd;
char *line;
size_t size;
long pid;
/* Find the Locale class. */
locale = (*android_java_env)->FindClass (android_java_env,
"java/util/Locale");
if (!locale)
emacs_abort ();
/* And the method from which the default locale can be
extracted. */
method = (*android_java_env)->GetStaticMethodID (android_java_env,
locale,
"getDefault",
"()Ljava/util/Locale;");
if (!method)
emacs_abort ();
/* Retrieve the default locale. */
object = (*android_java_env)->CallStaticObjectMethod (android_java_env,
locale, method);
android_exception_check_1 (locale);
if (!object)
emacs_abort ();
/* Retrieve its language field. Each of these methods is liable to
return the empty string, though if language is empty, the locale
is malformed. */
method = (*android_java_env)->GetMethodID (android_java_env, locale,
"getLanguage",
"()Ljava/lang/String;");
if (!method)
emacs_abort ();
string = (*android_java_env)->CallObjectMethod (android_java_env, object,
method);
android_exception_check_2 (object, locale);
if (!string)
language = empty_unibyte_string;
else
{
data = (*android_java_env)->GetStringUTFChars (android_java_env,
string, NULL);
android_exception_check_3 (object, locale, string);
if (!data)
language = empty_unibyte_string;
else
{
language = build_unibyte_string (data);
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
string, data);
}
}
/* Delete the reference to this string. */
ANDROID_DELETE_LOCAL_REF (string);
/* Proceed to retrieve the country code. */
method = (*android_java_env)->GetMethodID (android_java_env, locale,
"getCountry",
"()Ljava/lang/String;");
if (!method)
emacs_abort ();
string = (*android_java_env)->CallObjectMethod (android_java_env, object,
method);
android_exception_check_2 (object, locale);
if (!string)
country = empty_unibyte_string;
else
{
data = (*android_java_env)->GetStringUTFChars (android_java_env,
string, NULL);
android_exception_check_3 (object, locale, string);
if (!data)
country = empty_unibyte_string;
else
{
country = build_unibyte_string (data);
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
string, data);
}
}
ANDROID_DELETE_LOCAL_REF (string);
/* Proceed to retrieve the script. */
if (android_get_current_api_level () < 21)
script = empty_unibyte_string;
else
{
method = (*android_java_env)->GetMethodID (android_java_env, locale,
"getScript",
"()Ljava/lang/String;");
if (!method)
emacs_abort ();
string = (*android_java_env)->CallObjectMethod (android_java_env,
object, method);
android_exception_check_2 (object, locale);
if (!string)
script = empty_unibyte_string;
else
{
data = (*android_java_env)->GetStringUTFChars (android_java_env,
string, NULL);
android_exception_check_3 (object, locale, string);
if (!data)
script = empty_unibyte_string;
else
{
script = build_unibyte_string (data);
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
string, data);
}
}
ANDROID_DELETE_LOCAL_REF (string);
}
/* And variant. */
method = (*android_java_env)->GetMethodID (android_java_env, locale,
"getVariant",
"()Ljava/lang/String;");
if (!method)
emacs_abort ();
string = (*android_java_env)->CallObjectMethod (android_java_env, object,
method);
android_exception_check_2 (object, locale);
if (!string)
variant = empty_unibyte_string;
else
{
data = (*android_java_env)->GetStringUTFChars (android_java_env,
string, NULL);
android_exception_check_3 (object, locale, string);
if (!data)
variant = empty_unibyte_string;
else
{
variant = build_unibyte_string (data);
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
string, data);
}
}
/* Delete the reference to this string. */
ANDROID_DELETE_LOCAL_REF (string);
/* And other remaining local references. */
ANDROID_DELETE_LOCAL_REF (object);
ANDROID_DELETE_LOCAL_REF (locale);
/* Set Vandroid_os_language. */
Vandroid_os_language = list4 (language, country, script, variant);
/* Detect whether Emacs is running under libloader.so or another
process tracing mechanism, and disable `android_use_exec_loader' if
so, leaving subprocesses started by Emacs to the care of that
loader instance. */
if (android_get_current_api_level () >= 29) /* Q */
{
fd = fopen ("/proc/self/status", "r");
if (!fd)
return;
line = NULL;
while (getline (&line, &size, fd) != -1)
{
if (strncmp (line, "TracerPid:", sizeof "TracerPid:" - 1))
continue;
pid = atol (line + sizeof "TracerPid:" - 1);
if (pid)
android_use_exec_loader = false;
break;
}
free (line);
fclose (fd);
}
}
#endif /* ANDROID_STUBIFY */
void
syms_of_androidfns (void)
{
/* Miscellaneous symbols used by some functions here. */
DEFSYM (Qtrue_color, "true-color");
DEFSYM (Qstatic_gray, "static-color");
DEFSYM (Qwhen_mapped, "when-mapped");
DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_pointer_shape = Qnil;
#if false /* This doesn't really do anything. */
DEFVAR_LISP ("x-nontext-pointer-shape", Vx_nontext_pointer_shape,
doc: /* SKIP: real doc in xfns.c. */);
#endif
Vx_nontext_pointer_shape = Qnil;
DEFVAR_LISP ("x-hourglass-pointer-shape", Vx_hourglass_pointer_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_hourglass_pointer_shape = Qnil;
DEFVAR_LISP ("x-sensitive-text-pointer-shape",
Vx_sensitive_text_pointer_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_sensitive_text_pointer_shape = Qnil;
DEFVAR_LISP ("x-window-horizontal-drag-cursor",
Vx_window_horizontal_drag_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_horizontal_drag_shape = Qnil;
DEFVAR_LISP ("x-window-vertical-drag-cursor",
Vx_window_vertical_drag_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_vertical_drag_shape = Qnil;
DEFVAR_LISP ("x-window-left-edge-cursor",
Vx_window_left_edge_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_left_edge_shape = Qnil;
DEFVAR_LISP ("x-window-top-left-corner-cursor",
Vx_window_top_left_corner_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_top_left_corner_shape = Qnil;
DEFVAR_LISP ("x-window-top-edge-cursor",
Vx_window_top_edge_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_top_edge_shape = Qnil;
DEFVAR_LISP ("x-window-top-right-corner-cursor",
Vx_window_top_right_corner_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_top_right_corner_shape = Qnil;
DEFVAR_LISP ("x-window-right-edge-cursor",
Vx_window_right_edge_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_right_edge_shape = Qnil;
DEFVAR_LISP ("x-window-bottom-right-corner-cursor",
Vx_window_bottom_right_corner_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_bottom_right_corner_shape = Qnil;
DEFVAR_LISP ("x-window-bottom-edge-cursor",
Vx_window_bottom_edge_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_bottom_edge_shape = Qnil;
#if false /* This doesn't really do anything. */
DEFVAR_LISP ("x-mode-pointer-shape", Vx_mode_pointer_shape,
doc: /* SKIP: real doc in xfns.c. */);
#endif
Vx_mode_pointer_shape = Qnil;
DEFVAR_LISP ("x-window-bottom-left-corner-cursor",
Vx_window_bottom_left_corner_shape,
doc: /* SKIP: real text in xfns.c. */);
Vx_window_bottom_left_corner_shape = Qnil;
DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel,
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;
DEFVAR_BOOL ("android-pass-multimedia-buttons-to-system",
android_pass_multimedia_buttons_to_system,
doc: /* Whether or not to pass volume control buttons to the system.
Generally, the `volume-up', `volume-down' and `volume-mute' keys are
processed by Emacs, but setting this to non-nil they are passed to the
operating system instead of being intercepted by Emacs.
Note that if you set this, you will no longer be able to quit Emacs
using the volume down button. */);
android_pass_multimedia_buttons_to_system = false;
DEFVAR_BOOL ("android-intercept-control-space",
android_intercept_control_space,
doc: /* Whether Emacs should intercept C-SPC.
When this variable is set, Emacs intercepts C-SPC events as they are
delivered to a frame before they are registered and filtered by the
input method.
For no apparent purpose, Android input methods customarily discard SPC
events with the Ctrl modifier set without delivering them to Emacs
afterwards, which is an impediment to typing key sequences
incorporating such keys. */);
android_intercept_control_space = true;
DEFVAR_BOOL ("android-use-exec-loader", android_use_exec_loader,
doc: /* Whether or not to bypass system restrictions on program execution.
Android 10 and later prevent programs from executing files installed
in writable directories, such as the application data directory.
When non-nil, Emacs will bypass this restriction by running such
executables under system call tracing, and replacing the `execve'
system call with a version which ignores the system's security
restrictions.
This option has no effect on Android 9 and earlier. */);
android_use_exec_loader = true;
DEFVAR_INT ("android-keyboard-bell-duration",
android_keyboard_bell_duration,
doc: /* Number of milliseconds to vibrate after ringing the keyboard bell.
The keyboard bell under Android systems takes the form of a vibrating
element that is activated for a given number of milliseconds upon the
bell being rung. */);
android_keyboard_bell_duration = 50;
DEFVAR_LISP ("android-os-language", Vandroid_os_language,
doc: /* A list representing the configured system language on Android.
This list has four elements: LANGUAGE, COUNTRY, SCRIPT and VARIANT, where:
LANGUAGE and COUNTRY are ISO language and country codes identical to
those found in POSIX locale specifications.
SCRIPT is an ISO 15924 script tag, representing the script used
if available, or if required to disambiguate between distinct
writing systems for the same combination of language and country.
VARIANT is an arbitrary string representing the variant of the
LANGUAGE or SCRIPT.
Each of these fields might be empty or nil, but the locale is invalid
if LANGUAGE is empty. Users of this variable should consider the
language to be US English if LANGUAGE is empty. */);
Vandroid_os_language = Qnil;
/* Functions defined. */
defsubr (&Sx_create_frame);
defsubr (&Sxw_color_defined_p);
defsubr (&Sxw_color_values);
defsubr (&Sxw_display_color_p);
defsubr (&Sx_display_grayscale_p);
defsubr (&Sx_display_pixel_width);
defsubr (&Sx_display_pixel_height);
defsubr (&Sx_display_planes);
defsubr (&Sx_display_color_cells);
defsubr (&Sx_display_screens);
defsubr (&Sx_display_mm_width);
defsubr (&Sx_display_mm_height);
defsubr (&Sx_display_backing_store);
defsubr (&Sx_display_visual_class);
defsubr (&Sandroid_display_monitor_attributes_list);
defsubr (&Sandroid_frame_geometry);
defsubr (&Sandroid_frame_edges);
defsubr (&Sandroid_frame_list_z_order);
defsubr (&Sandroid_frame_restack);
defsubr (&Sandroid_mouse_absolute_pixel_position);
defsubr (&Sandroid_set_mouse_absolute_pixel_position);
defsubr (&Sandroid_get_connection);
defsubr (&Sx_display_list);
defsubr (&Sx_show_tip);
defsubr (&Sx_hide_tip);
defsubr (&Sandroid_detect_mouse);
defsubr (&Sandroid_detect_keyboard);
defsubr (&Sandroid_toggle_on_screen_keyboard);
defsubr (&Sx_server_vendor);
defsubr (&Sx_server_version);
#ifndef ANDROID_STUBIFY
defsubr (&Sandroid_query_battery);
defsubr (&Sandroid_request_directory_access);
defsubr (&Sandroid_external_storage_available_p);
defsubr (&Sandroid_request_storage_access);
defsubr (&Sandroid_recreate_activity);
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);
pdumper_do_now_and_after_load (syms_of_androidfns_for_pdumper);
#endif /* !ANDROID_STUBIFY */
}