From fa821ed18639aa1b0275c2938af9987c0c71b581 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 17 Jun 2023 11:24:54 +0800 Subject: [PATCH] ; * java/README: More documentation. --- java/README | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/java/README b/java/README index 96271279c28..a6adb805b9e 100644 --- a/java/README +++ b/java/README @@ -906,3 +906,144 @@ of memory. Otherwise, it applies the specified window attributes and returns the handle of the new window. } + + + +DRAWABLES, CURSORS AND HANDLES + +Each widget created by Emacs corresponds to a single ``window'', which +has its own backing store. This arrangement is quite similar to X. + +C code does not directly refer to the EmacsView widgets that implement +the UI logic behind windows. Instead, its handles refer to +EmacsWindow structures, which contain the state necessary to interact +with the widgets in an orderly and synchronized manner. + +Like X, both pixmaps and windows are drawable resources, and the same +graphics operations can be applied to both. Thus, a separate +EmacsPixmap structure is used to wrap around Android Bitmap resources, +and the Java-level graphics operation functions are capable of +operating on them both. + +Finally, graphics contexts are maintained on both the C and Java +levels; the C state recorded in `struct android_gc' is kept in sync +with the Java state in the GContext handle's corresponding EmacsGC +structure, and cursors are used through handles that refer to +EmacsCursor structures that hold system PointerIcons. + +In all cases, the interfaces provided are identical to X. + + + +EVENT LOOP + +In a typical Android application, the event loop is managed by the +operating system, and callbacks (implemented through overriding +separate functions in widgets) are run by the event loop wherever +necessary. The thread which runs the event loop is also the only +thread capable of creating and manipulating widgets and activities, +and is referred to as the ``UI thread''. + +These callbacks are used by Emacs to write representations of X-like +events to a separate event queue, which are then read from Emacs's own +event loop running in a separate thread. This is accomplished through +replacing `select' by a function which waits for the event queue to be +occupied, in addition to any file descriptors that `select' would +normally wait for. + +Conversely, Emacs's event loop sometimes needs to send events to the +UI thread. These events are implemented as tiny fragments of code, +which are run as they are received by the main thread. + +A typical example is `displayToast', which is implemented in +EmacsService.java: + + public void + displayToast (final String string) + { + runOnUiThread (new Runnable () { + @Override + public void + run () + { + Toast toast; + + toast = Toast.makeText (getApplicationContext (), + string, Toast.LENGTH_SHORT); + toast.show (); + } + }); + } + +Here, the variable `string' is used by a nested function. This nested +function contains a copy of that variable, and is run on the main +thread using the function `runOnUiThread', in order to display a short +status message on the display. + +When Emacs needs to wait for the nested function to finish, it uses a +mechanism implemented in `syncRunnable'. This mechanism first calls a +deadlock avoidance mechanism, then runs a nested function on the UI +thread, which is expected to signal itself as a condition variable +upon completion. It is typically used to allocate resources that can +only be allocated from the UI thread, or to obtain non-thread-safe +information. The following function is an example; it returns a new +EmacsView widget corresponding to the provided window: + + public EmacsView + getEmacsView (final EmacsWindow window, final int visibility, + final boolean isFocusedByDefault) + { + Runnable runnable; + final EmacsHolder view; + + view = new EmacsHolder (); + + runnable = new Runnable () { + public void + run () + { + synchronized (this) + { + view.thing = new EmacsView (window); + view.thing.setVisibility (visibility); + + /* The following function is only present on Android 26 + or later. */ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + view.thing.setFocusedByDefault (isFocusedByDefault); + + notify (); + } + } + }; + + syncRunnable (runnable); + return view.thing; + } + +As no value can be directly returned from the nested function, a +separate container object is used to hold the result after the +function finishes execution. Note the type name inside the angle +brackets: this type is substituted into the class definition as it is +used; a definition such as: + +public class Foo +{ + T bar; +}; + +can not be used alone: + + Foo holder; /* Error! */ + +but must have a type specified: + + Foo holder; + +in which case the effective definition is: + +public class Foo +{ + Object bar; +}; + -- 2.39.2