Initial import
|
@ -0,0 +1,2 @@
|
|||
bin/**
|
||||
gen/**
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="tdm.xserver"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<!-- We need SDK v10 (v2.3.x) for android.view.InputDevice -->
|
||||
<uses-sdk android:minSdkVersion="10" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application android:label="@string/app_name" android:icon="@drawable/icon">
|
||||
<activity android:name="XServer"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
|
@ -0,0 +1,17 @@
|
|||
# This file is used to override default values used by the Ant build system.
|
||||
#
|
||||
# This file must be checked in Version Control Systems, as it is
|
||||
# integral to the build system of your project.
|
||||
|
||||
# This file is only used by the Ant script.
|
||||
|
||||
# You can use this to override default values such as
|
||||
# 'source.dir' for the location of your java source folder and
|
||||
# 'out.dir' for the location of your output folder.
|
||||
|
||||
# You can also use it define how the release builds are signed by declaring
|
||||
# the following properties:
|
||||
# 'key.store' for the location of your keystore and
|
||||
# 'key.alias' for the name of the key to use.
|
||||
# The password will be asked during the build when you use the 'release' target.
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="XServer" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
|
||||
<!-- extension targets. Uncomment the ones where you want to do custom work
|
||||
in between standard targets -->
|
||||
<!--
|
||||
<target name="-pre-build">
|
||||
</target>
|
||||
<target name="-pre-compile">
|
||||
</target>
|
||||
|
||||
/* This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir} */
|
||||
<target name="-post-compile">
|
||||
</target>
|
||||
-->
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
</AbsoluteLayout>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
-optimizationpasses 5
|
||||
-dontusemixedcaseclassnames
|
||||
-dontskipnonpubliclibraryclasses
|
||||
-dontpreverify
|
||||
-verbose
|
||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||
-keep public class * extends android.preference.Preference
|
||||
-keep public class com.android.vending.licensing.ILicensingService
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keepclassmembers class * extends android.app.Activity {
|
||||
public void *(android.view.View);
|
||||
}
|
||||
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-10
|
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/menu_save"
|
||||
android:icon="@drawable/ic_menu_save"
|
||||
android:alphabeticShortcut='s'
|
||||
android:title="@string/menu_save" />
|
||||
<group android:id="@+id/menu_group_edit">
|
||||
<item android:id="@+id/menu_revert"
|
||||
android:icon="@drawable/ic_menu_revert"
|
||||
android:title="@string/menu_revert" />
|
||||
<item android:id="@+id/menu_delete"
|
||||
android:icon="@drawable/ic_menu_delete"
|
||||
android:title="@string/menu_delete" />
|
||||
</group>
|
||||
<group android:id="@+id/menu_group_insert">
|
||||
<item android:id="@+id/menu_discard"
|
||||
android:icon="@drawable/ic_menu_discard"
|
||||
android:title="@string/menu_discard" />
|
||||
</group>
|
||||
</menu>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">XServer</string>
|
||||
|
||||
<string name="menu_save">Save</string>
|
||||
<string name="menu_delete">Delete</string>
|
||||
<string name="menu_revert">Revert changes</string>
|
||||
<string name="menu_discard">Discard</string>
|
||||
</resources>
|
|
@ -0,0 +1,152 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
class ByteQueue
|
||||
{
|
||||
ByteBuffer mData;
|
||||
|
||||
ByteQueue() {
|
||||
mData = ByteBuffer.allocate(1);
|
||||
}
|
||||
ByteQueue(int len) {
|
||||
mData = ByteBuffer.allocate(len);
|
||||
mData.limit(0);
|
||||
}
|
||||
ByteQueue(byte[] src, int pos, int len) {
|
||||
mData = ByteBuffer.allocate(len);
|
||||
mData.put(src, pos, len);
|
||||
mData.position(0);
|
||||
}
|
||||
ByteQueue(byte[] src) {
|
||||
mData = ByteBuffer.allocate(src.length);
|
||||
mData.put(src);
|
||||
mData.position(0);
|
||||
}
|
||||
|
||||
void dump() {
|
||||
Log.e(XServer.TAG, "ByteQueue.dump: limit=" + mData.limit() +
|
||||
", capacity=" + mData.capacity() + ", pos=" + mData.position());
|
||||
StringBuffer hexbuf = new StringBuffer();
|
||||
int x, y;
|
||||
for (y = 0; y < mData.limit(); y += 16) {
|
||||
hexbuf.append(String.format("%04x: ", y));
|
||||
for (x = 0; x < 15 && y+x < mData.limit(); ++x) {
|
||||
if (x > 0) {
|
||||
hexbuf.append(" ");
|
||||
}
|
||||
hexbuf.append(String.format("%02x", mData.get(y+x)));
|
||||
}
|
||||
Log.e(XServer.TAG, " " + hexbuf);
|
||||
hexbuf = new StringBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void clear() { mData.position(0); mData.limit(0); }
|
||||
void resize(int len) {
|
||||
if (len == 0) {
|
||||
Log.e("X", "ByteQueue.resize: new len is zero");
|
||||
len = 1;
|
||||
}
|
||||
if (mData.capacity() < len) {
|
||||
int newlen = mData.capacity();
|
||||
if (newlen == 0) {
|
||||
Log.e("X", "ByteQueue.resize: capacity is zero");
|
||||
Thread.currentThread().dumpStack();
|
||||
newlen = 1;
|
||||
}
|
||||
while (newlen < len) { newlen *= 2; } //XXX: better way? overflow?
|
||||
ByteBuffer newbuf = ByteBuffer.allocate(newlen);
|
||||
newbuf.order(mData.order());
|
||||
System.arraycopy(mData.array(), 0, newbuf.array(), 0, mData.limit());
|
||||
newbuf.position(mData.position());
|
||||
mData = newbuf;
|
||||
}
|
||||
mData.limit(len);
|
||||
}
|
||||
|
||||
ByteOrder endian() { return mData.order(); }
|
||||
void endian(ByteOrder val) { mData.order(val); }
|
||||
|
||||
int pos() { return mData.position(); }
|
||||
void pos(int val) { mData.position(val); }
|
||||
|
||||
int length() { return mData.limit(); }
|
||||
int remain() { return length() - pos(); }
|
||||
|
||||
void compact() {
|
||||
mData.compact();
|
||||
mData.limit(mData.position());
|
||||
}
|
||||
|
||||
byte[] getBytes() {
|
||||
byte[] b = new byte[mData.position()];
|
||||
System.arraycopy(mData.array(), 0, b, 0, mData.position());
|
||||
return b;
|
||||
}
|
||||
|
||||
void deqSkip(int n) {
|
||||
int pos = mData.position();
|
||||
mData.position(pos+n);
|
||||
}
|
||||
void deqAlign(int n) {
|
||||
int pos = mData.position();
|
||||
mData.position(MathX.roundup(pos, n));
|
||||
}
|
||||
|
||||
byte deqByte() { return mData.get(); }
|
||||
short deqShort() { return mData.getShort(); }
|
||||
int deqInt() { return mData.getInt(); }
|
||||
|
||||
byte[] deqArray(int len) {
|
||||
byte[] val = new byte[len];
|
||||
mData.get(val);
|
||||
return val;
|
||||
}
|
||||
ByteQueue deqData(int len) {
|
||||
byte[] val = deqArray(len);
|
||||
ByteQueue data = new ByteQueue(val);
|
||||
data.mData.order(mData.order());
|
||||
return data;
|
||||
}
|
||||
String deqString(int len) {
|
||||
byte[] val = deqArray(len);
|
||||
return new String(val);
|
||||
}
|
||||
|
||||
void enqSkip(int n) {
|
||||
int pos = mData.position();
|
||||
int newpos = pos+n;
|
||||
resize(newpos);
|
||||
mData.position(newpos);
|
||||
}
|
||||
void enqAlign(int n) {
|
||||
int pos = mData.position();
|
||||
int newpos = MathX.roundup(pos, n);
|
||||
resize(newpos);
|
||||
mData.position(newpos);
|
||||
}
|
||||
|
||||
void enqByte(byte val) { resize(mData.position() + 1); mData.put(val); }
|
||||
void enqShort(short val) { resize(mData.position() + 2); mData.putShort(val); }
|
||||
void enqInt(int val) { resize(mData.position() + 4); mData.putInt(val); }
|
||||
|
||||
void enqArray(byte[] val, int pos, int len) {
|
||||
resize(mData.position() + len);
|
||||
mData.put(val, pos, len);
|
||||
}
|
||||
void enqArray(byte[] val) {
|
||||
resize(mData.position() + val.length);
|
||||
mData.put(val);
|
||||
}
|
||||
void enqData(ByteQueue val) {
|
||||
resize(mData.position() + val.pos());
|
||||
mData.put(val.mData.array(), 0, val.pos());
|
||||
}
|
||||
void enqString(String val) {
|
||||
enqArray(val.getBytes());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
class ClientView extends View
|
||||
{
|
||||
X11Window mWindow;
|
||||
X11Client mClient;
|
||||
|
||||
ClientView(Context ctx, X11Window w) {
|
||||
super(ctx);
|
||||
Log.d("X", "ClientView ctor");
|
||||
mWindow = w;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mClient = null;
|
||||
mWindow = null;
|
||||
}
|
||||
|
||||
protected void onMeasure(int wms, int hms) {
|
||||
Log.d("X", "ClientView#"+mWindow.mId+".onMeasure: wms=" + wms + ", hms=" + hms +
|
||||
", w=" + mWindow.mRect.w + ", h=" + mWindow.mRect.h);
|
||||
setMeasuredDimension(mWindow.mRect.w, mWindow.mRect.h);
|
||||
}
|
||||
|
||||
public void onDraw(Canvas canvas) {
|
||||
Log.d("X", "ClientView#"+mWindow.mId+".onDraw");
|
||||
canvas.drawBitmap(mWindow.mBitmap, 0, 0, null);
|
||||
}
|
||||
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
|
||||
// Do not handle non-pointer motion (eg. joystick)
|
||||
return true; //XXX? super.onGenericMotionEvent(event);
|
||||
}
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN: // 0
|
||||
Log.d("X", "MotionEvent: ACTION_DOWN");
|
||||
mWindow.onButtonPress(mClient, (int)event.getX(), (int)event.getY(), 0);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP: // 1
|
||||
Log.d("X", "MotionEvent: ACTION_UP");
|
||||
mWindow.onButtonRelease(mClient, (int)event.getX(), (int)event.getY(), 0);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE: // 2
|
||||
Log.d("X", "MotionEvent: ACTION_MOVE");
|
||||
mWindow.onMotion(mClient, (int)event.getX(), (int)event.getY());
|
||||
break;
|
||||
// ACTION_CANCEL == 3
|
||||
// ACTION_OUTSIDE == 4
|
||||
case MotionEvent.ACTION_POINTER_DOWN: // 5
|
||||
Log.d("X", "MotionEvent: ACTION_POINTER_DOWN");
|
||||
mWindow.onButtonPress(mClient, (int)event.getX(), (int)event.getY(), 0);
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP: // 6
|
||||
Log.d("X", "MotionEvent: ACTION_POINTER_UP");
|
||||
mWindow.onButtonRelease(mClient, (int)event.getX(), (int)event.getY(), 0);
|
||||
break;
|
||||
//XXX: MotionEvent.ACTION_HOVER_MOVE
|
||||
//XXX: MotionEvent.ACTION_SCROLL
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
//XXX: MotienEvent.getSource() is apparently not in FroYo :/
|
||||
// E/AndroidRuntime( 1992): java.lang.NoSuchMethodError: android.view.MotionEvent.getSource
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
|
||||
// Do not handle non-pointer motion (eg. joystick)
|
||||
return true; //XXX? super.onTouchEvent(event);
|
||||
}
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN: // 0
|
||||
Log.d("X", "TouchEvent: ACTION_DOWN");
|
||||
mWindow.onButtonPress(mClient, (int)event.getX(), (int)event.getY(), 0);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP: // 1
|
||||
Log.d("X", "TouchEvent: ACTION_UP");
|
||||
mWindow.onButtonRelease(mClient, (int)event.getX(), (int)event.getY(), 0);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE: // 2
|
||||
Log.d("X", "TouchEvent: ACTION_MOVE");
|
||||
mWindow.onMotion(mClient, (int)event.getX(), (int)event.getY());
|
||||
break;
|
||||
// ACTION_CANCEL == 3
|
||||
// ACTION_OUTSIDE == 4
|
||||
case MotionEvent.ACTION_POINTER_DOWN: // 5
|
||||
Log.d("X", "TouchEvent: ACTION_POINTER_DOWN");
|
||||
mWindow.onButtonPress(mClient, (int)event.getX(), (int)event.getY(), 0);
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP: // 6
|
||||
Log.d("X", "TouchEvent: ACTION_POINTER_UP");
|
||||
mWindow.onButtonRelease(mClient, (int)event.getX(), (int)event.getY(), 0);
|
||||
break;
|
||||
//XXX: MotionEvent.ACTION_HOVER_MOVE
|
||||
//XXX: MotionEvent.ACTION_SCROLL
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onKeyDown(int code, KeyEvent event) {
|
||||
Log.d("X", "ClientView#"+mWindow.mId+".onKeyDown("+code+"): char="+event.getUnicodeChar());
|
||||
mWindow.onKeyPress(mClient, code);
|
||||
mClient.mServer.mKeyboard.onKeyDown(code);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onKeyUp(int code, KeyEvent event) {
|
||||
Log.d("X", "ClientView#"+mWindow.mId+".onKeyUp("+code+")");
|
||||
mWindow.onKeyRelease(mClient, code);
|
||||
mClient.mServer.mKeyboard.onKeyUp(code);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void onFocusChanged(boolean gainFocus, int direction, Rect prev) {
|
||||
Log.d("X", "ClientView#"+mWindow.mId+".onFocusChanged("+gainFocus+")");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
class FontData
|
||||
{
|
||||
static void globalInit(X11Server server) {
|
||||
FontDataPCF.globalInit(server);
|
||||
FontDataNative.globalInit(server);
|
||||
}
|
||||
|
||||
String mName;
|
||||
boolean mMetadataLoaded;
|
||||
boolean mGlyphsLoaded;
|
||||
|
||||
X11CharInfo mMinBounds;
|
||||
X11CharInfo mMaxBounds;
|
||||
short mMinCharOrByte2;
|
||||
short mMaxCharOrByte2;
|
||||
short mDefaultChar;
|
||||
byte mDrawDirection;
|
||||
byte mMinByte1;
|
||||
byte mMaxByte1;
|
||||
byte mAllCharsExist;
|
||||
short mFontAscent;
|
||||
short mFontDescent;
|
||||
ArrayList<X11FontProp> mProperties;
|
||||
ArrayList<X11CharInfo> mCharInfos;
|
||||
|
||||
ArrayList<Bitmap> mImages;
|
||||
|
||||
FontData(String name) {
|
||||
mName = name;
|
||||
mMetadataLoaded = false;
|
||||
mGlyphsLoaded = false;
|
||||
|
||||
mMinBounds = new X11CharInfo();
|
||||
mMinBounds.left_side_bearing = 0;
|
||||
mMinBounds.right_side_bearing = 0;
|
||||
mMinBounds.character_width = 0;
|
||||
mMinBounds.ascent = 0;
|
||||
mMinBounds.descent = 0;
|
||||
mMinBounds.attributes = 0;
|
||||
|
||||
mMaxBounds = new X11CharInfo();
|
||||
mMaxBounds.left_side_bearing = 0;
|
||||
mMaxBounds.right_side_bearing = 0;
|
||||
mMaxBounds.character_width = 0;
|
||||
mMaxBounds.ascent = 0;
|
||||
mMaxBounds.descent = 0;
|
||||
mMaxBounds.attributes = 0;
|
||||
|
||||
mMinCharOrByte2 = 0;
|
||||
mMaxCharOrByte2 = 0;
|
||||
mDefaultChar = 0;
|
||||
mDrawDirection = 0;
|
||||
mMinByte1 = 0;
|
||||
mMaxByte1 = 0;
|
||||
mAllCharsExist = 1;
|
||||
mFontAscent = 0;
|
||||
mFontDescent = 0;
|
||||
mProperties = new ArrayList<X11FontProp>();
|
||||
mCharInfos = new ArrayList<X11CharInfo>();
|
||||
mImages = new ArrayList<Bitmap>();
|
||||
}
|
||||
|
||||
void loadMetadata(X11Server server) throws Exception { mMetadataLoaded = true; }
|
||||
void loadGlyphs(X11Server server) throws Exception { mGlyphsLoaded = true; }
|
||||
|
||||
boolean match(String pattern) {
|
||||
String[] patv = pattern.split("-");
|
||||
String[] v = mName.split("-");
|
||||
|
||||
if (patv.length != v.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int n = 0; n < v.length; ++n) {
|
||||
if (!patv[n].equals("*") && !patv[n].equals(v[n])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bitmap getBitmap(int idx) {
|
||||
return mImages.get(idx);
|
||||
}
|
||||
|
||||
void enqueueInfo(ByteQueue q) {
|
||||
q.enqShort(mMinBounds.left_side_bearing);
|
||||
q.enqShort(mMinBounds.right_side_bearing);
|
||||
q.enqShort(mMinBounds.character_width);
|
||||
q.enqShort(mMinBounds.ascent);
|
||||
q.enqShort(mMinBounds.descent);
|
||||
q.enqShort(mMinBounds.attributes);
|
||||
q.enqSkip(4);
|
||||
q.enqShort(mMaxBounds.left_side_bearing);
|
||||
q.enqShort(mMaxBounds.right_side_bearing);
|
||||
q.enqShort(mMaxBounds.character_width);
|
||||
q.enqShort(mMaxBounds.ascent);
|
||||
q.enqShort(mMaxBounds.descent);
|
||||
q.enqShort(mMaxBounds.attributes);
|
||||
q.enqSkip(4);
|
||||
q.enqShort(mMinCharOrByte2);
|
||||
q.enqShort(mMaxCharOrByte2);
|
||||
q.enqShort(mDefaultChar);
|
||||
q.enqShort((short)mProperties.size());
|
||||
q.enqByte(mDrawDirection);
|
||||
q.enqByte(mMinByte1);
|
||||
q.enqByte(mMaxByte1);
|
||||
q.enqByte(mAllCharsExist);
|
||||
q.enqShort(mFontAscent);
|
||||
q.enqShort(mFontDescent);
|
||||
}
|
||||
void enqueueProperties(ByteQueue q) {
|
||||
for (X11FontProp prop : mProperties) {
|
||||
q.enqInt(prop.name);
|
||||
q.enqInt(prop.value);
|
||||
}
|
||||
}
|
||||
void enqueueCharInfoCount(ByteQueue q) {
|
||||
q.enqInt((int)mCharInfos.size());
|
||||
}
|
||||
void enqueueCharInfo(ByteQueue q) {
|
||||
for (X11CharInfo info : mCharInfos) {
|
||||
q.enqShort(info.left_side_bearing);
|
||||
q.enqShort(info.right_side_bearing);
|
||||
q.enqShort(info.character_width);
|
||||
q.enqShort(info.ascent);
|
||||
q.enqShort(info.descent);
|
||||
q.enqShort(info.attributes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
class FontDataNative extends FontData
|
||||
{
|
||||
static void globalInit(X11Server server) {
|
||||
// Built-in Android fonts
|
||||
server.registerFont(new FontDataNative("sans", Typeface.SANS_SERIF));
|
||||
server.registerFont(new FontDataNative("serif", Typeface.SERIF));
|
||||
server.registerFont(new FontDataNative("monospace", Typeface.MONOSPACE));
|
||||
//server.registerFontAlias("fixed", "monospace");
|
||||
|
||||
File dir = new File("/system/fonts/");
|
||||
for (File f : dir.listFiles()) {
|
||||
String filename = f.getName();
|
||||
if (filename.endsWith(".ttf")) {
|
||||
String fontname = filename.substring(0, filename.lastIndexOf('.'));
|
||||
server.registerFont(new FontDataNative(fontname, f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Typeface mTypeFace;
|
||||
|
||||
FontDataNative(String name, Typeface tf) {
|
||||
super(name);
|
||||
mTypeFace = tf;
|
||||
}
|
||||
FontDataNative(String name, File f) {
|
||||
super(name);
|
||||
mTypeFace = Typeface.createFromFile(f);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,636 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.util.Log;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
class FontDataPCF extends FontData
|
||||
{
|
||||
static final int PATH_TYPE_FILE = 1;
|
||||
static final int PATH_TYPE_ASSET = 2;
|
||||
|
||||
static final int PCF_PROPERTIES = (1<<0);
|
||||
static final int PCF_ACCELERATORS = (1<<1);
|
||||
static final int PCF_METRICS = (1<<2);
|
||||
static final int PCF_BITMAPS = (1<<3);
|
||||
static final int PCF_INK_METRICS = (1<<4);
|
||||
static final int PCF_BDF_ENCODINGS = (1<<5);
|
||||
static final int PCF_SWIDTHS = (1<<6);
|
||||
static final int PCF_GLYPH_NAMES = (1<<7);
|
||||
static final int PCF_BDF_ACCELERATORS = (1<<8);
|
||||
|
||||
static final int PCF_DEFAULT_FORMAT = 0x00000000;
|
||||
static final int PCF_INKBOUNDS = 0x00000200;
|
||||
static final int PCF_ACCEL_W_INKBOUNDS = 0x00000100;
|
||||
static final int PCF_COMPRESSED_METRICS = 0x00000100;
|
||||
|
||||
static final int PCF_GLYPH_PAD_MASK = (3<<0); // See the bitmap table for explanation
|
||||
static final int PCF_BYTE_MASK = (1<<2); // If set then Most Sig Byte First
|
||||
static final int PCF_BIT_MASK = (1<<3); // If set then Most Sig Bit First
|
||||
static final int PCF_SCAN_UNIT_MASK = (3<<4); // See the bitmap table for explanation
|
||||
|
||||
class pcf_toc_entry
|
||||
{
|
||||
int type;
|
||||
int format;
|
||||
int size;
|
||||
int offset;
|
||||
}
|
||||
class pcf_toc_order_by_offset implements Comparator
|
||||
{
|
||||
public int compare(Object o1, Object o2) {
|
||||
pcf_toc_entry e1 = (pcf_toc_entry)o1;
|
||||
pcf_toc_entry e2 = (pcf_toc_entry)o2;
|
||||
return e1.offset - e2.offset;
|
||||
}
|
||||
}
|
||||
|
||||
class pcf_property
|
||||
{
|
||||
int name_offset;
|
||||
byte is_string;
|
||||
int value;
|
||||
}
|
||||
|
||||
class pcf_metrics
|
||||
{
|
||||
short left_side_bearing;
|
||||
short right_side_bearing;
|
||||
short character_width;
|
||||
short character_ascent;
|
||||
short character_descent;
|
||||
short character_attributes;
|
||||
}
|
||||
|
||||
class pcf_accelerator
|
||||
{
|
||||
byte no_overlap;
|
||||
byte constant_metrics;
|
||||
byte terminal_font;
|
||||
byte constant_width;
|
||||
byte ink_inside;
|
||||
byte ink_metrics;
|
||||
byte draw_direction;
|
||||
byte padding;
|
||||
int font_ascent;
|
||||
int font_descent;
|
||||
int max_overlap;
|
||||
pcf_metrics min_bounds;
|
||||
pcf_metrics max_bounds;
|
||||
pcf_metrics ink_min_bounds;
|
||||
pcf_metrics ink_max_bounds;
|
||||
|
||||
pcf_accelerator() {
|
||||
min_bounds = new pcf_metrics();
|
||||
max_bounds = new pcf_metrics();
|
||||
ink_min_bounds = new pcf_metrics();
|
||||
ink_max_bounds = new pcf_metrics();
|
||||
}
|
||||
}
|
||||
|
||||
class pcf_encoding
|
||||
{
|
||||
short min_char_or_byte2;
|
||||
short max_char_or_byte2;
|
||||
short min_byte1;
|
||||
short max_byte1;
|
||||
short default_char;
|
||||
short[] glyph_indices;
|
||||
}
|
||||
|
||||
static void globalInit(X11Server server) {
|
||||
BufferedReader br;
|
||||
String s;
|
||||
try {
|
||||
AssetManager am = server.mContext.getAssets();
|
||||
|
||||
br = new BufferedReader(new InputStreamReader(am.open("fonts/fonts.dir")));
|
||||
br.readLine(); // Skip first line
|
||||
while ((s = br.readLine()) != null) {
|
||||
String[] fields = s.split(" ", 2);
|
||||
String pathname = "fonts/" + fields[0];
|
||||
FontDataPCF pcf = new FontDataPCF(fields[1], PATH_TYPE_ASSET, pathname);
|
||||
server.registerFont(pcf);
|
||||
}
|
||||
|
||||
br = new BufferedReader(new InputStreamReader(am.open("fonts/fonts.alias")));
|
||||
while ((s = br.readLine()) != null) {
|
||||
if (s.length() == 0 || s.charAt(0) == '!') {
|
||||
continue;
|
||||
}
|
||||
String[] fields = s.split("[ \t]{1,}", 2);
|
||||
server.registerFontAlias(fields[0].toLowerCase(), fields[1].toLowerCase());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("X", "Failed to init PCF fonts from assets");
|
||||
}
|
||||
|
||||
try {
|
||||
br = new BufferedReader(new InputStreamReader(new FileInputStream("/data/local/fonts/fonts.dir")));
|
||||
br.readLine(); // Skip first line
|
||||
while ((s = br.readLine()) != null) {
|
||||
if (s.length() == 0 || s.charAt(0) == '!') {
|
||||
continue;
|
||||
}
|
||||
String[] fields = s.split(" ", 2);
|
||||
if (fields.length != 2) {
|
||||
Log.e("X", "bad line in fonts.dir: fields=" + fields.length + ", line=" + s);
|
||||
continue;
|
||||
}
|
||||
String pathname = "/data/local/fonts/" + fields[0];
|
||||
FontDataPCF pcf = new FontDataPCF(fields[1], PATH_TYPE_FILE, pathname);
|
||||
server.registerFont(pcf);
|
||||
}
|
||||
|
||||
br = new BufferedReader(new InputStreamReader(new FileInputStream("/data/local/fonts/fonts.alias")));
|
||||
while ((s = br.readLine()) != null) {
|
||||
if (s.length() == 0 || s.charAt(0) == '!') {
|
||||
continue;
|
||||
}
|
||||
String[] fields = s.split("[ \t]{1,}", 2);
|
||||
if (fields.length != 2) {
|
||||
Log.e("X", "bad line in fonts.alias: fields=" + fields.length + ", line=" + s);
|
||||
continue;
|
||||
}
|
||||
server.registerFontAlias(fields[0].toLowerCase(), fields[1].toLowerCase());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("X", "Failed to init PCF fonts from dir");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
int mPathtype; // FILE or ASSET
|
||||
String mPathname;
|
||||
|
||||
ArrayList<X11CharInfo> mGlyphInfos;
|
||||
|
||||
FontDataPCF(String name, int pathtype, String pathname) {
|
||||
super(name);
|
||||
mPathtype = pathtype;
|
||||
mPathname = pathname;
|
||||
mGlyphInfos = new ArrayList<X11CharInfo>();
|
||||
}
|
||||
|
||||
private void readPropertyTable(X11Server server, int fmt, ByteBuffer b) {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int format = b.getInt();
|
||||
b.order((format & PCF_BYTE_MASK) != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
int nprops = b.getInt();
|
||||
pcf_property[] props = new pcf_property[nprops];
|
||||
|
||||
int n;
|
||||
for (n = 0; n < nprops; ++n) {
|
||||
pcf_property prop = new pcf_property();
|
||||
prop.name_offset = b.getInt();
|
||||
prop.is_string = b.get();
|
||||
prop.value = b.getInt();
|
||||
props[n] = prop;
|
||||
}
|
||||
b.position(MathX.roundup(b.position(), 4));
|
||||
|
||||
int string_size = b.getInt();
|
||||
|
||||
byte[] string_table = new byte[string_size];
|
||||
b.get(string_table);
|
||||
|
||||
mProperties = new ArrayList<X11FontProp>(nprops);
|
||||
for (n = 0; n < nprops; ++n) {
|
||||
String s = new String(string_table, props[n].name_offset);
|
||||
X11FontProp prop = new X11FontProp();
|
||||
prop.name = server.doInternAtom(s);
|
||||
if (props[n].is_string != 0) {
|
||||
String val = new String(string_table, props[n].value);
|
||||
prop.value = server.doInternAtom(val);
|
||||
}
|
||||
else {
|
||||
prop.value = props[n].value;
|
||||
}
|
||||
mProperties.add(n, prop);
|
||||
}
|
||||
}
|
||||
|
||||
private void readAcceleratorTable(int fmt, ByteBuffer b) {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int format = b.getInt();
|
||||
b.order((format & PCF_BYTE_MASK) != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
pcf_accelerator a = new pcf_accelerator();
|
||||
|
||||
a.no_overlap = b.get();
|
||||
a.constant_metrics = b.get();
|
||||
a.terminal_font = b.get();
|
||||
a.constant_width = b.get();
|
||||
a.ink_inside = b.get();
|
||||
a.ink_metrics = b.get();
|
||||
a.draw_direction = b.get();
|
||||
a.padding = b.get();
|
||||
a.font_ascent = b.getInt();
|
||||
a.font_descent = b.getInt();
|
||||
a.max_overlap = b.getInt();
|
||||
|
||||
a.min_bounds.left_side_bearing = b.getShort();
|
||||
a.min_bounds.right_side_bearing = b.getShort();
|
||||
a.min_bounds.character_width = b.getShort();
|
||||
a.min_bounds.character_ascent = b.getShort();
|
||||
a.min_bounds.character_descent = b.getShort();
|
||||
a.min_bounds.character_attributes = b.getShort();
|
||||
|
||||
a.max_bounds.left_side_bearing = b.getShort();
|
||||
a.max_bounds.right_side_bearing = b.getShort();
|
||||
a.max_bounds.character_width = b.getShort();
|
||||
a.max_bounds.character_ascent = b.getShort();
|
||||
a.max_bounds.character_descent = b.getShort();
|
||||
a.max_bounds.character_attributes = b.getShort();
|
||||
|
||||
if ((fmt & PCF_ACCEL_W_INKBOUNDS) != 0) {
|
||||
a.ink_min_bounds.left_side_bearing = b.getShort();
|
||||
a.ink_min_bounds.right_side_bearing = b.getShort();
|
||||
a.ink_min_bounds.character_width = b.getShort();
|
||||
a.ink_min_bounds.character_ascent = b.getShort();
|
||||
a.ink_min_bounds.character_descent = b.getShort();
|
||||
a.ink_min_bounds.character_attributes = b.getShort();
|
||||
|
||||
a.ink_max_bounds.left_side_bearing = b.getShort();
|
||||
a.ink_max_bounds.right_side_bearing = b.getShort();
|
||||
a.ink_max_bounds.character_width = b.getShort();
|
||||
a.ink_max_bounds.character_ascent = b.getShort();
|
||||
a.ink_max_bounds.character_descent = b.getShort();
|
||||
a.ink_max_bounds.character_attributes = b.getShort();
|
||||
}
|
||||
else {
|
||||
a.ink_min_bounds = a.min_bounds;
|
||||
a.ink_max_bounds = a.max_bounds;
|
||||
}
|
||||
|
||||
mMinBounds.left_side_bearing = a.min_bounds.left_side_bearing;
|
||||
mMinBounds.right_side_bearing = a.min_bounds.right_side_bearing;
|
||||
mMinBounds.character_width = a.min_bounds.character_width;
|
||||
mMinBounds.ascent = a.min_bounds.character_ascent;
|
||||
mMinBounds.descent = a.min_bounds.character_descent;
|
||||
mMinBounds.attributes = a.min_bounds.character_attributes;
|
||||
|
||||
mMaxBounds.left_side_bearing = a.max_bounds.left_side_bearing;
|
||||
mMaxBounds.right_side_bearing = a.max_bounds.right_side_bearing;
|
||||
mMaxBounds.character_width = a.max_bounds.character_width;
|
||||
mMaxBounds.ascent = a.max_bounds.character_ascent;
|
||||
mMaxBounds.descent = a.max_bounds.character_descent;
|
||||
mMaxBounds.attributes = a.max_bounds.character_attributes;
|
||||
|
||||
mDrawDirection = a.draw_direction;
|
||||
mAllCharsExist = 0 /* false */; //XXX?
|
||||
mFontAscent = (short)a.font_ascent;
|
||||
mFontDescent = (short)a.font_descent;
|
||||
}
|
||||
|
||||
short decompress_metric(byte b) {
|
||||
if (b < 0) {
|
||||
return (short)(b & 0x7f);
|
||||
}
|
||||
return (short)(b - 0x80);
|
||||
}
|
||||
|
||||
private void readMetricsTable(int fmt, ByteBuffer b, ArrayList<X11CharInfo> infos) {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int format = b.getInt();
|
||||
b.order((format & PCF_BYTE_MASK) != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
if ((fmt & PCF_COMPRESSED_METRICS) != 0) {
|
||||
short count = b.getShort();
|
||||
short n;
|
||||
for (n = 0; n < count; ++n) {
|
||||
X11CharInfo info = new X11CharInfo();
|
||||
info.left_side_bearing = decompress_metric(b.get());
|
||||
info.right_side_bearing = decompress_metric(b.get());
|
||||
info.character_width = decompress_metric(b.get());
|
||||
info.ascent = decompress_metric(b.get());
|
||||
info.descent = decompress_metric(b.get());
|
||||
info.attributes = 0;
|
||||
infos.add(n, info);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int count = b.getInt();
|
||||
int n;
|
||||
for (n = 0; n < count; ++n) {
|
||||
X11CharInfo info = new X11CharInfo();
|
||||
info.left_side_bearing = b.getShort();
|
||||
info.right_side_bearing = b.getShort();
|
||||
info.character_width = b.getShort();
|
||||
info.ascent = b.getShort();
|
||||
info.descent = b.getShort();
|
||||
info.attributes = b.getShort();
|
||||
infos.add(n, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showBitmap(char ch) {
|
||||
Bitmap bmp = mImages.get((int)ch);
|
||||
Log.d("X", "Show bitmap for <"+ch+">: w="+bmp.getWidth()+", h="+bmp.getHeight()+" ...");
|
||||
Log.d("X", "-----------");
|
||||
for (int y = 0; y < bmp.getHeight(); ++y) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int x = 0; x < bmp.getWidth(); ++x) {
|
||||
if (bmp.getPixel(x, y) == Color.BLACK) {
|
||||
buf.append(".");
|
||||
}
|
||||
else {
|
||||
buf.append("X");
|
||||
}
|
||||
}
|
||||
Log.d("X", " " + buf);
|
||||
}
|
||||
Log.d("X", "-----------");
|
||||
}
|
||||
|
||||
private void readBitmapTable(int fmt, ByteBuffer b) {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int format = b.getInt();
|
||||
b.order((format & PCF_BYTE_MASK) != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
int glyph_count = b.getInt();
|
||||
int n;
|
||||
|
||||
int[] offsets = new int[glyph_count];
|
||||
for (n = 0; n < glyph_count; ++n) {
|
||||
offsets[n] = b.getInt();
|
||||
}
|
||||
|
||||
int[] bitmap_sizes = new int[4];
|
||||
bitmap_sizes[0] = b.getInt();
|
||||
bitmap_sizes[1] = b.getInt();
|
||||
bitmap_sizes[2] = b.getInt();
|
||||
bitmap_sizes[3] = b.getInt();
|
||||
|
||||
int bitmap_data_len = bitmap_sizes[format&3];
|
||||
ByteBuffer bitmap_data = b.slice();
|
||||
bitmap_data.limit(bitmap_data_len);
|
||||
|
||||
int bitmap_byte_order = (format&4) >> 2; // 1=LSByteFirst, 0=MSByteFirst
|
||||
int bitmap_bit_order = (format&8) >> 3; // 1=LSBitFirst, 0=MSBitFirst
|
||||
|
||||
mImages = new ArrayList<Bitmap>(glyph_count);
|
||||
|
||||
int row_pad_bytes = (1<<(format&3));
|
||||
int elem_bytes = (1<<((format>>4)&3));
|
||||
int elem_bits = elem_bytes*8;
|
||||
|
||||
Log.d("X", "readBitmapTable: name="+mName+", glyph_count="+glyph_count+", bitmap_data_len="+bitmap_data_len);
|
||||
|
||||
for (n = 0; n < glyph_count; ++n) {
|
||||
X11CharInfo info = mGlyphInfos.get(n);
|
||||
//XXX: should width be rsb-lsb or width?
|
||||
short w = info.character_width;
|
||||
short h = (short)(info.ascent + info.descent);
|
||||
if (w == 0 || h == 0) {
|
||||
mImages.add(n, null);
|
||||
continue;
|
||||
}
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
|
||||
int elem_per_row = (w+elem_bits-1)/elem_bits;
|
||||
int bytes_per_row = ((elem_per_row*elem_bytes+row_pad_bytes-1)/row_pad_bytes)*row_pad_bytes;
|
||||
|
||||
short row, col;
|
||||
int row_off, col_off, idx;
|
||||
int elem;
|
||||
int nbits, bit;
|
||||
for (row = 0; row < h; ++row) {
|
||||
row_off = row * bytes_per_row;
|
||||
for (col = 0; col < w; ++col) {
|
||||
int elem_off = (col/elem_bits)*elem_bytes;
|
||||
int elem_byte_off;
|
||||
if (bitmap_byte_order == 1 /*LSByteFirst*/) {
|
||||
elem_byte_off = (col%elem_bits)/8;
|
||||
}
|
||||
else {
|
||||
elem_byte_off = elem_bytes-1 - (col%elem_bits)/8;
|
||||
}
|
||||
int elem_bit_off;
|
||||
if (bitmap_bit_order == 1 /*LSBitFirst*/) {
|
||||
elem_bit_off = 8-1 - (col%8);
|
||||
}
|
||||
else {
|
||||
elem_bit_off = (col%8);
|
||||
}
|
||||
int valoff = offsets[n] + row_off + elem_off + elem_byte_off;
|
||||
byte val = bitmap_data.get(offsets[n] + row_off + elem_off + elem_byte_off);
|
||||
int pixel = (val >> elem_bit_off) & 1;
|
||||
int color = (pixel != 0 ? Color.WHITE : Color.BLACK);
|
||||
bmp.setPixel(col, row, color);
|
||||
}
|
||||
}
|
||||
mImages.add(n, bmp);
|
||||
}
|
||||
}
|
||||
|
||||
private void readEncodingTable(int fmt, ByteBuffer b) {
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int format = b.getInt();
|
||||
b.order((format & PCF_BYTE_MASK) != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
mMinCharOrByte2 = b.getShort();
|
||||
mMaxCharOrByte2 = b.getShort();
|
||||
mMinByte1 = (byte)b.getShort();
|
||||
mMaxByte1 = (byte)b.getShort();
|
||||
mDefaultChar = b.getShort();
|
||||
|
||||
//XXX: this fails on cu-pua12.pcf.gz
|
||||
int num_indices = (mMaxCharOrByte2 -
|
||||
mMinCharOrByte2 + 1) *
|
||||
(mMaxByte1 -
|
||||
mMinByte1 + 1);
|
||||
short[] glyph_indices = new short[num_indices];
|
||||
int n;
|
||||
for (n = 0; n < num_indices; ++n) {
|
||||
glyph_indices[n] = b.getShort();
|
||||
}
|
||||
}
|
||||
|
||||
private void readScalableWidthsTable(int fmt, ByteBuffer b) {
|
||||
//XXX: Skip this data
|
||||
}
|
||||
|
||||
private void readGlyphNamesTable(int fmt, ByteBuffer b) {
|
||||
//XXX: Skip this data
|
||||
}
|
||||
|
||||
void loadMetadata(X11Server server) throws Exception {
|
||||
if (mMetadataLoaded) {
|
||||
return;
|
||||
}
|
||||
InputStream is = null;
|
||||
if (mPathtype == PATH_TYPE_ASSET) {
|
||||
AssetManager am = server.mContext.getAssets();
|
||||
is = am.open(mPathname);
|
||||
}
|
||||
else {
|
||||
is = new FileInputStream(mPathname);
|
||||
}
|
||||
//XXX: should check for gzip signature, but what about rewind?
|
||||
if (mPathname.endsWith(".gz")) {
|
||||
is = new GZIPInputStream(is);
|
||||
}
|
||||
|
||||
long pos = 0; //XXX: seek() sure would be nice
|
||||
ByteBuffer b;
|
||||
|
||||
b = ByteBuffer.allocate(4);
|
||||
is.read(b.array(), 0, 4); pos += 4;
|
||||
byte[] sig = b.array();
|
||||
if (sig[0] != 1 || sig[1] != 'f' || sig[2] != 'c' || sig[3] != 'p') {
|
||||
throw new Exception("Bad PCF header");
|
||||
}
|
||||
|
||||
b = ByteBuffer.allocate(4);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
is.read(b.array(), 0, 4); pos += 4;
|
||||
int table_count = b.getInt();
|
||||
|
||||
int n;
|
||||
pcf_toc_entry[] toc = new pcf_toc_entry[table_count];
|
||||
for (n = 0; n < table_count; ++n) {
|
||||
b = ByteBuffer.allocate(16);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
is.read(b.array(), 0, 16); pos += 16;
|
||||
pcf_toc_entry ent = new pcf_toc_entry();
|
||||
ent.type = b.getInt();
|
||||
ent.format = b.getInt();
|
||||
ent.size = b.getInt();
|
||||
ent.offset = b.getInt();
|
||||
toc[n] = ent;
|
||||
}
|
||||
Arrays.sort(toc, new pcf_toc_order_by_offset());
|
||||
|
||||
for (pcf_toc_entry e : toc) {
|
||||
if (pos != e.offset) {
|
||||
is.skip(e.offset - pos);
|
||||
pos = e.offset;
|
||||
}
|
||||
|
||||
b = ByteBuffer.allocate(e.size);
|
||||
int off = 0;
|
||||
while (off < e.size) {
|
||||
int nread = is.read(b.array(), off, e.size-off);
|
||||
if (nread <= 0) {
|
||||
Log.w("X", "FontDataPCF.loadMetadata: short read in " + mPathname);
|
||||
break;
|
||||
}
|
||||
off += nread;
|
||||
pos += nread;
|
||||
}
|
||||
|
||||
switch (e.type) {
|
||||
case PCF_PROPERTIES: readPropertyTable(server, e.format, b); break;
|
||||
case PCF_ACCELERATORS: readAcceleratorTable(e.format, b); break;
|
||||
case PCF_METRICS: readMetricsTable(e.format, b, mGlyphInfos); break;
|
||||
case PCF_BITMAPS: /* Ignore */ break;
|
||||
case PCF_INK_METRICS: readMetricsTable(e.format, b, mCharInfos); break;
|
||||
case PCF_BDF_ENCODINGS: readEncodingTable(e.format, b); break;
|
||||
case PCF_SWIDTHS: readScalableWidthsTable(e.format, b); break;
|
||||
case PCF_GLYPH_NAMES: readGlyphNamesTable(e.format, b); break;
|
||||
case PCF_BDF_ACCELERATORS: readAcceleratorTable(e.format, b); break;
|
||||
default: throw new Exception("Bad PCF toc");
|
||||
}
|
||||
}
|
||||
|
||||
mMetadataLoaded = true;
|
||||
}
|
||||
|
||||
void loadGlyphs(X11Server server) throws Exception {
|
||||
if (mGlyphsLoaded) {
|
||||
return;
|
||||
}
|
||||
Log.d("X", "FontDataPCF.loadGlyphs");
|
||||
|
||||
InputStream is = null;
|
||||
if (mPathtype == PATH_TYPE_ASSET) {
|
||||
AssetManager am = server.mContext.getAssets();
|
||||
is = am.open(mPathname);
|
||||
}
|
||||
else {
|
||||
is = new FileInputStream(mPathname);
|
||||
}
|
||||
//XXX: should check for gzip signature, but what about rewind?
|
||||
if (mPathname.endsWith(".gz")) {
|
||||
is = new GZIPInputStream(is);
|
||||
}
|
||||
|
||||
long pos = 0; //XXX: seek() sure would be nice
|
||||
ByteBuffer b;
|
||||
|
||||
b = ByteBuffer.allocate(4);
|
||||
is.read(b.array(), 0, 4); pos += 4;
|
||||
byte[] sig = b.array();
|
||||
if (sig[0] != 1 || sig[1] != 'f' || sig[2] != 'c' || sig[3] != 'p') {
|
||||
throw new Exception("Bad PCF header");
|
||||
}
|
||||
|
||||
b = ByteBuffer.allocate(4);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
is.read(b.array(), 0, 4); pos += 4;
|
||||
int table_count = b.getInt();
|
||||
|
||||
int n;
|
||||
pcf_toc_entry[] toc = new pcf_toc_entry[table_count];
|
||||
for (n = 0; n < table_count; ++n) {
|
||||
b = ByteBuffer.allocate(16);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
is.read(b.array(), 0, 16); pos += 16;
|
||||
pcf_toc_entry ent = new pcf_toc_entry();
|
||||
ent.type = b.getInt();
|
||||
ent.format = b.getInt();
|
||||
ent.size = b.getInt();
|
||||
ent.offset = b.getInt();
|
||||
toc[n] = ent;
|
||||
}
|
||||
Arrays.sort(toc, new pcf_toc_order_by_offset());
|
||||
|
||||
for (pcf_toc_entry e : toc) {
|
||||
if (pos != e.offset) {
|
||||
is.skip(e.offset - pos);
|
||||
pos = e.offset;
|
||||
}
|
||||
|
||||
b = ByteBuffer.allocate(e.size);
|
||||
int off = 0;
|
||||
while (off < e.size) {
|
||||
int nread = is.read(b.array(), off, e.size-off);
|
||||
if (nread <= 0) {
|
||||
Log.w("X", "FontDataPCF.loadGlyphs: short read in " + mPathname);
|
||||
break;
|
||||
}
|
||||
off += nread;
|
||||
pos += nread;
|
||||
}
|
||||
|
||||
switch (e.type) {
|
||||
case PCF_BITMAPS: readBitmapTable(e.format, b); break;
|
||||
default: /* Ignore */ break;
|
||||
}
|
||||
}
|
||||
|
||||
mGlyphsLoaded = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class MathX
|
||||
{
|
||||
public static short divceil(short val, int n) {
|
||||
return (short)((val+n-1)/n);
|
||||
}
|
||||
public static int divceil(int val, int n) {
|
||||
return (val+n-1)/n;
|
||||
}
|
||||
|
||||
public static short roundup(short val, int n) {
|
||||
return (short)(divceil(val,n)*n);
|
||||
}
|
||||
public static int roundup(int val, int n) {
|
||||
return divceil(val,n)*n;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Gravity;
|
||||
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
class UIHandler extends Handler
|
||||
{
|
||||
public static final int MSG_VIEW_CREATE_ROOT = 0x1001;
|
||||
public static final int MSG_VIEW_CREATE = 0x1002;
|
||||
public static final int MSG_VIEW_REMOVE = 0x1003;
|
||||
public static final int MSG_VIEW_CONFIGURE = 0x1004;
|
||||
public static final int MSG_VIEW_SET_VISIBLE = 0x1010;
|
||||
public static final int MSG_VIEW_SET_BACKGROUND_COLOR = 0x1011;
|
||||
public static final int MSG_VIEW_SET_BACKGROUND_BITMAP = 0x1012;
|
||||
public static final int MSG_VIEW_INVALIDATE = 0x1020;
|
||||
|
||||
Context mContext;
|
||||
ViewGroup mViewGroup;
|
||||
|
||||
UIHandler(Context ctx, ViewGroup vg) {
|
||||
mContext = ctx;
|
||||
mViewGroup = vg;
|
||||
}
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
X11Window w;
|
||||
RelativeLayout.LayoutParams lp;
|
||||
switch (msg.what) {
|
||||
case MSG_VIEW_CREATE_ROOT:
|
||||
w = (X11Window)msg.obj;
|
||||
w.mView = new ClientView(mContext, w);
|
||||
lp = new RelativeLayout.LayoutParams(w.mRect.x, w.mRect.y);
|
||||
mViewGroup.addView(w.mView, lp);
|
||||
w.mView.setFocusable(true);
|
||||
w.mView.setFocusableInTouchMode(true);
|
||||
w.mView.setVisibility(View.VISIBLE);
|
||||
Log.d("X", "UI: w="+w.mId+": Attached ClientView to root window");
|
||||
break;
|
||||
case MSG_VIEW_CREATE:
|
||||
w = (X11Window)msg.obj;
|
||||
w.mView = new ClientView(mContext, w);
|
||||
lp = new RelativeLayout.LayoutParams(w.mRect.w, w.mRect.h);
|
||||
lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, -1);
|
||||
lp.addRule(RelativeLayout.ALIGN_PARENT_TOP, -1);
|
||||
lp.setMargins(w.mRect.x, w.mRect.y, 0, 0);
|
||||
mViewGroup.addView(w.mView, lp);
|
||||
w.mView.setFocusable(true);
|
||||
w.mView.setFocusableInTouchMode(true);
|
||||
w.mView.setVisibility(View.INVISIBLE);
|
||||
Log.d("X", "UI: w="+w.mId+": Attached ClientView to window at x="+w.mRect.x+", y=" + w.mRect.y);
|
||||
break;
|
||||
case MSG_VIEW_REMOVE:
|
||||
w = (X11Window)msg.obj;
|
||||
w.mRealized = false;
|
||||
mViewGroup.removeView(w.mView);
|
||||
w.mView.destroy();
|
||||
w.mView = null;
|
||||
break;
|
||||
case MSG_VIEW_CONFIGURE:
|
||||
w = (X11Window)msg.obj;
|
||||
lp = new RelativeLayout.LayoutParams(w.mRect.w, w.mRect.h);
|
||||
lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, -1);
|
||||
lp.addRule(RelativeLayout.ALIGN_PARENT_TOP, -1);
|
||||
lp.setMargins(w.mRect.x, w.mRect.y, 0, 0);
|
||||
//XXX: better way?
|
||||
mViewGroup.removeView(w.mView);
|
||||
mViewGroup.addView(w.mView, lp);
|
||||
break;
|
||||
case MSG_VIEW_SET_VISIBLE:
|
||||
w = (X11Window)msg.obj;
|
||||
w.mView.setVisibility(View.VISIBLE);
|
||||
w.mRealized = true;
|
||||
w.mView.requestFocus();
|
||||
Log.d("X", "UI: w="+w.mId+": Set window visible");
|
||||
break;
|
||||
case MSG_VIEW_SET_BACKGROUND_COLOR:
|
||||
w = (X11Window)msg.obj;
|
||||
w.mView.setBackgroundColor(w.mBgPixel);
|
||||
break;
|
||||
case MSG_VIEW_SET_BACKGROUND_BITMAP:
|
||||
w = (X11Window)msg.obj;
|
||||
w.mView.setBackgroundDrawable(
|
||||
new BitmapDrawable(mContext.getResources(),
|
||||
w.mBgPixmap.mBitmap));
|
||||
break;
|
||||
case MSG_VIEW_INVALIDATE:
|
||||
w = (X11Window)msg.obj;
|
||||
w.mView.invalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Atom
|
||||
{
|
||||
static final int NONE = 0;
|
||||
|
||||
static final int NR_PREDEFINED = 68;
|
||||
static final String predefined_names[] = {
|
||||
"(none)", // Invalid, placeholder
|
||||
"PRIMARY", // 1
|
||||
"SECONDARY",
|
||||
"ARC",
|
||||
"ATOM",
|
||||
"BITMAP",
|
||||
"CARDINAL",
|
||||
"COLORMAP",
|
||||
"CURSOR",
|
||||
"CUT_BUFFER0",
|
||||
"CUT_BUFFER1", // 10
|
||||
"CUT_BUFFER2",
|
||||
"CUT_BUFFER3",
|
||||
"CUT_BUFFER4",
|
||||
"CUT_BUFFER5",
|
||||
"CUT_BUFFER6",
|
||||
"CUT_BUFFER7",
|
||||
"DRAWABLE",
|
||||
"FONT",
|
||||
"INTEGER",
|
||||
"PIXMAP", // 20
|
||||
"POINT",
|
||||
"RECTANGLE",
|
||||
"RESOURCE_MANAGER",
|
||||
"RGB_COLOR_MAP",
|
||||
"RGB_BEST_MAP",
|
||||
"RGB_BLUE_MAP",
|
||||
"RGB_DEFAULT_MAP",
|
||||
"RGB_GRAY_MAP",
|
||||
"RGB_GREEN_MAP",
|
||||
"RGB_RED_MAP", // 30
|
||||
"STRING",
|
||||
"VISUALID",
|
||||
"WINDOW",
|
||||
"WM_COMMAND",
|
||||
"WM_HINTS",
|
||||
"WM_CLIENT_MACHINE",
|
||||
"WM_ICON_NAME",
|
||||
"WM_ICON_SIZE",
|
||||
"WM_NAME",
|
||||
"WM_NORMAL_HINTS", // 40
|
||||
"WM_SIZE_HINTS",
|
||||
"WM_ZOOM_HINTS",
|
||||
"MIN_SPACE",
|
||||
"NORM_SPACE",
|
||||
"MAX_SPACE",
|
||||
"END_SPACE",
|
||||
"SUPERSCRIPT_X",
|
||||
"SUPERSCRIPT_Y",
|
||||
"SUBSCRIPT_X",
|
||||
"SUBSCRIPT_Y", // 50
|
||||
"UNDERLINE_POSITION",
|
||||
"UNDERLINE_THICKNESS",
|
||||
"STRIKEOUT_ASCENT",
|
||||
"STRIKEOUT_DESCENT",
|
||||
"ITALIC_ANGLE",
|
||||
"X_HEIGHT",
|
||||
"QUAD_WIDTH",
|
||||
"WEIGHT",
|
||||
"POINT_SIZE",
|
||||
"RESOLUTION", // 60
|
||||
"COPYRIGHT",
|
||||
"NOTICE",
|
||||
"FONT_NAME",
|
||||
"FAMILY_NAME",
|
||||
"FULL_NAME",
|
||||
"CAP_HEIGHT",
|
||||
"WM_CLASS",
|
||||
"WM_TRANSIENT_FOR"
|
||||
};
|
||||
|
||||
static final boolean predefined(int id) {
|
||||
return (id >= 1 && id < NR_PREDEFINED);
|
||||
}
|
||||
|
||||
static void globalInit(X11Server server) {
|
||||
int i;
|
||||
for (i = 1; i <= NR_PREDEFINED; ++i) {
|
||||
server.doInternAtom(i, predefined_names[i]);
|
||||
}
|
||||
server.mLastAtomId = NR_PREDEFINED;
|
||||
}
|
||||
|
||||
int mId;
|
||||
String mName;
|
||||
|
||||
X11Atom(int id, String name) {
|
||||
mId = id;
|
||||
mName = name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11CharInfo
|
||||
{
|
||||
short left_side_bearing;
|
||||
short right_side_bearing;
|
||||
short character_width;
|
||||
short ascent;
|
||||
short descent;
|
||||
short attributes;
|
||||
}
|
|
@ -0,0 +1,320 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.os.Message;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class X11Client extends Thread implements X11ProtocolHandler
|
||||
{
|
||||
// NR_BITS_RESOURCES + NR_BITS_CLIENTS must be 29
|
||||
static final int NR_BITS_RESOURCES = 22;
|
||||
|
||||
static final int NR_BITS_CLIENTS = (29-NR_BITS_RESOURCES);
|
||||
static final int CLIENT_ID_SHIFT = NR_BITS_RESOURCES;
|
||||
static final int MAX_CLIENTS = (1<<NR_BITS_CLIENTS);
|
||||
|
||||
X11Server mServer;
|
||||
int mId;
|
||||
X11Protocol mProt;
|
||||
short mSeqNo;
|
||||
Map<Integer,X11Resource> mResources;
|
||||
|
||||
X11Client(X11Server server) {
|
||||
mServer = server;
|
||||
mResources = new HashMap<Integer,X11Resource>();
|
||||
}
|
||||
X11Client(X11Server server, int id, Socket sock) throws Exception {
|
||||
Log.e(XServer.TAG, "new client from " + sock.getRemoteSocketAddress().toString());
|
||||
mServer = server;
|
||||
mId = id;
|
||||
mProt = new X11Protocol(this, sock);
|
||||
mSeqNo = 0;
|
||||
mResources = new HashMap<Integer,X11Resource>();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (mProt != null) {
|
||||
try {
|
||||
mProt.read();
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(XServer.TAG, "X11Client: terminating on exception: " + e.toString());
|
||||
e.printStackTrace();
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
//XXX: release grabs
|
||||
//XXX: delete selection
|
||||
//XXX: free resources
|
||||
// ...
|
||||
for (X11Resource r : mResources.values()) {
|
||||
r.destroy();
|
||||
}
|
||||
|
||||
mServer.clientClosed(this);
|
||||
mServer = null;
|
||||
}
|
||||
|
||||
private final void close() {
|
||||
mProt = null;
|
||||
}
|
||||
|
||||
void addResource(X11Resource r) throws X11Error {
|
||||
if (mResources.containsKey(r.mId)) {
|
||||
throw new X11Error(X11Error.IDCHOICE, r.mId);
|
||||
}
|
||||
mResources.put(r.mId, r);
|
||||
}
|
||||
|
||||
void delResource(int id) {
|
||||
mResources.remove(id);
|
||||
}
|
||||
|
||||
X11Resource getResource(int id) throws X11Error {
|
||||
X11Client c = mServer.mClients[id >> CLIENT_ID_SHIFT];
|
||||
X11Resource r = c.mResources.get(id);
|
||||
if (r == null) {
|
||||
throw new X11Error(X11Error.MATCH, id);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
X11Resource getResource(int id, int type) throws X11Error {
|
||||
X11Resource r = getResource(id);
|
||||
if (r.mType != type) {
|
||||
throw new X11Error(X11Error.MATCH, id);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
X11Pixmap getPixmap(int id) throws X11Error {
|
||||
return (X11Pixmap)getResource(id, X11Resource.PIXMAP);
|
||||
}
|
||||
|
||||
X11Window getWindow(int id) throws X11Error {
|
||||
return (X11Window)getResource(id, X11Resource.WINDOW);
|
||||
}
|
||||
|
||||
X11Colormap getColormap(int id) throws X11Error {
|
||||
return (X11Colormap)getResource(id, X11Resource.COLORMAP);
|
||||
}
|
||||
|
||||
X11Cursor getCursor(int id) throws X11Error {
|
||||
return (X11Cursor)getResource(id, X11Resource.CURSOR);
|
||||
}
|
||||
|
||||
X11Font getFont(int id) throws X11Error {
|
||||
return (X11Font)getResource(id, X11Resource.FONT);
|
||||
}
|
||||
|
||||
X11GContext getGContext(int id) throws X11Error {
|
||||
return (X11GContext)getResource(id, X11Resource.GCONTEXT);
|
||||
}
|
||||
|
||||
X11Drawable getDrawable(int id) throws X11Error {
|
||||
X11Resource r = getResource(id);
|
||||
if (r.mType != X11Resource.PIXMAP && r.mType != X11Resource.WINDOW) {
|
||||
throw new X11Error(X11Error.MATCH, id);
|
||||
}
|
||||
return (X11Drawable)r;
|
||||
}
|
||||
|
||||
X11Fontable getFontable(int id) throws X11Error {
|
||||
X11Resource r = getResource(id);
|
||||
if (r.mType != X11Resource.GCONTEXT && r.mType != X11Resource.FONT) {
|
||||
throw new X11Error(X11Error.MATCH, id);
|
||||
}
|
||||
return (X11Fontable)r;
|
||||
}
|
||||
|
||||
void send(X11ReplyMessage msg) {
|
||||
msg.seqno(mSeqNo);
|
||||
Log.d(XServer.TAG, "Send reply: seqno=" + mSeqNo);
|
||||
try {
|
||||
mProt.send(msg);
|
||||
}
|
||||
catch (IOException e) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
void send(X11EventMessage msg) {
|
||||
msg.seqno(mSeqNo);
|
||||
Log.d(XServer.TAG, "Send event: seqno=" + mSeqNo + ", name=" + msg.name());
|
||||
try {
|
||||
mProt.send(msg);
|
||||
}
|
||||
catch (IOException e) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
void send(X11ErrorMessage msg) {
|
||||
msg.seqno(mSeqNo);
|
||||
Log.d(XServer.TAG, "Send error: seqno=" + mSeqNo + ", name=" + msg.name());
|
||||
try {
|
||||
mProt.send(msg);
|
||||
}
|
||||
catch (IOException e) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
X11Visual getVisual(int id) throws X11Error {
|
||||
return mServer.getVisual(id);
|
||||
}
|
||||
|
||||
public void onMessage(X11SetupRequest msg) {
|
||||
//XXX: always allow for now
|
||||
Log.e(XServer.TAG, "Got setup request");
|
||||
|
||||
String vendor = "My Vendor";
|
||||
|
||||
ArrayList<X11Format> pixmap_formats = mServer.getPixmapFormats();
|
||||
|
||||
X11SetupResponse r = new X11SetupResponse(msg);
|
||||
|
||||
r.mSuccess = 0x01; // Success
|
||||
r.mProtoMajor = 11;
|
||||
r.mProtoMinor = 0;
|
||||
|
||||
r.mData.enqInt((int)0); // release-number
|
||||
r.mData.enqInt(mId << CLIENT_ID_SHIFT); // resource-id-base
|
||||
r.mData.enqInt((1 << CLIENT_ID_SHIFT) - 1); // resource-id-mask
|
||||
r.mData.enqInt((int)0); // motion-buffer-size
|
||||
r.mData.enqShort((short)vendor.length());
|
||||
r.mData.enqShort((short)0xffff); // maximum-request-length
|
||||
r.mData.enqByte((byte)1); // number of SCREENs in roots
|
||||
r.mData.enqByte((byte)pixmap_formats.size()); // number of FORMATs in pixmap-formats
|
||||
r.mData.enqByte((byte)0); // image-byte-order = LSBFirst
|
||||
r.mData.enqByte((byte)0); // bitmap-format-bit-order = LeastSignificant
|
||||
r.mData.enqByte((byte)32); // bitmap-format-scanline-unit
|
||||
r.mData.enqByte((byte)32); // bitmap-format-scanline-pad
|
||||
r.mData.enqByte((byte)mServer.mKeyboard.minKeycode());
|
||||
r.mData.enqByte((byte)mServer.mKeyboard.maxKeycode());
|
||||
r.mData.enqSkip(4);
|
||||
r.mData.enqString(vendor);
|
||||
r.mData.enqAlign(4);
|
||||
|
||||
for (X11Format fmt : pixmap_formats) {
|
||||
r.mData.enqByte(fmt.mDepth);
|
||||
r.mData.enqByte(fmt.mBPP);
|
||||
r.mData.enqByte(fmt.mPad);
|
||||
r.mData.enqSkip(5);
|
||||
}
|
||||
|
||||
mServer.mDefaultScreen.enqueue(r.mData);
|
||||
|
||||
Log.e(XServer.TAG, "Sending setup response");
|
||||
try {
|
||||
mProt.send(r);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(XServer.TAG, "Exception: ");
|
||||
e.printStackTrace();
|
||||
close();
|
||||
}
|
||||
}
|
||||
public void onMessage(X11SetupResponse msg) { close(); }
|
||||
public void onMessage(X11RequestMessage msg) {
|
||||
while (mServer.mGrabClient != null && mServer.mGrabClient != this) {
|
||||
Log.d(XServer.TAG, "Client#"+mId+" waiting on server grab");
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
++mSeqNo;
|
||||
Log.d(XServer.TAG, "Message: seqno=" + mSeqNo + ", name=" + msg.name());
|
||||
try {
|
||||
switch (msg.requestType()) {
|
||||
case 1: X11Window.create(this, msg); break;
|
||||
case 2: getWindow(msg.mData.deqInt()).handleChangeWindowAttributes(this, msg); break;
|
||||
case 3: getWindow(msg.mData.deqInt()).handleGetWindowAttributes(this, msg); break;
|
||||
case 4: getWindow(msg.mData.deqInt()).handleDestroyWindow(this, msg); break;
|
||||
case 8: getWindow(msg.mData.deqInt()).handleMapWindow(this, msg); break;
|
||||
case 9: getWindow(msg.mData.deqInt()).handleMapSubwindows(this, msg); break;
|
||||
case 10: getWindow(msg.mData.deqInt()).handleUnmapWindow(this, msg); break;
|
||||
case 11: getWindow(msg.mData.deqInt()).handleUnmapSubwindows(this, msg); break;
|
||||
case 12: getWindow(msg.mData.deqInt()).handleConfigureWindow(this, msg); break;
|
||||
case 14: getDrawable(msg.mData.deqInt()).handleGetGeometry(this, msg); break;
|
||||
case 16: mServer.handleInternAtom(this, msg); break;
|
||||
case 18: getWindow(msg.mData.deqInt()).handleChangeProperty(this, msg); break;
|
||||
case 19: getWindow(msg.mData.deqInt()).handleDeleteProperty(this, msg); break;
|
||||
case 20: getWindow(msg.mData.deqInt()).handleGetProperty(this, msg); break;
|
||||
case 21: getWindow(msg.mData.deqInt()).handleListProperties(this, msg); break;
|
||||
case 22: mServer.handleSetSelectionOwner(this, msg); break;
|
||||
case 23: mServer.handleGetSelectionOwner(this, msg); break;
|
||||
case 36: mServer.handleGrabServer(this, msg); break;
|
||||
case 37: mServer.handleUngrabServer(this, msg); break;
|
||||
case 38: mServer.mKeyboard.handleQueryPointer(this, msg); break;
|
||||
case 40: getWindow(msg.mData.deqInt()).handleTranslateCoordinates(this, msg); break;
|
||||
case 42: mServer.handleSetInputFocus(this, msg); break;
|
||||
case 43: mServer.handleGetInputFocus(this, msg); break;
|
||||
case 45: mServer.handleOpenFont(this, msg); break;
|
||||
case 46: getFont(msg.mData.deqInt()).handleCloseFont(this, msg); break;
|
||||
case 47: getFontable(msg.mData.deqInt()).handleQueryFont(this, msg); break;
|
||||
case 49: mServer.handleListFonts(this, msg); break;
|
||||
case 50: mServer.handleListFontsWithInfo(this, msg); break;
|
||||
case 53: X11Pixmap.create(this, msg); break;
|
||||
case 54: getPixmap(msg.mData.deqInt()).handleFreePixmap(this, msg); break;
|
||||
case 55: X11GContext.create(this, msg); break;
|
||||
case 56: getGContext(msg.mData.deqInt()).handleChangeGC(this, msg); break;
|
||||
case 59: getGContext(msg.mData.deqInt()).handleSetClipRectangles(this, msg); break;
|
||||
case 60: getGContext(msg.mData.deqInt()).handleFreeGC(this, msg); break;
|
||||
case 61: getWindow(msg.mData.deqInt()).handleClearArea(this, msg); break;
|
||||
case 62: getDrawable(msg.mData.deqInt()).handleCopyArea(this, msg); break;
|
||||
case 64: getDrawable(msg.mData.deqInt()).handlePolyPoint(this, msg); break;
|
||||
case 65: getDrawable(msg.mData.deqInt()).handlePolyLine(this, msg); break;
|
||||
case 66: getDrawable(msg.mData.deqInt()).handlePolySegment(this, msg); break;
|
||||
case 67: getDrawable(msg.mData.deqInt()).handlePolyRectangle(this, msg); break;
|
||||
case 68: getDrawable(msg.mData.deqInt()).handlePolyArc(this, msg); break;
|
||||
case 69: getDrawable(msg.mData.deqInt()).handleFillPoly(this, msg); break;
|
||||
case 70: getDrawable(msg.mData.deqInt()).handlePolyFillRectangle(this, msg); break;
|
||||
case 71: getDrawable(msg.mData.deqInt()).handlePolyFillArc(this, msg); break;
|
||||
case 72: getDrawable(msg.mData.deqInt()).handlePutImage(this, msg); break;
|
||||
case 73: getDrawable(msg.mData.deqInt()).handleGetImage(this, msg); break;
|
||||
case 76: getDrawable(msg.mData.deqInt()).handleImageText8(this, msg); break;
|
||||
case 78: X11Colormap.create(this, msg); break;
|
||||
case 92: getColormap(msg.mData.deqInt()).handleLookupColor(this, msg); break;
|
||||
case 93: X11PixmapCursor.create(this, msg); break;
|
||||
case 94: X11GlyphCursor.create(this, msg); break;
|
||||
case 95: getCursor(msg.mData.deqInt()).handleFreeCursor(this, msg); break;
|
||||
case 96: getCursor(msg.mData.deqInt()).handleRecolorCursor(this, msg); break;
|
||||
case 98: mServer.handleQueryExtension(this, msg); break;
|
||||
case 101: mServer.mKeyboard.handleGetKeyboardMapping(this, msg); break;
|
||||
case 104: mServer.mKeyboard.handleBell(this, msg); break;
|
||||
case 119: mServer.mKeyboard.handleGetModifierMapping(this, msg); break;
|
||||
default : throw new X11Error(X11Error.IMPLEMENTATION, msg.requestType());
|
||||
}
|
||||
}
|
||||
catch (X11Error e) {
|
||||
Log.e(XServer.TAG, "X11Error: " + e.name());
|
||||
e.printStackTrace();
|
||||
X11ErrorMessage err = new X11ErrorMessage(mProt.mEndian, e.mCode);
|
||||
err.mData.enqInt(e.mVal);
|
||||
err.mData.enqShort(msg.requestType() <= 127 ? 0 : msg.headerData());
|
||||
err.mData.enqShort(msg.requestType());
|
||||
send(err);
|
||||
close(); //XXX: for debugging
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(XServer.TAG, "Exception: ");
|
||||
e.printStackTrace();
|
||||
close();
|
||||
}
|
||||
}
|
||||
public void onMessage(X11ReplyMessage msg) { close(); }
|
||||
public void onMessage(X11EventMessage msg) { close(); }
|
||||
public void onMessage(X11ErrorMessage msg) { close(); }
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Color
|
||||
{
|
||||
short r;
|
||||
short g;
|
||||
short b;
|
||||
|
||||
void set(byte _r, byte _g, byte _b) {
|
||||
r = (short)(_r << 8 | _r);
|
||||
g = (short)(_g << 8 | _g);
|
||||
b = (short)(_b << 8 | _b);
|
||||
}
|
||||
void set(short _r, short _g, short _b) {
|
||||
r = _r;
|
||||
g = _g;
|
||||
b = _b;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
class X11Colormap extends X11Resource
|
||||
{
|
||||
static Map<String,X11Color> rgbmap;
|
||||
|
||||
static void globalInit(X11Server server) {
|
||||
rgbmap = new HashMap<String,X11Color>();
|
||||
|
||||
BufferedReader br;
|
||||
String s;
|
||||
|
||||
try {
|
||||
AssetManager am = server.mContext.getAssets();
|
||||
br = new BufferedReader(new InputStreamReader(am.open("rgb.txt")));
|
||||
while ((s = br.readLine()) != null) {
|
||||
if (s.length() == 0 || s.charAt(0) == '#' || s.charAt(0) == '!') {
|
||||
continue;
|
||||
}
|
||||
String[] fields = s.trim().split("[ \t]{1,}", 4);
|
||||
if (fields.length != 4) {
|
||||
Log.d("X", "Bad line in rgb.txt: " + s);
|
||||
continue;
|
||||
}
|
||||
X11Color color = new X11Color();
|
||||
byte r = (byte)(Short.parseShort(fields[0]) & 0xff);
|
||||
byte g = (byte)(Short.parseShort(fields[1]) & 0xff);
|
||||
byte b = (byte)(Short.parseShort(fields[2]) & 0xff);
|
||||
color.set(r, g, b);
|
||||
String name = fields[3].toLowerCase();
|
||||
rgbmap.put(name, color);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("X", "Failed to init RGB data from assets");
|
||||
}
|
||||
|
||||
try {
|
||||
br = new BufferedReader(new InputStreamReader(new FileInputStream("/data/local/rgb.txt")));
|
||||
while ((s = br.readLine()) != null) {
|
||||
if (s.length() == 0 || s.charAt(0) == '#' || s.charAt(0) == '!') {
|
||||
continue;
|
||||
}
|
||||
String[] fields = s.trim().split("[ \t]{1,}", 4);
|
||||
if (fields.length != 4) {
|
||||
Log.d("X", "Bad line in rgb.txt: " + s);
|
||||
continue;
|
||||
}
|
||||
X11Color color = new X11Color();
|
||||
byte r = (byte)(Short.parseShort(fields[0]) & 0xff);
|
||||
byte g = (byte)(Short.parseShort(fields[1]) & 0xff);
|
||||
byte b = (byte)(Short.parseShort(fields[2]) & 0xff);
|
||||
color.set(r, g, b);
|
||||
String name = fields[3].toLowerCase();
|
||||
rgbmap.put(name, color);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("X", "Failed to init RGB data from dir");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static void create(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int id = msg.mData.deqInt();
|
||||
X11Colormap r = new X11Colormap(id);
|
||||
r.handleCreate(c, msg);
|
||||
c.addResource(r);
|
||||
}
|
||||
|
||||
int mVisual;
|
||||
byte mAlloc;
|
||||
|
||||
X11Colormap(int id) {
|
||||
super(X11Resource.COLORMAP, id);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void initDefault() {
|
||||
mVisual = X11Visual.NONE;
|
||||
mAlloc = (byte)1; // All
|
||||
}
|
||||
|
||||
void handleCreate(X11Client c, X11RequestMessage msg) {
|
||||
//XXX: parse and handle window and visual
|
||||
mVisual = X11Visual.NONE;
|
||||
mAlloc = (byte)1; // All
|
||||
}
|
||||
|
||||
void handleLookupColor(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
short len = msg.mData.deqShort();
|
||||
msg.mData.deqSkip(2);
|
||||
String name = msg.mData.deqString(len);
|
||||
Log.d("X", "LookupColor: name=<"+name+">");
|
||||
X11Color color = rgbmap.get(name);
|
||||
if (color == null) {
|
||||
throw new X11Error(X11Error.NAME, 92 /* LookupColor */); //XXX???
|
||||
}
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.mData.enqShort(color.r);
|
||||
reply.mData.enqShort(color.g);
|
||||
reply.mData.enqShort(color.b);
|
||||
reply.mData.enqShort(color.r);
|
||||
reply.mData.enqShort(color.g);
|
||||
reply.mData.enqShort(color.b);
|
||||
c.send(reply);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Cursor extends X11Resource
|
||||
{
|
||||
X11Color mFgColor;
|
||||
X11Color mBgColor;
|
||||
|
||||
X11Cursor(int id) {
|
||||
super(X11Resource.CURSOR, id);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mBgColor = null;
|
||||
mFgColor = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void handleFreeCursor(X11Client c, X11RequestMessage msg) {
|
||||
c.delResource(mId);
|
||||
}
|
||||
|
||||
void handleRecolorCursor(X11Client c, X11RequestMessage msg) {
|
||||
doRecolor(msg.mData);
|
||||
}
|
||||
|
||||
void doRecolor(ByteQueue q) {
|
||||
mFgColor = new X11Color();
|
||||
mFgColor.r = q.deqShort();
|
||||
mFgColor.g = q.deqShort();
|
||||
mFgColor.b = q.deqShort();
|
||||
mBgColor = new X11Color();
|
||||
mBgColor.r = q.deqShort();
|
||||
mBgColor.g = q.deqShort();
|
||||
mBgColor.b = q.deqShort();
|
||||
}
|
||||
}
|
||||
|
||||
class X11PixmapCursor extends X11Cursor
|
||||
{
|
||||
static void create(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int id = msg.mData.deqInt();
|
||||
X11PixmapCursor r = new X11PixmapCursor(id);
|
||||
r.handleCreate(c, msg);
|
||||
c.addResource(r);
|
||||
}
|
||||
|
||||
X11Pixmap mSource;
|
||||
X11Pixmap mMask;
|
||||
X11Point mHotSpot;
|
||||
|
||||
X11PixmapCursor(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mHotSpot = null;
|
||||
mMask = null;
|
||||
mSource = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void handleCreate(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
mSource = c.getPixmap(msg.mData.deqInt());
|
||||
mMask = c.getPixmap(msg.mData.deqInt());
|
||||
doRecolor(msg.mData);
|
||||
mHotSpot = new X11Point();
|
||||
mHotSpot.x = msg.mData.deqShort();
|
||||
mHotSpot.y = msg.mData.deqShort();
|
||||
}
|
||||
}
|
||||
|
||||
class X11GlyphCursor extends X11Cursor
|
||||
{
|
||||
static void create(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int id = msg.mData.deqInt();
|
||||
X11GlyphCursor r = new X11GlyphCursor(id);
|
||||
r.handleCreate(c, msg);
|
||||
c.addResource(r);
|
||||
}
|
||||
|
||||
X11Font mSource;
|
||||
short mSourceChar;
|
||||
X11Font mMask;
|
||||
short mMaskChar;
|
||||
|
||||
X11GlyphCursor(int id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mMask = null;
|
||||
mSource = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void handleCreate(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
mSource = c.getFont(msg.mData.deqInt());
|
||||
mMask = c.getFont(msg.mData.deqInt());
|
||||
mSourceChar = msg.mData.deqShort();
|
||||
mMaskChar = msg.mData.deqShort();
|
||||
doRecolor(msg.mData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
class X11Depth
|
||||
{
|
||||
byte depth;
|
||||
ArrayList<X11Visual> visuals;
|
||||
|
||||
X11Depth(byte d) {
|
||||
depth = d;
|
||||
visuals = new ArrayList<X11Visual>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,314 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
abstract class X11Drawable extends X11Resource
|
||||
{
|
||||
byte mDepth;
|
||||
byte mBPP;
|
||||
X11Rect mRect;
|
||||
short mBorderWidth; // This is here for GetGeometry
|
||||
X11Visual mVisual; // This is here for GetImage
|
||||
|
||||
Bitmap mBitmap;
|
||||
Canvas mCanvas;
|
||||
|
||||
X11Drawable(int type, int id) {
|
||||
super(type, id);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mCanvas = null;
|
||||
mBitmap = null;
|
||||
mVisual = null;
|
||||
mRect = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void handleGetGeometry(X11Client c, X11RequestMessage msg) {
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.headerData(mDepth);
|
||||
reply.mData.enqInt(c.mServer.mDefaultScreen.mRoot.mId);
|
||||
reply.mData.enqShort(mRect.x);
|
||||
reply.mData.enqShort(mRect.y);
|
||||
reply.mData.enqShort(mRect.w);
|
||||
reply.mData.enqShort(mRect.h);
|
||||
reply.mData.enqShort(mBorderWidth);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleCopyArea(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11Drawable dst = c.getDrawable(msg.mData.deqInt());
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
short src_x = msg.mData.deqShort();
|
||||
short src_y = msg.mData.deqShort();
|
||||
short dst_x = msg.mData.deqShort();
|
||||
short dst_y = msg.mData.deqShort();
|
||||
short w = msg.mData.deqShort();
|
||||
short h = msg.mData.deqShort();
|
||||
|
||||
//XXX: Use Canvas.drawBitmap with a clip mask?
|
||||
//XXX: handle window with tiled background
|
||||
short x, y;
|
||||
for (y = 0; y < h; ++y) {
|
||||
for (x = 0; x < w; ++x) {
|
||||
int pixel = mBitmap.getPixel(src_x + x, src_y + y);
|
||||
dst.mBitmap.setPixel(dst_x + x, dst_y + y, pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handlePolyPoint(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
int count = msg.mData.remain()/4;
|
||||
float[] points = new float[count*2];
|
||||
for (int n = 0; n < count; ++n) {
|
||||
points[n*2+0] = (float)msg.mData.deqShort();
|
||||
points[n*2+1] = (float)msg.mData.deqShort();
|
||||
}
|
||||
mCanvas.drawPoints(points, gc.mPaint);
|
||||
postRender();
|
||||
}
|
||||
|
||||
void handlePolyLine(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
byte coord_mode = msg.headerData();
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
int count = msg.mData.remain()/4 - 1;
|
||||
float[] points = new float[count*4];
|
||||
float lastx = (float)msg.mData.deqShort();
|
||||
float lasty = (float)msg.mData.deqShort();
|
||||
for (int n = 0; n < count; ++n) {
|
||||
points[n*4+0] = lastx;
|
||||
points[n*4+1] = lasty;
|
||||
points[n*4+2] = (float)msg.mData.deqShort();
|
||||
points[n*4+3] = (float)msg.mData.deqShort();
|
||||
if (coord_mode == 0 /* Origin */) {
|
||||
lastx = points[n*4+2];
|
||||
lasty = points[n*4+3];
|
||||
}
|
||||
else {
|
||||
lastx += points[n*4+2];
|
||||
lasty += points[n*4+3];
|
||||
}
|
||||
}
|
||||
mCanvas.drawLines(points, gc.mPaint);
|
||||
postRender();
|
||||
}
|
||||
|
||||
void handlePolySegment(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
int count = msg.mData.remain()/8;
|
||||
float[] points = new float[count*4];
|
||||
for (int n = 0; n < count; ++n) {
|
||||
points[n*4+0] = (float)msg.mData.deqShort();
|
||||
points[n*4+1] = (float)msg.mData.deqShort();
|
||||
points[n*4+2] = (float)msg.mData.deqShort();
|
||||
points[n*4+3] = (float)msg.mData.deqShort();
|
||||
}
|
||||
mCanvas.drawLines(points, gc.mPaint);
|
||||
postRender();
|
||||
}
|
||||
|
||||
void handlePolyRectangle(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
while (msg.mData.remain() > 0) {
|
||||
short x = msg.mData.deqShort();
|
||||
short y = msg.mData.deqShort();
|
||||
short w = msg.mData.deqShort();
|
||||
short h = msg.mData.deqShort();
|
||||
mCanvas.drawRect(x, y, x+w, y+h, gc.mPaint);
|
||||
}
|
||||
postRender();
|
||||
}
|
||||
|
||||
void handlePolyArc(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
int count = msg.mData.remain()/12;
|
||||
float[] points = new float[count*6];
|
||||
for (int n = 0; n < count; ++n) {
|
||||
points[n*4+0] = (float)msg.mData.deqShort();
|
||||
points[n*4+1] = (float)msg.mData.deqShort();
|
||||
points[n*4+2] = (float)msg.mData.deqShort();
|
||||
points[n*4+3] = (float)msg.mData.deqShort();
|
||||
points[n*4+4] = (float)msg.mData.deqShort();
|
||||
points[n*4+5] = (float)msg.mData.deqShort();
|
||||
}
|
||||
throw new X11Error(X11Error.IMPLEMENTATION, 0);
|
||||
}
|
||||
|
||||
void handleFillPoly(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
byte shape = msg.mData.deqByte();
|
||||
byte coord_mode = msg.mData.deqByte();
|
||||
msg.mData.deqSkip(2);
|
||||
|
||||
Path path = new Path();
|
||||
path.setFillType(Path.FillType.WINDING); //XXX: ???
|
||||
|
||||
float x, y;
|
||||
x = (float)msg.mData.deqShort();
|
||||
y = (float)msg.mData.deqShort();
|
||||
path.moveTo(x, y);
|
||||
while (msg.mData.remain() > 0) {
|
||||
x = (float)msg.mData.deqShort();
|
||||
y = (float)msg.mData.deqShort();
|
||||
path.lineTo(x, y);
|
||||
}
|
||||
mCanvas.drawPath(path, gc.mPaint);
|
||||
postRender();
|
||||
}
|
||||
|
||||
void handlePolyFillRectangle(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
|
||||
Paint.Style oldstyle = gc.mPaint.getStyle();
|
||||
gc.mPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
while (msg.mData.remain() > 0) {
|
||||
short x = msg.mData.deqShort();
|
||||
short y = msg.mData.deqShort();
|
||||
short w = msg.mData.deqShort();
|
||||
short h = msg.mData.deqShort();
|
||||
mCanvas.drawRect(x, y, x+w, y+h, gc.mPaint);
|
||||
}
|
||||
gc.mPaint.setStyle(oldstyle);
|
||||
postRender();
|
||||
}
|
||||
|
||||
void handlePolyFillArc(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
throw new X11Error(X11Error.IMPLEMENTATION, msg.requestType());
|
||||
}
|
||||
|
||||
void handlePutImage(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
byte fmt = msg.headerData();
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
X11Rect rect = new X11Rect();
|
||||
rect.w = msg.mData.deqShort();
|
||||
rect.h = msg.mData.deqShort();
|
||||
rect.x = msg.mData.deqShort();
|
||||
rect.y = msg.mData.deqShort();
|
||||
byte left_pad = msg.mData.deqByte();
|
||||
byte depth = msg.mData.deqByte();
|
||||
msg.mData.deqSkip(2);
|
||||
|
||||
if (fmt == 0 /* Bitmap */) {
|
||||
if (depth != (byte)1) {
|
||||
throw new X11Error(X11Error.VALUE, depth);
|
||||
}
|
||||
fmt = (byte)1 /* XYPixmap */;
|
||||
}
|
||||
|
||||
ArrayList<X11Format> formats = c.mServer.getPixmapFormats();
|
||||
X11Format f = null;
|
||||
for (X11Format cur : formats) {
|
||||
if (cur.mDepth == depth) {
|
||||
f = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//XXX: handle not found
|
||||
|
||||
Bitmap bmp;
|
||||
|
||||
switch (fmt) {
|
||||
case 1 /* XYPixmap */:
|
||||
bmp = f.decodeImageXY(rect.w, rect.h, msg.mData);
|
||||
break;
|
||||
case 2 /* ZPixmap */ :
|
||||
bmp = f.decodeImageZ(rect.w, rect.h, msg.mData);
|
||||
break;
|
||||
default:
|
||||
throw new X11Error(X11Error.VALUE, fmt);
|
||||
}
|
||||
|
||||
mCanvas.drawBitmap(bmp, rect.x, rect.y, null);
|
||||
postRender(rect);
|
||||
}
|
||||
|
||||
void handleGetImage(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
byte fmt = msg.headerData();
|
||||
X11Rect rect = new X11Rect();
|
||||
rect.x = msg.mData.deqShort();
|
||||
rect.y = msg.mData.deqShort();
|
||||
rect.w = msg.mData.deqShort();
|
||||
rect.h = msg.mData.deqShort();
|
||||
int plane_mask = msg.mData.deqInt();
|
||||
|
||||
ArrayList<X11Format> formats = c.mServer.getPixmapFormats();
|
||||
X11Format f = null;
|
||||
for (X11Format cur : formats) {
|
||||
if (cur.mDepth == mDepth) {
|
||||
f = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//XXX: handle not found
|
||||
|
||||
byte[] data;
|
||||
|
||||
switch (fmt) {
|
||||
case 1 /* XYPixmap */:
|
||||
data = f.encodeImageXY(rect, plane_mask, mBitmap);
|
||||
break;
|
||||
case 2 /* ZPixmap */ :
|
||||
data = f.encodeImageZ(rect, plane_mask, mBitmap);
|
||||
break;
|
||||
default:
|
||||
throw new X11Error(X11Error.VALUE, fmt);
|
||||
}
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.headerData(mDepth);
|
||||
//XXX: This looks ugly, is it the best way?
|
||||
reply.mData.enqInt( (mVisual == null ? 0 : mVisual.mId) );
|
||||
reply.mData.enqSkip(20);
|
||||
reply.mData.enqArray(data);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleImageText8(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
byte len = msg.headerData();
|
||||
X11GContext gc = c.getGContext(msg.mData.deqInt());
|
||||
short x = msg.mData.deqShort();
|
||||
short y = msg.mData.deqShort();
|
||||
String text = msg.mData.deqString(len);
|
||||
|
||||
short x_min, x_max, y_min, y_max;
|
||||
x_min = x;
|
||||
x_max = x;
|
||||
y_min = y;
|
||||
y_max = y;
|
||||
for (int idx = 0; idx < text.length(); ++idx) {
|
||||
char ch = text.charAt(idx);
|
||||
X11CharInfo info = gc.mFont.getCharInfo(ch);
|
||||
Bitmap bmp = gc.mFont.getCharImage(ch, gc.mForePixel, gc.mBackPixel);
|
||||
if (bmp != null) {
|
||||
//XXX: This is probably not correct
|
||||
mCanvas.drawBitmap(bmp, x, y-bmp.getHeight(), null);
|
||||
}
|
||||
x += info.character_width;
|
||||
|
||||
x_max += info.character_width;
|
||||
y_min = (short)Math.min(y_min, y-bmp.getHeight());
|
||||
//y_max = (short)Math.max(y_max, y+info.descent);
|
||||
}
|
||||
|
||||
X11Rect r = new X11Rect();
|
||||
r.x = x_min;
|
||||
r.w = (short)(x_max - x_min);
|
||||
r.y = y_min;
|
||||
r.h = (short)(y_max - y_min);
|
||||
|
||||
postRender(r);
|
||||
}
|
||||
|
||||
void postRender(X11Rect r) {}
|
||||
void postRender() {}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Error extends Throwable
|
||||
{
|
||||
static final byte NONE = (byte)0;
|
||||
static final byte REQUEST = (byte)1;
|
||||
static final byte VALUE = (byte)2;
|
||||
static final byte WINDOW = (byte)3;
|
||||
static final byte PIXMAP = (byte)4;
|
||||
static final byte ATOM = (byte)5;
|
||||
static final byte CURSOR = (byte)6;
|
||||
static final byte FONT = (byte)7;
|
||||
static final byte MATCH = (byte)8;
|
||||
static final byte DRAWABLE = (byte)9;
|
||||
static final byte ACCESS = (byte)10;
|
||||
static final byte ALLOC = (byte)11;
|
||||
static final byte COLORMAP = (byte)12;
|
||||
static final byte GCONTEXT = (byte)13;
|
||||
static final byte IDCHOICE = (byte)14;
|
||||
static final byte NAME = (byte)15;
|
||||
static final byte LENGTH = (byte)16;
|
||||
static final byte IMPLEMENTATION = (byte)17;
|
||||
|
||||
static final String[] error_names = {
|
||||
"NONE",
|
||||
"Request",
|
||||
"Value",
|
||||
"Window",
|
||||
"Pixmap",
|
||||
"Atom",
|
||||
"Cursor",
|
||||
"Font",
|
||||
"Match",
|
||||
"Drawable",
|
||||
"Access",
|
||||
"Alloc",
|
||||
"Colormap",
|
||||
"GContext",
|
||||
"IDChoice",
|
||||
"Name",
|
||||
"Length",
|
||||
"Implementation"
|
||||
};
|
||||
|
||||
String name() { return error_names[mCode]; }
|
||||
|
||||
byte mCode;
|
||||
int mVal;
|
||||
|
||||
X11Error(byte code, int val) {
|
||||
mCode = code;
|
||||
mVal = val;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
class X11ErrorMessage extends X11Message
|
||||
{
|
||||
static final String[] message_names = {
|
||||
"NONE", // 0
|
||||
"Request",
|
||||
"Value",
|
||||
"Window",
|
||||
"Pixmap",
|
||||
"Atom",
|
||||
"Cursor",
|
||||
"Font",
|
||||
"Match",
|
||||
"Drawable",
|
||||
"Access", // 10
|
||||
"Alloc",
|
||||
"Colormap",
|
||||
"GContext",
|
||||
"IDChoice",
|
||||
"Name",
|
||||
"Length",
|
||||
"Implementation"
|
||||
};
|
||||
|
||||
String name() { return message_names[mHeaderData]; }
|
||||
|
||||
byte mHeaderData;
|
||||
short mSeqNo;
|
||||
|
||||
X11ErrorMessage(ByteOrder endian, byte code) {
|
||||
super(endian);
|
||||
mHeaderData = code;
|
||||
}
|
||||
|
||||
void read(ByteQueue q) {
|
||||
byte event_type = q.deqByte(); // 0x00
|
||||
mHeaderData = q.deqByte();
|
||||
mSeqNo = q.deqShort();
|
||||
mData = q.deqData(28);
|
||||
}
|
||||
void write(ByteQueue q) {
|
||||
q.enqByte((byte)0x00);
|
||||
q.enqByte(mHeaderData);
|
||||
q.enqShort(mSeqNo);
|
||||
q.enqData(mData);
|
||||
q.enqSkip(28 - mData.pos());
|
||||
}
|
||||
void dispatch(X11ProtocolHandler h) { h.onMessage(this); }
|
||||
|
||||
void headerData(byte val) { mHeaderData = val; }
|
||||
byte headerData() { return mHeaderData; }
|
||||
void seqno(short val) { mSeqNo = val; }
|
||||
short seqno() { return mSeqNo; }
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Event
|
||||
{
|
||||
static final byte ERROR = 0; // pseudo-event
|
||||
static final byte REPLY = 1; // pseudo-event
|
||||
static final byte KEY_PRESS = 2;
|
||||
static final byte KEY_RELEASE = 3;
|
||||
static final byte BUTTON_PRESS = 4;
|
||||
static final byte BUTTON_RELEASE = 5;
|
||||
static final byte MOTION_NOTIFY = 6;
|
||||
static final byte ENTER_NOTIFY = 7;
|
||||
static final byte LEAVE_NOTIFY = 8;
|
||||
static final byte FOCUS_IN = 9;
|
||||
static final byte FOCUS_OUT = 10;
|
||||
static final byte KEYMAP_NOTIFY = 11;
|
||||
static final byte EXPOSE = 12;
|
||||
static final byte GRAPHICS_EXPOSE = 13;
|
||||
static final byte NO_EXPOSE = 14;
|
||||
static final byte VISIBILITY_NOTIFY = 15;
|
||||
static final byte CREATE_NOTIFY = 16;
|
||||
static final byte DESTROY_NOTIFY = 17;
|
||||
static final byte UNMAP_NOTIFY = 18;
|
||||
static final byte MAP_NOTIFY = 19;
|
||||
static final byte MAP_REQUEST = 20;
|
||||
static final byte REPARENT_NOTIFY = 21;
|
||||
static final byte CONFIGURE_NOTIFY = 22;
|
||||
static final byte CONFIGURE_REQUEST = 23;
|
||||
static final byte GRAVITY_NOTIFY = 24;
|
||||
static final byte RESIZE_REQUEST = 25;
|
||||
static final byte CIRCULATE_NOTIFY = 26;
|
||||
static final byte CIRCULATE_REQUEST = 27;
|
||||
static final byte PROPERTY_NOTIFY = 28;
|
||||
static final byte SELECTION_CLEAR = 29;
|
||||
static final byte SELECTION_REQUEST = 30;
|
||||
static final byte SELECTION_NOTIFY = 31;
|
||||
static final byte COLORMAP_NOTIFY = 32;
|
||||
static final byte CLIENT_MESSAGE = 33;
|
||||
static final byte MAPPING_NOTIFY = 34;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
class X11EventMessage extends X11Message
|
||||
{
|
||||
static final String[] message_names = {
|
||||
"NONE",
|
||||
"NONE",
|
||||
"KeyPress",
|
||||
"KeyRelease",
|
||||
"ButtonPress",
|
||||
"ButtonRelease",
|
||||
"MotionNotify",
|
||||
"EnterNotify",
|
||||
"LeaveNotify",
|
||||
"FocusIn",
|
||||
"FocusOut", // 10
|
||||
"KeymapNotify",
|
||||
"Expose",
|
||||
"GraphicsExposure",
|
||||
"NoExposure",
|
||||
"VisibilityNotify",
|
||||
"CreateNotify",
|
||||
"DestroyNotify",
|
||||
"UnmapNotify",
|
||||
"MapNotify",
|
||||
"MapRequest", // 20
|
||||
"ReparentNotify",
|
||||
"ConfigureNotify",
|
||||
"ConfigureRequest",
|
||||
"GravityNotify",
|
||||
"ResizeRequest",
|
||||
"CirculateNotify",
|
||||
"CirculateRequest",
|
||||
"PropertyNotify",
|
||||
"SelectionClear",
|
||||
"SelectionRequest", // 30
|
||||
"SelectionNotify",
|
||||
"ColormapNotify",
|
||||
"ClientMessage",
|
||||
"MappingNotify"
|
||||
};
|
||||
|
||||
String name() { return message_names[mEventType]; }
|
||||
|
||||
byte mEventType;
|
||||
byte mHeaderData;
|
||||
short mSeqNo;
|
||||
|
||||
X11EventMessage(ByteOrder endian, byte evtype) {
|
||||
super(endian);
|
||||
mEventType = evtype;
|
||||
mData.resize(28);
|
||||
}
|
||||
|
||||
void read(ByteQueue q) {
|
||||
mEventType = q.deqByte();
|
||||
mHeaderData = q.deqByte();
|
||||
mSeqNo = q.deqShort();
|
||||
mData = q.deqData(28);
|
||||
}
|
||||
void write(ByteQueue q) {
|
||||
q.enqByte(mEventType);
|
||||
q.enqByte(mHeaderData);
|
||||
q.enqShort(mSeqNo);
|
||||
q.enqData(mData);
|
||||
q.enqSkip(28 - mData.pos());
|
||||
}
|
||||
void dispatch(X11ProtocolHandler h) { h.onMessage(this); }
|
||||
|
||||
void headerData(byte val) { mHeaderData = val; }
|
||||
byte headerData() { return mHeaderData; }
|
||||
void seqno(short val) { mSeqNo = val; }
|
||||
short seqno() { return mSeqNo; }
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class X11Font extends X11Fontable
|
||||
{
|
||||
class CacheKey {
|
||||
char ch;
|
||||
int fore;
|
||||
int back;
|
||||
|
||||
CacheKey(char c, int f, int b) { ch = c; fore = f; back = b; }
|
||||
public int hashCode() { return ((ch << 24) | (fore ^ back)); }
|
||||
public boolean equals(Object obj) {
|
||||
CacheKey other = (CacheKey)obj;
|
||||
return (other.ch == ch && other.fore == fore && other.back == back);
|
||||
}
|
||||
}
|
||||
|
||||
FontData mData;
|
||||
Map<CacheKey,Bitmap> mImageCache;
|
||||
|
||||
X11Font(int id, FontData data) {
|
||||
super(X11Resource.FONT, id);
|
||||
mData = data;
|
||||
mImageCache = new HashMap<CacheKey,Bitmap>();
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mImageCache = null;
|
||||
mData = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void handleCloseFont(X11Client c, X11RequestMessage msg) {
|
||||
c.delResource(mId);
|
||||
}
|
||||
|
||||
void handleQueryFont(X11Client c, X11RequestMessage msg) {
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
mData.enqueueInfo(reply.mData);
|
||||
mData.enqueueCharInfoCount(reply.mData);
|
||||
mData.enqueueProperties(reply.mData);
|
||||
mData.enqueueCharInfo(reply.mData);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
X11CharInfo getCharInfo(char ch) {
|
||||
return mData.mCharInfos.get(ch);
|
||||
}
|
||||
|
||||
Bitmap getCharImage(char ch, int fore, int back) {
|
||||
CacheKey key = new CacheKey(ch, fore, back);
|
||||
Bitmap bmp = mImageCache.get(key);
|
||||
if (bmp == null) {
|
||||
Bitmap glyph = mData.getBitmap(ch);
|
||||
if (glyph == null) {
|
||||
return null;
|
||||
}
|
||||
int w = glyph.getWidth();
|
||||
int h = glyph.getHeight();
|
||||
bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
int x, y;
|
||||
for (y = 0; y < h; ++y) {
|
||||
for (x = 0; x < w; ++x) {
|
||||
int pixel = glyph.getPixel(x, y);
|
||||
bmp.setPixel(x, y, (pixel == Color.BLACK ? back : fore));
|
||||
}
|
||||
}
|
||||
mImageCache.put(key, bmp);
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
void showBitmap(char ch) {
|
||||
Log.d("X", "Show bitmap for <"+ch+">...");
|
||||
X11CharInfo info = getCharInfo(ch);
|
||||
Bitmap bmp = mData.getBitmap(ch);
|
||||
if (bmp == null) {
|
||||
Log.d("X", " (null)");
|
||||
return;
|
||||
}
|
||||
Log.d("X", " w="+bmp.getWidth()+", h="+bmp.getHeight()+", a="+info.ascent+", d="+info.descent+" ...");
|
||||
for (int y = 0; y < bmp.getHeight(); ++y) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int x = 0; x < bmp.getWidth(); ++x) {
|
||||
if (bmp.getPixel(x, y) == Color.BLACK) {
|
||||
buf.append(".");
|
||||
}
|
||||
else {
|
||||
buf.append("X");
|
||||
}
|
||||
}
|
||||
Log.d("X", " " + buf);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11FontProp
|
||||
{
|
||||
int name;
|
||||
int value;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package tdm.xserver;
|
||||
|
||||
abstract class X11Fontable extends X11Resource
|
||||
{
|
||||
X11Fontable(int t, int n) {
|
||||
super(t, n);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
abstract void handleQueryFont(X11Client c, X11RequestMessage msg);
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
abstract class X11Format
|
||||
{
|
||||
byte mDepth;
|
||||
byte mBPP;
|
||||
byte mPad;
|
||||
|
||||
X11Format(byte d, byte b, byte p) {
|
||||
mDepth = d;
|
||||
mBPP = b;
|
||||
mPad = p;
|
||||
}
|
||||
|
||||
protected void decodePlane(short w, short h, byte[] buf, byte plane, Bitmap bmp) {
|
||||
int plane_shift = (mDepth - plane);
|
||||
int bytes_per_row = MathX.divceil(w, 8);
|
||||
int bytes_per_plane = h * bytes_per_row;
|
||||
short y, x;
|
||||
int plane_off, y_off, x_off;
|
||||
byte val;
|
||||
|
||||
plane_off = plane * bytes_per_plane;
|
||||
for (y = 0; y < h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < w; ++x) {
|
||||
x_off = x/8;
|
||||
val = buf[plane_off + y_off + x_off];
|
||||
int shift = (7 - (x%8));
|
||||
|
||||
int tmp = bmp.getPixel(x, y);
|
||||
tmp |= ((val >> shift) & 0x1) << plane_shift;
|
||||
bmp.setPixel(x, y, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap decodeImageXY(short w, short h, ByteQueue q) {
|
||||
byte[] buf = q.deqArray(w*h*mBPP/8); //XXX
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
byte plane;
|
||||
for (plane = 0; plane < mBPP; ++plane) {
|
||||
decodePlane(w, h, buf, plane, bmp);
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
abstract Bitmap decodeImageZ(short w, short h, ByteQueue q);
|
||||
|
||||
protected void encodePlane(X11Rect r, Bitmap bmp, byte plane, byte[] buf) {
|
||||
int plane_shift = (mDepth - plane);
|
||||
int bytes_per_row = MathX.divceil(r.w, 8);
|
||||
int bytes_per_plane = r.h * bytes_per_row;
|
||||
short y, x;
|
||||
int plane_off, y_off, x_off;
|
||||
int val;
|
||||
|
||||
plane_off = plane * bytes_per_plane;
|
||||
for (y = 0; y < r.h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < r.w; ++x) {
|
||||
x_off = x/8;
|
||||
val = bmp.getPixel(r.x + x, r.y + y);
|
||||
int shift = (7 - (x%8));
|
||||
byte v;
|
||||
v = buf[plane_off + y_off + x_off];
|
||||
v |= ((val >> plane_shift) & 0x1) << shift;
|
||||
buf[plane_off + y_off + x_off] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] encodeImageXY(X11Rect r, int plane_mask, Bitmap bmp) {
|
||||
byte[] buf = new byte[r.w*r.h*mBPP/8]; //XXX
|
||||
byte plane;
|
||||
for (plane = 0; plane < mBPP; ++plane) {
|
||||
if ((plane_mask & (1 << plane)) != 0) {
|
||||
encodePlane(r, bmp, plane, buf);
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
abstract byte[] encodeImageZ(X11Rect r, int plane_mask, Bitmap bmp);
|
||||
}
|
||||
|
||||
class X11Format_1 extends X11Format
|
||||
{
|
||||
X11Format_1() { super((byte)1, (byte)1, (byte)8); }
|
||||
|
||||
Bitmap decodeImageZ(short w, short h, ByteQueue q) {
|
||||
int bytes_per_row = MathX.divceil(w, 8);
|
||||
byte[] buf = q.deqArray(bytes_per_row*h);
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
decodePlane(w, h, buf, (byte)0, bmp);
|
||||
return bmp;
|
||||
}
|
||||
|
||||
byte[] encodeImageZ(X11Rect r, int plane_mask, Bitmap bmp) {
|
||||
int bytes_per_row = MathX.divceil(r.w, 8);
|
||||
byte[] buf = new byte[bytes_per_row*r.h];
|
||||
if ((plane_mask & 1) != 0) {
|
||||
encodePlane(r, bmp, (byte)0, buf);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
class X11Format_4 extends X11Format
|
||||
{
|
||||
X11Format_4() { super((byte)4, (byte)4, (byte)8); }
|
||||
|
||||
Bitmap decodeImageZ(short w, short h, ByteQueue q) {
|
||||
int bytes_per_row = MathX.divceil(w, 2);
|
||||
byte[] buf = q.deqArray(bytes_per_row*h);
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < w; ++x) {
|
||||
x_off = x/2;
|
||||
val = buf[y_off + x_off];
|
||||
bmp.setPixel(x, y, (val >> (4*(1-x%2))) & 0xf);
|
||||
}
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
byte[] encodeImageZ(X11Rect r, int plane_mask, Bitmap bmp) {
|
||||
int bytes_per_row = MathX.divceil(r.w, 2);
|
||||
byte[] buf = new byte[bytes_per_row*r.h];
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < r.h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < r.w; ++x) {
|
||||
x_off = x/2;
|
||||
val = bmp.getPixel(r.x + x, r.y + y) & 0xf;
|
||||
val &= plane_mask;
|
||||
buf[y_off + x_off] = (byte)(val << 4*(1-x%2));
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
class X11Format_8 extends X11Format
|
||||
{
|
||||
X11Format_8() { super((byte)8, (byte)8, (byte)8); }
|
||||
|
||||
Bitmap decodeImageZ(short w, short h, ByteQueue q) {
|
||||
byte[] buf = q.deqArray(w*h);
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < h; ++y) {
|
||||
y_off = y * w;
|
||||
for (x = 0; x < w; ++x) {
|
||||
x_off = x;
|
||||
val = buf[y_off + x_off];
|
||||
bmp.setPixel(x, y, val);
|
||||
}
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
byte[] encodeImageZ(X11Rect r, int plane_mask, Bitmap bmp) {
|
||||
int bytes_per_row = r.w;
|
||||
byte[] buf = new byte[bytes_per_row*r.h];
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < r.h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < r.w; ++x) {
|
||||
x_off = x;
|
||||
val = bmp.getPixel(r.x + x, r.y + y);
|
||||
val &= plane_mask;
|
||||
buf[y_off + x_off] = (byte)val;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
class X11Format_16 extends X11Format
|
||||
{
|
||||
X11Format_16() { super((byte)16, (byte)16, (byte)16); }
|
||||
|
||||
Bitmap decodeImageZ(short w, short h, ByteQueue q) {
|
||||
int bytes_per_row = w*2;
|
||||
byte[] buf = q.deqArray(bytes_per_row*h);
|
||||
//XXX: This is wrong. Use RGB_565 and copyPixelsFromBuffer?
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < w; ++x) {
|
||||
x_off = x*2;
|
||||
val = (buf[y_off + x_off + 0] << 8) |
|
||||
buf[y_off + x_off + 1];
|
||||
bmp.setPixel(x, y, val);
|
||||
}
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
byte[] encodeImageZ(X11Rect r, int plane_mask, Bitmap bmp) {
|
||||
int bytes_per_row = r.w*2;
|
||||
byte[] buf = new byte[bytes_per_row*r.h];
|
||||
//XXX: This is wrong. Use RGB_565 and copyPixelsToBuffer?
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < r.h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < r.w; ++x) {
|
||||
x_off = x*2;
|
||||
val = bmp.getPixel(r.x + x, r.y + y);
|
||||
val &= plane_mask;
|
||||
buf[y_off + x_off + 0] = (byte)(val >> 8);
|
||||
buf[y_off + x_off + 1] = (byte)val;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
class X11Format_24 extends X11Format
|
||||
{
|
||||
X11Format_24() { super((byte)24, (byte)32, (byte)32); }
|
||||
|
||||
Bitmap decodeImageZ(short w, short h, ByteQueue q) {
|
||||
int bytes_per_row = w*4;
|
||||
byte[] buf = q.deqArray(bytes_per_row*h);
|
||||
//XXX: Use copyPixelsFromBuffer?
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < w; ++x) {
|
||||
x_off = x*4;
|
||||
val = (buf[y_off + x_off + 1] << 16) |
|
||||
(buf[y_off + x_off + 2] << 8) |
|
||||
buf[y_off + x_off + 3];
|
||||
bmp.setPixel(x, y, 0xff000000 | val);
|
||||
}
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
byte[] encodeImageZ(X11Rect r, int plane_mask, Bitmap bmp) {
|
||||
int bytes_per_row = r.w*4;
|
||||
byte[] buf = new byte[bytes_per_row*r.h];
|
||||
//XXX: Use copyPixelsToBuffer?
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < r.h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < r.w; ++x) {
|
||||
x_off = x*4;
|
||||
val = bmp.getPixel(r.x + x, r.y + y);
|
||||
val &= plane_mask;
|
||||
buf[y_off + x_off + 0] = (byte)0;
|
||||
buf[y_off + x_off + 1] = (byte)(val >> 16);
|
||||
buf[y_off + x_off + 2] = (byte)(val >> 8);
|
||||
buf[y_off + x_off + 3] = (byte)val;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
class X11Format_32 extends X11Format
|
||||
{
|
||||
X11Format_32() { super((byte)32, (byte)32, (byte)32); }
|
||||
|
||||
Bitmap decodeImageZ(short w, short h, ByteQueue q) {
|
||||
int bytes_per_row = w*4;
|
||||
byte[] buf = q.deqArray(bytes_per_row*h);
|
||||
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < w; ++x) {
|
||||
x_off = x*4;
|
||||
//XXX: what about alpha?
|
||||
val = (buf[y_off + x_off + 0] << 24) |
|
||||
(buf[y_off + x_off + 1] << 16) |
|
||||
(buf[y_off + x_off + 2] << 8) |
|
||||
buf[y_off + x_off + 3];
|
||||
bmp.setPixel(x, y, val);
|
||||
}
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
byte[] encodeImageZ(X11Rect r, int plane_mask, Bitmap bmp) {
|
||||
int bytes_per_row = r.w*4;
|
||||
byte[] buf = new byte[bytes_per_row*r.h];
|
||||
short y, x;
|
||||
int y_off, x_off;
|
||||
int val;
|
||||
for (y = 0; y < r.h; ++y) {
|
||||
y_off = y * bytes_per_row;
|
||||
for (x = 0; x < r.w; ++x) {
|
||||
x_off = x*4;
|
||||
//XXX: what about alpha?
|
||||
val = bmp.getPixel(r.x + x, r.y + y);
|
||||
val &= plane_mask;
|
||||
buf[y_off + x_off + 0] = (byte)(val >> 24);
|
||||
buf[y_off + x_off + 1] = (byte)(val >> 16);
|
||||
buf[y_off + x_off + 2] = (byte)(val >> 8);
|
||||
buf[y_off + x_off + 3] = (byte)val;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
|
||||
class X11GContext extends X11Fontable
|
||||
{
|
||||
static void create(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int id = msg.mData.deqInt();
|
||||
X11GContext r = new X11GContext(id);
|
||||
r.handleCreate(c, msg);
|
||||
c.addResource(r);
|
||||
}
|
||||
|
||||
Paint mPaint;
|
||||
|
||||
X11Drawable mDrawable;
|
||||
byte mFunction;
|
||||
int mPlaneMask;
|
||||
int mForePixel;
|
||||
int mBackPixel;
|
||||
short mLineWidth;
|
||||
byte mLineStyle;
|
||||
byte mCapStyle;
|
||||
byte mJoinStyle;
|
||||
byte mFillStyle;
|
||||
byte mFillRule;
|
||||
X11Pixmap mTile;
|
||||
X11Pixmap mStipple;
|
||||
X11Point mTileStippleOrigin;
|
||||
X11Font mFont;
|
||||
byte mSubWindowMode;
|
||||
byte mGraphicsExposures;
|
||||
X11Point mClipOrigin;
|
||||
X11Pixmap mClipMask;
|
||||
Path mClipPath;
|
||||
short mDashOffset;
|
||||
byte mDashes;
|
||||
byte mArcMode;
|
||||
|
||||
X11GContext(int n) {
|
||||
super(X11Resource.GCONTEXT, n);
|
||||
mPaint = new Paint();
|
||||
mForePixel = 0xff000000;
|
||||
mPaint.setColor(mForePixel);
|
||||
mBackPixel = 0xffffffff;
|
||||
mTileStippleOrigin = new X11Point();
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mClipPath = null;
|
||||
mClipMask = null;
|
||||
mClipOrigin = null;
|
||||
mFont = null;
|
||||
mTileStippleOrigin = null;
|
||||
mStipple = null;
|
||||
mTile = null;
|
||||
mDrawable = null;
|
||||
mPaint = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void handleQueryFont(X11Client c, X11RequestMessage msg) {
|
||||
mFont.handleQueryFont(c, msg);
|
||||
}
|
||||
|
||||
void handleCreate(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int id = msg.mData.deqInt();
|
||||
mDrawable = c.getDrawable(id);
|
||||
doChangeAttributes(c, msg.mData);
|
||||
}
|
||||
|
||||
void handleChangeGC(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
doChangeAttributes(c, msg.mData);
|
||||
}
|
||||
|
||||
void handleSetClipRectangles(X11Client c, X11RequestMessage msg) {
|
||||
byte ordering = msg.headerData();
|
||||
mClipOrigin = new X11Point();
|
||||
mClipOrigin.x = msg.mData.deqShort();
|
||||
mClipOrigin.y = msg.mData.deqShort();
|
||||
mClipPath = new Path();
|
||||
while (msg.mData.remain() > 0) {
|
||||
short x = msg.mData.deqShort();
|
||||
short y = msg.mData.deqShort();
|
||||
short w = msg.mData.deqShort();
|
||||
short h = msg.mData.deqShort();
|
||||
mClipPath.addRect(x, y, x+w, y+h, Path.Direction.CW);
|
||||
}
|
||||
}
|
||||
|
||||
void handleFreeGC(X11Client c, X11RequestMessage msg) {
|
||||
c.delResource(mId);
|
||||
}
|
||||
|
||||
private void doChangeAttributes(X11Client c, ByteQueue q) throws X11Error {
|
||||
int mask = q.deqInt();
|
||||
int val;
|
||||
|
||||
if ((mask & 0x000001) != 0) { // function
|
||||
mFunction = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x000002) != 0) { // plane-mask
|
||||
mPlaneMask = q.deqInt();
|
||||
}
|
||||
if ((mask & 0x000004) != 0) { // foreground
|
||||
mForePixel = (q.deqInt() | 0xff000000);
|
||||
mPaint.setColor(mForePixel);
|
||||
}
|
||||
if ((mask & 0x000008) != 0) { // background
|
||||
mBackPixel = (q.deqInt() | 0xff000000);
|
||||
}
|
||||
if ((mask & 0x000010) != 0) { // line-width
|
||||
mLineWidth = (short)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x000020) != 0) { // line-style
|
||||
mLineStyle = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x000040) != 0) { // cap-style
|
||||
mCapStyle = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x000080) != 0) { // join-style
|
||||
mJoinStyle = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x000100) != 0) { // fill-style
|
||||
mFillStyle = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x000200) != 0) { // fill-rule
|
||||
mFillRule = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x000400) != 0) { // tile
|
||||
mTile = c.getPixmap(q.deqInt());
|
||||
}
|
||||
if ((mask & 0x000800) != 0) { // stipple
|
||||
mStipple = c.getPixmap(q.deqInt());
|
||||
}
|
||||
if ((mask & 0x001000) != 0) { // tile-stipple-x-origin
|
||||
mTileStippleOrigin.x = (short)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x002000) != 0) { // tile-stipple-y-origin
|
||||
mTileStippleOrigin.y = (short)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x004000) != 0) { // font
|
||||
mFont = c.getFont(q.deqInt());
|
||||
}
|
||||
if ((mask & 0x008000) != 0) { // subwindow-mode
|
||||
mSubWindowMode = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x010000) != 0) { // graphics-exposures
|
||||
mGraphicsExposures = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x020000) != 0) { // clip-x-origin
|
||||
mClipOrigin.x = (short)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x040000) != 0) { // clip-y-origin
|
||||
mClipOrigin.y = (short)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x080000) != 0) { // clip-mask
|
||||
val = q.deqInt();
|
||||
if (val == X11Resource.NONE) {
|
||||
mClipMask = null;
|
||||
}
|
||||
else {
|
||||
mClipMask = c.getPixmap(val);
|
||||
}
|
||||
}
|
||||
if ((mask & 0x100000) != 0) { // dash-offset
|
||||
mDashOffset = (short)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x200000) != 0) { // dashes
|
||||
mDashes = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x400000) != 0) { // arc-mode
|
||||
mArcMode = (byte)q.deqInt();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioTrack;
|
||||
import android.media.AudioManager;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
class X11Keyboard
|
||||
{
|
||||
static final byte NO_SYMBOL = 0;
|
||||
|
||||
static final int X_MIN_KEYCODE = 8;
|
||||
|
||||
static final int NUM_KEYCODES = 100;
|
||||
static final int NUM_MODIFIERS = 8;
|
||||
|
||||
/*
|
||||
* NB: Many keycodes are undefined in v2.3.
|
||||
* (ESCAPE, Fn keys, numpad, etc.)
|
||||
*/
|
||||
static final int[][] key_codes = {
|
||||
{ 0, 0 }, // 0
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 }, // KEYCODE_CALL
|
||||
{ 0, 0 }, // KEYCODE_ENDCALL
|
||||
{ '0', ')' }, // KEYCODE_0
|
||||
{ '1', '!' }, // KEYCODE_1
|
||||
{ '2', '@' }, // KEYCODE_2
|
||||
{ '3', '#' }, // KEYCODE_3 10
|
||||
{ '4', '$' }, // KEYCODE_4
|
||||
{ '5', '%' }, // KEYCODE_5
|
||||
{ '6', '^' }, // KEYCODE_6
|
||||
{ '7', '&' }, // KEYCODE_7
|
||||
{ '8', '*' }, // KEYCODE_8
|
||||
{ '9', '(' }, // KEYCODE_9
|
||||
{ '*', '*' }, // KEYCODE_STAR (XXX: see KEYCODE_8)
|
||||
{ '#', '#' }, // KEYCODE_POUND (XXX: see KEYCODE_3)
|
||||
{ 0, 0 }, // KEYCODE_DPAD_UP
|
||||
{ 0, 0 }, // KEYCODE_DPAD_DOWN 20
|
||||
{ 0, 0 }, // KEYCODE_DPAD_LEFT
|
||||
{ 0, 0 }, // KEYCODE_DPAD_RIGHT
|
||||
{ 0xffe3, 0 }, // KEYCODE_DPAD_CENTER (=> L.CTRL)
|
||||
{ 0, 0 }, // KEYCODE_VOLUME_UP
|
||||
{ 0, 0 }, // KEYCODE_VOLUME_DOWN
|
||||
{ 0, 0 }, // KEYCODE_POWER
|
||||
{ 0, 0 }, // KEYCODE_CAMERA
|
||||
{ 0, 0 }, // KEYCODE_CLEAR
|
||||
{ 'a', 'A' }, // KEYCODE_A
|
||||
{ 'b', 'B' }, // KEYCODE_B 30
|
||||
{ 'c', 'C' }, // KEYCODE_C
|
||||
{ 'd', 'D' }, // KEYCODE_D
|
||||
{ 'e', 'E' }, // KEYCODE_E
|
||||
{ 'f', 'F' }, // KEYCODE_F
|
||||
{ 'g', 'G' }, // KEYCODE_G
|
||||
{ 'h', 'H' }, // KEYCODE_H
|
||||
{ 'i', 'I' }, // KEYCODE_I
|
||||
{ 'j', 'J' }, // KEYCODE_J
|
||||
{ 'k', 'K' }, // KEYCODE_K
|
||||
{ 'l', 'L' }, // KEYCODE_L 40
|
||||
{ 'm', 'M' }, // KEYCODE_M
|
||||
{ 'n', 'N' }, // KEYCODE_N
|
||||
{ 'o', 'O' }, // KEYCODE_O
|
||||
{ 'p', 'P' }, // KEYCODE_P
|
||||
{ 'q', 'Q' }, // KEYCODE_Q
|
||||
{ 'r', 'R' }, // KEYCODE_R
|
||||
{ 's', 'S' }, // KEYCODE_S
|
||||
{ 't', 'T' }, // KEYCODE_T
|
||||
{ 'u', 'U' }, // KEYCODE_U
|
||||
{ 'v', 'V' }, // KEYCODE_V 50
|
||||
{ 'w', 'W' }, // KEYCODE_W
|
||||
{ 'x', 'X' }, // KEYCODE_X
|
||||
{ 'y', 'Y' }, // KEYCODE_Y
|
||||
{ 'z', 'Z' }, // KEYCODE_Z
|
||||
{ ',', '<' }, // KEYCODE_COMMA
|
||||
{ '.', '>' }, // KEYCODE_PERIOD
|
||||
{ 0x0101, 0 }, // KEYCODE_ALT_LEFT
|
||||
{ 0x0102, 0 }, // KEYCODE_ALT_RIGHT
|
||||
{ 0x0113, 0 }, // KEYCODE_SHIFT_LEFT
|
||||
{ 0x0114, 0 }, // KEYCODE_SHIFT_RIGHT 60
|
||||
{ 0xff09, 0xff09 }, // KEYCODE_TAB
|
||||
{ ' ', ' ' }, // KEYCODE_SPACE
|
||||
{ 0, 0 }, // KEYCODE_SYM
|
||||
{ 0, 0 },
|
||||
{ 0, 0 }, // KEYCODE_ENVELOPE
|
||||
{ 0xff0d, 0xff0d }, // KEYCODE_ENTER
|
||||
{ 0xff08, 0xff08 }, // KEYCODE_DEL (backspace)
|
||||
{ '`', '~' }, // KEYCODE_GRAVE
|
||||
{ '-', '_' }, // KEYCODE_MINUS
|
||||
{ '=', '+' }, // KEYCODE_EQUALS 70
|
||||
{ '[', '{' }, // KEYCODE_LEFT_BRACKET
|
||||
{ ']', '}' }, // KEYCODE_RIGHT_BRACKET
|
||||
{ '\\', '|' }, // KEYCODE_BACKSLASH
|
||||
{ ';', ':' }, // KEYCODE_SEMICOLON
|
||||
{ '\'', '"' }, // KEYCODE_APOSTROPHE
|
||||
{ '/', '?' }, // KEYCODE_SLASH
|
||||
{ '@', '@' }, // KEYCODE_AT (XXX: see KEYCODE_2)
|
||||
{ 0, 0 }, // KEYCODE_NUM (XXX: not numlock, see docs)
|
||||
{ 0, 0 }, // KEYCODE_HEADSETHOOK
|
||||
{ 0, 0 }, // KEYCODE_FOCUS 80
|
||||
{ '+', '+' }, // KEYCODE_PLUS (XXX: see KEYCODE_EQUALS)
|
||||
{ 0, 0 }, // KEYCODE_MENU
|
||||
{ 0, 0 }, // KEYCODE_NOTIFICATION
|
||||
{ 0, 0 }, // KEYCODE_SEARCH
|
||||
{ 0, 0 }, // KEYCODE_MEDIA_PLAY_PAUSE
|
||||
{ 0, 0 }, // KEYCODE_MEDIA_STOP
|
||||
{ 0, 0 }, // KEYCODE_MEDIA_NEXT
|
||||
{ 0, 0 }, // KEYCODE_MEDIA_PREVIOUS
|
||||
{ 0, 0 }, // KEYCODE_MEDIA_REWIND
|
||||
{ 0, 0 }, // KEYCODE_MEDIA_FAST_FORWARD 90
|
||||
{ 0, 0 }, // KEYCODE_MUTE
|
||||
{ 0x0111, 0 }, // KEYCODE_PAGE_UP
|
||||
{ 0x0110, 0 }, // KEYCODE_PAGE_DOWN
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 } // 100
|
||||
};
|
||||
|
||||
static final int[][] mod_map = {
|
||||
{ 59, 60 }, // Shift = KEYCODE_SHIFT_LEFT, KEYCODE_SHIFT_RIGHT
|
||||
{ 0, 0 }, // Lock = (none)
|
||||
{ 23, 0 }, // Control = KEYCODE_DPAD_CENTER, (none)
|
||||
{ 57, 58 }, // Mod1 = KEYCODE_ALT_LEFT, KEYCODE_ALT_RIGHT
|
||||
{ 0, 0 }, // Mod2 = (none)
|
||||
{ 0, 0 }, // Mod3 = (none)
|
||||
{ 0, 0 }, // Mod4 = (none)
|
||||
{ 0, 0 }, // Mod5 = (none)
|
||||
};
|
||||
|
||||
byte mGlobalAutoRepeat;
|
||||
byte mKeyClickPercent;
|
||||
|
||||
byte mBellVolume;
|
||||
short mBellPitchHZ;
|
||||
short mBellDurationMS;
|
||||
int mBellSampleCount;
|
||||
AudioTrack mBellAudioTrack;
|
||||
|
||||
int mLedMask;
|
||||
|
||||
byte mMinKeycode;
|
||||
byte mMaxKeycode;
|
||||
|
||||
short mModState;
|
||||
|
||||
short mPointerX;
|
||||
short mPointerY;
|
||||
|
||||
X11Keyboard() {
|
||||
mGlobalAutoRepeat = 0;
|
||||
mKeyClickPercent = 50;
|
||||
mBellVolume = 50;
|
||||
mBellPitchHZ = 2000;
|
||||
mBellDurationMS = 100;
|
||||
mLedMask = 0x00000000;
|
||||
mMinKeycode = X_MIN_KEYCODE;
|
||||
mMaxKeycode = X_MIN_KEYCODE + NUM_KEYCODES - 1;
|
||||
createBellAudioTrack();
|
||||
}
|
||||
|
||||
byte minKeycode() { return mMinKeycode; }
|
||||
byte maxKeycode() { return mMaxKeycode; }
|
||||
|
||||
void handleQueryPointer(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11Window w = c.getWindow(msg.mData.deqInt());
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.headerData((byte)1 /*True*/);
|
||||
reply.mData.enqInt(c.mServer.mDefaultScreen.mRoot.mId);
|
||||
reply.mData.enqInt(X11Resource.NONE); //XXX: child
|
||||
reply.mData.enqShort(mPointerX);
|
||||
reply.mData.enqShort(mPointerY);
|
||||
reply.mData.enqShort((short)(mPointerX - w.mRect.x)); // win-x
|
||||
reply.mData.enqShort((short)(mPointerY - w.mRect.y)); // win-y
|
||||
reply.mData.enqShort(mModState);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleGetKeyboardMapping(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int first_keycode = msg.mData.deqByte();
|
||||
int count = msg.mData.deqByte();
|
||||
Log.d("X", "handleGetKeyboardMapping: fc="+first_keycode+", count="+count);
|
||||
if (first_keycode < mMinKeycode) {
|
||||
throw new X11Error(X11Error.VALUE, first_keycode);
|
||||
}
|
||||
if (first_keycode+count-1 > mMaxKeycode) {
|
||||
throw new X11Error(X11Error.VALUE, count);
|
||||
}
|
||||
|
||||
byte keysyms_per_keycode = 2;
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.headerData(keysyms_per_keycode);
|
||||
reply.mData.enqSkip(24);
|
||||
int kc;
|
||||
for (kc = first_keycode; kc < first_keycode+count; ++kc) {
|
||||
reply.mData.enqInt(key_codes[kc-X_MIN_KEYCODE][0]);
|
||||
reply.mData.enqInt(key_codes[kc-X_MIN_KEYCODE][1]);
|
||||
}
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleBell(X11Client c, X11RequestMessage msg) {
|
||||
byte volumePercent = msg.headerData();
|
||||
int volume;
|
||||
if (volumePercent >= 0) {
|
||||
volume = mBellVolume - ((mBellVolume * volumePercent) / 100) + volumePercent;
|
||||
}
|
||||
else {
|
||||
volume = mBellVolume + ((mBellVolume * volumePercent) / 100);
|
||||
}
|
||||
int frame_count = mBellSampleCount/2; //XXX ???
|
||||
int loop_count = mBellDurationMS * mBellPitchHZ / 1000;
|
||||
mBellAudioTrack.setStereoVolume(volume, volume);
|
||||
mBellAudioTrack.setLoopPoints(0, frame_count, loop_count);
|
||||
mBellAudioTrack.play();
|
||||
}
|
||||
|
||||
void handleGetModifierMapping(X11Client c, X11RequestMessage msg) {
|
||||
byte keycodes_per_modifier = 2;
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.headerData(keycodes_per_modifier);
|
||||
reply.mData.enqSkip(24);
|
||||
int m;
|
||||
for (m = 0; m < NUM_MODIFIERS; ++m) {
|
||||
reply.mData.enqInt(mod_map[m][0] + X_MIN_KEYCODE);
|
||||
reply.mData.enqInt(mod_map[m][1] + X_MIN_KEYCODE);
|
||||
}
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void onKeyDown(int code) {
|
||||
int m;
|
||||
for (m = 0; m < NUM_MODIFIERS; ++m) {
|
||||
if (mod_map[m][0] == code || mod_map[m][1] == code) {
|
||||
mModState |= (1 << m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onKeyUp(int code) {
|
||||
int m;
|
||||
for (m = 0; m < NUM_MODIFIERS; ++m) {
|
||||
if (mod_map[m][0] == code || mod_map[m][1] == code) {
|
||||
mModState &= ~(1 << m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createBellAudioTrack() {
|
||||
int sample_rate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_NOTIFICATION);
|
||||
mBellSampleCount = (sample_rate / mBellPitchHZ);
|
||||
byte[] pcm_data = new byte[2*mBellSampleCount];
|
||||
for (int i = 0; i < mBellSampleCount; ++i) {
|
||||
short val = (short)(32767 * Math.sin(2 * Math.PI * i / mBellSampleCount));
|
||||
pcm_data[2*i+0] = (byte)(val & 0xff);
|
||||
pcm_data[2*i+1] = (byte)(val >> 8);
|
||||
}
|
||||
mBellAudioTrack = new AudioTrack(
|
||||
AudioManager.STREAM_NOTIFICATION,
|
||||
sample_rate,
|
||||
AudioFormat.CHANNEL_CONFIGURATION_MONO,
|
||||
AudioFormat.ENCODING_PCM_16BIT,
|
||||
mBellSampleCount,
|
||||
AudioTrack.MODE_STATIC);
|
||||
mBellAudioTrack.write(pcm_data, 0, mBellSampleCount);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
abstract class X11Message
|
||||
{
|
||||
ByteQueue mData;
|
||||
|
||||
abstract void read(ByteQueue q) throws Exception;
|
||||
abstract void write(ByteQueue q);
|
||||
abstract void dispatch(X11ProtocolHandler h);
|
||||
|
||||
X11Message(ByteOrder endian) {
|
||||
mData = new ByteQueue(32-4);
|
||||
mData.endian(endian);
|
||||
}
|
||||
|
||||
int QUADLEN(int val) {
|
||||
return ((val+3)/4);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
|
||||
class X11Pixmap extends X11Drawable
|
||||
{
|
||||
static void create(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int id = msg.mData.deqInt();
|
||||
X11Pixmap r = new X11Pixmap(id);
|
||||
r.handleCreate(c, msg);
|
||||
c.addResource(r);
|
||||
}
|
||||
|
||||
|
||||
X11Drawable mDrawable;
|
||||
|
||||
X11Pixmap(int id) {
|
||||
super(X11Resource.PIXMAP, id);
|
||||
mDrawable = null;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mDrawable = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void handleCreate(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
byte depth = msg.headerData();
|
||||
X11Drawable d = c.getDrawable(msg.mData.deqInt());
|
||||
short w = msg.mData.deqShort();
|
||||
short h = msg.mData.deqShort();
|
||||
if (w == 0 || h == 0) {
|
||||
throw new X11Error(X11Error.VALUE, 0);
|
||||
}
|
||||
doCreate(depth, w, h, d);
|
||||
}
|
||||
|
||||
void handleFreePixmap(X11Client c, X11RequestMessage msg) {
|
||||
c.delResource(mId);
|
||||
}
|
||||
|
||||
void doCreate(byte depth, short w, short h, X11Drawable d) {
|
||||
mDepth = depth;
|
||||
mRect = new X11Rect((short)0, (short)0, w, h);
|
||||
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
||||
mCanvas = new Canvas(mBitmap);
|
||||
mDrawable = d;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Point
|
||||
{
|
||||
short x;
|
||||
short y;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
class X11Pointer
|
||||
{
|
||||
int mButtonState;
|
||||
X11Point mLocation;
|
||||
|
||||
X11Pointer() {
|
||||
mLocation = new X11Point();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Property
|
||||
{
|
||||
int mType;
|
||||
byte mFormat;
|
||||
byte[] mVal;
|
||||
|
||||
X11Property(int t, byte f) {
|
||||
mType = t;
|
||||
mFormat = f;
|
||||
mVal = null;
|
||||
}
|
||||
|
||||
void setValue(byte[] buf) {
|
||||
mVal = buf;
|
||||
}
|
||||
void appendValue(byte[] buf) {
|
||||
byte[] newval = new byte[mVal.length + buf.length];
|
||||
System.arraycopy(mVal, 0, newval, 0, mVal.length);
|
||||
System.arraycopy(buf, 0, newval, mVal.length, buf.length);
|
||||
mVal = newval;
|
||||
}
|
||||
void prependValue(byte[] buf) {
|
||||
byte[] newval = new byte[mVal.length + buf.length];
|
||||
System.arraycopy(buf, 0, newval, 0, buf.length);
|
||||
System.arraycopy(mVal, 0, newval, buf.length, mVal.length);
|
||||
mVal = newval;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.EOFException;
|
||||
import java.net.SocketException;
|
||||
import java.lang.Exception;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
interface X11ProtocolHandler
|
||||
{
|
||||
void onMessage(X11SetupRequest msg);
|
||||
void onMessage(X11SetupResponse msg);
|
||||
void onMessage(X11RequestMessage msg);
|
||||
void onMessage(X11ReplyMessage msg);
|
||||
void onMessage(X11EventMessage msg);
|
||||
void onMessage(X11ErrorMessage msg);
|
||||
}
|
||||
|
||||
class X11Protocol
|
||||
{
|
||||
X11ProtocolHandler mHandler;
|
||||
Socket mSock;
|
||||
ByteOrder mEndian;
|
||||
ByteQueue mQueue;
|
||||
short mSendSeqNo;
|
||||
short mRecvSeqNo;
|
||||
boolean mBigReq;
|
||||
|
||||
X11Protocol(X11ProtocolHandler handler, Socket sock) {
|
||||
mHandler = handler;
|
||||
mSock = sock;
|
||||
|
||||
try {
|
||||
sock.setTcpNoDelay(true);
|
||||
}
|
||||
catch (SocketException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
void close() {
|
||||
try {
|
||||
mSock.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
void send(X11Message msg) throws IOException {
|
||||
ByteQueue q = new ByteQueue(32);
|
||||
q.endian(mEndian);
|
||||
msg.write(q);
|
||||
mSock.getOutputStream().write(q.getBytes());
|
||||
}
|
||||
|
||||
void read() throws IOException {
|
||||
byte[] buf = new byte[1500];
|
||||
int len = mSock.getInputStream().read(buf, 0, buf.length);
|
||||
if (len < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
if (mQueue == null) {
|
||||
if (buf[0] == 0x42) {
|
||||
mEndian = ByteOrder.BIG_ENDIAN;
|
||||
}
|
||||
else {
|
||||
mEndian = ByteOrder.LITTLE_ENDIAN;
|
||||
}
|
||||
mQueue = new ByteQueue(32);
|
||||
mQueue.endian(mEndian);
|
||||
}
|
||||
mQueue.pos(mQueue.length());
|
||||
mQueue.enqArray(buf, 0, len);
|
||||
|
||||
mQueue.pos(0);
|
||||
while (mQueue.remain() >= 4) {
|
||||
X11Message msg = null;
|
||||
if (mRecvSeqNo == 0) {
|
||||
msg = new X11SetupRequest(mEndian);
|
||||
}
|
||||
else {
|
||||
msg = new X11RequestMessage(mEndian, mBigReq);
|
||||
}
|
||||
|
||||
int oldpos = mQueue.pos();
|
||||
try {
|
||||
msg.read(mQueue);
|
||||
}
|
||||
catch (Exception e) {
|
||||
mQueue.pos(oldpos);
|
||||
break;
|
||||
}
|
||||
|
||||
msg.dispatch(mHandler);
|
||||
++mRecvSeqNo;
|
||||
}
|
||||
|
||||
mQueue.compact();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Rect
|
||||
{
|
||||
short x;
|
||||
short y;
|
||||
short w;
|
||||
short h;
|
||||
|
||||
X11Rect() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = 0;
|
||||
h = 0;
|
||||
}
|
||||
X11Rect(short _x, short _y, short _w, short _h) {
|
||||
x = _x;
|
||||
y = _y;
|
||||
w = _w;
|
||||
h = _h;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
class X11ReplyMessage extends X11Message
|
||||
{
|
||||
byte mHeaderData;
|
||||
short mSeqNo;
|
||||
|
||||
X11ReplyMessage(X11RequestMessage msg) {
|
||||
super(msg.mData.endian());
|
||||
mData.resize(28);
|
||||
}
|
||||
|
||||
void read(ByteQueue q) {
|
||||
byte event_type = q.deqByte(); // 0x01
|
||||
mHeaderData = q.deqByte();
|
||||
mSeqNo = q.deqShort();
|
||||
int exlen = q.deqInt();
|
||||
mData = q.deqData(24 + exlen*4);
|
||||
}
|
||||
void write(ByteQueue q) {
|
||||
q.enqByte((byte)0x01);
|
||||
q.enqByte(mHeaderData);
|
||||
q.enqShort(mSeqNo);
|
||||
|
||||
mData.enqAlign(4);
|
||||
int datalen = Math.max(24, mData.pos());
|
||||
q.enqInt((datalen-24)/4);
|
||||
q.enqData(mData);
|
||||
q.enqSkip(datalen - mData.pos());
|
||||
}
|
||||
void dispatch(X11ProtocolHandler h) { h.onMessage(this); }
|
||||
|
||||
void headerData(byte val) { mHeaderData = val; }
|
||||
byte headerData() { return mHeaderData; }
|
||||
void seqno(short val) { mSeqNo = val; }
|
||||
short seqno() { return mSeqNo; }
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
class X11RequestMessage extends X11Message
|
||||
{
|
||||
static final String[] message_names = {
|
||||
"NONE", // 0
|
||||
"CreateWindow",
|
||||
"ChangeWindowAttributes",
|
||||
"GetWindowAttributes",
|
||||
"DestroyWindow",
|
||||
"DestroySubwindows",
|
||||
"ChangeSaveSet",
|
||||
"ReparentWindow",
|
||||
"MapWindow",
|
||||
"MapSubwindows",
|
||||
"UnmapWindow", // 10
|
||||
"UnmapSubwindows",
|
||||
"ConfigureWindow",
|
||||
"CirculateWindow",
|
||||
"GetGeometry",
|
||||
"QueryTree",
|
||||
"InternAtom",
|
||||
"GetAtomName",
|
||||
"ChangeProperty",
|
||||
"DeleteProperty",
|
||||
"GetProperty", // 20
|
||||
"ListProperties",
|
||||
"SetSelectionOwner",
|
||||
"GetSelectionOwner",
|
||||
"ConvertSelection",
|
||||
"SendEvent",
|
||||
"GrabPointer",
|
||||
"UngrabPointer",
|
||||
"GrabButton",
|
||||
"UngrabButton",
|
||||
"ChangeActivePointerGrab", // 30
|
||||
"GrabKeyboard",
|
||||
"UngrabKeyboard",
|
||||
"GrabKey",
|
||||
"UngrabKey",
|
||||
"AllowEvents",
|
||||
"GrabServer",
|
||||
"UngrabServer",
|
||||
"QueryPointer",
|
||||
"GetMotionEvents",
|
||||
"TranslateCoords", // 40
|
||||
"WarpPointer",
|
||||
"SetInputFocus",
|
||||
"GetInputFocus",
|
||||
"QueryKeymap",
|
||||
"OpenFont",
|
||||
"CloseFont",
|
||||
"QueryFont",
|
||||
"QueryTextExtents",
|
||||
"ListFonts",
|
||||
"ListFontsWithInfo", // 50
|
||||
"SetFontPath",
|
||||
"GetFontPath",
|
||||
"CreatePixmap",
|
||||
"FreePixmap",
|
||||
"CreateGC",
|
||||
"ChangeGC",
|
||||
"CopyGC",
|
||||
"SetDashes",
|
||||
"SetClipRectangles",
|
||||
"FreeGC", // 60
|
||||
"ClearArea",
|
||||
"CopyArea",
|
||||
"CopyPlane",
|
||||
"PolyPoint",
|
||||
"PolyLine",
|
||||
"PolySegment",
|
||||
"PolyRectangle",
|
||||
"PolyArc",
|
||||
"FillPoly",
|
||||
"PolyFillRectangle", // 70
|
||||
"PolyFillArc",
|
||||
"PutImage",
|
||||
"GetImage",
|
||||
"PolyText8",
|
||||
"PolyText16",
|
||||
"ImageText8",
|
||||
"ImageText16",
|
||||
"CreateColormap",
|
||||
"FreeColormap",
|
||||
"CopyColormapAndFree", // 80
|
||||
"InstallColormap",
|
||||
"UninstallColormap",
|
||||
"ListInstalledColormaps",
|
||||
"AllocColor",
|
||||
"AllocNamedColor",
|
||||
"AllocColorCells",
|
||||
"AllocColorPlanes",
|
||||
"FreeColors",
|
||||
"StoreColors",
|
||||
"StoreNamedColor", // 90
|
||||
"QueryColors",
|
||||
"LookupColor",
|
||||
"CreateCursor",
|
||||
"CreateGlyphCursor",
|
||||
"FreeCursor",
|
||||
"RecolorCursor",
|
||||
"QueryBestSize",
|
||||
"QueryExtension",
|
||||
"ListExtensions",
|
||||
"ChangeKeyboardMapping", // 100
|
||||
"GetKeyboardMapping",
|
||||
"ChangeKeyboardControl",
|
||||
"GetKeyboardControl",
|
||||
"Bell",
|
||||
"ChangePointerControl",
|
||||
"GetPointerControl",
|
||||
"SetScreenSaver",
|
||||
"GetScreenSaver",
|
||||
"ChangeHosts",
|
||||
"ListHosts", // 110
|
||||
"SetAccessControl",
|
||||
"SetCloseDownMode",
|
||||
"KillClient",
|
||||
"RotateProperties",
|
||||
"ForceScreenSaver",
|
||||
"SetPointerMapping",
|
||||
"GetPointerMapping",
|
||||
"SetModifierMapping",
|
||||
"GetModifierMapping",
|
||||
"120", // 120
|
||||
"121",
|
||||
"122",
|
||||
"123",
|
||||
"124",
|
||||
"125",
|
||||
"126",
|
||||
"NoOperation"
|
||||
};
|
||||
|
||||
String name() { return message_names[mRequestType]; }
|
||||
|
||||
byte mRequestType;
|
||||
byte mHeaderData;
|
||||
boolean mBigReq;
|
||||
|
||||
X11RequestMessage(ByteOrder endian, boolean bigreq) {
|
||||
super(endian);
|
||||
mBigReq = bigreq;
|
||||
}
|
||||
|
||||
void read(ByteQueue q) throws Exception {
|
||||
mRequestType = q.deqByte();
|
||||
mHeaderData = q.deqByte();
|
||||
short reqlen = q.deqShort();
|
||||
if (reqlen == 0) {
|
||||
if (!mBigReq) {
|
||||
throw new Exception("X11 protocol error: invalid message length");
|
||||
}
|
||||
int bigreqlen = q.deqInt();
|
||||
if (bigreqlen < 2) {
|
||||
throw new Exception("X11 protocol error: invalid message length");
|
||||
}
|
||||
mData = q.deqData(bigreqlen*4-8);
|
||||
}
|
||||
else {
|
||||
mData = q.deqData((int)reqlen*4-4); //XXX: cast needed and functional?
|
||||
}
|
||||
}
|
||||
void write(ByteQueue q) {
|
||||
q.enqByte(mRequestType);
|
||||
q.enqByte(mHeaderData);
|
||||
|
||||
int reqlen = ((4+mData.length())+3)/4;
|
||||
if (reqlen > 0xffff) {
|
||||
if (!mBigReq) {
|
||||
//XXX: throw new Exception("X11 protocol error: message too big");
|
||||
System.exit(-1);
|
||||
}
|
||||
reqlen += 1;
|
||||
q.enqShort((short)0);
|
||||
q.enqInt(reqlen);
|
||||
}
|
||||
else {
|
||||
q.enqShort((short)reqlen);
|
||||
}
|
||||
q.enqData(mData);
|
||||
q.enqAlign(4);
|
||||
}
|
||||
void dispatch(X11ProtocolHandler h) { h.onMessage(this); }
|
||||
|
||||
void requestType(byte val) { mRequestType = val; }
|
||||
byte requestType() { return mRequestType; }
|
||||
void headerData(byte val) { mHeaderData = val; }
|
||||
byte headerData() { return mHeaderData; }
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Resource
|
||||
{
|
||||
// Resource constants
|
||||
static final int MIN_ID = 4;
|
||||
static final int ID_DEF_COLORMAP = MIN_ID+0;
|
||||
static final int ID_ROOT_WINDOW = MIN_ID+1;
|
||||
|
||||
static final int NONE = 0;
|
||||
|
||||
static final int NEVER = 0;
|
||||
|
||||
// Resource types
|
||||
static final int WINDOW = 1;
|
||||
static final int PIXMAP = 2;
|
||||
static final int GCONTEXT = 3;
|
||||
static final int FONT = 4;
|
||||
static final int CURSOR = 5;
|
||||
static final int COLORMAP = 6;
|
||||
static final int CMAPENTRY = 7;
|
||||
static final int OTHERCLIENT = 8;
|
||||
static final int PASSIVEGRAB = 9;
|
||||
|
||||
int mType;
|
||||
int mId;
|
||||
|
||||
X11Resource(int t, int n) {
|
||||
mType = t;
|
||||
mId = n;
|
||||
}
|
||||
|
||||
void destroy() {}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
class X11Screen
|
||||
{
|
||||
X11Window mRoot;
|
||||
X11Colormap mDefaultColormap;
|
||||
int mWhitePixel;
|
||||
int mBlackPixel;
|
||||
int mCurrentInputMasks;
|
||||
short mWidthPx;
|
||||
short mHeightPx;
|
||||
short mWidthMM;
|
||||
short mHeightMM;
|
||||
short mMinInstalledMaps;
|
||||
short mMaxInstalledMaps;
|
||||
int mRootVisual; //XXX: property of root?
|
||||
byte mBackingStores;
|
||||
byte mSaveUnders;
|
||||
byte mRootDepth; //XXX: property of root?
|
||||
ArrayList<X11Depth> mAllowedDepths;
|
||||
// ...
|
||||
|
||||
|
||||
X11Screen(X11Server server, X11Client client, short w, short h, short dpi) throws X11Error {
|
||||
mAllowedDepths = new ArrayList();
|
||||
|
||||
mDefaultColormap = new X11Colormap(X11Resource.ID_DEF_COLORMAP);
|
||||
client.addResource(mDefaultColormap);
|
||||
|
||||
mRoot = new X11Window(X11Resource.ID_ROOT_WINDOW);
|
||||
client.addResource(mRoot);
|
||||
|
||||
mDefaultColormap.initDefault();
|
||||
mRoot.mColormap = mDefaultColormap;
|
||||
|
||||
int vid = 0;
|
||||
X11Depth d;
|
||||
X11Visual v;
|
||||
|
||||
d = new X11Depth((byte)24);
|
||||
|
||||
v = new X11Visual(++vid, (byte)24);
|
||||
v.mVisClass = X11Visual.DIRECT_COLOR;
|
||||
v.mRedMask = (0xff << 16);
|
||||
v.mGreenMask = (0xff << 8);
|
||||
v.mBlueMask = (0xff);
|
||||
v.mBitsPerRgbValue = 8;
|
||||
v.mColormapEntries = (1 << 8);
|
||||
server.addVisual(v);
|
||||
d.visuals.add(v);
|
||||
|
||||
v = new X11Visual(++vid, (byte)24);
|
||||
v.mVisClass = X11Visual.TRUE_COLOR;
|
||||
v.mRedMask = (0xff << 16);
|
||||
v.mGreenMask = (0xff << 8);
|
||||
v.mBlueMask = (0xff);
|
||||
v.mBitsPerRgbValue = 8;
|
||||
v.mColormapEntries = (1 << 8);
|
||||
server.addVisual(v);
|
||||
d.visuals.add(v);
|
||||
|
||||
mAllowedDepths.add(d);
|
||||
|
||||
// root is depth 24, visual DirectColor
|
||||
mRoot.createRoot(client, w, h, d.depth, v);
|
||||
|
||||
//XXX: depth 1, 4, 8, 15, 16?
|
||||
|
||||
d = new X11Depth((byte)32);
|
||||
|
||||
v = new X11Visual(++vid, (byte)32);
|
||||
v.mVisClass = X11Visual.DIRECT_COLOR;
|
||||
v.mRedMask = (0xff << 16);
|
||||
v.mGreenMask = (0xff << 8);
|
||||
v.mBlueMask = (0xff);
|
||||
v.mBitsPerRgbValue = 8;
|
||||
v.mColormapEntries = (1 << 8);
|
||||
server.addVisual(v);
|
||||
d.visuals.add(v);
|
||||
|
||||
v = new X11Visual(++vid, (byte)32);
|
||||
v.mVisClass = X11Visual.TRUE_COLOR;
|
||||
v.mRedMask = (0xff << 16);
|
||||
v.mGreenMask = (0xff << 8);
|
||||
v.mBlueMask = (0xff);
|
||||
v.mBitsPerRgbValue = 8;
|
||||
v.mColormapEntries = (1 << 8);
|
||||
server.addVisual(v);
|
||||
d.visuals.add(v);
|
||||
|
||||
mAllowedDepths.add(d);
|
||||
|
||||
mWhitePixel = 0x00ffffff;
|
||||
mBlackPixel = 0;
|
||||
mCurrentInputMasks = 0;
|
||||
mWidthPx = w;
|
||||
mHeightPx = h;
|
||||
mWidthMM = (short)((254*w)/(10*dpi));
|
||||
mHeightMM = (short)((254*h)/(10*dpi));
|
||||
mMinInstalledMaps = 1;
|
||||
mMaxInstalledMaps = 1;
|
||||
mRootVisual = mRoot.mVisual.mId;
|
||||
mBackingStores = X11Resource.NEVER;
|
||||
mSaveUnders = 0;
|
||||
mRootDepth = mRoot.mDepth;
|
||||
}
|
||||
|
||||
void enqueue(ByteQueue q) {
|
||||
q.enqInt(mRoot.mId);
|
||||
q.enqInt(mDefaultColormap.mId);
|
||||
q.enqInt(mWhitePixel);
|
||||
q.enqInt(mBlackPixel);
|
||||
q.enqInt(mCurrentInputMasks);
|
||||
q.enqShort(mWidthPx);
|
||||
q.enqShort(mHeightPx);
|
||||
q.enqShort(mWidthMM);
|
||||
q.enqShort(mHeightMM);
|
||||
q.enqShort(mMinInstalledMaps);
|
||||
q.enqShort(mMaxInstalledMaps);
|
||||
q.enqInt(mRoot.mVisual.mId);
|
||||
q.enqByte(mBackingStores);
|
||||
q.enqByte(mSaveUnders);
|
||||
q.enqByte(mRoot.mDepth);
|
||||
|
||||
q.enqByte((byte)mAllowedDepths.size());
|
||||
for (X11Depth dep : mAllowedDepths) {
|
||||
q.enqByte(dep.depth);
|
||||
q.enqSkip(1);
|
||||
q.enqShort((short)dep.visuals.size());
|
||||
q.enqSkip(4);
|
||||
|
||||
for (X11Visual vis : dep.visuals) {
|
||||
q.enqInt(vis.mId);
|
||||
q.enqByte(vis.mVisClass);
|
||||
q.enqByte(vis.mBitsPerRgbValue);
|
||||
q.enqShort(vis.mColormapEntries);
|
||||
q.enqInt(vis.mRedMask);
|
||||
q.enqInt(vis.mGreenMask);
|
||||
q.enqInt(vis.mBlueMask);
|
||||
q.enqSkip(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Selection
|
||||
{
|
||||
X11Atom mSelection;
|
||||
X11Client mOwnerClient;
|
||||
X11Window mOwnerWindow;
|
||||
int mLastChangeTime;
|
||||
}
|
|
@ -0,0 +1,425 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.net.ServerSocket;
|
||||
|
||||
class X11Server extends Thread
|
||||
{
|
||||
Context mContext;
|
||||
UIHandler mHandler;
|
||||
|
||||
X11Client[] mClients;
|
||||
|
||||
Map<Integer,X11Visual> mVisuals;
|
||||
ArrayList<X11Format> mPixmapFormats;
|
||||
|
||||
Map<Integer,X11Atom> mAtomsById;
|
||||
Map<String,X11Atom> mAtomsByName;
|
||||
int mLastAtomId;
|
||||
|
||||
Map<Integer,X11Selection> mSelections;
|
||||
|
||||
Map<String,FontData> mFonts;
|
||||
Map<String,String> mFontAliases;
|
||||
|
||||
boolean mRunning;
|
||||
long mStartTime;
|
||||
ServerSocket mSock;
|
||||
|
||||
X11Keyboard mKeyboard;
|
||||
|
||||
X11Screen mDefaultScreen;
|
||||
X11Window mInputFocus;
|
||||
|
||||
X11Client mGrabClient;
|
||||
|
||||
X11Server(Context ctx, UIHandler handler) {
|
||||
mContext = ctx;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
mClients = new X11Client[X11Client.MAX_CLIENTS];
|
||||
mClients[0] = new X11Client(this);
|
||||
|
||||
mVisuals = new HashMap<Integer,X11Visual>();
|
||||
|
||||
mPixmapFormats = new ArrayList();
|
||||
mPixmapFormats.add(new X11Format_1()); //XXX
|
||||
mPixmapFormats.add(new X11Format_4());
|
||||
mPixmapFormats.add(new X11Format_8());
|
||||
mPixmapFormats.add(new X11Format_16());
|
||||
mPixmapFormats.add(new X11Format_24());
|
||||
mPixmapFormats.add(new X11Format_32());
|
||||
|
||||
X11Colormap.globalInit(this);
|
||||
|
||||
mAtomsById = new HashMap<Integer,X11Atom>();
|
||||
mAtomsByName = new HashMap<String,X11Atom>();
|
||||
mLastAtomId = 0;
|
||||
X11Atom.globalInit(this);
|
||||
|
||||
mSelections = new HashMap<Integer,X11Selection>();
|
||||
|
||||
mFonts = new HashMap<String,FontData>();
|
||||
mFontAliases = new HashMap<String,String>();
|
||||
FontData.globalInit(this);
|
||||
|
||||
// NB: PixelFormat (see dpy.getPixelFormat()) has bitsPerPixel/bytesPerPixel etc.
|
||||
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display dpy = wm.getDefaultDisplay();
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
dpy.getMetrics(dm);
|
||||
|
||||
mKeyboard = new X11Keyboard();
|
||||
|
||||
try {
|
||||
mDefaultScreen = new X11Screen(this, mClients[0],
|
||||
(short)dm.widthPixels,
|
||||
(short)dm.heightPixels,
|
||||
(short)dm.densityDpi);
|
||||
}
|
||||
catch (X11Error e) {
|
||||
Log.e(XServer.TAG, "Cannot create screen");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mSock = new ServerSocket(6000);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(XServer.TAG, "Cannot create server socket");
|
||||
return;
|
||||
}
|
||||
|
||||
mStartTime = System.currentTimeMillis();
|
||||
mRunning = true;
|
||||
while (mRunning) {
|
||||
try {
|
||||
for (int i = 1; i < X11Client.MAX_CLIENTS; ++i) {
|
||||
if (mClients[i] == null) {
|
||||
X11Client c = new X11Client(this, i, mSock.accept());
|
||||
mClients[i] = c;
|
||||
c.start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(XServer.TAG, "Exception in run");
|
||||
mRunning = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onStop() {
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
int currentTime() {
|
||||
return (int)(System.currentTimeMillis() - mStartTime);
|
||||
}
|
||||
|
||||
void clientClosed(X11Client c) {
|
||||
//XXX: locking
|
||||
if (mGrabClient == c) {
|
||||
mGrabClient = null;
|
||||
}
|
||||
//XXX: delete selections
|
||||
//XXX: ...???
|
||||
for (int i = 1; i < X11Client.MAX_CLIENTS; ++i) {
|
||||
if (mClients[i] == c) {
|
||||
c = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addVisual(X11Visual v) throws X11Error {
|
||||
if (mVisuals.containsKey(v.mId)) {
|
||||
throw new X11Error(X11Error.IDCHOICE, v.mId);
|
||||
}
|
||||
mVisuals.put(v.mId, v);
|
||||
}
|
||||
|
||||
void delVisual(int id) {
|
||||
mVisuals.remove(id);
|
||||
}
|
||||
|
||||
X11Visual getVisual(int id) {
|
||||
return mVisuals.get(id);
|
||||
}
|
||||
|
||||
ArrayList<X11Format> getPixmapFormats() {
|
||||
return mPixmapFormats;
|
||||
}
|
||||
|
||||
void registerFont(FontData f) {
|
||||
mFonts.put(f.mName, f);
|
||||
}
|
||||
void registerFontAlias(String alias, String name) {
|
||||
mFontAliases.put(alias, name);
|
||||
}
|
||||
|
||||
void handleInternAtom(X11Client c, X11RequestMessage msg) {
|
||||
byte onlyifexist = msg.headerData();
|
||||
short namelen = msg.mData.deqShort();
|
||||
msg.mData.deqSkip(2);
|
||||
String name = msg.mData.deqString(namelen);
|
||||
|
||||
int id = X11Atom.NONE;
|
||||
boolean created = false;
|
||||
if (!mAtomsByName.containsKey(name)) {
|
||||
if (onlyifexist == 0 /* False */) {
|
||||
id = doInternAtom(name);
|
||||
created = true;
|
||||
}
|
||||
}
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.mData.enqInt(id);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleSetSelectionOwner(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11Window owner = c.getWindow(msg.mData.deqInt());
|
||||
X11Atom selection_name = mAtomsById.get(msg.mData.deqInt());
|
||||
int time = msg.mData.deqInt();
|
||||
|
||||
X11Selection selection = mSelections.get(selection_name.mId);
|
||||
if (selection == null) {
|
||||
selection = new X11Selection();
|
||||
selection.mSelection = selection_name;
|
||||
selection.mOwnerClient = c;
|
||||
selection.mOwnerWindow = owner;
|
||||
selection.mLastChangeTime = currentTime();
|
||||
mSelections.put(selection_name.mId, selection);
|
||||
}
|
||||
|
||||
if (time < selection.mLastChangeTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selection.mOwnerClient != null && selection.mOwnerClient != c) {
|
||||
X11EventMessage event = new X11EventMessage(selection.mOwnerClient.mProt.mEndian, X11Event.SELECTION_CLEAR);
|
||||
event.mData.enqInt(time);
|
||||
event.mData.enqInt(owner.mId);
|
||||
event.mData.enqInt(selection_name.mId);
|
||||
selection.mOwnerClient.send(event);
|
||||
}
|
||||
|
||||
selection.mLastChangeTime = time;
|
||||
if (owner == null) {
|
||||
selection.mOwnerClient = null;
|
||||
selection.mOwnerWindow = null;
|
||||
}
|
||||
else {
|
||||
selection.mOwnerClient = c;
|
||||
selection.mOwnerWindow = owner;
|
||||
}
|
||||
}
|
||||
|
||||
void handleGetSelectionOwner(X11Client c, X11RequestMessage msg) {
|
||||
int id = X11Resource.NONE;
|
||||
X11Selection selection = mSelections.get(msg.mData.deqInt());
|
||||
if (selection != null) {
|
||||
id = selection.mOwnerWindow.mId;
|
||||
}
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.mData.enqInt(id);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleGrabServer(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
if (mGrabClient != null) {
|
||||
//XXX: handle recursion?
|
||||
Log.e("X", "Error: GrabServer while server is grabbed");
|
||||
throw new X11Error(X11Error.IMPLEMENTATION, 0);
|
||||
}
|
||||
mGrabClient = c;
|
||||
}
|
||||
|
||||
void handleUngrabServer(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
if (mGrabClient != c) {
|
||||
//XXX: ignore this?
|
||||
Log.e("X", "Error: UngrabServer while server is not grabbed");
|
||||
throw new X11Error(X11Error.IMPLEMENTATION, 0);
|
||||
}
|
||||
mGrabClient = null;
|
||||
}
|
||||
|
||||
void handleSetInputFocus(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
//XXX
|
||||
byte revert_to = msg.headerData();
|
||||
X11Window w = c.getWindow(msg.mData.deqInt());
|
||||
int timestamp = msg.mData.deqInt();
|
||||
mInputFocus = w;
|
||||
}
|
||||
|
||||
void handleGetInputFocus(X11Client c, X11RequestMessage msg) {
|
||||
//XXX
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.headerData((byte)0); // revert-to = None
|
||||
reply.mData.enqInt(mInputFocus.mId); // None
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleOpenFont(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int fid = msg.mData.deqInt();
|
||||
short len = msg.mData.deqShort();
|
||||
msg.mData.deqSkip(2);
|
||||
String name = msg.mData.deqString(len);
|
||||
name = name.toLowerCase();
|
||||
|
||||
if (mFontAliases.containsKey(name)) {
|
||||
Log.d("X", "OpenFont: alias: <" + name + "> => <" + mFontAliases.get(name) + ">");
|
||||
name = mFontAliases.get(name);
|
||||
}
|
||||
|
||||
FontData data = null;
|
||||
for (FontData i : mFonts.values()) {
|
||||
if (i.match(name)) {
|
||||
data = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
Log.d("X", "OpenFont: cannot find font <" + name + ">: trying fixed instead");
|
||||
data = mFonts.get(mFontAliases.get("fixed"));
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
Log.d("X", "OpenFont: cannot find font <" + name + ">");
|
||||
throw new X11Error(X11Error.NAME, fid);
|
||||
}
|
||||
Log.d("X", "OpenFont: opening " + data.mName);
|
||||
try {
|
||||
data.loadMetadata(this);
|
||||
data.loadGlyphs(this);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("X", "OpenFont: failed to load metadata");
|
||||
e.printStackTrace();
|
||||
throw new X11Error(X11Error.IMPLEMENTATION, 0);
|
||||
}
|
||||
X11Font font = new X11Font(fid, data);
|
||||
c.addResource(font);
|
||||
}
|
||||
|
||||
void handleListFonts(X11Client c, X11RequestMessage msg) {
|
||||
short maxnames = msg.mData.deqShort();
|
||||
short len = msg.mData.deqShort();
|
||||
String name = msg.mData.deqString(len);
|
||||
name = name.toLowerCase();
|
||||
|
||||
ArrayList<String> v = new ArrayList<String>();
|
||||
|
||||
for (FontData f : mFonts.values()) {
|
||||
if (f.match(name)) {
|
||||
v.add(f.mName);
|
||||
if (v.size() == maxnames) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//XXX: how should this be done?
|
||||
if (v.size() < maxnames) {
|
||||
String realname = mFontAliases.get(name);
|
||||
if (realname != null) {
|
||||
v.add(realname); //XXX?
|
||||
}
|
||||
}
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.mData.enqShort((short)v.size());
|
||||
reply.mData.enqSkip(22);
|
||||
|
||||
for (String s : v) {
|
||||
reply.mData.enqByte((byte)s.length());
|
||||
reply.mData.enqString(s);
|
||||
}
|
||||
reply.mData.enqAlign(4);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleListFontsWithInfo(X11Client c, X11RequestMessage msg) {
|
||||
short maxnames = msg.mData.deqShort();
|
||||
short len = msg.mData.deqShort();
|
||||
String pattern = msg.mData.deqString(len);
|
||||
pattern = pattern.toLowerCase();
|
||||
|
||||
ArrayList<FontData> v = new ArrayList<FontData>();
|
||||
|
||||
for (FontData f : mFonts.values()) {
|
||||
if (f.match(pattern)) {
|
||||
try {
|
||||
f.loadMetadata(this);
|
||||
v.add(f);
|
||||
if (v.size() == maxnames) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e("X", "Failed to read font " + f.mName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
|
||||
for (int n = 0; n < v.size(); ++n) {
|
||||
FontData f = v.get(n);
|
||||
reply.mData.clear();
|
||||
f.enqueueInfo(reply.mData);
|
||||
reply.mData.enqInt(v.size() - n);
|
||||
f.enqueueProperties(reply.mData);
|
||||
reply.mData.enqString(f.mName);
|
||||
reply.headerData((byte)f.mName.length());
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
reply.mData.clear();
|
||||
reply.mData.enqSkip(52);
|
||||
reply.headerData((byte)0);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleQueryExtension(X11Client c, X11RequestMessage msg) {
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.mData.enqByte((byte)0); // present
|
||||
reply.mData.enqByte((byte)0); // major-opcode
|
||||
reply.mData.enqByte((byte)0); // first-event
|
||||
reply.mData.enqByte((byte)0); // first-error
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void doInternAtom(int id, String name) {
|
||||
X11Atom atom = new X11Atom(id, name);
|
||||
mAtomsById.put(id, atom);
|
||||
mAtomsByName.put(name, atom);
|
||||
}
|
||||
|
||||
int doInternAtom(String name) {
|
||||
int id = ++mLastAtomId;
|
||||
doInternAtom(id, name);
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
class X11SetupRequest extends X11Message //XXX: extends X11Consumer?
|
||||
{
|
||||
ByteOrder mByteOrder;
|
||||
short mProtoMajor;
|
||||
short mProtoMinor;
|
||||
String mAuthProtoName;
|
||||
byte[] mAuthProtoData;
|
||||
|
||||
X11SetupRequest(ByteOrder endian) {
|
||||
super(endian);
|
||||
}
|
||||
|
||||
void read(ByteQueue q) throws Exception {
|
||||
short name_len, data_len;
|
||||
|
||||
mByteOrder = (q.deqByte() == (byte)0x42) ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
|
||||
q.deqSkip(1);
|
||||
mProtoMajor = q.deqShort();
|
||||
mProtoMinor = q.deqShort();
|
||||
name_len = q.deqShort();
|
||||
data_len = q.deqShort();
|
||||
q.deqSkip(2);
|
||||
mAuthProtoName = q.deqString(name_len);
|
||||
q.deqAlign(4);
|
||||
mAuthProtoData = q.deqArray(data_len);
|
||||
q.deqAlign(4);
|
||||
}
|
||||
void write(ByteQueue q) {
|
||||
short name_len = (short)mAuthProtoName.length();
|
||||
short data_len = (short)mAuthProtoData.length;
|
||||
|
||||
q.enqByte((mByteOrder == ByteOrder.BIG_ENDIAN) ? (byte)0x42 : (byte)0x6c);
|
||||
q.enqSkip(1);
|
||||
q.enqShort(mProtoMajor);
|
||||
q.enqShort(mProtoMinor);
|
||||
q.enqShort(name_len);
|
||||
q.enqShort(data_len);
|
||||
q.enqSkip(2);
|
||||
q.enqString(mAuthProtoName);
|
||||
q.enqArray(mAuthProtoData);
|
||||
}
|
||||
void dispatch(X11ProtocolHandler h) { h.onMessage(this); }
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
class X11SetupResponse extends X11Message //XXX: extends X11Consumer?
|
||||
{
|
||||
byte mSuccess;
|
||||
short mProtoMajor;
|
||||
short mProtoMinor;
|
||||
String mReason;
|
||||
|
||||
X11SetupResponse(X11SetupRequest msg) {
|
||||
super(msg.mData.endian());
|
||||
}
|
||||
|
||||
void read(ByteQueue q) throws Exception {
|
||||
mSuccess = q.deqByte();
|
||||
if (mSuccess != 1 /* Success */) {
|
||||
if (mSuccess == 2 /* Authenticate */) {
|
||||
short add_len;
|
||||
q.deqSkip(2);
|
||||
add_len = q.deqShort();
|
||||
mReason = q.deqString(add_len*4);
|
||||
}
|
||||
else { /* Failed */
|
||||
short add_len;
|
||||
byte reason_len;
|
||||
reason_len = q.deqByte();
|
||||
mProtoMajor = q.deqShort();
|
||||
mProtoMinor = q.deqShort();
|
||||
add_len = q.deqShort();
|
||||
mReason = q.deqString(reason_len);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
q.deqSkip(1);
|
||||
mProtoMajor = q.deqShort();
|
||||
mProtoMinor = q.deqShort();
|
||||
short add_len = q.deqShort();
|
||||
mData = q.deqData(add_len*4);
|
||||
}
|
||||
void write(ByteQueue q) {
|
||||
q.enqByte(mSuccess);
|
||||
if (mSuccess != 1 /* Success */) {
|
||||
if (mSuccess == 2 /* Authenticate */) {
|
||||
short add_len = (short)MathX.divceil(mReason.length(), 4);
|
||||
q.enqSkip(5);
|
||||
q.enqShort(add_len);
|
||||
q.enqString(mReason);
|
||||
}
|
||||
else { /* Failed */
|
||||
short add_len = (short)MathX.divceil(mReason.length(), 4);
|
||||
byte reason_len = (byte)mReason.length();
|
||||
q.enqByte(reason_len);
|
||||
q.enqShort(mProtoMajor);
|
||||
q.enqShort(mProtoMinor);
|
||||
q.enqShort(add_len);
|
||||
q.enqString(mReason);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
q.enqSkip(1);
|
||||
q.enqShort(mProtoMajor);
|
||||
q.enqShort(mProtoMinor);
|
||||
short add_len = (short)MathX.divceil(mData.pos(), 4);
|
||||
q.enqShort(add_len);
|
||||
q.enqData(mData);
|
||||
}
|
||||
void dispatch(X11ProtocolHandler h) { h.onMessage(this); }
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package tdm.xserver;
|
||||
|
||||
class X11Visual
|
||||
{
|
||||
static final int NONE = 0;
|
||||
|
||||
static final byte STATIC_GRAY = 0;
|
||||
static final byte GRAYSCALE = 1;
|
||||
static final byte STATIC_COLOR = 2;
|
||||
static final byte PSEUDO_COLOR = 3;
|
||||
static final byte TRUE_COLOR = 4;
|
||||
static final byte DIRECT_COLOR = 5;
|
||||
|
||||
int mId;
|
||||
byte mDepth;
|
||||
|
||||
byte mVisClass;
|
||||
byte mBitsPerRgbValue;
|
||||
short mColormapEntries;
|
||||
int mRedMask;
|
||||
int mGreenMask;
|
||||
int mBlueMask;
|
||||
|
||||
X11Visual(int n, byte d) {
|
||||
mId = n;
|
||||
mDepth = d;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,790 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Canvas;
|
||||
import android.os.Message;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.content.Context;
|
||||
|
||||
import java.lang.Thread;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class X11Window extends X11Drawable
|
||||
{
|
||||
static final int EVENT_EXPOSURE = 0x00008000;
|
||||
|
||||
static final short COPY_FROM_PARENT = 0;
|
||||
static final short INPUT_OUTPUT = 1;
|
||||
static final short INPUT_ONLY = 2;
|
||||
|
||||
static void create(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int id = msg.mData.deqInt();
|
||||
X11Window r = new X11Window(id);
|
||||
r.handleCreate(c, msg);
|
||||
c.addResource(r);
|
||||
}
|
||||
|
||||
X11Window mParent;
|
||||
short mWndClass;
|
||||
X11Pixmap mBgPixmap;
|
||||
int mBgPixel;
|
||||
X11Pixmap mBorderPixmap;
|
||||
int mBorderPixel;
|
||||
byte mBitGravity;
|
||||
byte mWinGravity;
|
||||
byte mBackingStore;
|
||||
int mBackingPlanes;
|
||||
int mBackingPixel;
|
||||
byte mOverrideRedirect;
|
||||
byte mSaveUnder;
|
||||
int mEventMask;
|
||||
short mDoNotPropagateMask;
|
||||
X11Colormap mColormap;
|
||||
X11Cursor mCursor;
|
||||
|
||||
Map<Integer,X11Property> mProperties;
|
||||
|
||||
// sibling position
|
||||
ArrayList<X11Window> mChildren;
|
||||
|
||||
UIHandler mHandler;
|
||||
ClientView mView;
|
||||
|
||||
boolean mMapped;
|
||||
boolean mRealized;
|
||||
|
||||
X11Window(int id) {
|
||||
super(X11Resource.WINDOW, id);
|
||||
mProperties = new HashMap<Integer,X11Property>();
|
||||
mChildren = new ArrayList<X11Window>();
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (mView != null) {
|
||||
sendViewMessage(UIHandler.MSG_VIEW_REMOVE);
|
||||
while (mView != null) { Thread.yield(); }
|
||||
}
|
||||
mChildren = null;
|
||||
mProperties = null;
|
||||
mCursor = null;
|
||||
mColormap = null;
|
||||
mBorderPixmap = null;
|
||||
mBgPixmap = null;
|
||||
mParent = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
void createRoot(X11Client c, short w, short h, byte d, X11Visual v) {
|
||||
mDepth = d;
|
||||
mRect = new X11Rect((short)0, (short)0, w, h);
|
||||
mBitmap = Bitmap.createBitmap(mRect.w, mRect.h, Bitmap.Config.ARGB_8888);
|
||||
mCanvas = new Canvas(mBitmap);
|
||||
mBorderWidth = 0;
|
||||
mWndClass = INPUT_OUTPUT;
|
||||
mVisual = v;
|
||||
|
||||
mBgPixmap = new X11Pixmap(0); //XXX: should use a real (global) id
|
||||
mBgPixmap.doCreate(mDepth, (short)3, (short)3, this);
|
||||
mBgPixmap.mBitmap.setPixel((short)0, (short)0, Color.WHITE);
|
||||
mBgPixmap.mBitmap.setPixel((short)1, (short)0, Color.BLACK);
|
||||
mBgPixmap.mBitmap.setPixel((short)2, (short)0, Color.WHITE);
|
||||
mBgPixmap.mBitmap.setPixel((short)0, (short)1, Color.BLACK);
|
||||
mBgPixmap.mBitmap.setPixel((short)1, (short)1, Color.WHITE);
|
||||
mBgPixmap.mBitmap.setPixel((short)2, (short)1, Color.BLACK);
|
||||
mBgPixmap.mBitmap.setPixel((short)0, (short)2, Color.WHITE);
|
||||
mBgPixmap.mBitmap.setPixel((short)1, (short)2, Color.BLACK);
|
||||
mBgPixmap.mBitmap.setPixel((short)2, (short)2, Color.WHITE);
|
||||
|
||||
mHandler = c.mServer.mHandler;
|
||||
|
||||
mMapped = true;
|
||||
mRealized = true;
|
||||
|
||||
paintBackgroundArea(mRect);
|
||||
|
||||
Log.d("X", "Creating root ClientView");
|
||||
sendViewMessage(UIHandler.MSG_VIEW_CREATE_ROOT);
|
||||
while (mView == null) { Thread.yield(); }
|
||||
mView.mClient = c;
|
||||
c.mServer.mInputFocus = this;
|
||||
}
|
||||
|
||||
void handleCreate(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
mDepth = msg.headerData();
|
||||
mParent = c.getWindow(msg.mData.deqInt());
|
||||
mParent.mChildren.add(this);
|
||||
|
||||
mRect = new X11Rect();
|
||||
mRect.x = msg.mData.deqShort();
|
||||
mRect.y = msg.mData.deqShort();
|
||||
mRect.w = msg.mData.deqShort();
|
||||
mRect.h = msg.mData.deqShort();
|
||||
mBorderWidth = msg.mData.deqShort();
|
||||
|
||||
mBitmap = Bitmap.createBitmap(mRect.w, mRect.h, Bitmap.Config.ARGB_8888);
|
||||
mCanvas = new Canvas(mBitmap);
|
||||
|
||||
mWndClass = msg.mData.deqShort();
|
||||
int vid = msg.mData.deqInt();
|
||||
if (mWndClass == COPY_FROM_PARENT) {
|
||||
mWndClass = mParent.mWndClass;
|
||||
}
|
||||
if (mWndClass == INPUT_ONLY) {
|
||||
if (mDepth != 0) {
|
||||
throw new X11Error(X11Error.MATCH, mDepth);
|
||||
}
|
||||
if (mBorderWidth != 0) {
|
||||
throw new X11Error(X11Error.MATCH, mBorderWidth);
|
||||
}
|
||||
}
|
||||
else if (mWndClass == INPUT_OUTPUT) {
|
||||
if (mDepth == 0) {
|
||||
mDepth = mParent.mDepth;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new X11Error(X11Error.MATCH, mWndClass);
|
||||
}
|
||||
|
||||
if (vid == 0 /* CopyFromParent */) {
|
||||
mVisual = mParent.mVisual;
|
||||
}
|
||||
else {
|
||||
mVisual = c.getVisual(vid);
|
||||
}
|
||||
if (mRect.w == 0 && mRect.h == 0) {
|
||||
throw new X11Error(X11Error.VALUE, 0);
|
||||
}
|
||||
|
||||
//XXX: Add checks per spec here?
|
||||
|
||||
mBorderPixmap = mParent.mBorderPixmap;
|
||||
mColormap = mParent.mColormap;
|
||||
|
||||
doChangeAttributes(c, msg.mData);
|
||||
|
||||
mHandler = c.mServer.mHandler;
|
||||
|
||||
sendViewMessage(UIHandler.MSG_VIEW_CREATE);
|
||||
while (mView == null) { Thread.yield(); }
|
||||
mView.mClient = c;
|
||||
|
||||
paintBackgroundArea(mRect);
|
||||
|
||||
//XXX: xorg server does not seem to send a CreateNotify event?
|
||||
|
||||
}
|
||||
|
||||
void handleChangeWindowAttributes(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
if (mParent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
doChangeAttributes(c, msg.mData);
|
||||
}
|
||||
|
||||
void handleGetWindowAttributes(X11Client c, X11RequestMessage msg) {
|
||||
byte map_state = (byte)0 /* Unmapped */;
|
||||
if (mMapped) {
|
||||
map_state = 1 /* Unviewable */;
|
||||
if (mRealized) {
|
||||
map_state = 2 /* Viewable */;
|
||||
}
|
||||
}
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.headerData(mBackingStore);
|
||||
reply.mData.enqInt(mVisual.mId);
|
||||
reply.mData.enqShort(mWndClass);
|
||||
reply.mData.enqByte(mBitGravity);
|
||||
reply.mData.enqByte(mWinGravity);
|
||||
reply.mData.enqInt(mBackingPlanes);
|
||||
reply.mData.enqInt(mBackingPixel);
|
||||
reply.mData.enqByte(mSaveUnder);
|
||||
reply.mData.enqByte((byte)1 /* True */); //XXX: map-is-installed
|
||||
reply.mData.enqByte(map_state);
|
||||
reply.mData.enqByte(mOverrideRedirect);
|
||||
reply.mData.enqInt(mColormap.mId);
|
||||
reply.mData.enqInt(mEventMask);
|
||||
reply.mData.enqInt(mEventMask);
|
||||
reply.mData.enqShort(mDoNotPropagateMask);
|
||||
reply.mData.enqSkip(2);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleDestroyWindow(X11Client c, X11RequestMessage msg) {
|
||||
doDestroy(c);
|
||||
}
|
||||
|
||||
void handleDestroySubwindows(X11Client c, X11RequestMessage msg) {
|
||||
doDestroySub(c);
|
||||
}
|
||||
|
||||
void handleMapWindow(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
doMap(c);
|
||||
}
|
||||
|
||||
void handleMapSubwindows(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
doMapSub(c);
|
||||
}
|
||||
|
||||
void handleUnmapWindow(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
doUnmap(c);
|
||||
}
|
||||
|
||||
void handleUnmapSubwindows(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
doUnmapSub(c);
|
||||
}
|
||||
|
||||
void handleConfigureWindow(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
boolean size_changed = false;
|
||||
boolean position_changed = false;
|
||||
short mask = msg.mData.deqShort();
|
||||
if ((mask & 0x0001) != 0) { // x
|
||||
mRect.x = (short)(msg.mData.deqInt() & 0xffff);
|
||||
position_changed = true;
|
||||
}
|
||||
if ((mask & 0x0002) != 0) { // y
|
||||
mRect.y = (short)(msg.mData.deqInt() & 0xffff);
|
||||
position_changed = true;
|
||||
}
|
||||
if ((mask & 0x0004) != 0) { // width
|
||||
mRect.w = (short)(msg.mData.deqInt() & 0xffff);
|
||||
size_changed = true;
|
||||
}
|
||||
if ((mask & 0x0008) != 0) { // height
|
||||
size_changed = true;
|
||||
mRect.h = (short)(msg.mData.deqInt() & 0xffff);
|
||||
}
|
||||
if ((mask & 0x0010) != 0) { // border-width
|
||||
mBorderWidth = (short)(msg.mData.deqInt() & 0xffff);
|
||||
}
|
||||
if ((mask & 0x0020) != 0) { // sibling
|
||||
//XXX
|
||||
c.getWindow(msg.mData.deqInt());
|
||||
}
|
||||
if ((mask & 0x0040) != 0) { // stack-mode
|
||||
//XXX
|
||||
msg.mData.deqInt();
|
||||
}
|
||||
|
||||
if (size_changed) {
|
||||
mBitmap = Bitmap.createBitmap(mRect.w, mRect.h, Bitmap.Config.ARGB_8888);
|
||||
mCanvas.setBitmap(mBitmap);
|
||||
paintBackgroundArea(mRect);
|
||||
}
|
||||
if (size_changed || position_changed) {
|
||||
sendViewMessage(UIHandler.MSG_VIEW_CONFIGURE);
|
||||
}
|
||||
}
|
||||
|
||||
void handleChangeProperty(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
byte mode = msg.headerData(); // Replace, Prepend, Append
|
||||
int name = msg.mData.deqInt();
|
||||
int type = msg.mData.deqInt();
|
||||
byte fmt = msg.mData.deqByte();
|
||||
msg.mData.deqSkip(3);
|
||||
if (fmt != 8 && fmt != 16 && fmt != 32) {
|
||||
throw new X11Error(X11Error.VALUE, fmt);
|
||||
}
|
||||
int datalen = msg.mData.deqInt();
|
||||
ByteQueue data = new ByteQueue(); //XXX endian?
|
||||
while (datalen-- != 0) {
|
||||
switch (fmt) {
|
||||
case 8: data.enqByte(msg.mData.deqByte()); break;
|
||||
case 16: data.enqShort(msg.mData.deqShort()); break;
|
||||
case 32: data.enqInt(msg.mData.deqInt()); break;
|
||||
}
|
||||
}
|
||||
|
||||
//XXX: lots of checks are missing here
|
||||
|
||||
X11Property prop = mProperties.get(name);
|
||||
if (prop == null) {
|
||||
prop = new X11Property(type, fmt);
|
||||
mProperties.put(name, prop);
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case 0: prop.setValue(data.getBytes()); break;
|
||||
case 1: prop.appendValue(data.getBytes()); break;
|
||||
case 2: prop.prependValue(data.getBytes()); break;
|
||||
}
|
||||
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.PROPERTY_NOTIFY);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqInt(name);
|
||||
evt.mData.enqInt(c.mServer.currentTime());
|
||||
evt.mData.enqByte((byte)0); // NewValue
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
void handleDeleteProperty(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
int name = msg.mData.deqInt();
|
||||
if (mProperties.containsKey(name)) {
|
||||
mProperties.remove(name);
|
||||
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.PROPERTY_NOTIFY);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqInt(name);
|
||||
evt.mData.enqInt(c.mServer.currentTime());
|
||||
evt.mData.enqByte((byte)1); // Deleted
|
||||
c.send(evt);
|
||||
}
|
||||
}
|
||||
|
||||
void handleGetProperty(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
byte del = msg.headerData();
|
||||
int name = msg.mData.deqInt();
|
||||
int type = msg.mData.deqInt();
|
||||
int off = msg.mData.deqInt();
|
||||
int len = msg.mData.deqInt();
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
|
||||
X11Property prop = mProperties.get(name);
|
||||
if (prop != null) {
|
||||
int rpos = off * 4;
|
||||
if (rpos > prop.mVal.length) {
|
||||
throw new X11Error(X11Error.VALUE, off);
|
||||
}
|
||||
int rlen = Math.min(prop.mVal.length - rpos, len*4);
|
||||
byte[] rval = new byte[rlen];
|
||||
System.arraycopy(prop.mVal, rpos, rval, 0, rlen); //XXX: endian?
|
||||
if (type != 0 /* AnyPropertyType */ && type != prop.mType) {
|
||||
rpos = 0;
|
||||
rlen = 0;
|
||||
del = 0 /* False */;
|
||||
}
|
||||
else {
|
||||
if (prop.mVal.length < (rpos+rlen)) {
|
||||
del = 0 /* False */;
|
||||
}
|
||||
}
|
||||
|
||||
reply.headerData(prop.mFormat);
|
||||
reply.mData.enqInt(prop.mType);
|
||||
reply.mData.enqInt(prop.mVal.length - (rpos + rlen));
|
||||
reply.mData.enqInt(rval.length / (prop.mFormat/8));
|
||||
reply.mData.enqSkip(12);
|
||||
reply.mData.enqArray(rval);
|
||||
|
||||
if (del != 0 /* False */) {
|
||||
mProperties.remove(name);
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.PROPERTY_NOTIFY);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqInt(name);
|
||||
evt.mData.enqInt(c.mServer.currentTime());
|
||||
evt.mData.enqByte((byte)1); // Deleted
|
||||
c.send(evt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
reply.mData.enqInt(0); // None
|
||||
reply.mData.enqInt(0);
|
||||
reply.mData.enqInt(0);
|
||||
}
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleListProperties(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.mData.enqShort((short)mProperties.size());
|
||||
reply.mData.enqSkip(22);
|
||||
for (Integer name : mProperties.keySet()) {
|
||||
reply.mData.enqInt(name);
|
||||
}
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleTranslateCoordinates(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
X11Window dst = c.getWindow(msg.mData.deqInt());
|
||||
short src_x = msg.mData.deqShort();
|
||||
short src_y = msg.mData.deqShort();
|
||||
|
||||
X11Point src_origin = absolutePosition(c);
|
||||
X11Point dst_origin = dst.absolutePosition(c);
|
||||
|
||||
short dst_x = (short)(src_origin.x + src_x - dst_origin.x);
|
||||
short dst_y = (short)(src_origin.y + src_y - dst_origin.y);
|
||||
|
||||
int childid = 0 /* None */;
|
||||
for (X11Window child : mChildren) {
|
||||
if (src_x >= child.mRect.x && src_y >= child.mRect.y &&
|
||||
src_x < child.mRect.x + child.mRect.w &&
|
||||
src_y < child.mRect.y + child.mRect.h) {
|
||||
childid = child.mId;
|
||||
break; //XXX: which child(ren) to return here?
|
||||
}
|
||||
}
|
||||
|
||||
X11ReplyMessage reply = new X11ReplyMessage(msg);
|
||||
reply.headerData((byte)1 /* True */); // same-screen
|
||||
reply.mData.enqInt(childid); // WINDOW or None
|
||||
reply.mData.enqShort(dst_x);
|
||||
reply.mData.enqShort(dst_y);
|
||||
c.send(reply);
|
||||
}
|
||||
|
||||
void handleClearArea(X11Client c, X11RequestMessage msg) throws X11Error {
|
||||
if (mWndClass == INPUT_ONLY) {
|
||||
throw new X11Error(X11Error.MATCH, mId);
|
||||
}
|
||||
byte exposures = msg.headerData();
|
||||
X11Rect r = new X11Rect();
|
||||
r.x = msg.mData.deqShort();
|
||||
r.y = msg.mData.deqShort();
|
||||
r.w = msg.mData.deqShort();
|
||||
if (r.w == 0) {
|
||||
r.w = (short)(mRect.x - r.x);
|
||||
}
|
||||
r.h = msg.mData.deqShort();
|
||||
if (r.h == 0) {
|
||||
r.h = (short)(mRect.y - r.y);
|
||||
}
|
||||
paintBackgroundArea(r);
|
||||
mView.postInvalidate(r.x, r.y, r.x+r.w, r.y+r.h);
|
||||
if (exposures != 0 /* False */) { //XXX: independent of EXPOSURES event mask?
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.EXPOSE);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqShort((short)0); // x
|
||||
evt.mData.enqShort((short)0); // y
|
||||
evt.mData.enqShort(mRect.w); // width
|
||||
evt.mData.enqShort(mRect.h); // height
|
||||
evt.mData.enqShort((short)0); // count
|
||||
c.send(evt); // XXX: thread sync?
|
||||
}
|
||||
}
|
||||
|
||||
void postRender(X11Rect r) {
|
||||
mView.postInvalidate(r.x, r.y, r.x+r.w, r.y+r.h);
|
||||
}
|
||||
|
||||
void postRender() {
|
||||
mView.postInvalidate();
|
||||
}
|
||||
|
||||
X11Point absolutePosition(X11Client c) throws X11Error {
|
||||
X11Point pos = new X11Point();
|
||||
if (mParent != null) {
|
||||
pos = c.getWindow(mParent.mId).absolutePosition(c);
|
||||
}
|
||||
pos.x += mRect.x;
|
||||
pos.y += mRect.y;
|
||||
return pos;
|
||||
}
|
||||
|
||||
private void doChangeAttributes(X11Client c, ByteQueue q) throws X11Error {
|
||||
int mask = q.deqInt();
|
||||
int val;
|
||||
|
||||
if (mWndClass == INPUT_ONLY) {
|
||||
if ((mask & 0x25df) != 0) {
|
||||
throw new X11Error(X11Error.MATCH, mask);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mask & 0x0001) != 0) { // background-pixmap
|
||||
val = q.deqInt();
|
||||
if (val == 0 /* None */) {
|
||||
mBgPixmap = null;
|
||||
}
|
||||
else if (val == 1 /* ParentRelative */) {
|
||||
//XXX
|
||||
mBgPixmap = null;
|
||||
}
|
||||
else {
|
||||
mBgPixmap = c.getPixmap(val);
|
||||
}
|
||||
paintBackgroundArea(mRect);
|
||||
}
|
||||
if ((mask & 0x0002) != 0) { // background-pixel
|
||||
mBgPixel = (q.deqInt() | 0xff000000);
|
||||
paintBackgroundArea(mRect);
|
||||
}
|
||||
if ((mask & 0x0004) != 0) { // border-pixmap
|
||||
mBorderPixmap = c.getPixmap(q.deqInt());
|
||||
}
|
||||
if ((mask & 0x0008) != 0) { // border-pixel
|
||||
mBorderPixel = (q.deqInt() | 0xff000000);
|
||||
}
|
||||
if ((mask & 0x0010) != 0) { // bit-gravity
|
||||
mBitGravity = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x0020) != 0) { // win-gravity
|
||||
mWinGravity = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x0040) != 0) { // backing-store
|
||||
mBackingStore = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x0080) != 0) { // backing-planes
|
||||
mBackingPlanes = q.deqInt();
|
||||
}
|
||||
if ((mask & 0x0100) != 0) { // backing-pixel
|
||||
mBackingPixel = (q.deqInt() | 0xff000000);
|
||||
}
|
||||
if ((mask & 0x0200) != 0) { // override-redirect
|
||||
mOverrideRedirect = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x0400) != 0) { // save-under
|
||||
mSaveUnder = (byte)q.deqInt();
|
||||
}
|
||||
if ((mask & 0x0800) != 0) { // event-mask
|
||||
mEventMask = q.deqInt();
|
||||
}
|
||||
if ((mask & 0x1000) != 0) { // do-not-propagate-mask
|
||||
mDoNotPropagateMask = (short)(q.deqInt() & ~0xffffc0b0);
|
||||
}
|
||||
if ((mask & 0x2000) != 0) { // colormap
|
||||
//XXX: 0 = CopyFromParent
|
||||
mColormap = c.getColormap(q.deqInt());
|
||||
}
|
||||
if ((mask & 0x4000) != 0) { // cursor
|
||||
mCursor = c.getCursor(q.deqInt());
|
||||
}
|
||||
}
|
||||
|
||||
private void doDestroy(X11Client c) {
|
||||
if (mParent == null) {
|
||||
return;
|
||||
}
|
||||
for (X11Window child : mChildren) {
|
||||
child.doDestroy(c);
|
||||
}
|
||||
doUnmap(c);
|
||||
|
||||
sendViewMessage(UIHandler.MSG_VIEW_REMOVE);
|
||||
mCursor = null;
|
||||
mColormap = null;
|
||||
mBorderPixmap = null;
|
||||
mBgPixmap = null;
|
||||
mVisual = null;
|
||||
mCanvas = null;
|
||||
mBitmap = null;
|
||||
mRect = null;
|
||||
mParent.mChildren.remove(this);
|
||||
mParent= null;
|
||||
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.DESTROY_NOTIFY);
|
||||
evt.mData.enqInt(mId); // event
|
||||
evt.mData.enqInt(mId); // window
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
private void doDestroySub(X11Client c) {
|
||||
//XXX: bottom-to-top stacking order
|
||||
for (X11Window child : mChildren) {
|
||||
child.doDestroy(c);
|
||||
}
|
||||
}
|
||||
|
||||
private void doMap(X11Client c) {
|
||||
if (mMapped) {
|
||||
return;
|
||||
}
|
||||
//XXX: check override-redirect
|
||||
mMapped = true;
|
||||
if (mParent == null) {
|
||||
mRealized = true;
|
||||
}
|
||||
else {
|
||||
if (mParent.mRealized) {
|
||||
doRealizeSub(c);
|
||||
doRealize(c);
|
||||
}
|
||||
}
|
||||
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.MAP_NOTIFY);
|
||||
evt.mData.enqInt(mId); // event
|
||||
evt.mData.enqInt(mId); // window
|
||||
evt.mData.enqByte(mOverrideRedirect);
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
private void doMapSub(X11Client c) {
|
||||
for (X11Window child : mChildren) {
|
||||
child.doMapSub(c);
|
||||
child.doMap(c);
|
||||
}
|
||||
}
|
||||
|
||||
private void doUnmap(X11Client c) {
|
||||
if (!mMapped) {
|
||||
return;
|
||||
}
|
||||
if (mParent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMapped = false;
|
||||
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.UNMAP_NOTIFY);
|
||||
evt.mData.enqInt(mId); // event
|
||||
evt.mData.enqInt(mId); // window
|
||||
evt.mData.enqByte((byte)0); // from-configure
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
private void doUnmapSub(X11Client c) {
|
||||
for (X11Window child : mChildren) {
|
||||
child.doUnmap(c);
|
||||
child.doUnmapSub(c);
|
||||
}
|
||||
}
|
||||
|
||||
private void doRealizeSub(X11Client c) {
|
||||
for (X11Window child : mChildren) {
|
||||
child.doRealizeSub(c);
|
||||
child.doRealize(c);
|
||||
}
|
||||
}
|
||||
|
||||
private void doRealize(X11Client c) {
|
||||
Log.d("X", "Window#"+mId+".doRealize: set visible");
|
||||
sendViewMessage(UIHandler.MSG_VIEW_SET_VISIBLE);
|
||||
while (!mRealized) { Thread.yield(); }
|
||||
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.EXPOSE);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqShort((short)0); // x
|
||||
evt.mData.enqShort((short)0); // y
|
||||
evt.mData.enqShort(mRect.w); // width
|
||||
evt.mData.enqShort(mRect.h); // height
|
||||
evt.mData.enqShort((short)0); // count
|
||||
c.send(evt); // XXX: thread sync?
|
||||
}
|
||||
|
||||
void onKeyPress(X11Client c, int code) {
|
||||
if ((mEventMask & X11Event.KEY_PRESS) == 0) {
|
||||
return; //XXX ???
|
||||
}
|
||||
X11Window root = c.mServer.mDefaultScreen.mRoot;
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.KEY_PRESS);
|
||||
evt.headerData((byte)(X11Keyboard.X_MIN_KEYCODE+code));
|
||||
evt.mData.enqInt(c.mServer.currentTime());
|
||||
evt.mData.enqInt(root.mId);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqInt(0 /*None*/);
|
||||
evt.mData.enqShort((short)0); // root-x
|
||||
evt.mData.enqShort((short)0); // root-y
|
||||
evt.mData.enqShort((short)0); // event-x
|
||||
evt.mData.enqShort((short)0); // event-y
|
||||
evt.mData.enqShort(c.mServer.mKeyboard.mModState);
|
||||
evt.mData.enqByte((byte)1); // same-screen = True
|
||||
evt.mData.enqSkip(1);
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
void onKeyRelease(X11Client c, int code) {
|
||||
if ((mEventMask & X11Event.KEY_RELEASE) == 0) {
|
||||
return; //XXX ???
|
||||
}
|
||||
X11Window root = c.mServer.mDefaultScreen.mRoot;
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.KEY_RELEASE);
|
||||
evt.headerData((byte)(X11Keyboard.X_MIN_KEYCODE+code));
|
||||
evt.mData.enqInt(c.mServer.currentTime());
|
||||
evt.mData.enqInt(root.mId);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqInt(0 /*None*/);
|
||||
evt.mData.enqShort((short)0); // root-x
|
||||
evt.mData.enqShort((short)0); // root-y
|
||||
evt.mData.enqShort((short)0); // event-x
|
||||
evt.mData.enqShort((short)0); // event-y
|
||||
evt.mData.enqShort(c.mServer.mKeyboard.mModState); // state
|
||||
evt.mData.enqByte((byte)1); // same-screen = True
|
||||
evt.mData.enqSkip(1);
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
void onButtonPress(X11Client c, int x, int y, int num) {
|
||||
if ((mEventMask & X11Event.BUTTON_PRESS) == 0) {
|
||||
return; //XXX ???
|
||||
}
|
||||
X11Window root = c.mServer.mDefaultScreen.mRoot;
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.BUTTON_PRESS);
|
||||
evt.headerData((byte)num);
|
||||
evt.mData.enqInt(c.mServer.currentTime());
|
||||
evt.mData.enqInt(root.mId);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqInt(0 /*None*/);
|
||||
evt.mData.enqShort((short)(mRect.x+x)); // root-x
|
||||
evt.mData.enqShort((short)(mRect.y+y)); // root-y
|
||||
evt.mData.enqShort((short)x); // event-x
|
||||
evt.mData.enqShort((short)y); // event-y
|
||||
evt.mData.enqShort((short)0); // state
|
||||
evt.mData.enqByte((byte)1); // same-screen = True
|
||||
evt.mData.enqSkip(1);
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
void onButtonRelease(X11Client c, int x, int y, int num) {
|
||||
if ((mEventMask & X11Event.BUTTON_RELEASE) == 0) {
|
||||
return; //XXX ???
|
||||
}
|
||||
X11Window root = c.mServer.mDefaultScreen.mRoot;
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.BUTTON_RELEASE);
|
||||
evt.headerData((byte)num);
|
||||
evt.mData.enqInt(c.mServer.currentTime());
|
||||
evt.mData.enqInt(root.mId);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqInt(0 /*None*/);
|
||||
evt.mData.enqShort((short)(mRect.x+x)); // root-x
|
||||
evt.mData.enqShort((short)(mRect.y+y)); // root-y
|
||||
evt.mData.enqShort((short)x); // event-x
|
||||
evt.mData.enqShort((short)y); // event-y
|
||||
evt.mData.enqShort((short)0); // state
|
||||
evt.mData.enqByte((byte)1); // same-screen = True
|
||||
evt.mData.enqSkip(1);
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
void onMotion(X11Client c, int x, int y) {
|
||||
if ((mEventMask & X11Event.MOTION_NOTIFY) == 0) {
|
||||
return; //XXX ???
|
||||
}
|
||||
X11Window root = c.mServer.mDefaultScreen.mRoot;
|
||||
X11EventMessage evt = new X11EventMessage(c.mProt.mEndian, X11Event.MOTION_NOTIFY);
|
||||
evt.headerData((byte)0 /*Normal*/);
|
||||
evt.mData.enqInt(c.mServer.currentTime());
|
||||
evt.mData.enqInt(root.mId);
|
||||
evt.mData.enqInt(mId);
|
||||
evt.mData.enqInt(0 /*None*/);
|
||||
evt.mData.enqShort((short)(mRect.x+x)); // root-x
|
||||
evt.mData.enqShort((short)(mRect.y+y)); // root-y
|
||||
evt.mData.enqShort((short)x); // event-x
|
||||
evt.mData.enqShort((short)y); // event-y
|
||||
evt.mData.enqShort((short)0); // state
|
||||
evt.mData.enqByte((byte)1); // same-screen = True
|
||||
evt.mData.enqSkip(1);
|
||||
c.send(evt);
|
||||
}
|
||||
|
||||
private void paintBackgroundArea(X11Rect r) {
|
||||
mCanvas.save(Canvas.CLIP_SAVE_FLAG);
|
||||
mCanvas.clipRect(r.x, r.y, r.x+r.w, r.y+r.h);
|
||||
if (mBgPixel != 0) { //XXX: need a flag, 0 is a valid value
|
||||
mCanvas.drawColor(0xff000000 | (mBgPixel & 0x00ffffff));
|
||||
}
|
||||
else if (mBgPixmap != null) {
|
||||
for (int x = 0; x < mRect.w; x += mBgPixmap.mRect.w) {
|
||||
for (int y = 0; y < mRect.h; y += mBgPixmap.mRect.h) {
|
||||
mCanvas.drawBitmap(mBgPixmap.mBitmap, x, y, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
mCanvas.restore();
|
||||
}
|
||||
|
||||
private void sendViewMessage(int func) {
|
||||
Message msg = Message.obtain(mHandler, func, this);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package tdm.xserver;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import java.net.ServerSocket;
|
||||
|
||||
public class XServer extends Activity
|
||||
{
|
||||
static final String TAG = "XServer";
|
||||
|
||||
static XServer mInstance;
|
||||
|
||||
RelativeLayout mLayout;
|
||||
X11Server mServer;
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mInstance = this;
|
||||
}
|
||||
|
||||
protected void onResume() {
|
||||
Log.e(TAG, "onResume");
|
||||
super.onResume();
|
||||
|
||||
try {
|
||||
mLayout = new RelativeLayout(this);
|
||||
setContentView(mLayout);
|
||||
|
||||
UIHandler handler = new UIHandler(this, mLayout);
|
||||
|
||||
mServer = new X11Server(this, handler);
|
||||
mServer.start();
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(TAG, "Cannot create server", e);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
// ...?
|
||||
}
|
||||
|
||||
protected void onPause() {
|
||||
Log.e(TAG, "onPause");
|
||||
super.onPause();
|
||||
// ...?
|
||||
}
|
||||
|
||||
protected void onStop() {
|
||||
Log.e(TAG, "onStop");
|
||||
super.onStop();
|
||||
mServer.onStop();
|
||||
// ...?
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.options_menu, menu);
|
||||
|
||||
// Other manipulations...
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
// Other manipulations...
|
||||
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_save:
|
||||
// ...
|
||||
break;
|
||||
case R.id.menu_delete:
|
||||
// ...
|
||||
break;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|