mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-15 10:30:25 -08:00
Update Android port
* java/Makefile.in (clean): Fix distclean and bootstrap-clean rules. * java/debug.sh (jdb_port): (attach_existing): (num_pids): (line): Add new options to upload a gdbserver binary to the device. * java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): Make focusedActivities public. * java/org/gnu/emacs/EmacsContextMenu.java (EmacsContextMenu): New class. * java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Fix bounds computation. * java/org/gnu/emacs/EmacsGC.java (markDirty): Set stroke width explicitly. * java/org/gnu/emacs/EmacsService.java (EmacsService) (getLocationOnScreen, nameKeysym): New functions. * java/org/gnu/emacs/EmacsView.java (EmacsView): Disable focus highlight. (onCreateContextMenu, popupMenu, cancelPopupMenu): New functions. * java/org/gnu/emacs/EmacsWindow.java (EmacsWindow): Implement a kind of ``override redirect'' window for tooltips. * src/android.c (struct android_emacs_service): New method `name_keysym'. (android_run_select_thread, android_init_events): (android_select): Release select thread on semaphores instead of signals to avoid one nasty race on SIGUSR2 delivery. (android_init_emacs_service): Initialize new method. (android_create_window): Handle CW_OVERRIDE_REDIRECT. (android_move_resize_window, android_map_raised) (android_translate_coordinates, android_get_keysym_name) (android_build_string, android_exception_check): New functions. * src/android.h: Update prototypes. * src/androidfns.c (android_set_parent_frame, Fx_create_frame) (unwind_create_tip_frame, android_create_tip_frame) (android_hide_tip, compute_tip_xy, Fx_show_tip, Fx_hide_tip) (syms_of_androidfns): Implement tooltips and iconification reporting. * src/androidgui.h (enum android_window_value_mask): Add CWOverrideRedirect. (struct android_set_window_attributes): Add `override_redirect'. (ANDROID_IS_MODIFIER_KEY): Recognize Caps Lock. * src/androidmenu.c (struct android_emacs_context_menu): New struct. (android_init_emacs_context_menu, android_unwind_local_frame) (android_push_local_frame, android_menu_show, init_androidmenu): New functions. * src/androidterm.c (handle_one_android_event): Fix NULL pointer dereference. (android_fullscreen_hook): Handle fullscreen correctly. (android_draw_box_rect): Fix top line. (get_keysym_name): Implement function. (android_create_terminal): Remove scroll bar stubs and add menu hook. * src/androidterm.h: Update prototypes. * src/emacs.c (android_emacs_init): Initialize androidmenu.c. * xcompile/Makefile.in: Fix clean rules.
This commit is contained in:
parent
28a9baccd4
commit
2b87ab7b27
18 changed files with 1683 additions and 110 deletions
|
|
@ -168,4 +168,4 @@ clean:
|
|||
rm -rf install-temp
|
||||
find . -name '*.class' -delete
|
||||
|
||||
maintainer-clean: clean
|
||||
maintainer-clean distclean bootstrap-clean: clean
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ gdb_port=5039
|
|||
jdb_port=64013
|
||||
jdb=no
|
||||
attach_existing=no
|
||||
gdbserver=
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
|
|
@ -41,6 +42,7 @@ while [ $# -gt 0 ]; do
|
|||
echo "You must specify an argument to --device"
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
"--help" )
|
||||
echo "Usage: $progname [options] -- [gdb options]"
|
||||
|
|
@ -50,6 +52,7 @@ while [ $# -gt 0 ]; do
|
|||
echo " --jdb-port PORT run the JDB server on a specific port"
|
||||
echo " --jdb run JDB instead of GDB"
|
||||
echo " --attach-existing attach to an existing process"
|
||||
echo " --gdbserver BINARY upload and use the specified gdbserver binary"
|
||||
echo " --help print this message"
|
||||
echo ""
|
||||
echo "Available devices:"
|
||||
|
|
@ -62,9 +65,18 @@ while [ $# -gt 0 ]; do
|
|||
"--jdb" )
|
||||
jdb=yes
|
||||
;;
|
||||
"--gdbserver" )
|
||||
shift
|
||||
gdbserver=$1
|
||||
;;
|
||||
"--port" )
|
||||
shift
|
||||
gdb_port=$1
|
||||
;;
|
||||
"--jdb-port" )
|
||||
shift
|
||||
jdb_port=$1
|
||||
;;
|
||||
"--attach-existing" )
|
||||
attach_existing=yes
|
||||
;;
|
||||
|
|
@ -170,46 +182,71 @@ elif [ -z $package_pids ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# Start JDB to make the wait dialog disappear.
|
||||
echo "Attaching JDB to unblock the application."
|
||||
adb -s $device forward --remove-all
|
||||
adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
|
||||
# This isn't necessary when attaching gdb to an existing process.
|
||||
if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
|
||||
# Start JDB to make the wait dialog disappear.
|
||||
echo "Attaching JDB to unblock the application."
|
||||
adb -s $device forward --remove-all
|
||||
adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
|
||||
|
||||
if [ ! $? ]; then
|
||||
if [ ! $? ]; then
|
||||
echo "Failed to forward jdwp:$pid to $jdb_port!"
|
||||
echo "Perhaps you need to specify a different port with --port?"
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
|
||||
jdb_command="jdb -connect \
|
||||
jdb_command="jdb -connect \
|
||||
com.sun.jdi.SocketAttach:hostname=localhost,port=$jdb_port"
|
||||
|
||||
if [ $jdb = "yes" ]; then
|
||||
if [ $jdb = "yes" ]; then
|
||||
# Just start JDB and then exit
|
||||
$jdb_command
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exec 4<> /tmp/file-descriptor-stamp
|
||||
exec 4<> /tmp/file-descriptor-stamp
|
||||
|
||||
# Now run JDB with IO redirected to file descriptor 4 in a subprocess.
|
||||
$jdb_command <&4 >&4 &
|
||||
# Now run JDB with IO redirected to file descriptor 4 in a subprocess.
|
||||
$jdb_command <&4 >&4 &
|
||||
|
||||
character=
|
||||
# Next, wait until the prompt is found.
|
||||
while read -n1 -u 4 character; do
|
||||
character=
|
||||
# Next, wait until the prompt is found.
|
||||
while read -n1 -u 4 character; do
|
||||
if [ "$character" = ">" ]; then
|
||||
echo "JDB attached successfully"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
# See if gdbserver has to be uploaded
|
||||
if [ -z "$gdbserver" ]; then
|
||||
gdbserver_bin=/system/bin/gdbserver
|
||||
else
|
||||
gdbserver_bin=/data/local/tmp/gdbserver
|
||||
|
||||
# Upload the specified gdbserver binary to the device.
|
||||
adb -s $device push "$gdbserver" "$gdbserver_bin"
|
||||
adb -s $device shell chmod +x "$gdbserver_bin"
|
||||
fi
|
||||
|
||||
# Now start gdbserver on the device asynchronously.
|
||||
|
||||
echo "Attaching gdbserver to $pid on $device..."
|
||||
exec 5<> /tmp/file-descriptor-stamp
|
||||
adb -s $device shell run-as $package /system/bin/gdbserver --once \
|
||||
|
||||
if [ -z "$gdbserver" ]; then
|
||||
adb -s $device shell run-as $package $gdbserver_bin --once \
|
||||
"+debug.$package_uid.socket" --attach $pid >&5 &
|
||||
gdb_socket="localfilesystem:$app_data_dir/debug.$package_uid.socket"
|
||||
else
|
||||
# Normally the program cannot access $gdbserver_bin when it is
|
||||
# placed in /data/local/tmp.
|
||||
adb -s $device shell $gdbserver_bin --once \
|
||||
"+/data/local/tmp/debug.$package_uid.socket" \
|
||||
--attach $pid >&5 &
|
||||
gdb_socket="localfilesystem:/data/local/tmp/debug.$package_uid.socket"
|
||||
fi
|
||||
|
||||
# Wait until gdbserver successfully runs.
|
||||
line=
|
||||
|
|
@ -227,16 +264,17 @@ while read -u 5 line; do
|
|||
esac
|
||||
done
|
||||
|
||||
# Send EOF to JDB to make it go away. This will also cause Android to
|
||||
# allow Emacs to continue executing.
|
||||
echo "Making JDB go away..."
|
||||
echo "exit" >&4
|
||||
read -u 4 line
|
||||
echo "JDB has gone away with $line"
|
||||
if [ "$attach_existing" != "yes" ]; then
|
||||
# Send EOF to JDB to make it go away. This will also cause
|
||||
# Android to allow Emacs to continue executing.
|
||||
echo "Making JDB go away..."
|
||||
echo "exit" >&4
|
||||
read -u 4 line
|
||||
echo "JDB has gone away with $line"
|
||||
fi
|
||||
|
||||
# Forward the gdb server port here.
|
||||
adb -s $device forward "tcp:$gdb_port" \
|
||||
"localfilesystem:$app_data_dir/debug.$package_uid.socket"
|
||||
adb -s $device forward "tcp:$gdb_port" $gdb_socket
|
||||
if [ ! $? ]; then
|
||||
echo "Failed to forward $app_data_dir/debug.$package_uid.socket"
|
||||
echo "to $gdb_port! Perhaps you need to specify a different port"
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public class EmacsActivity extends Activity
|
|||
private FrameLayout layout;
|
||||
|
||||
/* List of activities with focus. */
|
||||
private static List<EmacsActivity> focusedActivities;
|
||||
public static List<EmacsActivity> focusedActivities;
|
||||
|
||||
/* The currently focused window. */
|
||||
public static EmacsWindow focusedWindow;
|
||||
|
|
|
|||
213
java/org/gnu/emacs/EmacsContextMenu.java
Normal file
213
java/org/gnu/emacs/EmacsContextMenu.java
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 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/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
/* Context menu implementation. This object is built from JNI and
|
||||
describes a menu hiearchy. Then, `inflate' can turn it into an
|
||||
Android menu, which can be turned into a popup (or other kind of)
|
||||
menu. */
|
||||
|
||||
public class EmacsContextMenu
|
||||
{
|
||||
private class Item
|
||||
{
|
||||
public int itemID;
|
||||
public String itemName;
|
||||
public EmacsContextMenu subMenu;
|
||||
public boolean isEnabled;
|
||||
};
|
||||
|
||||
public List<Item> menuItems;
|
||||
public String title;
|
||||
private EmacsContextMenu parent;
|
||||
|
||||
/* Create a context menu with no items inside and the title TITLE,
|
||||
which may be NULL. */
|
||||
|
||||
public static EmacsContextMenu
|
||||
createContextMenu (String title)
|
||||
{
|
||||
EmacsContextMenu menu;
|
||||
|
||||
menu = new EmacsContextMenu ();
|
||||
menu.menuItems = new ArrayList<Item> ();
|
||||
menu.title = title;
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
/* Add a normal menu item to the context menu with the id ITEMID and
|
||||
the name ITEMNAME. Enable it if ISENABLED, else keep it
|
||||
disabled. */
|
||||
|
||||
public void
|
||||
addItem (int itemID, String itemName, boolean isEnabled)
|
||||
{
|
||||
Item item;
|
||||
|
||||
item = new Item ();
|
||||
item.itemID = itemID;
|
||||
item.itemName = itemName;
|
||||
item.isEnabled = isEnabled;
|
||||
|
||||
menuItems.add (item);
|
||||
}
|
||||
|
||||
/* Create a disabled menu item with the name ITEMNAME. */
|
||||
|
||||
public void
|
||||
addPane (String itemName)
|
||||
{
|
||||
Item item;
|
||||
|
||||
item = new Item ();
|
||||
item.itemName = itemName;
|
||||
|
||||
menuItems.add (item);
|
||||
}
|
||||
|
||||
/* Add a submenu to the context menu with the specified title and
|
||||
item name. */
|
||||
|
||||
public EmacsContextMenu
|
||||
addSubmenu (String itemName, String title)
|
||||
{
|
||||
EmacsContextMenu submenu;
|
||||
Item item;
|
||||
|
||||
item = new Item ();
|
||||
item.itemID = 0;
|
||||
item.itemName = itemName;
|
||||
item.subMenu = createContextMenu (title);
|
||||
item.subMenu.parent = this;
|
||||
|
||||
menuItems.add (item);
|
||||
return item.subMenu;
|
||||
}
|
||||
|
||||
/* Add the contents of this menu to MENU. */
|
||||
|
||||
private void
|
||||
inflateMenuItems (Menu menu)
|
||||
{
|
||||
Intent intent;
|
||||
MenuItem menuItem;
|
||||
Menu submenu;
|
||||
|
||||
for (Item item : menuItems)
|
||||
{
|
||||
if (item.subMenu != null)
|
||||
{
|
||||
/* This is a submenu. Create the submenu and add the
|
||||
contents of the menu to it. */
|
||||
submenu = menu.addSubMenu (item.itemName);
|
||||
inflateMenuItems (submenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
menuItem = menu.add (item.itemName);
|
||||
|
||||
/* If the item ID is zero, then disable the item. */
|
||||
if (item.itemID == 0 || !item.isEnabled)
|
||||
menuItem.setEnabled (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the items in this context menu to MENU. Create each menu
|
||||
item with an Intent containing a Bundle, where the key
|
||||
"emacs:menu_item_hi" maps to the high 16 bits of the
|
||||
corresponding item ID, and the key "emacs:menu_item_low" maps to
|
||||
the low 16 bits of the item ID. */
|
||||
|
||||
public void
|
||||
expandTo (Menu menu)
|
||||
{
|
||||
inflateMenuItems (menu);
|
||||
}
|
||||
|
||||
/* Return the parent or NULL. */
|
||||
|
||||
public EmacsContextMenu
|
||||
parent ()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
/* Like display, but does the actual work and runs in the main
|
||||
thread. */
|
||||
|
||||
private boolean
|
||||
display1 (EmacsWindow window, int xPosition, int yPosition)
|
||||
{
|
||||
return window.view.popupMenu (this, xPosition, yPosition);
|
||||
}
|
||||
|
||||
/* Display this context menu on WINDOW, at xPosition and
|
||||
yPosition. */
|
||||
|
||||
public boolean
|
||||
display (final EmacsWindow window, final int xPosition,
|
||||
final int yPosition)
|
||||
{
|
||||
Runnable runnable;
|
||||
final Holder<Boolean> rc;
|
||||
|
||||
rc = new Holder<Boolean> ();
|
||||
|
||||
runnable = new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
rc.thing = display1 (window, xPosition, yPosition);
|
||||
notify ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
runnable.wait ();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
EmacsNative.emacsAbort ();
|
||||
}
|
||||
|
||||
return rc.thing;
|
||||
}
|
||||
};
|
||||
|
|
@ -59,7 +59,7 @@ public class EmacsDrawRectangle
|
|||
}
|
||||
|
||||
paint = gc.gcPaint;
|
||||
rect = new Rect (x, y, x + width, y + height);
|
||||
rect = new Rect (x + 1, y + 1, x + width, y + height);
|
||||
|
||||
paint.setStyle (Paint.Style.STROKE);
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ public class EmacsGC extends EmacsHandleObject
|
|||
else
|
||||
real_clip_rects = clip_rects;
|
||||
|
||||
gcPaint.setStrokeWidth (1f);
|
||||
gcPaint.setColor (foreground | 0xff000000);
|
||||
gcPaint.setXfermode (function == GC_XOR
|
||||
? xorAlu : srcInAlu);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import android.graphics.Point;
|
|||
|
||||
import android.view.View;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Service;
|
||||
|
|
@ -150,13 +151,13 @@ public class EmacsService extends Service
|
|||
/* Functions from here on must only be called from the Emacs
|
||||
thread. */
|
||||
|
||||
void
|
||||
public void
|
||||
runOnUiThread (Runnable runnable)
|
||||
{
|
||||
handler.post (runnable);
|
||||
}
|
||||
|
||||
EmacsView
|
||||
public EmacsView
|
||||
getEmacsView (final EmacsWindow window, final int visibility,
|
||||
final boolean isFocusedByDefault)
|
||||
{
|
||||
|
|
@ -196,6 +197,38 @@ public class EmacsService extends Service
|
|||
return view.thing;
|
||||
}
|
||||
|
||||
public void
|
||||
getLocationOnScreen (final EmacsView view, final int[] coordinates)
|
||||
{
|
||||
Runnable runnable;
|
||||
|
||||
runnable = new Runnable () {
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
view.getLocationOnScreen (coordinates);
|
||||
notify ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
synchronized (runnable)
|
||||
{
|
||||
runOnUiThread (runnable);
|
||||
|
||||
try
|
||||
{
|
||||
runnable.wait ();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
EmacsNative.emacsAbort ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
fillRectangle (EmacsDrawable drawable, EmacsGC gc,
|
||||
int x, int y, int width, int height)
|
||||
|
|
@ -368,4 +401,10 @@ public class EmacsService extends Service
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String
|
||||
nameKeysym (int keysym)
|
||||
{
|
||||
return KeyEvent.keyCodeToString (keysym);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package org.gnu.emacs;
|
|||
|
||||
import android.content.res.ColorStateList;
|
||||
|
||||
import android.view.ContextMenu;
|
||||
import android.view.View;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
|
@ -73,6 +74,12 @@ public class EmacsView extends ViewGroup
|
|||
next call to getBitmap. */
|
||||
private Rect bitmapDirty;
|
||||
|
||||
/* Whether or not a popup is active. */
|
||||
private boolean popupActive;
|
||||
|
||||
/* The current context menu. */
|
||||
private EmacsContextMenu contextMenu;
|
||||
|
||||
public
|
||||
EmacsView (EmacsWindow window)
|
||||
{
|
||||
|
|
@ -98,6 +105,10 @@ public class EmacsView extends ViewGroup
|
|||
/* Get rid of the foreground and background tint. */
|
||||
setBackgroundTintList (null);
|
||||
setForegroundTintList (null);
|
||||
|
||||
/* Get rid of the default focus highlight. */
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
|
||||
setDefaultFocusHighlightEnabled (false);
|
||||
}
|
||||
|
||||
private void
|
||||
|
|
@ -423,4 +434,40 @@ public class EmacsView extends ViewGroup
|
|||
removeView (surfaceView);
|
||||
addView (surfaceView, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void
|
||||
onCreateContextMenu (ContextMenu menu)
|
||||
{
|
||||
if (contextMenu == null)
|
||||
return;
|
||||
|
||||
contextMenu.expandTo (menu);
|
||||
}
|
||||
|
||||
public boolean
|
||||
popupMenu (EmacsContextMenu menu, int xPosition,
|
||||
int yPosition)
|
||||
{
|
||||
if (popupActive)
|
||||
return false;
|
||||
|
||||
contextMenu = menu;
|
||||
|
||||
/* On API 21 or later, use showContextMenu (float, float). */
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP)
|
||||
return showContextMenu ((float) xPosition, (float) yPosition);
|
||||
else
|
||||
return showContextMenu ();
|
||||
}
|
||||
|
||||
public void
|
||||
cancelPopupMenu ()
|
||||
{
|
||||
if (!popupActive)
|
||||
throw new IllegalStateException ("cancelPopupMenu called without"
|
||||
+ " popupActive set");
|
||||
|
||||
contextMenu = null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,16 +24,22 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PixelFormat;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewManager;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.InputDevice;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
|
@ -110,9 +116,17 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
not the window should be focusable. */
|
||||
private boolean dontFocusOnMap, dontAcceptFocus;
|
||||
|
||||
/* Whether or not the window is override-redirect. An
|
||||
override-redirect window always has its own system window. */
|
||||
private boolean overrideRedirect;
|
||||
|
||||
/* The window manager that is the parent of this window. NULL if
|
||||
there is no such window manager. */
|
||||
private WindowManager windowManager;
|
||||
|
||||
public
|
||||
EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
|
||||
int width, int height)
|
||||
int width, int height, boolean overrideRedirect)
|
||||
{
|
||||
super (handle);
|
||||
|
||||
|
|
@ -124,6 +138,7 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
view = EmacsService.SERVICE.getEmacsView (this, View.GONE,
|
||||
parent == null);
|
||||
this.parent = parent;
|
||||
this.overrideRedirect = overrideRedirect;
|
||||
|
||||
/* Create the list of children. */
|
||||
children = new ArrayList<EmacsWindow> ();
|
||||
|
|
@ -180,7 +195,7 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
public void
|
||||
run ()
|
||||
{
|
||||
View parent;
|
||||
ViewManager parent;
|
||||
EmacsWindowAttachmentManager manager;
|
||||
|
||||
if (EmacsActivity.focusedWindow == EmacsWindow.this)
|
||||
|
|
@ -189,10 +204,15 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
manager = EmacsWindowAttachmentManager.MANAGER;
|
||||
view.setVisibility (View.GONE);
|
||||
|
||||
parent = (View) view.getParent ();
|
||||
/* If the window manager is set, use that instead. */
|
||||
if (windowManager != null)
|
||||
parent = windowManager;
|
||||
else
|
||||
parent = (ViewManager) view.getParent ();
|
||||
windowManager = null;
|
||||
|
||||
if (parent != null)
|
||||
((ViewGroup) parent).removeView (view);
|
||||
parent.removeView (view);
|
||||
|
||||
manager.detachWindow (EmacsWindow.this);
|
||||
}
|
||||
|
|
@ -247,6 +267,10 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
public void
|
||||
run ()
|
||||
{
|
||||
if (overrideRedirect)
|
||||
/* Set the layout parameters again. */
|
||||
view.setLayoutParams (getWindowLayoutParams ());
|
||||
|
||||
view.mustReportLayout = true;
|
||||
view.requestLayout ();
|
||||
}
|
||||
|
|
@ -284,6 +308,39 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
}
|
||||
}
|
||||
|
||||
private WindowManager.LayoutParams
|
||||
getWindowLayoutParams ()
|
||||
{
|
||||
WindowManager.LayoutParams params;
|
||||
int flags, type;
|
||||
Rect rect;
|
||||
|
||||
flags = 0;
|
||||
rect = getGeometry ();
|
||||
flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||
type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
|
||||
|
||||
params
|
||||
= new WindowManager.LayoutParams (rect.width (), rect.height (),
|
||||
rect.left, rect.top,
|
||||
type, flags,
|
||||
PixelFormat.RGBA_8888);
|
||||
params.gravity = Gravity.TOP | Gravity.LEFT;
|
||||
return params;
|
||||
}
|
||||
|
||||
private Context
|
||||
findSuitableActivityContext ()
|
||||
{
|
||||
/* Find a recently focused activity. */
|
||||
if (!EmacsActivity.focusedActivities.isEmpty ())
|
||||
return EmacsActivity.focusedActivities.get (0);
|
||||
|
||||
/* Return the service context, which probably won't work. */
|
||||
return EmacsService.SERVICE;
|
||||
}
|
||||
|
||||
public void
|
||||
mapWindow ()
|
||||
{
|
||||
|
|
@ -300,10 +357,16 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
run ()
|
||||
{
|
||||
EmacsWindowAttachmentManager manager;
|
||||
WindowManager windowManager;
|
||||
Context ctx;
|
||||
Object tem;
|
||||
WindowManager.LayoutParams params;
|
||||
|
||||
/* Make the view visible, first of all. */
|
||||
view.setVisibility (View.VISIBLE);
|
||||
|
||||
if (!overrideRedirect)
|
||||
{
|
||||
manager = EmacsWindowAttachmentManager.MANAGER;
|
||||
|
||||
/* If parent is the root window, notice that there are new
|
||||
|
|
@ -315,6 +378,40 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
/* Eventually this should check no-focus-on-map. */
|
||||
view.requestFocus ();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* But if the window is an override-redirect window,
|
||||
then:
|
||||
|
||||
- Find an activity that is currently active.
|
||||
|
||||
- Map the window as a panel on top of that
|
||||
activity using the system window manager. */
|
||||
|
||||
ctx = findSuitableActivityContext ();
|
||||
tem = ctx.getSystemService (Context.WINDOW_SERVICE);
|
||||
windowManager = (WindowManager) tem;
|
||||
|
||||
/* Calculate layout parameters. */
|
||||
params = getWindowLayoutParams ();
|
||||
view.setLayoutParams (params);
|
||||
|
||||
/* Attach the view. */
|
||||
try
|
||||
{
|
||||
windowManager.addView (view, params);
|
||||
|
||||
/* Record the window manager being used in the
|
||||
EmacsWindow object. */
|
||||
EmacsWindow.this.windowManager = windowManager;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.w (TAG,
|
||||
"failed to attach override-redirect window, " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
@ -355,6 +452,11 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
|
||||
view.setVisibility (View.GONE);
|
||||
|
||||
/* Detach the view from the window manager if possible. */
|
||||
if (windowManager != null)
|
||||
windowManager.removeView (view);
|
||||
windowManager = null;
|
||||
|
||||
/* Now that the window is unmapped, unregister it as
|
||||
well. */
|
||||
manager.detachWindow (EmacsWindow.this);
|
||||
|
|
@ -756,17 +858,23 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
run ()
|
||||
{
|
||||
EmacsWindowAttachmentManager manager;
|
||||
View parent;
|
||||
ViewManager parent;
|
||||
|
||||
/* First, detach this window if necessary. */
|
||||
manager = EmacsWindowAttachmentManager.MANAGER;
|
||||
manager.detachWindow (EmacsWindow.this);
|
||||
|
||||
/* Also unparent this view. */
|
||||
parent = (View) view.getParent ();
|
||||
|
||||
/* If the window manager is set, use that instead. */
|
||||
if (windowManager != null)
|
||||
parent = windowManager;
|
||||
else
|
||||
parent = (ViewManager) view.getParent ();
|
||||
windowManager = null;
|
||||
|
||||
if (parent != null)
|
||||
((ViewGroup) parent).removeView (view);
|
||||
parent.removeView (view);
|
||||
|
||||
/* Next, either add this window as a child of the new
|
||||
parent's view, or make it available again. */
|
||||
|
|
@ -899,4 +1007,23 @@ public class EmacsWindow extends EmacsHandleObject
|
|||
{
|
||||
return dontFocusOnMap;
|
||||
}
|
||||
|
||||
public int[]
|
||||
translateCoordinates (int x, int y)
|
||||
{
|
||||
int[] array;
|
||||
|
||||
/* This is supposed to translate coordinates to the root
|
||||
window. */
|
||||
array = new int[2];
|
||||
EmacsService.SERVICE.getLocationOnScreen (view, array);
|
||||
|
||||
/* Now, the coordinates of the view should be in array. Offset X
|
||||
and Y by them. */
|
||||
array[0] += x;
|
||||
array[1] += y;
|
||||
|
||||
/* Return the resulting coordinates. */
|
||||
return array;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
169
src/android.c
169
src/android.c
|
|
@ -87,6 +87,7 @@ struct android_emacs_service
|
|||
jmethodID get_screen_width;
|
||||
jmethodID get_screen_height;
|
||||
jmethodID detect_mouse;
|
||||
jmethodID name_keysym;
|
||||
};
|
||||
|
||||
struct android_emacs_pixmap
|
||||
|
|
@ -229,14 +230,14 @@ static volatile bool android_pselect_completed;
|
|||
/* The global event queue. */
|
||||
static struct android_event_queue event_queue;
|
||||
|
||||
/* Semaphore used to signal select completion. */
|
||||
static sem_t android_pselect_sem;
|
||||
/* Semaphores used to signal select completion and start. */
|
||||
static sem_t android_pselect_sem, android_pselect_start_sem;
|
||||
|
||||
static void *
|
||||
android_run_select_thread (void *data)
|
||||
{
|
||||
sigset_t signals;
|
||||
int sig, rc;
|
||||
int rc;
|
||||
|
||||
sigfillset (&signals);
|
||||
|
||||
|
|
@ -245,23 +246,10 @@ android_run_select_thread (void *data)
|
|||
"pthread_sigmask: %s",
|
||||
strerror (errno));
|
||||
|
||||
sigemptyset (&signals);
|
||||
sigaddset (&signals, SIGUSR1);
|
||||
|
||||
if (pthread_sigmask (SIG_UNBLOCK, &signals, NULL))
|
||||
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||
"pthread_sigmask: %s",
|
||||
strerror (errno));
|
||||
|
||||
sigemptyset (&signals);
|
||||
sigaddset (&signals, SIGUSR2);
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* Keep waiting for SIGUSR2, ignoring EINTR in the meantime. */
|
||||
|
||||
while (sigwait (&signals, &sig))
|
||||
/* Spin. */;
|
||||
/* Wait for the thread to be released. */
|
||||
sem_wait (&android_pselect_start_sem);
|
||||
|
||||
/* Get the select lock and call pselect. */
|
||||
pthread_mutex_lock (&event_queue.select_mutex);
|
||||
|
|
@ -322,6 +310,7 @@ android_init_events (void)
|
|||
strerror (errno));
|
||||
|
||||
sem_init (&android_pselect_sem, 0, 0);
|
||||
sem_init (&android_pselect_start_sem, 0, 0);
|
||||
|
||||
event_queue.events.next = &event_queue.events;
|
||||
event_queue.events.last = &event_queue.events;
|
||||
|
|
@ -444,7 +433,9 @@ android_select (int nfds, fd_set *readfds, fd_set *writefds,
|
|||
android_pselect_sigset = sigset;
|
||||
pthread_mutex_unlock (&event_queue.select_mutex);
|
||||
|
||||
pthread_kill (event_queue.select_thread, SIGUSR2);
|
||||
/* Release the select thread. */
|
||||
sem_post (&android_pselect_start_sem);
|
||||
|
||||
pthread_cond_wait (&event_queue.read_var, &event_queue.mutex);
|
||||
|
||||
/* Interrupt the select thread now, in case it's still in
|
||||
|
|
@ -1058,6 +1049,7 @@ android_init_emacs_service (void)
|
|||
FIND_METHOD (get_screen_width, "getScreenWidth", "(Z)I");
|
||||
FIND_METHOD (get_screen_height, "getScreenHeight", "(Z)I");
|
||||
FIND_METHOD (detect_mouse, "detectMouse", "()Z");
|
||||
FIND_METHOD (name_keysym, "nameKeysym", "(I)Ljava/lang/String;");
|
||||
#undef FIND_METHOD
|
||||
}
|
||||
|
||||
|
|
@ -1678,6 +1670,7 @@ android_create_window (android_window parent, int x, int y,
|
|||
jobject object, parent_object, old;
|
||||
android_window window;
|
||||
android_handle prev_max_handle;
|
||||
bool override_redirect;
|
||||
|
||||
parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW);
|
||||
|
||||
|
|
@ -1695,7 +1688,8 @@ android_create_window (android_window parent, int x, int y,
|
|||
|
||||
constructor
|
||||
= (*android_java_env)->GetMethodID (android_java_env, class, "<init>",
|
||||
"(SLorg/gnu/emacs/EmacsWindow;IIII)V");
|
||||
"(SLorg/gnu/emacs/EmacsWindow;"
|
||||
"IIIIZ)V");
|
||||
assert (constructor != NULL);
|
||||
|
||||
old = class;
|
||||
|
|
@ -1707,10 +1701,17 @@ android_create_window (android_window parent, int x, int y,
|
|||
memory_full (0);
|
||||
}
|
||||
|
||||
/* N.B. that ANDROID_CW_OVERRIDE_REDIRECT can only be set at window
|
||||
creation time. */
|
||||
override_redirect = ((value_mask
|
||||
& ANDROID_CW_OVERRIDE_REDIRECT)
|
||||
&& attrs->override_redirect);
|
||||
|
||||
object = (*android_java_env)->NewObject (android_java_env, class,
|
||||
constructor, (jshort) window,
|
||||
parent_object, (jint) x, (jint) y,
|
||||
(jint) width, (jint) height);
|
||||
(jint) width, (jint) height,
|
||||
(jboolean) override_redirect);
|
||||
if (!object)
|
||||
{
|
||||
(*android_java_env)->ExceptionClear (android_java_env);
|
||||
|
|
@ -3212,6 +3213,66 @@ android_get_geometry (android_window handle,
|
|||
ANDROID_DELETE_LOCAL_REF (window_geometry);
|
||||
}
|
||||
|
||||
void
|
||||
android_move_resize_window (android_window window, int x, int y,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
android_move_window (window, x, y);
|
||||
android_resize_window (window, width, height);
|
||||
}
|
||||
|
||||
void
|
||||
android_map_raised (android_window window)
|
||||
{
|
||||
android_raise_window (window);
|
||||
android_map_window (window);
|
||||
}
|
||||
|
||||
void
|
||||
android_translate_coordinates (android_window src, int x,
|
||||
int y, int *root_x, int *root_y)
|
||||
{
|
||||
jobject window;
|
||||
jarray coordinates;
|
||||
jmethodID method;
|
||||
jint *ints;
|
||||
|
||||
window = android_resolve_handle (src, ANDROID_HANDLE_WINDOW);
|
||||
method = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
||||
"translateCoordinates",
|
||||
"(II)[I");
|
||||
coordinates
|
||||
= (*android_java_env)->CallObjectMethod (android_java_env,
|
||||
window, method,
|
||||
(jint) x, (jint) y);
|
||||
|
||||
if (!coordinates)
|
||||
{
|
||||
(*android_java_env)->ExceptionClear (android_java_env);
|
||||
memory_full (0);
|
||||
}
|
||||
|
||||
/* The array must contain two elements: X, Y translated to the root
|
||||
window. */
|
||||
eassert ((*android_java_env)->GetArrayLength (android_java_env,
|
||||
coordinates)
|
||||
== 2);
|
||||
|
||||
/* Obtain the coordinates from the array. */
|
||||
ints = (*android_java_env)->GetIntArrayElements (android_java_env,
|
||||
coordinates, NULL);
|
||||
*root_x = ints[0];
|
||||
*root_y = ints[1];
|
||||
|
||||
/* Release the coordinates. */
|
||||
(*android_java_env)->ReleaseIntArrayElements (android_java_env,
|
||||
coordinates, ints,
|
||||
JNI_ABORT);
|
||||
|
||||
/* And free the local reference. */
|
||||
ANDROID_DELETE_LOCAL_REF (coordinates);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Low level drawing primitives. */
|
||||
|
|
@ -3384,6 +3445,30 @@ android_set_dont_accept_focus (android_window handle,
|
|||
(jboolean) no_accept_focus);
|
||||
}
|
||||
|
||||
void
|
||||
android_get_keysym_name (int keysym, char *name_return, size_t size)
|
||||
{
|
||||
jobject string;
|
||||
const char *buffer;
|
||||
|
||||
string = (*android_java_env)->CallObjectMethod (android_java_env,
|
||||
emacs_service,
|
||||
service_class.name_keysym,
|
||||
(jint) keysym);
|
||||
android_exception_check ();
|
||||
|
||||
buffer = (*android_java_env)->GetStringUTFChars (android_java_env,
|
||||
(jstring) string,
|
||||
NULL);
|
||||
android_exception_check ();
|
||||
strncpy (name_return, buffer, size - 1);
|
||||
|
||||
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
|
||||
(jstring) string,
|
||||
buffer);
|
||||
ANDROID_DELETE_LOCAL_REF (string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef faccessat
|
||||
|
|
@ -3525,6 +3610,48 @@ emacs_abort (void)
|
|||
abort ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Given a Lisp string TEXT, return a local reference to an equivalent
|
||||
Java string. */
|
||||
|
||||
jstring
|
||||
android_build_string (Lisp_Object text)
|
||||
{
|
||||
Lisp_Object encoded;
|
||||
jstring string;
|
||||
|
||||
encoded = ENCODE_UTF_8 (text);
|
||||
|
||||
/* Note that Java expects this string to be in ``modified UTF
|
||||
encoding'', which is actually UTF-8, except with NUL encoded as a
|
||||
two-byte sequence. The only consequence of passing an actual
|
||||
UTF-8 string is that NUL bytes cannot be represented, which is
|
||||
not really of consequence. */
|
||||
string = (*android_java_env)->NewStringUTF (android_java_env,
|
||||
SSDATA (encoded));
|
||||
if (!string)
|
||||
{
|
||||
(*android_java_env)->ExceptionClear (android_java_env);
|
||||
memory_full (0);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/* Check for JNI exceptions and call memory_full in that
|
||||
situation. */
|
||||
|
||||
void
|
||||
android_exception_check (void)
|
||||
{
|
||||
if ((*android_java_env)->ExceptionCheck (android_java_env))
|
||||
{
|
||||
(*android_java_env)->ExceptionClear (android_java_env);
|
||||
memory_full (0);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* ANDROID_STUBIFY */
|
||||
|
||||
/* X emulation functions for Android. */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <android/bitmap.h>
|
||||
|
||||
#include "androidgui.h"
|
||||
#include "lisp.h"
|
||||
#endif
|
||||
|
||||
/* This must be used in every symbol declaration to export it to the
|
||||
|
|
@ -84,6 +85,11 @@ extern bool android_detect_mouse (void);
|
|||
extern void android_set_dont_focus_on_map (android_window, bool);
|
||||
extern void android_set_dont_accept_focus (android_window, bool);
|
||||
|
||||
extern jstring android_build_string (Lisp_Object);
|
||||
extern void android_exception_check (void);
|
||||
|
||||
extern void android_get_keysym_name (int, char *, size_t);
|
||||
|
||||
|
||||
|
||||
/* Directory listing emulation. */
|
||||
|
|
|
|||
677
src/androidfns.c
677
src/androidfns.c
|
|
@ -25,12 +25,36 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include "androidterm.h"
|
||||
#include "blockinput.h"
|
||||
#include "keyboard.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
/* Some kind of reference count for the image cache. */
|
||||
static ptrdiff_t image_cache_refcount;
|
||||
|
||||
/* The frame of the currently visible tooltip, or nil if none. */
|
||||
static Lisp_Object tip_frame;
|
||||
|
||||
/* The window-system window corresponding to the frame of the
|
||||
currently visible tooltip. */
|
||||
static android_window tip_window;
|
||||
|
||||
/* The X and Y deltas of the last call to `x-show-tip'. */
|
||||
static Lisp_Object tip_dx, tip_dy;
|
||||
|
||||
/* A timer that hides or deletes the currently visible tooltip when it
|
||||
fires. */
|
||||
static Lisp_Object tip_timer;
|
||||
|
||||
/* STRING argument of last `x-show-tip' call. */
|
||||
static Lisp_Object tip_last_string;
|
||||
|
||||
/* Normalized FRAME argument of last `x-show-tip' call. */
|
||||
static Lisp_Object tip_last_frame;
|
||||
|
||||
/* PARMS argument of last `x-show-tip' call. */
|
||||
static Lisp_Object tip_last_parms;
|
||||
|
||||
#endif
|
||||
|
||||
static struct android_display_info *
|
||||
|
|
@ -180,6 +204,9 @@ android_set_parent_frame (struct frame *f, Lisp_Object new_value,
|
|||
|
||||
fset_parent_frame (f, new_value);
|
||||
}
|
||||
|
||||
/* Update the fullscreen frame parameter as well. */
|
||||
FRAME_TERMINAL (f)->fullscreen_hook (f);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -858,13 +885,13 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
|
|||
gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
|
||||
NULL, NULL, RES_TYPE_NUMBER);
|
||||
|
||||
/* gui_default_parameter (f, parms, Qvertical_scroll_bars, */
|
||||
/* Qleft, */
|
||||
/* "verticalScrollBars", "ScrollBars", */
|
||||
/* RES_TYPE_SYMBOL); */
|
||||
/* gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil, */
|
||||
/* "horizontalScrollBars", "ScrollBars", */
|
||||
/* RES_TYPE_SYMBOL); TODO */
|
||||
gui_default_parameter (f, parms, Qvertical_scroll_bars,
|
||||
Qleft,
|
||||
"verticalScrollBars", "ScrollBars",
|
||||
RES_TYPE_SYMBOL);
|
||||
gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
|
||||
"horizontalScrollBars", "ScrollBars",
|
||||
RES_TYPE_SYMBOL);
|
||||
|
||||
/* Also do the stuff which must be set before the window exists. */
|
||||
gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
|
||||
|
|
@ -893,7 +920,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
|
|||
android_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_background,
|
||||
"scrollBarBackground",
|
||||
"ScrollBarBackground", false);
|
||||
#endif /* TODO */
|
||||
#endif
|
||||
|
||||
/* Init faces before gui_default_parameter is called for the
|
||||
scroll-bar-width parameter because otherwise we end up in
|
||||
|
|
@ -974,12 +1001,16 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
|
|||
"autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
|
||||
gui_default_parameter (f, parms, Qcursor_type, Qbox,
|
||||
"cursorType", "CursorType", RES_TYPE_SYMBOL);
|
||||
/* Scroll bars are not supported on Android, as they are near
|
||||
useless. */
|
||||
#if 0
|
||||
gui_default_parameter (f, parms, Qscroll_bar_width, Qnil,
|
||||
"scrollBarWidth", "ScrollBarWidth",
|
||||
RES_TYPE_NUMBER);
|
||||
gui_default_parameter (f, parms, Qscroll_bar_height, Qnil,
|
||||
"scrollBarHeight", "ScrollBarHeight",
|
||||
RES_TYPE_NUMBER);
|
||||
#endif
|
||||
gui_default_parameter (f, parms, Qalpha, Qnil,
|
||||
"alpha", "Alpha", RES_TYPE_NUMBER);
|
||||
gui_default_parameter (f, parms, Qalpha_background, Qnil,
|
||||
|
|
@ -1009,8 +1040,9 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
|
|||
|
||||
/* Process fullscreen parameter here in the hope that normalizing a
|
||||
fullheight/fullwidth frame will produce the size set by the last
|
||||
adjust_frame_size call. */
|
||||
gui_default_parameter (f, parms, Qfullscreen, Qnil,
|
||||
adjust_frame_size call. Note that Android only supports the
|
||||
`maximized' state. */
|
||||
gui_default_parameter (f, parms, Qfullscreen, Qmaximized,
|
||||
"fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
|
||||
|
||||
/* When called from `x-create-frame-with-faces' visibility is
|
||||
|
|
@ -1661,6 +1693,391 @@ DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
static void
|
||||
unwind_create_tip_frame (Lisp_Object frame)
|
||||
{
|
||||
Lisp_Object deleted;
|
||||
|
||||
deleted = unwind_create_frame (frame);
|
||||
if (EQ (deleted, Qt))
|
||||
{
|
||||
tip_window = ANDROID_NONE;
|
||||
tip_frame = Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
android_create_tip_frame (struct android_display_info *dpyinfo,
|
||||
Lisp_Object parms)
|
||||
{
|
||||
struct frame *f;
|
||||
Lisp_Object frame;
|
||||
Lisp_Object name;
|
||||
specpdl_ref count = SPECPDL_INDEX ();
|
||||
bool face_change_before = face_change;
|
||||
|
||||
if (!dpyinfo->terminal->name)
|
||||
error ("Terminal is not live, can't create new frames on it");
|
||||
|
||||
parms = Fcopy_alist (parms);
|
||||
|
||||
/* Get the name of the frame to use for resource lookup. */
|
||||
name = gui_display_get_arg (dpyinfo, parms, Qname, "name", "Name",
|
||||
RES_TYPE_STRING);
|
||||
if (!STRINGP (name)
|
||||
&& !BASE_EQ (name, Qunbound)
|
||||
&& !NILP (name))
|
||||
error ("Invalid frame name--not a string or nil");
|
||||
|
||||
frame = Qnil;
|
||||
f = make_frame (false);
|
||||
f->wants_modeline = false;
|
||||
XSETFRAME (frame, f);
|
||||
record_unwind_protect (unwind_create_tip_frame, frame);
|
||||
|
||||
f->terminal = dpyinfo->terminal;
|
||||
|
||||
/* By setting the output method, we're essentially saying that
|
||||
the frame is live, as per FRAME_LIVE_P. If we get a signal
|
||||
from this point on, x_destroy_window might screw up reference
|
||||
counts etc. */
|
||||
f->output_method = output_android;
|
||||
f->output_data.android = xzalloc (sizeof *f->output_data.android);
|
||||
FRAME_FONTSET (f) = -1;
|
||||
f->output_data.android->white_relief.pixel = -1;
|
||||
f->output_data.android->black_relief.pixel = -1;
|
||||
|
||||
f->tooltip = true;
|
||||
fset_icon_name (f, Qnil);
|
||||
FRAME_DISPLAY_INFO (f) = dpyinfo;
|
||||
f->output_data.android->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
|
||||
|
||||
/* These colors will be set anyway later, but it's important
|
||||
to get the color reference counts right, so initialize them! */
|
||||
{
|
||||
Lisp_Object black;
|
||||
|
||||
/* Function android_decode_color can signal an error. Make sure
|
||||
to initialize color slots so that we won't try to free colors
|
||||
we haven't allocated. */
|
||||
FRAME_FOREGROUND_PIXEL (f) = -1;
|
||||
FRAME_BACKGROUND_PIXEL (f) = -1;
|
||||
f->output_data.android->cursor_pixel = -1;
|
||||
f->output_data.android->cursor_foreground_pixel = -1;
|
||||
|
||||
black = build_string ("black");
|
||||
FRAME_FOREGROUND_PIXEL (f)
|
||||
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
|
||||
FRAME_BACKGROUND_PIXEL (f)
|
||||
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
|
||||
f->output_data.android->cursor_pixel
|
||||
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
|
||||
f->output_data.android->cursor_foreground_pixel
|
||||
= android_decode_color (f, black, BLACK_PIX_DEFAULT (f));
|
||||
}
|
||||
|
||||
/* Set the name; the functions to which we pass f expect the name to
|
||||
be set. */
|
||||
if (BASE_EQ (name, Qunbound) || NILP (name))
|
||||
f->explicit_name = false;
|
||||
else
|
||||
{
|
||||
fset_name (f, name);
|
||||
f->explicit_name = true;
|
||||
/* use the frame's title when getting resources for this frame. */
|
||||
specbind (Qx_resource_name, name);
|
||||
}
|
||||
|
||||
register_font_driver (&androidfont_driver, f);
|
||||
register_font_driver (&android_sfntfont_driver, f);
|
||||
|
||||
image_cache_refcount
|
||||
= FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
|
||||
#ifdef GLYPH_DEBUG
|
||||
dpyinfo_refcount = dpyinfo->reference_count;
|
||||
#endif /* GLYPH_DEBUG */
|
||||
|
||||
gui_default_parameter (f, parms, Qfont_backend, Qnil,
|
||||
"fontBackend", "FontBackend", RES_TYPE_STRING);
|
||||
|
||||
/* Extract the window parameters from the supplied values that are
|
||||
needed to determine window geometry. */
|
||||
android_default_font_parameter (f, parms);
|
||||
|
||||
gui_default_parameter (f, parms, Qborder_width, make_fixnum (0),
|
||||
"borderWidth", "BorderWidth", RES_TYPE_NUMBER);
|
||||
|
||||
/* This defaults to 1 in order to match xterm. We recognize either
|
||||
internalBorderWidth or internalBorder (which is what xterm calls
|
||||
it). */
|
||||
if (NILP (Fassq (Qinternal_border_width, parms)))
|
||||
{
|
||||
Lisp_Object value;
|
||||
|
||||
value = gui_display_get_arg (dpyinfo, parms, Qinternal_border_width,
|
||||
"internalBorder", "internalBorder",
|
||||
RES_TYPE_NUMBER);
|
||||
if (! BASE_EQ (value, Qunbound))
|
||||
parms = Fcons (Fcons (Qinternal_border_width, value),
|
||||
parms);
|
||||
}
|
||||
|
||||
gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (1),
|
||||
"internalBorderWidth", "internalBorderWidth",
|
||||
RES_TYPE_NUMBER);
|
||||
gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0),
|
||||
NULL, NULL, RES_TYPE_NUMBER);
|
||||
gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0),
|
||||
NULL, NULL, RES_TYPE_NUMBER);
|
||||
|
||||
/* Also do the stuff which must be set before the window exists. */
|
||||
gui_default_parameter (f, parms, Qforeground_color, build_string ("black"),
|
||||
"foreground", "Foreground", RES_TYPE_STRING);
|
||||
gui_default_parameter (f, parms, Qbackground_color, build_string ("white"),
|
||||
"background", "Background", RES_TYPE_STRING);
|
||||
gui_default_parameter (f, parms, Qmouse_color, build_string ("black"),
|
||||
"pointerColor", "Foreground", RES_TYPE_STRING);
|
||||
gui_default_parameter (f, parms, Qcursor_color, build_string ("black"),
|
||||
"cursorColor", "Foreground", RES_TYPE_STRING);
|
||||
gui_default_parameter (f, parms, Qborder_color, build_string ("black"),
|
||||
"borderColor", "BorderColor", RES_TYPE_STRING);
|
||||
gui_default_parameter (f, parms, Qno_special_glyphs, Qnil,
|
||||
NULL, NULL, RES_TYPE_BOOLEAN);
|
||||
|
||||
{
|
||||
struct android_set_window_attributes attrs;
|
||||
unsigned long mask;
|
||||
|
||||
block_input ();
|
||||
mask = ANDROID_CW_OVERRIDE_REDIRECT;
|
||||
|
||||
attrs.override_redirect = true;
|
||||
tip_window
|
||||
= FRAME_ANDROID_WINDOW (f)
|
||||
= android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
|
||||
/* x, y, width, height, value-mask,
|
||||
attrs. */
|
||||
0, 0, 1, 1, mask, &attrs);
|
||||
unblock_input ();
|
||||
}
|
||||
|
||||
/* Init faces before gui_default_parameter is called for the
|
||||
scroll-bar-width parameter because otherwise we end up in
|
||||
init_iterator with a null face cache, which should not happen. */
|
||||
init_frame_faces (f);
|
||||
|
||||
gui_default_parameter (f, parms, Qinhibit_double_buffering, Qnil,
|
||||
"inhibitDoubleBuffering", "InhibitDoubleBuffering",
|
||||
RES_TYPE_BOOLEAN);
|
||||
|
||||
gui_figure_window_size (f, parms, false, false);
|
||||
|
||||
f->output_data.android->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
|
||||
|
||||
android_make_gc (f);
|
||||
|
||||
gui_default_parameter (f, parms, Qauto_raise, Qnil,
|
||||
"autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
|
||||
gui_default_parameter (f, parms, Qauto_lower, Qnil,
|
||||
"autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
|
||||
gui_default_parameter (f, parms, Qcursor_type, Qbox,
|
||||
"cursorType", "CursorType", RES_TYPE_SYMBOL);
|
||||
gui_default_parameter (f, parms, Qalpha, Qnil,
|
||||
"alpha", "Alpha", RES_TYPE_NUMBER);
|
||||
gui_default_parameter (f, parms, Qalpha_background, Qnil,
|
||||
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
|
||||
|
||||
/* Add `tooltip' frame parameter's default value. */
|
||||
if (NILP (Fframe_parameter (frame, Qtooltip)))
|
||||
{
|
||||
AUTO_FRAME_ARG (arg, Qtooltip, Qt);
|
||||
Fmodify_frame_parameters (frame, arg);
|
||||
}
|
||||
|
||||
/* FIXME - can this be done in a similar way to normal frames?
|
||||
https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */
|
||||
|
||||
/* Set the `display-type' frame parameter before setting up faces. */
|
||||
{
|
||||
Lisp_Object disptype;
|
||||
|
||||
disptype = Qcolor;
|
||||
|
||||
if (NILP (Fframe_parameter (frame, Qdisplay_type)))
|
||||
{
|
||||
AUTO_FRAME_ARG (arg, Qdisplay_type, disptype);
|
||||
Fmodify_frame_parameters (frame, arg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up faces after all frame parameters are known. This call
|
||||
also merges in face attributes specified for new frames. */
|
||||
{
|
||||
Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
|
||||
|
||||
call2 (Qface_set_after_frame_default, frame, Qnil);
|
||||
|
||||
if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
|
||||
{
|
||||
AUTO_FRAME_ARG (arg, Qbackground_color, bg);
|
||||
Fmodify_frame_parameters (frame, arg);
|
||||
}
|
||||
}
|
||||
|
||||
f->no_split = true;
|
||||
|
||||
/* Now that the frame will be official, it counts as a reference to
|
||||
its display and terminal. */
|
||||
f->terminal->reference_count++;
|
||||
|
||||
/* It is now ok to make the frame official even if we get an error
|
||||
below. And the frame needs to be on Vframe_list or making it
|
||||
visible won't work. */
|
||||
Vframe_list = Fcons (frame, Vframe_list);
|
||||
f->can_set_window_size = true;
|
||||
adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
|
||||
0, true, Qtip_frame);
|
||||
|
||||
/* Setting attributes of faces of the tooltip frame from resources
|
||||
and similar will set face_change, which leads to the clearing of
|
||||
all current matrices. Since this isn't necessary here, avoid it
|
||||
by resetting face_change to the value it had before we created
|
||||
the tip frame. */
|
||||
face_change = face_change_before;
|
||||
|
||||
/* Discard the unwind_protect. */
|
||||
return unbind_to (count, frame);
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
android_hide_tip (bool delete)
|
||||
{
|
||||
if (!NILP (tip_timer))
|
||||
{
|
||||
call1 (Qcancel_timer, tip_timer);
|
||||
tip_timer = Qnil;
|
||||
}
|
||||
|
||||
if (NILP (tip_frame)
|
||||
|| (!delete
|
||||
&& !NILP (tip_frame)
|
||||
&& FRAME_LIVE_P (XFRAME (tip_frame))
|
||||
&& !FRAME_VISIBLE_P (XFRAME (tip_frame))))
|
||||
return Qnil;
|
||||
else
|
||||
{
|
||||
Lisp_Object was_open = Qnil;
|
||||
|
||||
specpdl_ref count = SPECPDL_INDEX ();
|
||||
specbind (Qinhibit_redisplay, Qt);
|
||||
specbind (Qinhibit_quit, Qt);
|
||||
|
||||
if (!NILP (tip_frame))
|
||||
{
|
||||
struct frame *f = XFRAME (tip_frame);
|
||||
|
||||
if (FRAME_LIVE_P (f))
|
||||
{
|
||||
if (delete)
|
||||
{
|
||||
delete_frame (tip_frame, Qnil);
|
||||
tip_frame = Qnil;
|
||||
}
|
||||
else
|
||||
android_make_frame_invisible (XFRAME (tip_frame));
|
||||
|
||||
was_open = Qt;
|
||||
}
|
||||
else
|
||||
tip_frame = Qnil;
|
||||
}
|
||||
else
|
||||
tip_frame = Qnil;
|
||||
|
||||
return unbind_to (count, was_open);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx,
|
||||
Lisp_Object dy, int width, int height, int *root_x,
|
||||
int *root_y)
|
||||
{
|
||||
Lisp_Object left, top, right, bottom;
|
||||
int min_x, min_y, max_x, max_y = -1;
|
||||
android_window window;
|
||||
struct frame *mouse_frame;
|
||||
|
||||
/* Initialize these values in case there is no mouse frame. */
|
||||
*root_x = 0;
|
||||
*root_y = 0;
|
||||
|
||||
/* User-specified position? */
|
||||
left = CDR (Fassq (Qleft, parms));
|
||||
top = CDR (Fassq (Qtop, parms));
|
||||
right = CDR (Fassq (Qright, parms));
|
||||
bottom = CDR (Fassq (Qbottom, parms));
|
||||
|
||||
/* Move the tooltip window where the mouse pointer was last seen.
|
||||
Resize and show it. */
|
||||
if ((!FIXNUMP (left) && !FIXNUMP (right))
|
||||
|| (!FIXNUMP (top) && !FIXNUMP (bottom)))
|
||||
{
|
||||
if (x_display_list->last_mouse_motion_frame)
|
||||
{
|
||||
*root_x = x_display_list->last_mouse_motion_x;
|
||||
*root_y = x_display_list->last_mouse_motion_y;
|
||||
mouse_frame = x_display_list->last_mouse_motion_frame;
|
||||
window = FRAME_ANDROID_WINDOW (mouse_frame);
|
||||
|
||||
/* Translate the coordinates to the screen. */
|
||||
android_translate_coordinates (window, *root_x, *root_y,
|
||||
root_x, root_y);
|
||||
}
|
||||
}
|
||||
|
||||
min_x = 0;
|
||||
min_y = 0;
|
||||
max_x = android_get_screen_width ();
|
||||
max_y = android_get_screen_height ();
|
||||
|
||||
if (FIXNUMP (top))
|
||||
*root_y = XFIXNUM (top);
|
||||
else if (FIXNUMP (bottom))
|
||||
*root_y = XFIXNUM (bottom) - height;
|
||||
else if (*root_y + XFIXNUM (dy) <= min_y)
|
||||
*root_y = min_y; /* Can happen for negative dy */
|
||||
else if (*root_y + XFIXNUM (dy) + height <= max_y)
|
||||
/* It fits below the pointer */
|
||||
*root_y += XFIXNUM (dy);
|
||||
else if (height + XFIXNUM (dy) + min_y <= *root_y)
|
||||
/* It fits above the pointer. */
|
||||
*root_y -= height + XFIXNUM (dy);
|
||||
else
|
||||
/* Put it on the top. */
|
||||
*root_y = min_y;
|
||||
|
||||
if (FIXNUMP (left))
|
||||
*root_x = XFIXNUM (left);
|
||||
else if (FIXNUMP (right))
|
||||
*root_x = XFIXNUM (right) - width;
|
||||
else if (*root_x + XFIXNUM (dx) <= min_x)
|
||||
*root_x = 0; /* Can happen for negative dx */
|
||||
else if (*root_x + XFIXNUM (dx) + width <= max_x)
|
||||
/* It fits to the right of the pointer. */
|
||||
*root_x += XFIXNUM (dx);
|
||||
else if (width + XFIXNUM (dx) + min_x <= *root_x)
|
||||
/* It fits to the left of the pointer. */
|
||||
*root_x -= width + XFIXNUM (dx);
|
||||
else
|
||||
/* Put it left justified on the screen -- it ought to fit that way. */
|
||||
*root_x = min_x;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
|
||||
doc: /* SKIP: real doc in xfns.c. */)
|
||||
(Lisp_Object string, Lisp_Object frame, Lisp_Object parms,
|
||||
|
|
@ -1670,8 +2087,214 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
|
|||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
/* TODO tooltips */
|
||||
return Qnil;
|
||||
struct frame *f, *tip_f;
|
||||
struct window *w;
|
||||
int root_x, root_y;
|
||||
struct buffer *old_buffer;
|
||||
struct text_pos pos;
|
||||
int width, height;
|
||||
int old_windows_or_buffers_changed = windows_or_buffers_changed;
|
||||
specpdl_ref count = SPECPDL_INDEX ();
|
||||
Lisp_Object window, size, tip_buf;
|
||||
bool displayed;
|
||||
#ifdef ENABLE_CHECKING
|
||||
struct glyph_row *row, *end;
|
||||
#endif
|
||||
AUTO_STRING (tip, " *tip*");
|
||||
|
||||
specbind (Qinhibit_redisplay, Qt);
|
||||
|
||||
CHECK_STRING (string);
|
||||
if (SCHARS (string) == 0)
|
||||
string = make_unibyte_string (" ", 1);
|
||||
|
||||
if (NILP (frame))
|
||||
frame = selected_frame;
|
||||
f = decode_window_system_frame (frame);
|
||||
|
||||
if (NILP (timeout))
|
||||
timeout = Vx_show_tooltip_timeout;
|
||||
CHECK_FIXNAT (timeout);
|
||||
|
||||
if (NILP (dx))
|
||||
dx = make_fixnum (5);
|
||||
else
|
||||
CHECK_FIXNUM (dx);
|
||||
|
||||
if (NILP (dy))
|
||||
dy = make_fixnum (-10);
|
||||
else
|
||||
CHECK_FIXNUM (dy);
|
||||
|
||||
tip_dx = dx;
|
||||
tip_dy = dy;
|
||||
|
||||
if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
|
||||
{
|
||||
if (FRAME_VISIBLE_P (XFRAME (tip_frame))
|
||||
&& !NILP (Fequal_including_properties (tip_last_string,
|
||||
string))
|
||||
&& !NILP (Fequal (tip_last_parms, parms)))
|
||||
{
|
||||
/* Only DX and DY have changed. */
|
||||
tip_f = XFRAME (tip_frame);
|
||||
if (!NILP (tip_timer))
|
||||
{
|
||||
call1 (Qcancel_timer, tip_timer);
|
||||
tip_timer = Qnil;
|
||||
}
|
||||
|
||||
block_input ();
|
||||
compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
|
||||
FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
|
||||
android_move_window (FRAME_ANDROID_WINDOW (tip_f),
|
||||
root_x, root_y);
|
||||
unblock_input ();
|
||||
|
||||
goto start_timer;
|
||||
}
|
||||
else
|
||||
android_hide_tip (true);
|
||||
}
|
||||
else
|
||||
android_hide_tip (true);
|
||||
|
||||
tip_last_frame = frame;
|
||||
tip_last_string = string;
|
||||
tip_last_parms = parms;
|
||||
|
||||
if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
|
||||
{
|
||||
/* Add default values to frame parameters. */
|
||||
if (NILP (Fassq (Qname, parms)))
|
||||
parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
|
||||
if (NILP (Fassq (Qinternal_border_width, parms)))
|
||||
parms = Fcons (Fcons (Qinternal_border_width, make_fixnum (3)),
|
||||
parms);
|
||||
if (NILP (Fassq (Qborder_width, parms)))
|
||||
parms = Fcons (Fcons (Qborder_width, make_fixnum (1)), parms);
|
||||
if (NILP (Fassq (Qborder_color, parms)))
|
||||
parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")),
|
||||
parms);
|
||||
if (NILP (Fassq (Qbackground_color, parms)))
|
||||
parms = Fcons (Fcons (Qbackground_color,
|
||||
build_string ("lightyellow")),
|
||||
parms);
|
||||
|
||||
/* Create a frame for the tooltip, and record it in the global
|
||||
variable tip_frame. */
|
||||
if (NILP (tip_frame = android_create_tip_frame (FRAME_DISPLAY_INFO (f),
|
||||
parms)))
|
||||
/* Creating the tip frame failed. */
|
||||
return unbind_to (count, Qnil);
|
||||
}
|
||||
|
||||
tip_f = XFRAME (tip_frame);
|
||||
window = FRAME_ROOT_WINDOW (tip_f);
|
||||
tip_buf = Fget_buffer_create (tip, Qnil);
|
||||
/* We will mark the tip window a "pseudo-window" below, and such
|
||||
windows cannot have display margins. */
|
||||
bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
|
||||
bset_right_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
|
||||
set_window_buffer (window, tip_buf, false, false);
|
||||
w = XWINDOW (window);
|
||||
w->pseudo_window_p = true;
|
||||
/* Try to avoid that `other-window' select us (Bug#47207). */
|
||||
Fset_window_parameter (window, Qno_other_window, Qt);
|
||||
|
||||
/* Set up the frame's root window. Note: The following code does not
|
||||
try to size the window or its frame correctly. Its only purpose is
|
||||
to make the subsequent text size calculations work. The right
|
||||
sizes should get installed when the toolkit gets back to us. */
|
||||
w->left_col = 0;
|
||||
w->top_line = 0;
|
||||
w->pixel_left = 0;
|
||||
w->pixel_top = 0;
|
||||
|
||||
if (CONSP (Vx_max_tooltip_size)
|
||||
&& RANGED_FIXNUMP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
|
||||
&& RANGED_FIXNUMP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
|
||||
{
|
||||
w->total_cols = XFIXNAT (XCAR (Vx_max_tooltip_size));
|
||||
w->total_lines = XFIXNAT (XCDR (Vx_max_tooltip_size));
|
||||
}
|
||||
else
|
||||
{
|
||||
w->total_cols = 80;
|
||||
w->total_lines = 40;
|
||||
}
|
||||
|
||||
w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
|
||||
w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
|
||||
FRAME_TOTAL_COLS (tip_f) = w->total_cols;
|
||||
adjust_frame_glyphs (tip_f);
|
||||
|
||||
/* Insert STRING into root window's buffer and fit the frame to the
|
||||
buffer. */
|
||||
specpdl_ref count_1 = SPECPDL_INDEX ();
|
||||
old_buffer = current_buffer;
|
||||
set_buffer_internal_1 (XBUFFER (w->contents));
|
||||
bset_truncate_lines (current_buffer, Qnil);
|
||||
specbind (Qinhibit_read_only, Qt);
|
||||
specbind (Qinhibit_modification_hooks, Qt);
|
||||
specbind (Qinhibit_point_motion_hooks, Qt);
|
||||
Ferase_buffer ();
|
||||
Finsert (1, &string);
|
||||
clear_glyph_matrix (w->desired_matrix);
|
||||
clear_glyph_matrix (w->current_matrix);
|
||||
SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
|
||||
displayed = try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
|
||||
|
||||
if (!displayed && NILP (Vx_max_tooltip_size))
|
||||
{
|
||||
#ifdef ENABLE_CHECKING
|
||||
row = w->desired_matrix->rows;
|
||||
end = w->desired_matrix->rows + w->desired_matrix->nrows;
|
||||
|
||||
while (row < end)
|
||||
{
|
||||
if (!row->displays_text_p
|
||||
|| row->ends_at_zv_p)
|
||||
break;
|
||||
++row;
|
||||
}
|
||||
|
||||
eassert (row < end && row->ends_at_zv_p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Calculate size of tooltip window. */
|
||||
size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
|
||||
make_fixnum (w->pixel_height), Qnil,
|
||||
Qnil);
|
||||
/* Add the frame's internal border to calculated size. */
|
||||
width = XFIXNUM (CAR (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
|
||||
height = XFIXNUM (CDR (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
|
||||
|
||||
/* Calculate position of tooltip frame. */
|
||||
compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
|
||||
|
||||
/* Show tooltip frame. */
|
||||
block_input ();
|
||||
android_move_resize_window (FRAME_ANDROID_WINDOW (tip_f),
|
||||
root_x, root_y, width,
|
||||
height);
|
||||
android_map_raised (FRAME_ANDROID_WINDOW (tip_f));
|
||||
unblock_input ();
|
||||
|
||||
w->must_be_updated_p = true;
|
||||
update_single_window (w);
|
||||
flush_frame (tip_f);
|
||||
set_buffer_internal_1 (old_buffer);
|
||||
unbind_to (count_1, Qnil);
|
||||
windows_or_buffers_changed = old_windows_or_buffers_changed;
|
||||
|
||||
start_timer:
|
||||
/* Let the tip disappear after timeout seconds. */
|
||||
tip_timer = call3 (Qrun_at_time, timeout, Qnil,
|
||||
Qx_hide_tip);
|
||||
|
||||
return unbind_to (count, Qnil);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1683,7 +2306,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
|
|||
error ("Android cross-compilation stub called!");
|
||||
return Qnil;
|
||||
#else
|
||||
return Qnil;
|
||||
return android_hide_tip (true);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -2112,6 +2735,17 @@ syms_of_androidfns (void)
|
|||
doc: /* SKIP: real doc in xfns.c. */);
|
||||
Vx_cursor_fore_pixel = Qnil;
|
||||
|
||||
/* Used by Fx_show_tip. */
|
||||
DEFSYM (Qrun_at_time, "run-at-time");
|
||||
DEFSYM (Qx_hide_tip, "x-hide-tip");
|
||||
DEFSYM (Qcancel_timer, "cancel-timer");
|
||||
DEFSYM (Qassq_delete_all, "assq-delete-all");
|
||||
DEFSYM (Qcolor, "color");
|
||||
|
||||
DEFVAR_LISP ("x-max-tooltip-size", Vx_max_tooltip_size,
|
||||
doc: /* SKIP: real doc in xfns.c. */);
|
||||
Vx_max_tooltip_size = Qnil;
|
||||
|
||||
/* Functions defined. */
|
||||
defsubr (&Sx_create_frame);
|
||||
defsubr (&Sxw_color_defined_p);
|
||||
|
|
@ -2139,4 +2773,21 @@ syms_of_androidfns (void)
|
|||
defsubr (&Sx_show_tip);
|
||||
defsubr (&Sx_hide_tip);
|
||||
defsubr (&Sandroid_detect_mouse);
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
tip_timer = Qnil;
|
||||
staticpro (&tip_timer);
|
||||
tip_frame = Qnil;
|
||||
staticpro (&tip_frame);
|
||||
tip_last_frame = Qnil;
|
||||
staticpro (&tip_last_frame);
|
||||
tip_last_string = Qnil;
|
||||
staticpro (&tip_last_string);
|
||||
tip_last_parms = Qnil;
|
||||
staticpro (&tip_last_parms);
|
||||
tip_dx = Qnil;
|
||||
staticpro (&tip_dx);
|
||||
tip_dy = Qnil;
|
||||
staticpro (&tip_dy);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,12 +81,17 @@ enum android_fill_style
|
|||
enum android_window_value_mask
|
||||
{
|
||||
ANDROID_CW_BACK_PIXEL = (1 << 1),
|
||||
ANDROID_CW_OVERRIDE_REDIRECT = (1 << 2),
|
||||
};
|
||||
|
||||
struct android_set_window_attributes
|
||||
{
|
||||
/* The background pixel. */
|
||||
unsigned long background_pixel;
|
||||
|
||||
/* Whether or not the window is override redirect. This cannot be
|
||||
set after creation on Android. */
|
||||
bool override_redirect;
|
||||
};
|
||||
|
||||
struct android_gc_values
|
||||
|
|
@ -260,7 +265,7 @@ struct android_key_event
|
|||
((key) == 57 || (key) == 58 || (key) == 113 || (key) == 114 \
|
||||
|| (key) == 119 || (key) == 117 || (key) == 118 || (key) == 78 \
|
||||
|| (key) == 94 || (key) == 59 || (key) == 60 || (key) == 95 \
|
||||
|| (key) == 63)
|
||||
|| (key) == 63 || (key) == 115)
|
||||
|
||||
struct android_configure_event
|
||||
{
|
||||
|
|
@ -478,6 +483,11 @@ extern int android_query_tree (android_window, android_window *,
|
|||
extern void android_get_geometry (android_window, android_window *,
|
||||
int *, int *, unsigned int *,
|
||||
unsigned int *, unsigned int *);
|
||||
extern void android_move_resize_window (android_window, int, int,
|
||||
unsigned int, unsigned int);
|
||||
extern void android_map_raised (android_window);
|
||||
extern void android_translate_coordinates (android_window, int,
|
||||
int, int *, int *);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
|
||||
#include "lisp.h"
|
||||
#include "androidterm.h"
|
||||
#include "android.h"
|
||||
#include "blockinput.h"
|
||||
#include "keyboard.h"
|
||||
#include "menu.h"
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
|
|
@ -35,4 +39,293 @@ popup_activated (void)
|
|||
return popup_activated_flag;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Toolkit menu implementation. */
|
||||
|
||||
/* Structure describing the EmacsContextMenu class. */
|
||||
|
||||
struct android_emacs_context_menu
|
||||
{
|
||||
jclass class;
|
||||
jmethodID create_context_menu;
|
||||
jmethodID add_item;
|
||||
jmethodID add_submenu;
|
||||
jmethodID add_pane;
|
||||
jmethodID parent;
|
||||
jmethodID display;
|
||||
};
|
||||
|
||||
/* Identifiers associated with the EmacsContextMenu class. */
|
||||
static struct android_emacs_context_menu menu_class;
|
||||
|
||||
static void
|
||||
android_init_emacs_context_menu (void)
|
||||
{
|
||||
jclass old;
|
||||
|
||||
menu_class.class
|
||||
= (*android_java_env)->FindClass (android_java_env,
|
||||
"org/gnu/emacs/EmacsContextMenu");
|
||||
eassert (menu_class.class);
|
||||
|
||||
old = menu_class.class;
|
||||
menu_class.class
|
||||
= (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
|
||||
(jobject) old);
|
||||
ANDROID_DELETE_LOCAL_REF (old);
|
||||
|
||||
if (!menu_class.class)
|
||||
emacs_abort ();
|
||||
|
||||
#define FIND_METHOD(c_name, name, signature) \
|
||||
menu_class.c_name \
|
||||
= (*android_java_env)->GetMethodID (android_java_env, \
|
||||
menu_class.class, \
|
||||
name, signature); \
|
||||
eassert (menu_class.c_name);
|
||||
|
||||
#define FIND_METHOD_STATIC(c_name, name, signature) \
|
||||
menu_class.c_name \
|
||||
= (*android_java_env)->GetStaticMethodID (android_java_env, \
|
||||
menu_class.class, \
|
||||
name, signature); \
|
||||
eassert (menu_class.c_name);
|
||||
|
||||
FIND_METHOD_STATIC (create_context_menu, "createContextMenu",
|
||||
"(Ljava/lang/String;)Lorg/gnu/emacs/EmacsContextMenu;");
|
||||
|
||||
FIND_METHOD (add_item, "addItem", "(ILjava/lang/String;Z)V");
|
||||
FIND_METHOD (add_submenu, "addSubmenu", "(Ljava/lang/String;"
|
||||
"Ljava/lang/String;)Lorg/gnu/emacs/EmacsContextMenu;");
|
||||
FIND_METHOD (add_pane, "addPane", "(Ljava/lang/String;)V");
|
||||
FIND_METHOD (parent, "parent", "()Lorg/gnu/emacs/EmacsContextMenu;");
|
||||
FIND_METHOD (display, "display", "(Lorg/gnu/emacs/EmacsWindow;II)Z");
|
||||
|
||||
#undef FIND_METHOD
|
||||
#undef FIND_METHOD_STATIC
|
||||
}
|
||||
|
||||
static void
|
||||
android_unwind_local_frame (void)
|
||||
{
|
||||
(*android_java_env)->PopLocalFrame (android_java_env, NULL);
|
||||
}
|
||||
|
||||
/* Push a local reference frame to the JVM stack and record it on the
|
||||
specpdl. Release local references created within that frame when
|
||||
the specpdl is unwound past where it is after returning. */
|
||||
|
||||
static void
|
||||
android_push_local_frame (void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = (*android_java_env)->PushLocalFrame (android_java_env, 30);
|
||||
|
||||
/* This means the JVM ran out of memory. */
|
||||
if (rc < 1)
|
||||
android_exception_check ();
|
||||
|
||||
record_unwind_protect_void (android_unwind_local_frame);
|
||||
}
|
||||
|
||||
Lisp_Object
|
||||
android_menu_show (struct frame *f, int x, int y, int menuflags,
|
||||
Lisp_Object title, const char **error_name)
|
||||
{
|
||||
jobject context_menu, current_context_menu;
|
||||
jobject title_string, temp;
|
||||
size_t i;
|
||||
Lisp_Object pane_name, prefix;
|
||||
const char *pane_string;
|
||||
specpdl_ref count, count1;
|
||||
Lisp_Object item_name, enable, def;
|
||||
jmethodID method;
|
||||
jobject store;
|
||||
bool rc;
|
||||
jobject window;
|
||||
|
||||
count = SPECPDL_INDEX ();
|
||||
|
||||
block_input ();
|
||||
|
||||
/* Push the first local frame. */
|
||||
android_push_local_frame ();
|
||||
|
||||
/* Push the first local frame for the context menu. */
|
||||
title_string = (!NILP (title)
|
||||
? (jobject) android_build_string (title)
|
||||
: NULL);
|
||||
method = menu_class.create_context_menu;
|
||||
current_context_menu = context_menu
|
||||
= (*android_java_env)->CallStaticObjectMethod (android_java_env,
|
||||
menu_class.class,
|
||||
method,
|
||||
title_string);
|
||||
|
||||
if (title_string)
|
||||
ANDROID_DELETE_LOCAL_REF (title_string);
|
||||
|
||||
/* Push the second local frame for temporaries. */
|
||||
count1 = SPECPDL_INDEX ();
|
||||
android_push_local_frame ();
|
||||
|
||||
/* Iterate over the menu. */
|
||||
i = 0;
|
||||
|
||||
while (i < menu_items_used)
|
||||
{
|
||||
if (NILP (AREF (menu_items, i)))
|
||||
{
|
||||
/* This is the start of a new submenu. However, it can be
|
||||
ignored here. */
|
||||
i += 1;
|
||||
}
|
||||
else if (EQ (AREF (menu_items, i), Qlambda))
|
||||
{
|
||||
/* This is the end of a submenu. Go back to the previous
|
||||
context menu. */
|
||||
store = current_context_menu;
|
||||
current_context_menu
|
||||
= (*android_java_env)->CallObjectMethod (android_java_env,
|
||||
current_context_menu,
|
||||
menu_class.parent);
|
||||
android_exception_check ();
|
||||
|
||||
if (store != context_menu)
|
||||
ANDROID_DELETE_LOCAL_REF (store);
|
||||
i += 1;
|
||||
|
||||
eassert (current_context_menu);
|
||||
}
|
||||
else if (EQ (AREF (menu_items, i), Qquote))
|
||||
i += 1;
|
||||
else if (EQ (AREF (menu_items, i), Qt))
|
||||
{
|
||||
/* This is a new pane. Switch back to the topmost context
|
||||
menu. */
|
||||
if (current_context_menu != context_menu)
|
||||
ANDROID_DELETE_LOCAL_REF (current_context_menu);
|
||||
current_context_menu = context_menu;
|
||||
|
||||
/* Now figure out the title of this pane. */
|
||||
pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
|
||||
prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
|
||||
pane_string = (NILP (pane_name)
|
||||
? "" : SSDATA (pane_name));
|
||||
if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
|
||||
pane_string++;
|
||||
|
||||
/* Add the pane. */
|
||||
temp = (*android_java_env)->NewStringUTF (android_java_env,
|
||||
pane_string);
|
||||
android_exception_check ();
|
||||
|
||||
(*android_java_env)->CallVoidMethod (android_java_env,
|
||||
current_context_menu,
|
||||
menu_class.add_pane,
|
||||
temp);
|
||||
android_exception_check ();
|
||||
ANDROID_DELETE_LOCAL_REF (temp);
|
||||
|
||||
i += MENU_ITEMS_PANE_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
|
||||
enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
|
||||
def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
|
||||
|
||||
/* This is an actual menu item (or submenu). Add it to the
|
||||
menu. */
|
||||
|
||||
if (i + MENU_ITEMS_ITEM_LENGTH < menu_items_used &&
|
||||
NILP (AREF (menu_items, i + MENU_ITEMS_ITEM_LENGTH)))
|
||||
{
|
||||
/* This is a submenu. Add it. */
|
||||
title_string = (!NILP (item_name)
|
||||
? android_build_string (item_name)
|
||||
: NULL);
|
||||
store = current_context_menu;
|
||||
current_context_menu
|
||||
= (*android_java_env)->CallObjectMethod (android_java_env,
|
||||
current_context_menu,
|
||||
menu_class.add_submenu,
|
||||
title_string);
|
||||
android_exception_check ();
|
||||
|
||||
if (store != context_menu)
|
||||
ANDROID_DELETE_LOCAL_REF (store);
|
||||
|
||||
if (title_string)
|
||||
ANDROID_DELETE_LOCAL_REF (title_string);
|
||||
}
|
||||
else if (NILP (def) && menu_separator_name_p (SSDATA (item_name)))
|
||||
/* Ignore this separator item. */
|
||||
;
|
||||
else
|
||||
{
|
||||
/* Add this menu item with the appropriate state. */
|
||||
|
||||
title_string = (!NILP (item_name)
|
||||
? android_build_string (item_name)
|
||||
: NULL);
|
||||
(*android_java_env)->CallVoidMethod (android_java_env,
|
||||
current_context_menu,
|
||||
menu_class.add_item,
|
||||
(jint) 1,
|
||||
title_string,
|
||||
(jboolean) !NILP (enable));
|
||||
android_exception_check ();
|
||||
|
||||
if (title_string)
|
||||
ANDROID_DELETE_LOCAL_REF (title_string);
|
||||
}
|
||||
|
||||
i += MENU_ITEMS_ITEM_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
/* The menu has now been built. Pop the second local frame. */
|
||||
unbind_to (count1, Qnil);
|
||||
|
||||
/* Now, display the context menu. */
|
||||
window = android_resolve_handle (FRAME_ANDROID_WINDOW (f),
|
||||
ANDROID_HANDLE_WINDOW);
|
||||
rc = (*android_java_env)->CallBooleanMethod (android_java_env,
|
||||
context_menu,
|
||||
window, (jint) x,
|
||||
(jint) y);
|
||||
android_exception_check ();
|
||||
|
||||
if (!rc)
|
||||
/* This means displaying the menu failed. */
|
||||
goto finish;
|
||||
|
||||
#if 0
|
||||
record_unwind_protect_ptr (android_dismiss_menu, &context_menu);
|
||||
|
||||
/* Otherwise, loop waiting for the menu event to arrive. */
|
||||
android_process_events_for_menu (&id);
|
||||
|
||||
if (!id)
|
||||
/* This means no menu item was selected. */
|
||||
goto finish;
|
||||
|
||||
#endif
|
||||
|
||||
finish:
|
||||
unblock_input ();
|
||||
return unbind_to (count, Qnil);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
init_androidmenu (void)
|
||||
{
|
||||
#ifndef ANDROID_STUBIFY
|
||||
android_init_emacs_context_menu ();
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -559,6 +559,9 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
|||
f = android_window_to_frame (dpyinfo,
|
||||
configureEvent.xconfigure.window);
|
||||
|
||||
if (!f)
|
||||
goto OTHER;
|
||||
|
||||
int width = configureEvent.xconfigure.width;
|
||||
int height = configureEvent.xconfigure.height;
|
||||
|
||||
|
|
@ -884,10 +887,6 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
|||
inev.ie.arg = tab_bar_arg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: scroll bars */
|
||||
}
|
||||
|
||||
if (event->type == ANDROID_BUTTON_PRESS)
|
||||
{
|
||||
|
|
@ -1451,7 +1450,12 @@ android_make_frame_visible_invisible (struct frame *f, bool visible)
|
|||
static void
|
||||
android_fullscreen_hook (struct frame *f)
|
||||
{
|
||||
/* TODO */
|
||||
/* Explicitly setting fullscreen is not supported on Android. */
|
||||
|
||||
if (!FRAME_PARENT_FRAME (f))
|
||||
store_frame_param (f, Qfullscreen, Qmaximized);
|
||||
else
|
||||
store_frame_param (f, Qfullscreen, Qnil);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2360,7 +2364,7 @@ android_draw_box_rect (struct glyph_string *s,
|
|||
|
||||
/* Top. */
|
||||
android_fill_rectangle (FRAME_ANDROID_DRAWABLE (s->f), s->gc, left_x,
|
||||
left_x, right_x - left_x + 1, hwidth);
|
||||
top_y, right_x - left_x + 1, hwidth);
|
||||
|
||||
/* Left. */
|
||||
if (left_p)
|
||||
|
|
@ -3958,7 +3962,14 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
|
|||
char *
|
||||
get_keysym_name (int keysym)
|
||||
{
|
||||
return (char *) "UNKNOWN KEYSYM";
|
||||
static char buffer[64];
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
android_get_keysym_name (keysym, buffer, 64);
|
||||
#else
|
||||
emacs_abort ();
|
||||
#endif
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -4009,20 +4020,13 @@ android_create_terminal (struct android_display_info *dpyinfo)
|
|||
terminal->set_new_font_hook = android_new_font;
|
||||
terminal->set_bitmap_icon_hook = android_bitmap_icon;
|
||||
terminal->implicit_set_name_hook = android_implicitly_set_name;
|
||||
/* terminal->menu_show_hook = android_menu_show; XXX */
|
||||
terminal->menu_show_hook = android_menu_show;
|
||||
terminal->change_tab_bar_height_hook = android_change_tab_bar_height;
|
||||
terminal->change_tool_bar_height_hook = android_change_tool_bar_height;
|
||||
/* terminal->set_vertical_scroll_bar_hook */
|
||||
/* = android_set_vertical_scroll_bar; */
|
||||
/* terminal->set_horizontal_scroll_bar_hook */
|
||||
/* = android_set_horizontal_scroll_bar; */
|
||||
terminal->set_scroll_bar_default_width_hook
|
||||
= android_set_scroll_bar_default_width;
|
||||
terminal->set_scroll_bar_default_height_hook
|
||||
= android_set_scroll_bar_default_height;
|
||||
/* terminal->condemn_scroll_bars_hook = android_condemn_scroll_bars; */
|
||||
/* terminal->redeem_scroll_bars_hook = android_redeem_scroll_bars; */
|
||||
/* terminal->judge_scroll_bars_hook = android_judge_scroll_bars; */
|
||||
terminal->free_pixmap = android_free_pixmap_hook;
|
||||
terminal->delete_frame_hook = android_delete_frame;
|
||||
terminal->delete_terminal_hook = android_delete_terminal;
|
||||
|
|
|
|||
|
|
@ -402,6 +402,12 @@ extern void syms_of_androidfont (void);
|
|||
|
||||
extern void android_finalize_font_entity (struct font_entity *);
|
||||
|
||||
/* Defined in androidmenu.c. */
|
||||
|
||||
extern Lisp_Object android_menu_show (struct frame *, int, int, int,
|
||||
Lisp_Object, const char **);
|
||||
extern void init_androidmenu (void);
|
||||
|
||||
/* Defined in sfntfont-android.c. */
|
||||
|
||||
extern const struct font_driver android_sfntfont_driver;
|
||||
|
|
|
|||
|
|
@ -2499,6 +2499,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
|
|||
init_window ();
|
||||
init_font ();
|
||||
|
||||
#ifdef HAVE_ANDROID
|
||||
init_androidmenu ();
|
||||
#endif
|
||||
|
||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||
init_androidfont ();
|
||||
init_sfntfont ();
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ lib/libgnu.a: src/verbose.mk config.status $(LIB_DEPS) $(PRE_BUILD_DEPS)
|
|||
+make -C lib libgnu.a
|
||||
|
||||
src/Makefile src/config.h &: $(top_builddir)/src/config.h.android \
|
||||
$(top_builddir)/src/Makefile.android $(PRE_BUILD_DEPS)
|
||||
$(top_builddir)/src/Makefile.android
|
||||
mkdir -p src src/deps
|
||||
# Copy config.h to src/
|
||||
cp -f -p $(top_builddir)/src/config.h.android src/config.h
|
||||
|
|
@ -155,13 +155,20 @@ $(LIBSRC_BINARIES) &: src/verbose.mk $(top_builddir)/$@ lib/libgnu.a \
|
|||
# Finally, go into lib-src and make everything being built
|
||||
+make -C lib-src $(foreach bin,$(LIBSRC_BINARIES),$(notdir $(bin)))
|
||||
|
||||
.PHONY: clean maintainer-clean
|
||||
.PHONY: clean maintainer-clean distclean
|
||||
clean:
|
||||
rm -rf $(CLEAN_SUBDIRS) *.bak sys
|
||||
if [ -e lib/Makefile ]; then \
|
||||
make -C lib clean; \
|
||||
fi
|
||||
rm -rf lib/gnulib.mk lib/Makefile lib/config.h
|
||||
rm -rf lib/config.h
|
||||
|
||||
distclean bootstrap-clean: clean
|
||||
if [ -e lib/Makefile ]; then \
|
||||
make -C lib distclean; \
|
||||
fi
|
||||
# Just in case.
|
||||
rm -rf lib/Makefile lib/gnulib.mk
|
||||
|
||||
maintainer-clean: clean
|
||||
if [ -e lib/Makefile ]; then \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue