└── XServer
├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── proguard.cfg
├── project.properties
├── res
├── drawable-hdpi
│ └── icon.png
├── drawable-ldpi
│ └── icon.png
├── drawable-mdpi
│ └── icon.png
├── drawable-xhdpi
│ └── icon.png
├── drawable
│ ├── xc_arrow.png
│ ├── xc_based_arrow_down.png
│ ├── xc_based_arrow_up.png
│ ├── xc_boat.png
│ ├── xc_bogosity.png
│ ├── xc_bottom_left_corner.png
│ ├── xc_bottom_right_corner.png
│ ├── xc_bottom_side.png
│ ├── xc_bottom_tee.png
│ ├── xc_box_spiral.png
│ ├── xc_center_ptr.png
│ ├── xc_circle.png
│ ├── xc_clock.png
│ ├── xc_coffee_mug.png
│ ├── xc_cross.png
│ ├── xc_cross_reverse.png
│ ├── xc_crosshair.png
│ ├── xc_diamond_cross.png
│ ├── xc_dot.png
│ ├── xc_dotbox.png
│ ├── xc_double_arrow.png
│ ├── xc_draft_large.png
│ ├── xc_draft_small.png
│ ├── xc_draped_box.png
│ ├── xc_exchange.png
│ ├── xc_fleur.png
│ ├── xc_gobbler.png
│ ├── xc_gumby.png
│ ├── xc_hand1.png
│ ├── xc_hand2.png
│ ├── xc_heart.png
│ ├── xc_icon.png
│ ├── xc_iron_cross.png
│ ├── xc_left_ptr.png
│ ├── xc_left_side.png
│ ├── xc_left_tee.png
│ ├── xc_leftbutton.png
│ ├── xc_ll_angle.png
│ ├── xc_lr_angle.png
│ ├── xc_man.png
│ ├── xc_middlebutton.png
│ ├── xc_mouse.png
│ ├── xc_pencil.png
│ ├── xc_pirate.png
│ ├── xc_plus.png
│ ├── xc_question_arrow.png
│ ├── xc_right_ptr.png
│ ├── xc_right_side.png
│ ├── xc_right_tee.png
│ ├── xc_rightbutton.png
│ ├── xc_rtl_logo.png
│ ├── xc_sailboat.png
│ ├── xc_sb_down_arrow.png
│ ├── xc_sb_h_double_arrow.png
│ ├── xc_sb_left_arrow.png
│ ├── xc_sb_right_arrow.png
│ ├── xc_sb_up_arrow.png
│ ├── xc_sb_v_double_arrow.png
│ ├── xc_shuttle.png
│ ├── xc_sizing.png
│ ├── xc_spider.png
│ ├── xc_spraycan.png
│ ├── xc_star.png
│ ├── xc_target.png
│ ├── xc_tcross.png
│ ├── xc_top_left_arrow.png
│ ├── xc_top_left_corner.png
│ ├── xc_top_right_corner.png
│ ├── xc_top_side.png
│ ├── xc_top_tee.png
│ ├── xc_trek.png
│ ├── xc_ul_angle.png
│ ├── xc_umbrella.png
│ ├── xc_ur_angle.png
│ ├── xc_watch.png
│ ├── xc_x_cursor.png
│ └── xc_xterm.png
├── layout
│ ├── access_control_editor.xml
│ └── main.xml
└── values
│ └── strings.xml
└── src
└── au
└── com
└── darkside
├── XDemo
├── AccessControlEditor.java
└── XServerActivity.java
└── XServer
├── Atom.java
├── Client.java
├── Colormap.java
├── Cursor.java
├── Drawable.java
├── ErrorCode.java
├── EventCode.java
├── Font.java
├── Format.java
├── GContext.java
├── InputOutput.java
├── Keyboard.java
├── PassiveButtonGrab.java
├── PassiveKeyGrab.java
├── Pixmap.java
├── Pointer.java
├── Property.java
├── RequestCode.java
├── Resource.java
├── ScreenView.java
├── Selection.java
├── Util.java
├── Visual.java
├── Window.java
├── XServer.java
└── Xext
├── Extensions.java
├── XShape.java
└── XTest.java
/XServer/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/XServer/.gitignore:
--------------------------------------------------------------------------------
1 | /bin
2 | /gen
3 | /assets
4 |
--------------------------------------------------------------------------------
/XServer/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | XServer
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/XServer/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
8 |
9 |
10 |
12 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/XServer/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class * extends android.app.backup.BackupAgentHelper
14 | -keep public class * extends android.preference.Preference
15 | -keep public class com.android.vending.licensing.ILicensingService
16 |
17 | -keepclasseswithmembernames class * {
18 | native ;
19 | }
20 |
21 | -keepclasseswithmembers class * {
22 | public (android.content.Context, android.util.AttributeSet);
23 | }
24 |
25 | -keepclasseswithmembers class * {
26 | public (android.content.Context, android.util.AttributeSet, int);
27 | }
28 |
29 | -keepclassmembers class * extends android.app.Activity {
30 | public void *(android.view.View);
31 | }
32 |
33 | -keepclassmembers enum * {
34 | public static **[] values();
35 | public static ** valueOf(java.lang.String);
36 | }
37 |
38 | -keep class * implements android.os.Parcelable {
39 | public static final android.os.Parcelable$Creator *;
40 | }
41 |
--------------------------------------------------------------------------------
/XServer/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-8
12 |
--------------------------------------------------------------------------------
/XServer/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/XServer/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/XServer/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/XServer/res/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_based_arrow_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_based_arrow_down.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_based_arrow_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_based_arrow_up.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_boat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_boat.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_bogosity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_bogosity.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_bottom_left_corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_bottom_left_corner.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_bottom_right_corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_bottom_right_corner.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_bottom_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_bottom_side.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_bottom_tee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_bottom_tee.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_box_spiral.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_box_spiral.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_center_ptr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_center_ptr.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_circle.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_clock.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_coffee_mug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_coffee_mug.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_cross.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_cross.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_cross_reverse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_cross_reverse.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_crosshair.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_crosshair.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_diamond_cross.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_diamond_cross.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_dot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_dot.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_dotbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_dotbox.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_double_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_double_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_draft_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_draft_large.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_draft_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_draft_small.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_draped_box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_draped_box.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_exchange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_exchange.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_fleur.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_fleur.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_gobbler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_gobbler.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_gumby.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_gumby.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_hand1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_hand1.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_hand2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_hand2.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_heart.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_icon.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_iron_cross.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_iron_cross.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_left_ptr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_left_ptr.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_left_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_left_side.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_left_tee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_left_tee.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_leftbutton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_leftbutton.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_ll_angle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_ll_angle.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_lr_angle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_lr_angle.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_man.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_man.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_middlebutton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_middlebutton.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_mouse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_mouse.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_pencil.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_pirate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_pirate.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_plus.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_question_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_question_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_right_ptr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_right_ptr.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_right_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_right_side.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_right_tee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_right_tee.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_rightbutton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_rightbutton.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_rtl_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_rtl_logo.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_sailboat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_sailboat.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_sb_down_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_sb_down_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_sb_h_double_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_sb_h_double_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_sb_left_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_sb_left_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_sb_right_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_sb_right_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_sb_up_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_sb_up_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_sb_v_double_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_sb_v_double_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_shuttle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_shuttle.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_sizing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_sizing.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_spider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_spider.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_spraycan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_spraycan.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_star.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_target.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_target.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_tcross.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_tcross.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_top_left_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_top_left_arrow.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_top_left_corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_top_left_corner.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_top_right_corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_top_right_corner.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_top_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_top_side.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_top_tee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_top_tee.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_trek.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_trek.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_ul_angle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_ul_angle.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_umbrella.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_umbrella.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_ur_angle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_ur_angle.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_watch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_watch.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_x_cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_x_cursor.png
--------------------------------------------------------------------------------
/XServer/res/drawable/xc_xterm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattkwan-zz/android-xserver/451e360be52dcb98d17c29d9948d758dd1a12cd0/XServer/res/drawable/xc_xterm.png
--------------------------------------------------------------------------------
/XServer/res/layout/access_control_editor.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
17 |
22 |
23 |
29 |
35 |
39 |
40 |
47 |
52 |
57 |
58 |
--------------------------------------------------------------------------------
/XServer/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/XServer/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | X Server
4 |
5 |
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XDemo/AccessControlEditor.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Editor for the list of hosts allowed to access the X server.
3 | *
4 | * Written by Matthew Kwan - March 2012
5 | */
6 | package au.com.darkside.XDemo;
7 |
8 | import java.util.LinkedList;
9 | import java.util.Map;
10 | import java.util.Set;
11 |
12 | import android.app.AlertDialog;
13 | import android.app.Dialog;
14 | import android.app.ListActivity;
15 | import android.content.DialogInterface;
16 | import android.content.SharedPreferences;
17 | import android.os.Bundle;
18 | import android.view.View;
19 | import android.widget.AdapterView;
20 | import android.widget.AdapterView.OnItemClickListener;
21 | import android.widget.ArrayAdapter;
22 | import android.widget.Button;
23 | import android.widget.EditText;
24 | import android.widget.Toast;
25 | import au.com.darkside.XServer.R;
26 |
27 | /**
28 | * Editor for the list of hosts allowed to access the X server.
29 | *
30 | * @author mkwan
31 | */
32 | public class AccessControlEditor extends ListActivity
33 | implements OnItemClickListener {
34 | private ArrayAdapter _adapter;
35 | private EditText _hostField;
36 | private int _deletePosition = -1;
37 |
38 | private static final int DIALOG_DELETE_HOST = 1;
39 |
40 | /**
41 | * Called when the activity is first created.
42 | */
43 | @Override
44 | public void
45 | onCreate (
46 | Bundle savedInstanceState
47 | ) {
48 | super.onCreate (savedInstanceState);
49 | setContentView (R.layout.access_control_editor);
50 |
51 | _hostField = (EditText) findViewById (R.id.host_field);
52 |
53 | Button button;
54 |
55 | button = (Button) findViewById (R.id.add_button);
56 | button.setOnClickListener (
57 | new View.OnClickListener () {
58 | public void onClick (View v) {
59 | addHost ();
60 | }
61 | }
62 | );
63 |
64 | button = (Button) findViewById (R.id.cancel_button);
65 | button.setOnClickListener (
66 | new View.OnClickListener () {
67 | public void onClick (View v) {
68 | setResult (RESULT_CANCELED, null);
69 | finish ();
70 | }
71 | }
72 | );
73 |
74 | button = (Button) findViewById (R.id.apply_button);
75 | button.setOnClickListener (
76 | new View.OnClickListener () {
77 | public void onClick (View v) {
78 | saveAccessList ();
79 | setResult (RESULT_OK, null);
80 | finish ();
81 | }
82 | }
83 | );
84 |
85 | getListView().setOnItemClickListener (this);
86 | loadAccessList ();
87 | }
88 |
89 | /**
90 | * Called when a list item is selected.
91 | */
92 | @Override
93 | public void
94 | onItemClick (
95 | AdapterView> parent,
96 | View v,
97 | int position,
98 | long id
99 | ) {
100 | _deletePosition = position;
101 | showDialog (DIALOG_DELETE_HOST);
102 | }
103 |
104 | /**
105 | * Callback for creating a dialog.
106 | */
107 | @Override
108 | protected Dialog
109 | onCreateDialog (
110 | int id
111 | ) {
112 | if (id == DIALOG_DELETE_HOST) {
113 | AlertDialog.Builder builder = new AlertDialog.Builder (this);
114 |
115 | builder.setMessage ("Delete the IP address?")
116 | .setPositiveButton ("OK",
117 | new DialogInterface.OnClickListener () {
118 | public void onClick (DialogInterface dialog, int id) {
119 | deleteSelectedHost ();
120 | }
121 | })
122 | .setNegativeButton ("Cancel",
123 | new DialogInterface.OnClickListener () {
124 | public void onClick (DialogInterface dialog, int id) {
125 | dialog.cancel ();
126 | }
127 | });
128 |
129 | return builder.create ();
130 | }
131 |
132 | return null;
133 | }
134 |
135 | /**
136 | * Delete the host that was selected by the user.
137 | */
138 | private void
139 | deleteSelectedHost () {
140 | if (_deletePosition < 0)
141 | return;
142 |
143 | _adapter.remove (_adapter.getItem (_deletePosition));
144 | }
145 |
146 | /**
147 | * Convert a hexadecimal IP address into a human-readable dot-separated
148 | * format.
149 | *
150 | * @param host The host IP address, in hexadecimal format.
151 | * @return The host IP address in dot-separated format.
152 | */
153 | private static String
154 | hostToString (
155 | String host
156 | ) {
157 | int n;
158 |
159 | try {
160 | n = (int) Long.parseLong (host, 16);
161 | } catch (Exception e) {
162 | return "Error";
163 | }
164 |
165 | int b1 = (n >> 24) & 0xff;
166 | int b2 = (n >> 16) & 0xff;
167 | int b3 = (n >> 8) & 0xff;
168 | int b4 = n & 0xff;
169 |
170 | return "" + b1 + "." + b2 + "." + b3 + "." + b4;
171 | }
172 |
173 | /**
174 | * Load the list of hosts that are allowed to access the X server.
175 | */
176 | private void
177 | loadAccessList () {
178 | SharedPreferences prefs = getSharedPreferences ("AccessControlHosts",
179 | MODE_PRIVATE);
180 | Map map = prefs.getAll ();
181 | Set set = map.keySet ();
182 | LinkedList hosts = new LinkedList ();
183 |
184 | for (String s: set)
185 | hosts.add (hostToString (s));
186 |
187 | _adapter = new ArrayAdapter (this,
188 | android.R.layout.simple_list_item_1, hosts);
189 | setListAdapter (_adapter);
190 | }
191 |
192 | /**
193 | * Convert a human-readable dot-separated IP address into hexadecimal.
194 | * Return null if there's a parse error.
195 | *
196 | * @param s The host IP address, in dot-separated format.
197 | * @return The host IP address in hexadecimal format, or null.
198 | */
199 | private static String
200 | stringToHost (
201 | String s
202 | ) {
203 | String[] sa = s.split ("\\.");
204 |
205 | if (sa.length != 4)
206 | return null;
207 |
208 | int n = 0;
209 |
210 | for (int i = 0; i < 4; i++) {
211 | int b;
212 |
213 | try {
214 | b = Integer.parseInt (sa[i]);
215 | } catch (Exception e) {
216 | return null;
217 | }
218 |
219 | if (b < 0 || b > 255)
220 | return null;
221 |
222 | n = (n << 8) | b;
223 | }
224 |
225 | return Integer.toHexString (n);
226 | }
227 |
228 | /**
229 | * Save the list of hosts that are allowed to access the X server.
230 | */
231 | private void
232 | saveAccessList () {
233 | SharedPreferences prefs = getSharedPreferences ("AccessControlHosts",
234 | MODE_PRIVATE);
235 | SharedPreferences.Editor editor = prefs.edit ();
236 |
237 | editor.clear ();
238 |
239 | int n = _adapter.getCount ();
240 |
241 | for (int i = 0; i < n; i++) {
242 | String host = stringToHost (_adapter.getItem (i));
243 |
244 | if (host != null)
245 | editor.putBoolean (host, true);
246 | }
247 |
248 | editor.commit ();
249 | }
250 |
251 | /**
252 | * Parse the IP address in the host field and add it to the list.
253 | */
254 | private void
255 | addHost () {
256 | String s = _hostField.getText().toString ();
257 |
258 | if (stringToHost (s) != null)
259 | _adapter.add (s);
260 | else
261 | Toast.makeText (this, "Bad IP address '" + s + "'",
262 | Toast.LENGTH_LONG).show ();
263 | }
264 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XDemo/XServerActivity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This activity launches an X server and provides a screen for it.
3 | */
4 | package au.com.darkside.XDemo;
5 |
6 | import java.net.InetAddress;
7 | import java.net.NetworkInterface;
8 | import java.util.Enumeration;
9 | import java.util.HashSet;
10 | import java.util.Map;
11 | import java.util.Set;
12 |
13 | import android.app.Activity;
14 | import android.app.AlertDialog;
15 | import android.app.Dialog;
16 | import android.app.Service;
17 | import android.content.ActivityNotFoundException;
18 | import android.content.ComponentName;
19 | import android.content.Context;
20 | import android.content.DialogInterface;
21 | import android.content.Intent;
22 | import android.content.SharedPreferences;
23 | import android.net.Uri;
24 | import android.os.Bundle;
25 | import android.os.PowerManager;
26 | import android.os.PowerManager.WakeLock;
27 | import android.view.Menu;
28 | import android.view.MenuItem;
29 | import android.view.inputmethod.InputMethodManager;
30 | import android.widget.FrameLayout;
31 | import android.widget.Toast;
32 | import au.com.darkside.XServer.R;
33 | import au.com.darkside.XServer.ScreenView;
34 | import au.com.darkside.XServer.XServer;
35 |
36 | /**
37 | * @author Matthew Kwan
38 | *
39 | * This class launches an X server.
40 | */
41 | public class XServerActivity extends Activity {
42 | private XServer _xServer;
43 | private ScreenView _screenView;
44 | private WakeLock _wakeLock;
45 |
46 | private static final int MENU_KEYBOARD = 1;
47 | private static final int MENU_IP_ADDRESS = 2;
48 | private static final int MENU_ACCESS_CONTROL = 3;
49 | private static final int MENU_REMOTE_LOGIN = 4;
50 | private static final int ACTIVITY_ACCESS_CONTROL = 1;
51 |
52 | /**
53 | * Called when the activity is first created.
54 | *
55 | * @param savedInstanceState Saved state.
56 | */
57 | @Override
58 | public void
59 | onCreate (
60 | Bundle savedInstanceState
61 | ) {
62 | super.onCreate (savedInstanceState);
63 | setContentView (R.layout.main);
64 |
65 | int port = 6000;
66 | Intent intent = getIntent ();
67 |
68 | // If it was launched from an intent, get the port number.
69 | if (intent != null) {
70 | Uri uri = intent.getData ();
71 |
72 | if (uri != null) {
73 | int p = uri.getPort ();
74 |
75 | if (p >= 0) {
76 | if (p < 10)
77 | port = p + 6000;
78 | else
79 | port = p;
80 | }
81 | }
82 | }
83 |
84 | _xServer = new XServer (this, port, null);
85 | setAccessControl ();
86 |
87 | FrameLayout fl = (FrameLayout) findViewById (R.id.frame);
88 |
89 | _screenView = _xServer.getScreen ();
90 | fl.addView (_screenView);
91 |
92 | PowerManager pm;
93 |
94 | pm = (PowerManager) getSystemService (Context.POWER_SERVICE);
95 | _wakeLock = pm.newWakeLock (PowerManager.SCREEN_DIM_WAKE_LOCK,
96 | "XServer");
97 | }
98 |
99 | /**
100 | * Called when the activity resumes.
101 | */
102 | @Override
103 | public void
104 | onResume () {
105 | super.onResume ();
106 | _wakeLock.acquire ();
107 | }
108 |
109 | /**
110 | * Called when the activity pauses.
111 | */
112 | @Override
113 | public void
114 | onPause () {
115 | super.onPause ();
116 | _wakeLock.release ();
117 | }
118 |
119 | /**
120 | * Called when the activity is destroyed.
121 | */
122 | @Override
123 | public void
124 | onDestroy () {
125 | _xServer.stop ();
126 | super.onDestroy ();
127 | }
128 |
129 | /**
130 | * Called the first time a menu is needed.
131 | *
132 | * @param menu The options menu in which you place your items.
133 | * @return True for the menu to be displayed.
134 | */
135 | @Override
136 | public boolean
137 | onCreateOptionsMenu (
138 | Menu menu
139 | ) {
140 | MenuItem item;
141 |
142 | item = menu.add (0, MENU_KEYBOARD, 0, "Keyboard");
143 | item.setIcon (android.R.drawable.ic_menu_add);
144 |
145 | item = menu.add (0, MENU_IP_ADDRESS, 0, "IP address");
146 | item.setIcon (android.R.drawable.ic_menu_info_details);
147 |
148 | item = menu.add (0, MENU_ACCESS_CONTROL, 0, "Access control");
149 | item.setIcon (android.R.drawable.ic_menu_edit);
150 |
151 | item = menu.add (0, MENU_REMOTE_LOGIN, 0, "Remote login");
152 | item.setIcon (android.R.drawable.ic_menu_upload);
153 |
154 | return true;
155 | }
156 |
157 | /**
158 | * Called when a menu selection has been made.
159 | *
160 | * @param item The menu item that was selected.
161 | * @return True if the menu selection has been handled.
162 | */
163 | @Override
164 | public boolean
165 | onOptionsItemSelected (
166 | MenuItem item
167 | ) {
168 | super.onOptionsItemSelected (item);
169 |
170 | switch (item.getItemId ()) {
171 | case MENU_KEYBOARD:
172 | InputMethodManager imm = (InputMethodManager)
173 | getSystemService (Service.INPUT_METHOD_SERVICE);
174 |
175 | // If anyone knows a better way to bring up the soft
176 | // keyboard, I'd love to hear about it.
177 | _screenView.requestFocus ();
178 | imm.hideSoftInputFromWindow (_screenView.getWindowToken(), 0);
179 | imm.toggleSoftInput (InputMethodManager.SHOW_FORCED, 0);
180 | return true;
181 | case MENU_IP_ADDRESS:
182 | showDialog (MENU_IP_ADDRESS);
183 | return true;
184 | case MENU_ACCESS_CONTROL:
185 | launchAccessControlEditor ();
186 | return true;
187 | case MENU_REMOTE_LOGIN:
188 | launchSshApp ();
189 | return true;
190 | }
191 |
192 | return false;
193 | }
194 |
195 | /**
196 | * Return a string describing the IP address(es) of this device.
197 | *
198 | * @return A string describing the IP address(es) of this device.
199 | */
200 | private String
201 | getAddressInfo () {
202 | String s = "Listening on port 6000";
203 |
204 | try {
205 | for (Enumeration nie =
206 | NetworkInterface.getNetworkInterfaces ();
207 | nie.hasMoreElements ();) {
208 | NetworkInterface ni = nie.nextElement ();
209 |
210 | for (Enumeration iae = ni.getInetAddresses ();
211 | iae.hasMoreElements ();) {
212 | InetAddress ia = iae.nextElement ();
213 |
214 | if (ia.isLoopbackAddress ())
215 | continue;
216 |
217 | s += "\n" + ni.getDisplayName () + ": "
218 | + ia.getHostAddress ();
219 | }
220 | }
221 | } catch (Exception e) {
222 | s += "\nError: " + e.getMessage ();
223 | }
224 |
225 | return s;
226 | }
227 |
228 | /**
229 | * This is called when a dialog is requested.
230 | *
231 | * @param id Identifies the dialog to create.
232 | */
233 | @Override
234 | protected Dialog
235 | onCreateDialog (
236 | int id
237 | ) {
238 | if (id != MENU_IP_ADDRESS)
239 | return null;
240 |
241 | AlertDialog.Builder builder = new AlertDialog.Builder (this);
242 |
243 | builder.setTitle ("IP address")
244 | .setMessage (getAddressInfo ())
245 | .setPositiveButton ("OK", new DialogInterface.OnClickListener () {
246 | public void onClick (DialogInterface dialog, int id) {
247 | dialog.cancel ();
248 | }
249 | });
250 |
251 | return builder.create ();
252 | }
253 |
254 | /**
255 | * Load the access control hosts from persistent storage.
256 | */
257 | private void
258 | setAccessControl () {
259 | SharedPreferences prefs = getSharedPreferences ("AccessControlHosts",
260 | MODE_PRIVATE);
261 | Map map = prefs.getAll ();
262 | HashSet hosts = _xServer.getAccessControlHosts ();
263 |
264 | hosts.clear ();
265 | if (!map.isEmpty ()) {
266 | Set set = map.keySet ();
267 |
268 | for (String s: set) {
269 | try {
270 | int host = (int) Long.parseLong (s, 16);
271 |
272 | hosts.add (host);
273 | } catch (Exception e) {
274 | }
275 | }
276 | }
277 |
278 | _xServer.setAccessControl (!hosts.isEmpty ());
279 | }
280 |
281 | /**
282 | * Called when an activity returns a result.
283 | */
284 | @Override
285 | protected void
286 | onActivityResult (
287 | int requestCode,
288 | int resultCode,
289 | Intent data
290 | ) {
291 | if (requestCode == ACTIVITY_ACCESS_CONTROL && resultCode == RESULT_OK)
292 | setAccessControl ();
293 | }
294 |
295 | /**
296 | * Launch the access control list editor.
297 | */
298 | private void
299 | launchAccessControlEditor () {
300 | Intent intent = new Intent (this, AccessControlEditor.class);
301 |
302 | startActivityForResult (intent, ACTIVITY_ACCESS_CONTROL);
303 | }
304 |
305 | /**
306 | * Launch an application.
307 | */
308 | private boolean
309 | launchApp (
310 | String pkg,
311 | String cls
312 | ) {
313 | Intent intent = new Intent (Intent.ACTION_MAIN);
314 |
315 | intent.setComponent (new ComponentName (pkg, cls));
316 | try {
317 | startActivity (intent);
318 | } catch (ActivityNotFoundException e) {
319 | return false;
320 | }
321 |
322 | return true;
323 | }
324 |
325 | /**
326 | * Launch an application that will allow an SSH login.
327 | */
328 | private void
329 | launchSshApp () {
330 | if (launchApp ("org.connectbot", "org.connectbot.HostListActivity"))
331 | return;
332 | if (launchApp ("com.madgag.ssh.agent",
333 | "com.madgag.ssh.agent.HostListActivity"))
334 | return;
335 | if (launchApp ("sk.vx.connectbot",
336 | "sk.vx.connectbot.HostListActivity"))
337 | return;
338 |
339 | Toast.makeText (this,
340 | "The ConnectBot application needs to be installed",
341 | Toast.LENGTH_LONG).show ();
342 | }
343 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Atom.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class implements an X atom.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 |
9 | /**
10 | * @author Matthew KWan
11 | *
12 | * This class implements an X atom.
13 | */
14 | public class Atom {
15 | private static final String[] _predefinedAtoms = {
16 | "PRIMARY",
17 | "SECONDARY",
18 | "ARC",
19 | "ATOM",
20 | "BITMAP",
21 | "CARDINAL",
22 | "COLORMAP",
23 | "CURSOR",
24 | "CUT_BUFFER0",
25 | "CUT_BUFFER1",
26 | "CUT_BUFFER2",
27 | "CUT_BUFFER3",
28 | "CUT_BUFFER4",
29 | "CUT_BUFFER5",
30 | "CUT_BUFFER6",
31 | "CUT_BUFFER7",
32 | "DRAWABLE",
33 | "FONT",
34 | "INTEGER",
35 | "PIXMAP",
36 | "POINT",
37 | "RECTANGLE",
38 | "RESOURCE_MANAGER",
39 | "RGB_COLOR_MAP",
40 | "RGB_BEST_MAP",
41 | "RGB_BLUE_MAP",
42 | "RGB_DEFAULT_MAP",
43 | "RGB_GRAY_MAP",
44 | "RGB_GREEN_MAP",
45 | "RGB_RED_MAP",
46 | "STRING",
47 | "VISUALID",
48 | "WINDOW",
49 | "WM_COMMAND",
50 | "WM_HINTS",
51 | "WM_CLIENT_MACHINE",
52 | "WM_ICON_NAME",
53 | "WM_ICON_SIZE",
54 | "WM_NAME",
55 | "WM_NORMAL_HINTS",
56 | "WM_SIZE_HINTS",
57 | "WM_ZOOM_HINTS",
58 | "MIN_SPACE",
59 | "NORM_SPACE",
60 | "MAX_SPACE",
61 | "END_SPACE",
62 | "SUPERSCRIPT_X",
63 | "SUPERSCRIPT_Y",
64 | "SUBSCRIPT_X",
65 | "SUBSCRIPT_Y",
66 | "UNDERLINE_POSITION",
67 | "UNDERLINE_THICKNESS",
68 | "STRIKEOUT_ASCENT",
69 | "STRIKEOUT_DESCENT",
70 | "ITALIC_ANGLE",
71 | "X_HEIGHT",
72 | "QUAD_WIDTH",
73 | "WEIGHT",
74 | "POINT_SIZE",
75 | "RESOLUTION",
76 | "COPYRIGHT",
77 | "NOTICE",
78 | "FONT_NAME",
79 | "FAMILY_NAME",
80 | "FULL_NAME",
81 | "CAP_HEIGHT",
82 | "WM_CLASS",
83 | "WM_TRANSIENT_FOR"
84 | };
85 |
86 | private final int _id;
87 | private final String _name;
88 |
89 | /**
90 | * Constructor.
91 | *
92 | * @param id The atom's ID.
93 | */
94 | public Atom (
95 | int id,
96 | String name
97 | ) {
98 | _id = id;
99 | _name = name;
100 | }
101 |
102 | /**
103 | * Register the predefined atoms with the X server.
104 | *
105 | * @param xServer
106 | */
107 | public static void
108 | registerPredefinedAtoms (
109 | XServer xServer
110 | ) {
111 | for (int i = 0; i < _predefinedAtoms.length; i++)
112 | xServer.addAtom (new Atom (i + 1, _predefinedAtoms[i]));
113 | }
114 |
115 | /**
116 | * Return the number of predefined atoms.
117 | * @return The number of predefined atoms.
118 | */
119 | public static int
120 | numPredefinedAtoms () {
121 | return _predefinedAtoms.length;
122 | }
123 |
124 | /**
125 | * Return the atom's ID.
126 | * @return The atom's ID.
127 | */
128 | public int
129 | getId () {
130 | return _id;
131 | }
132 |
133 | /**
134 | * Return the atom's name.
135 | * @return The atom's name.
136 | */
137 | public String
138 | getName () {
139 | return _name;
140 | }
141 |
142 | /**
143 | * Process a GetAtomName request.
144 | *
145 | * @param xServer The X server.
146 | * @param client The remote client.
147 | * @param bytesRemaining Bytes yet to be read in the request.
148 | * @throws IOException
149 | */
150 | public static void
151 | processGetAtomNameRequest (
152 | XServer xServer,
153 | Client client,
154 | int bytesRemaining
155 | ) throws IOException {
156 | InputOutput io = client.getInputOutput ();
157 |
158 | if (bytesRemaining != 4) {
159 | io.readSkip (bytesRemaining);
160 | ErrorCode.write (client, ErrorCode.Length,
161 | RequestCode.GetAtomName, 0);
162 | return;
163 | }
164 |
165 | int id = io.readInt ();
166 | Atom a = xServer.getAtom (id);
167 |
168 | if (a == null) {
169 | ErrorCode.write (client, ErrorCode.Atom, RequestCode.GetAtomName,
170 | id);
171 | return;
172 | }
173 |
174 | byte[] bytes = a._name.getBytes ();
175 | int length = bytes.length;
176 | int pad = -length & 3;
177 |
178 | synchronized (io) {
179 | Util.writeReplyHeader (client, (byte) 0);
180 | io.writeInt ((length + pad) / 4); // Reply length.
181 | io.writeShort ((short) length); // Name length.
182 | io.writePadBytes (22); // Unused.
183 | io.writeBytes (bytes, 0, length); // Name.
184 | io.writePadBytes (pad); // Unused.
185 | }
186 | io.flush ();
187 | }
188 |
189 | /**
190 | * Process an InternAtom request.
191 | * Return or create an atom with the specified name.
192 | *
193 | * @param xServer The X server.
194 | * @param client The remote client.
195 | * @param arg Optional first argument.
196 | * @param bytesRemaining Bytes yet to be read in the request.
197 | * @throws IOException
198 | */
199 | public static void
200 | processInternAtomRequest (
201 | XServer xServer,
202 | Client client,
203 | byte arg,
204 | int bytesRemaining
205 | ) throws IOException {
206 | InputOutput io = client.getInputOutput ();
207 |
208 | if (bytesRemaining < 4) {
209 | io.readSkip (bytesRemaining);
210 | ErrorCode.write (client, ErrorCode.Length, RequestCode.InternAtom,
211 | 0);
212 | return;
213 | }
214 |
215 | boolean onlyIfExists = (arg != 0);
216 | int n = io.readShort (); // Length of name.
217 | int pad = -n & 3;
218 |
219 | io.readSkip (2); // Unused.
220 | bytesRemaining -= 4;
221 |
222 | if (bytesRemaining != n + pad) {
223 | io.readSkip (bytesRemaining);
224 | ErrorCode.write (client, ErrorCode.Length, RequestCode.InternAtom,
225 | 0);
226 | return;
227 | }
228 |
229 | byte[] name = new byte[n];
230 |
231 | io.readBytes (name, 0, n); // The atom name.
232 | io.readSkip (pad); // Unused.
233 |
234 | int id = 0;
235 | String s = new String (name);
236 | Atom a = xServer.findAtom (s);
237 |
238 | if (a != null) {
239 | id = a.getId ();
240 | } else if (!onlyIfExists) {
241 | a = new Atom (xServer.nextFreeAtomId (), s);
242 | xServer.addAtom (a);
243 | id = a.getId ();
244 | }
245 |
246 | synchronized (io) {
247 | Util.writeReplyHeader (client, (byte) 0);
248 | io.writeInt (0); // Reply length.
249 | io.writeInt (id); // The atom ID.
250 | io.writePadBytes (20); // Unused.
251 | }
252 | io.flush ();
253 | }
254 | }
255 |
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Cursor.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class implements an X Windows cursor.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 | import android.graphics.Bitmap;
9 | import android.graphics.BitmapFactory;
10 |
11 |
12 | /**
13 | * @author Matthew Kwan
14 | *
15 | * This class implements an X Windows cursor.
16 | */
17 | public class Cursor extends Resource {
18 | private final int _hotspotX;
19 | private final int _hotspotY;
20 | private Bitmap _bitmap;
21 | private int _foregroundColor;
22 | private int _backgroundColor;
23 |
24 | private static final int _glyphs[][] = {
25 | {R.drawable.xc_x_cursor, 7, 7},
26 | {R.drawable.xc_arrow, 14, 1},
27 | {R.drawable.xc_based_arrow_down, 4, 10},
28 | {R.drawable.xc_based_arrow_up, 4, 10},
29 | {R.drawable.xc_boat, 14, 4},
30 | {R.drawable.xc_bogosity, 7, 7},
31 | {R.drawable.xc_bottom_left_corner, 1, 14},
32 | {R.drawable.xc_bottom_right_corner, 14, 14},
33 | {R.drawable.xc_bottom_side, 7, 14},
34 | {R.drawable.xc_bottom_tee, 8, 10},
35 | {R.drawable.xc_box_spiral, 8, 8},
36 | {R.drawable.xc_center_ptr, 5, 1},
37 | {R.drawable.xc_circle, 8, 8},
38 | {R.drawable.xc_clock, 6, 3},
39 | {R.drawable.xc_coffee_mug, 7, 9},
40 | {R.drawable.xc_cross, 7, 7},
41 | {R.drawable.xc_cross_reverse, 7, 7},
42 | {R.drawable.xc_crosshair, 7, 7},
43 | {R.drawable.xc_diamond_cross, 7, 7},
44 | {R.drawable.xc_dot, 6, 6},
45 | {R.drawable.xc_dotbox, 7, 6},
46 | {R.drawable.xc_double_arrow, 6, 8},
47 | {R.drawable.xc_draft_large, 14, 0},
48 | {R.drawable.xc_draft_small, 14, 0},
49 | {R.drawable.xc_draped_box, 7, 6},
50 | {R.drawable.xc_exchange, 7, 7},
51 | {R.drawable.xc_fleur, 8, 8},
52 | {R.drawable.xc_gobbler, 14, 3},
53 | {R.drawable.xc_gumby, 2, 0},
54 | {R.drawable.xc_hand1, 12, 0},
55 | {R.drawable.xc_hand2, 0, 1},
56 | {R.drawable.xc_heart, 6, 8},
57 | {R.drawable.xc_icon, 8, 8},
58 | {R.drawable.xc_iron_cross, 8, 7},
59 | {R.drawable.xc_left_ptr, 1, 1},
60 | {R.drawable.xc_left_side, 1, 7},
61 | {R.drawable.xc_left_tee, 1, 8},
62 | {R.drawable.xc_leftbutton, 8, 8},
63 | {R.drawable.xc_ll_angle, 1, 10},
64 | {R.drawable.xc_lr_angle, 10, 10},
65 | {R.drawable.xc_man, 14, 5},
66 | {R.drawable.xc_middlebutton, 8, 8},
67 | {R.drawable.xc_mouse, 4, 1},
68 | {R.drawable.xc_pencil, 11, 15},
69 | {R.drawable.xc_pirate, 7, 12},
70 | {R.drawable.xc_plus, 5, 6},
71 | {R.drawable.xc_question_arrow, 5, 8},
72 | {R.drawable.xc_right_ptr, 8, 1},
73 | {R.drawable.xc_right_side, 14, 7},
74 | {R.drawable.xc_right_tee, 10, 8},
75 | {R.drawable.xc_rightbutton, 8, 8},
76 | {R.drawable.xc_rtl_logo, 7, 7},
77 | {R.drawable.xc_sailboat, 8, 0},
78 | {R.drawable.xc_sb_down_arrow, 4, 15},
79 | {R.drawable.xc_sb_h_double_arrow, 7, 4},
80 | {R.drawable.xc_sb_left_arrow, 0, 4},
81 | {R.drawable.xc_sb_right_arrow, 15, 4},
82 | {R.drawable.xc_sb_up_arrow, 4, 0},
83 | {R.drawable.xc_sb_v_double_arrow, 4, 7},
84 | {R.drawable.xc_shuttle, 11, 0},
85 | {R.drawable.xc_sizing, 8, 8},
86 | {R.drawable.xc_spider, 6, 7},
87 | {R.drawable.xc_spraycan, 10, 2},
88 | {R.drawable.xc_star, 7, 7},
89 | {R.drawable.xc_target, 7, 7},
90 | {R.drawable.xc_tcross, 7, 7},
91 | {R.drawable.xc_top_left_arrow, 1, 1},
92 | {R.drawable.xc_top_left_corner, 1, 1},
93 | {R.drawable.xc_top_right_corner, 14, 1},
94 | {R.drawable.xc_top_side, 7, 1},
95 | {R.drawable.xc_top_tee, 8, 1},
96 | {R.drawable.xc_trek, 4, 0},
97 | {R.drawable.xc_ul_angle, 1, 1},
98 | {R.drawable.xc_umbrella, 8, 2},
99 | {R.drawable.xc_ur_angle, 10, 1},
100 | {R.drawable.xc_watch, 15, 9},
101 | {R.drawable.xc_xterm, 4, 8}
102 | };
103 |
104 | /**
105 | * Constructor for a pixmap cursor.
106 | *
107 | * @param id The server cursor ID.
108 | * @param xServer The X server.
109 | * @param client The client issuing the request.
110 | * @param p Cursor pixmap.
111 | * @param mp Mask pixmap. May be null.
112 | * @param x Hotspot X coordinate.
113 | * @param y Hotspot Y coordinate.
114 | * @param foregroundColor Foreground color of the cursor.
115 | * @param backgroundColor Foreground color of the cursor.
116 | */
117 | public Cursor (
118 | int id,
119 | XServer xServer,
120 | Client client,
121 | Pixmap p,
122 | Pixmap mp,
123 | int x,
124 | int y,
125 | int foregroundColor,
126 | int backgroundColor
127 | ) {
128 | super (CURSOR, id, xServer, client);
129 |
130 | _hotspotX = x;
131 | _hotspotY = y;
132 | _foregroundColor = foregroundColor;
133 | _backgroundColor = backgroundColor;
134 |
135 | Bitmap bm = p.getDrawable().getBitmap ();
136 | int width = bm.getWidth ();
137 | int height = bm.getHeight ();
138 | int[] pixels = new int [width * height];
139 |
140 | bm.getPixels (pixels, 0, width, 0, 0, width, height);
141 | if (mp == null) {
142 | for (int i = 0; i < pixels.length; i++) {
143 | if (pixels[i] == 0xffffffff)
144 | pixels[i] = foregroundColor;
145 | else
146 | pixels[i] = backgroundColor;
147 | }
148 | } else {
149 | Bitmap mbm = mp.getDrawable().getBitmap ();
150 | int[] mask = new int [width * height];
151 |
152 | mbm.getPixels (mask, 0, width, 0, 0, width, height);
153 | for (int i = 0; i < pixels.length; i++) {
154 | if (mask[i] != 0xffffffff)
155 | pixels[i] = 0;
156 | else if (pixels[i] == 0xffffffff)
157 | pixels[i] = foregroundColor;
158 | else
159 | pixels[i] = backgroundColor;
160 | }
161 | }
162 |
163 | _bitmap = Bitmap.createBitmap (pixels, width, height,
164 | Bitmap.Config.ARGB_8888);
165 | }
166 |
167 | /**
168 | * Constructor for a glyph cursor.
169 | * This functions just assumes the caller wants one of the 77 predefined
170 | * cursors from the "cursor" font, so the sourceFont, maskFont, and
171 | * maskChar are all ignored.
172 | *
173 | * @param id The server cursor ID.
174 | * @param xServer The X server.
175 | * @param client The client issuing the request.
176 | * @param sourceFont Font to use for the cursor character.
177 | * @param maskFont Font for the mask character. May be null.
178 | * @param sourceChar Character to use as the cursor.
179 | * @param maskChar Character to use as the mask.
180 | * @param foregroundColor Foreground color of the cursor.
181 | * @param backgroundColor Foreground color of the cursor.
182 | */
183 | public Cursor (
184 | int id,
185 | XServer xServer,
186 | Client client,
187 | Font sourceFont,
188 | Font maskFont,
189 | int sourceChar,
190 | int maskChar,
191 | int foregroundColor,
192 | int backgroundColor
193 | ) {
194 | super (CURSOR, id, xServer, client);
195 |
196 | sourceChar /= 2;
197 | if (sourceChar < 0 || sourceChar >= _glyphs.length)
198 | sourceChar = 0;
199 |
200 | if (maskChar == 32) {
201 | _bitmap = Bitmap.createBitmap (16, 16, Bitmap.Config.ARGB_8888);
202 | _bitmap.eraseColor (0);
203 | } else {
204 | _bitmap = BitmapFactory.decodeResource (
205 | xServer.getContext ().getResources (),
206 | _glyphs[sourceChar][0]);
207 | }
208 |
209 | _foregroundColor = 0xff000000;
210 | _backgroundColor = 0xffffffff;
211 | setColor (foregroundColor, backgroundColor);
212 |
213 | _hotspotX = _glyphs[sourceChar][1];
214 | _hotspotY = _glyphs[sourceChar][2];
215 | }
216 |
217 | /**
218 | * Return the cursor's bitmap.
219 | *
220 | * @return The cursor's bitmap.
221 | */
222 | public Bitmap
223 | getBitmap () {
224 | return _bitmap;
225 | }
226 |
227 | /**
228 | * Return the X coordinate of the cursor's hotspot.
229 | *
230 | * @return The X coordinate of the cursor's hotspot.
231 | */
232 | public int
233 | getHotspotX () {
234 | return _hotspotX;
235 | }
236 |
237 | /**
238 | * Return the Y coordinate of the cursor's hotspot.
239 | *
240 | * @return The Y coordinate of the cursor's hotspot.
241 | */
242 | public int
243 | getHotspotY () {
244 | return _hotspotY;
245 | }
246 |
247 | /**
248 | * Set the foreground and background colors of the cursor.
249 | *
250 | * @param fg Foreground color.
251 | * @param bg Background color.
252 | */
253 | private void
254 | setColor (
255 | int fg,
256 | int bg
257 | ) {
258 | if (fg == _foregroundColor && bg == _backgroundColor)
259 | return;
260 |
261 | int width = _bitmap.getWidth ();
262 | int height = _bitmap.getHeight ();
263 | int[] pixels = new int [width * height];
264 |
265 | _bitmap.getPixels (pixels, 0, width, 0, 0, width, height);
266 | for (int i = 0; i < pixels.length; i++) {
267 | int pix = pixels[i];
268 |
269 | if (pix == _foregroundColor)
270 | pixels[i] = fg;
271 | else if (pix == _backgroundColor)
272 | pixels[i] = bg;
273 | }
274 |
275 | _bitmap = Bitmap.createBitmap (pixels, width, height,
276 | Bitmap.Config.ARGB_8888);
277 | _foregroundColor = fg;
278 | _backgroundColor = bg;
279 | }
280 |
281 | /**
282 | * Process an X request relating to this cursor.
283 | *
284 | * @param client The remote client.
285 | * @param opcode The request's opcode.
286 | * @param arg Optional first argument.
287 | * @param bytesRemaining Bytes yet to be read in the request.
288 | * @throws IOException
289 | */
290 | @Override
291 | public void
292 | processRequest (
293 | Client client,
294 | byte opcode,
295 | byte arg,
296 | int bytesRemaining
297 | ) throws IOException {
298 | InputOutput io = client.getInputOutput ();
299 |
300 | switch (opcode) {
301 | case RequestCode.FreeCursor:
302 | if (bytesRemaining != 0) {
303 | io.readSkip (bytesRemaining);
304 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
305 | } else {
306 | _xServer.freeResource (_id);
307 | if (_client != null)
308 | _client.freeResource (this);
309 | break;
310 | }
311 | case RequestCode.RecolorCursor:
312 | if (bytesRemaining != 12) {
313 | io.readSkip (bytesRemaining);
314 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
315 | } else {
316 | int fgRed = io.readShort ();
317 | int fgGreen = io.readShort ();
318 | int fgBlue = io.readShort ();
319 | int bgRed = io.readShort ();
320 | int bgGreen = io.readShort ();
321 | int bgBlue = io.readShort ();
322 |
323 | setColor (Colormap.fromParts16 (fgRed, fgGreen, fgBlue),
324 | Colormap.fromParts16 (bgRed, bgGreen, bgBlue));
325 | }
326 | break;
327 | default:
328 | io.readSkip (bytesRemaining);
329 | ErrorCode.write (client, ErrorCode.Implementation, opcode,
330 | _id);
331 | break;
332 | }
333 | }
334 |
335 | /**
336 | * Process a create request.
337 | *
338 | * @param xServer The X server.
339 | * @param client The client issuing the request.
340 | * @param opcode The request opcode.
341 | * @param id The ID of the cursor to create.
342 | * @param bytesRemaining Bytes yet to be read in the request.
343 | * @throws IOException
344 | */
345 | public static void
346 | processCreateRequest (
347 | XServer xServer,
348 | Client client,
349 | byte opcode,
350 | int id,
351 | int bytesRemaining
352 | ) throws IOException {
353 | InputOutput io = client.getInputOutput ();
354 |
355 | if (opcode == RequestCode.CreateCursor) {
356 | int sid = io.readInt (); // Source pixmap ID.
357 | int mid = io.readInt (); // Mask pixmap ID.
358 | int fgRed = io.readShort ();
359 | int fgGreen = io.readShort ();
360 | int fgBlue = io.readShort ();
361 | int bgRed = io.readShort ();
362 | int bgGreen = io.readShort ();
363 | int bgBlue = io.readShort ();
364 | short x = (short) io.readShort ();
365 | short y = (short) io.readShort ();
366 | Resource r = xServer.getResource (sid);
367 | Resource mr = null;
368 |
369 | if (r == null || r.getType () != Resource.PIXMAP) {
370 | ErrorCode.write (client, ErrorCode.Pixmap, opcode, sid);
371 | return;
372 | } else if (mid != 0) {
373 | mr = xServer.getResource (mid);
374 | if (mr == null || mr.getType () != Resource.PIXMAP) {
375 | ErrorCode.write (client, ErrorCode.Pixmap, opcode, mid);
376 | return;
377 | }
378 | }
379 |
380 | Pixmap p = (Pixmap) r;
381 | Pixmap mp = (Pixmap) mr;
382 |
383 | if (p.getDepth () != 1) {
384 | ErrorCode.write (client, ErrorCode.Match, opcode, sid);
385 | return;
386 | } else if (mp != null) {
387 | if (mp.getDepth () != 1) {
388 | ErrorCode.write (client, ErrorCode.Match, opcode, mid);
389 | return;
390 | }
391 |
392 | Bitmap bm1 = p.getDrawable().getBitmap ();
393 | Bitmap bm2 = mp.getDrawable().getBitmap ();
394 |
395 | if (bm1.getWidth () != bm2.getWidth ()
396 | || bm1.getHeight () != bm2.getHeight ()) {
397 | ErrorCode.write (client, ErrorCode.Match, opcode, mid);
398 | return;
399 | }
400 | }
401 |
402 | int fg = Colormap.fromParts16 (fgRed, fgGreen, fgBlue);
403 | int bg = Colormap.fromParts16 (bgRed, bgGreen, bgBlue);
404 | Cursor c = new Cursor (id, xServer, client, p, mp, x, y,
405 | fg, bg);
406 |
407 | xServer.addResource (c);
408 | client.addResource (c);
409 | } else if (opcode == RequestCode.CreateGlyphCursor) {
410 | int sid = io.readInt (); // Source font ID.
411 | int mid = io.readInt (); // Mask font ID.
412 | int sourceChar = io.readShort (); // Source char.
413 | int maskChar = io.readShort (); // Mask char.
414 | int fgRed = io.readShort ();
415 | int fgGreen = io.readShort ();
416 | int fgBlue = io.readShort ();
417 | int bgRed = io.readShort ();
418 | int bgGreen = io.readShort ();
419 | int bgBlue = io.readShort ();
420 | Resource r = xServer.getResource (sid);
421 | Resource mr = null;
422 |
423 | if (r == null || r.getType () != Resource.FONT) {
424 | ErrorCode.write (client, ErrorCode.Font, opcode, sid);
425 | return;
426 | } else if (mid != 0) {
427 | mr = xServer.getResource (mid);
428 | if (mr == null || mr.getType () != Resource.FONT) {
429 | ErrorCode.write (client, ErrorCode.Font, opcode, mid);
430 | return;
431 | }
432 | }
433 |
434 | int fg = Colormap.fromParts16 (fgRed, fgGreen, fgBlue);
435 | int bg = Colormap.fromParts16 (bgRed, bgGreen, bgBlue);
436 | Cursor c = new Cursor (id, xServer, client, (Font) r,
437 | (Font) mr, sourceChar, maskChar, fg, bg);
438 |
439 | xServer.addResource (c);
440 | client.addResource (c);
441 | }
442 | }
443 | }
444 |
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/ErrorCode.java:
--------------------------------------------------------------------------------
1 | /**
2 | * All the X error codes.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 | /**
9 | * @author Matthew Kwan
10 | *
11 | * All the X error codes.
12 | */
13 | public class ErrorCode {
14 | public static final byte None = 0;
15 | public static final byte Request = 1;
16 | public static final byte Value = 2;
17 | public static final byte Window = 3;
18 | public static final byte Pixmap = 4;
19 | public static final byte Atom = 5;
20 | public static final byte Cursor = 6;
21 | public static final byte Font = 7;
22 | public static final byte Match = 8;
23 | public static final byte Drawable = 9;
24 | public static final byte Access = 10;
25 | public static final byte Alloc = 11;
26 | public static final byte Colormap = 12;
27 | public static final byte GContext = 13;
28 | public static final byte IDChoice = 14;
29 | public static final byte Name = 15;
30 | public static final byte Length = 16;
31 | public static final byte Implementation = 17;
32 |
33 | /**
34 | * Write an X error.
35 | *
36 | * @param client The remote client.
37 | * @param error The error code.
38 | * @param opcode The opcode of the error request.
39 | * @param resourceId The (optional) resource ID that caused the error.
40 | * @throws IOException
41 | */
42 | public static void
43 | write (
44 | Client client,
45 | byte error,
46 | byte opcode,
47 | int resourceId
48 | ) throws IOException {
49 | writeWithMinorOpcode (client, error, (short) 0, opcode, resourceId);
50 | }
51 |
52 | /**
53 | * Write an X error with a minor opcode specified.
54 | *
55 | * @param client The remote client.
56 | * @param error The error code.
57 | * @param minorOpcode The minor opcode of the error request.
58 | * @param opcode The major opcode of the error request.
59 | * @param resourceId The (optional) resource ID that caused the error.
60 | * @throws IOException
61 | */
62 | public static void
63 | writeWithMinorOpcode (
64 | Client client,
65 | byte error,
66 | short minorOpcode,
67 | byte opcode,
68 | int resourceId
69 | ) throws IOException {
70 | InputOutput io = client.getInputOutput ();
71 | short sn = (short) (client.getSequenceNumber () & 0xffff);
72 |
73 | synchronized (io) {
74 | io.writeByte ((byte) 0); // Indicates an error.
75 | io.writeByte (error); // Error code.
76 | io.writeShort (sn); // Sequence number.
77 | io.writeInt (resourceId); // Bad resource ID.
78 | io.writeShort (minorOpcode); // Minor opcode.
79 | io.writeByte (opcode); // Major opcode.
80 | io.writePadBytes (21); // Unused.
81 | }
82 | io.flush ();
83 | }
84 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Font.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class implements an X font.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 | import java.util.Vector;
8 |
9 | import android.graphics.Paint;
10 | import android.graphics.Rect;
11 | import android.graphics.Typeface;
12 |
13 |
14 | /**
15 | * @author Matthew Kwan
16 | *
17 | * This class implements an X font.
18 | */
19 | public class Font extends Resource {
20 | private static int _dpi = 250;
21 |
22 | private final Paint _paint;
23 | private final float _minWidth;
24 | private final float _maxWidth;
25 | private final short _ascent;
26 | private final short _descent;
27 | private final short _maxAscent;
28 | private final short _maxDescent;
29 | private final char _maxChar;
30 | private Atom _nameAtom = null;
31 |
32 | private static final String[] _allFonts = {
33 | "-android-default-medium-r-normal--0-0-0-0-p-0-iso8859-1",
34 | "-android-default-bold-r-normal--0-0-0-0-p-0-iso8859-1",
35 | "-android-default-medium-i-normal--0-0-0-0-p-0-iso8859-1",
36 | "-android-default-bold-i-normal--0-0-0-0-p-0-iso8859-1",
37 | "-android-default-medium-r-normal--0-0-0-0-p-0-iso10646-1",
38 | "-android-default-bold-r-normal--0-0-0-0-p-0-iso10646-1",
39 | "-android-default-medium-i-normal--0-0-0-0-p-0-iso10646-1",
40 | "-android-default-bold-i-normal--0-0-0-0-p-0-iso10646-1",
41 | "-android-monospace-medium-r-normal--0-0-0-0-m-0-iso8859-1",
42 | "-android-monospace-bold-r-normal--0-0-0-0-m-0-iso8859-1",
43 | "-android-monospace-medium-i-normal--0-0-0-0-m-0-iso8859-1",
44 | "-android-monospace-bold-i-normal--0-0-0-0-m-0-iso8859-1",
45 | "-android-monospace-medium-r-normal--0-0-0-0-m-0-iso10646-1",
46 | "-android-monospace-bold-r-normal--0-0-0-0-m-0-iso10646-1",
47 | "-android-monospace-medium-i-normal--0-0-0-0-m-0-iso10646-1",
48 | "-android-monospace-bold-i-normal--0-0-0-0-m-0-iso10646-1",
49 | "-android-serif-medium-r-normal--0-0-0-0-p-0-iso8859-1",
50 | "-android-serif-bold-r-normal--0-0-0-0-p-0-iso8859-1",
51 | "-android-serif-medium-i-normal--0-0-0-0-p-0-iso8859-1",
52 | "-android-serif-bold-i-normal--0-0-0-0-p-0-iso8859-1",
53 | "-android-serif-medium-r-normal--0-0-0-0-p-0-iso10646-1",
54 | "-android-serif-bold-r-normal--0-0-0-0-p-0-iso10646-1",
55 | "-android-serif-medium-i-normal--0-0-0-0-p-0-iso10646-1",
56 | "-android-serif-bold-i-normal--0-0-0-0-p-0-iso10646-1",
57 | "-android-sans serif-medium-r-normal--0-0-0-0-p-0-iso8859-1",
58 | "-android-sans serif-bold-r-normal--0-0-0-0-p-0-iso8859-1",
59 | "-android-sans serif-medium-i-normal--0-0-0-0-p-0-iso8859-1",
60 | "-android-sans serif-bold-i-normal--0-0-0-0-p-0-iso8859-1",
61 | "-android-sans serif-medium-r-normal--0-0-0-0-p-0-iso10646-1",
62 | "-android-sans serif-bold-r-normal--0-0-0-0-p-0-iso10646-1",
63 | "-android-sans serif-medium-i-normal--0-0-0-0-p-0-iso10646-1",
64 | "-android-sans serif-bold-i-normal--0-0-0-0-p-0-iso10646-1",
65 | "fixed",
66 | "cursor"
67 | };
68 |
69 | private static String[][] _allFontFields = null;
70 |
71 | /**
72 | * Set the dots-per-inch resolution at which fonts will be displayed.
73 | *
74 | * @param dpi The dots-per-inch resolution.
75 | */
76 | public static void
77 | setDpi (
78 | int dpi
79 | ) {
80 | _dpi = dpi;
81 | }
82 |
83 | /**
84 | * Constructor.
85 | *
86 | * @param id The server font ID.
87 | * @param xserver The X server.
88 | * @param client The client issuing the request.
89 | * @param name The name of the font. May be null.
90 | */
91 | public Font (
92 | int id,
93 | XServer xServer,
94 | Client client,
95 | String name
96 | ) {
97 | super (FONT, id, xServer, client);
98 |
99 | char maxChar = 255;
100 |
101 | _paint = new Paint ();
102 | if (name == null || name.equalsIgnoreCase ("cursor")) {
103 | _paint.setTypeface (Typeface.DEFAULT);
104 | } else if (name.equalsIgnoreCase ("fixed")) {
105 | _paint.setTypeface (Typeface.MONOSPACE);
106 | } else {
107 | String[] fields = name.split ("-");
108 | Typeface base = Typeface.DEFAULT;
109 | int style = Typeface.NORMAL;
110 |
111 | if (fields.length == 15) {
112 | if (fields[3].equalsIgnoreCase ("bold"))
113 | style |= Typeface.BOLD;
114 | if (fields[4].equalsIgnoreCase ("i"))
115 | style |= Typeface.ITALIC;
116 |
117 | try {
118 | int n = Integer.valueOf (fields[7]);
119 |
120 | if (n > 0)
121 | _paint.setTextSize (n);
122 | } catch (java.lang.NumberFormatException e) {
123 | }
124 |
125 | if (!fields[11].equalsIgnoreCase ("p"))
126 | base = Typeface.MONOSPACE;
127 | else if (fields[2].equalsIgnoreCase ("default"))
128 | base = Typeface.DEFAULT;
129 | else if (fields[2].equalsIgnoreCase ("serif"))
130 | base = Typeface.SERIF;
131 | else if (fields[2].equalsIgnoreCase ("sans serif"))
132 | base = Typeface.SANS_SERIF;
133 | else
134 | base = Typeface.create (fields[2], style);
135 |
136 | if (fields[13].equalsIgnoreCase ("iso10646"))
137 | maxChar = 65534;
138 | }
139 |
140 | _paint.setTypeface (Typeface.create (base, style));
141 | }
142 |
143 | _maxChar = maxChar;
144 |
145 | // Calculate the minimum and maximum widths.
146 | byte[] bytes = new byte[126 - 32 + 1];
147 | float[] widths = new float[bytes.length];
148 |
149 | for (int i = 0; i < bytes.length; i++)
150 | bytes[i] = (byte) (i + 32);
151 |
152 | _paint.getTextWidths (new String (bytes), widths);
153 |
154 | float minw = widths[0];
155 | float maxw = widths[0];
156 |
157 | for (float width: widths) {
158 | if (width < minw)
159 | minw = width;
160 | if (width > maxw)
161 | maxw = width;
162 | }
163 |
164 | _minWidth = minw;
165 | _maxWidth = maxw;
166 |
167 | Paint.FontMetricsInt metrics = _paint.getFontMetricsInt ();
168 |
169 | _ascent = (short) -metrics.ascent;
170 | _descent = (short) metrics.descent;
171 | _maxAscent = (short) -metrics.top;
172 | _maxDescent = (short) metrics.bottom;
173 | }
174 |
175 | /**
176 | * Return the font's typeface.
177 | *
178 | * @return The font's typeface.
179 | */
180 | public Typeface
181 | getTypeface () {
182 | return _paint.getTypeface ();
183 | }
184 |
185 | /**
186 | * Return the font's size.
187 | *
188 | * @return The font's size.
189 | */
190 | public int
191 | getSize () {
192 | return (int) _paint.getTextSize ();
193 | }
194 |
195 | /**
196 | * Calculate the bounding rectangle for text drawn at a location.
197 | *
198 | * @param s The text.
199 | * @param x X coordinate.
200 | * @param y Y coordinate.
201 | * @param rect Return value. The bounding rectangle.
202 | */
203 | public void
204 | getTextBounds (
205 | String s,
206 | int x,
207 | int y,
208 | Rect rect
209 | ) {
210 | rect.left = x;
211 | rect.right = x + (int) _paint.measureText (s);
212 | rect.top = y - _ascent;
213 | rect.bottom = y + _descent;
214 | }
215 |
216 | /**
217 | * Process an X request relating to this font.
218 | *
219 | * @param client The remote client.
220 | * @param opcode The request's opcode.
221 | * @param arg Optional first argument.
222 | * @param bytesRemaining Bytes yet to be read in the request.
223 | * @throws IOException
224 | */
225 | @Override
226 | public void
227 | processRequest (
228 | Client client,
229 | byte opcode,
230 | byte arg,
231 | int bytesRemaining
232 | ) throws IOException {
233 | InputOutput io = client.getInputOutput ();
234 |
235 | switch (opcode) {
236 | case RequestCode.CloseFont:
237 | if (bytesRemaining != 0) {
238 | io.readSkip (bytesRemaining);
239 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
240 | } else {
241 | _xServer.freeResource (_id);
242 | if (_client != null)
243 | _client.freeResource (this);
244 | }
245 | break;
246 | case RequestCode.QueryFont:
247 | if (bytesRemaining != 0) {
248 | io.readSkip (bytesRemaining);
249 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
250 | } else {
251 | processQueryFontRequest (client);
252 | }
253 | break;
254 | case RequestCode.QueryTextExtents:
255 | if (bytesRemaining < 4 || (bytesRemaining & 3) != 0) {
256 | io.readSkip (bytesRemaining);
257 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
258 | } else {
259 | int pad = (arg == 0) ? 0 : 2;
260 | int length = (bytesRemaining - pad) / 2;
261 | char[] chars = new char[length];
262 |
263 | for (int i = 0; i < length; i++) {
264 | int b1 = io.readByte ();
265 | int b2 = io.readByte ();
266 |
267 | chars[i] = (char) ((b1 << 8) | b2);
268 | }
269 |
270 | io.readSkip (pad);
271 | processQueryTextExtentsRequest (client,
272 | new String (chars));
273 | }
274 | break;
275 | default:
276 | io.readSkip (bytesRemaining);
277 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
278 | break;
279 | }
280 | }
281 |
282 | /**
283 | * Process an OpenFont request.
284 | *
285 | * @param xServer The X server.
286 | * @param client The client issuing the request.
287 | * @param id The ID of the font to create.
288 | * @param bytesRemaining Bytes yet to be read in the request.
289 | * @throws IOException
290 | */
291 | public static void
292 | processOpenFontRequest (
293 | XServer xServer,
294 | Client client,
295 | int id,
296 | int bytesRemaining
297 | ) throws IOException {
298 | InputOutput io = client.getInputOutput ();
299 | int length = io.readShort (); // Length of name.
300 | int pad = -length & 3;
301 |
302 | io.readSkip (2); // Unused.
303 | bytesRemaining -= 4;
304 | if (bytesRemaining != length + pad) {
305 | io.readSkip (bytesRemaining);
306 | ErrorCode.write (client, ErrorCode.Length, RequestCode.OpenFont,
307 | 0);
308 | return;
309 | }
310 |
311 | byte[] nameBytes = new byte[length];
312 |
313 | io.readBytes (nameBytes, 0, length);
314 | io.readSkip (pad);
315 |
316 | String name = new String (nameBytes);
317 | Font f = new Font (id, xServer, client, name);
318 |
319 | xServer.addResource (f);
320 | client.addResource (f);
321 |
322 | // Create an atom containing the font name.
323 | Atom a = xServer.findAtom (name);
324 |
325 | if (a == null) {
326 | a = new Atom (xServer.nextFreeAtomId (), name);
327 | xServer.addAtom (a);
328 | }
329 |
330 | f._nameAtom = a;
331 | }
332 |
333 | /**
334 | * Process a QueryFont request.
335 | *
336 | * @param client The client issuing the request.
337 | * @throws IOException
338 | */
339 | private void
340 | processQueryFontRequest (
341 | Client client
342 | ) throws IOException {
343 | InputOutput io = client.getInputOutput ();
344 | int numFontProperties = (_nameAtom == null) ? 0 : 1;
345 | int numCharInfos = _maxChar - 31;
346 | char[] chars = new char[numCharInfos];
347 |
348 | for (char c = 32; c <= _maxChar; c++)
349 | chars[c - 32] = c;
350 |
351 | String s = new String (chars);
352 | Rect bounds = new Rect ();
353 | float[] widths = new float[numCharInfos];
354 |
355 | _paint.getTextWidths (s, widths);
356 |
357 | synchronized (io) {
358 | Util.writeReplyHeader (client, (byte) 0);
359 | // Reply length.
360 | io.writeInt (7 + numFontProperties * 2 + numCharInfos * 3);
361 |
362 | // Min bounds.
363 | io.writeShort ((short) 0); // Left side bearing.
364 | io.writeShort ((short) 0); // Right side bearing.
365 | io.writeShort ((short) _minWidth); // Character width.
366 | io.writeShort ((short) 0); // Ascent.
367 | io.writeShort ((short) 0); // Descent.
368 | io.writeShort ((short) 0); // Attributes.
369 | io.writePadBytes (4); // Unused.
370 |
371 | // Max bounds.
372 | io.writeShort ((short) 0); // Left side bearing.
373 | io.writeShort ((short) _maxWidth); // Right side bearing.
374 | io.writeShort ((short) _maxWidth); // Character width.
375 | io.writeShort (_maxAscent); // Ascent.
376 | io.writeShort (_maxDescent); // Descent.
377 | io.writeShort ((short) 0); // Attributes.
378 | io.writePadBytes (4); // Unused.
379 |
380 | io.writeShort ((short) 32); // Min char or byte2.
381 | io.writeShort ((short) _maxChar); // Max char or byte2.
382 | io.writeShort ((short) 32); // Default char.
383 | io.writeShort ((short) numFontProperties);
384 | io.writeByte ((byte) 0); // Draw direction = left-to-right.
385 | io.writeByte ((byte) 0); // Min byte 1.
386 | io.writeByte ((byte) 0); // Max byte 1.
387 | io.writeByte ((byte) 0); // All chars exist = false.
388 | io.writeShort (_ascent); // Font ascent.
389 | io.writeShort (_descent); // Font descent.
390 | io.writeInt (numCharInfos);
391 |
392 | // If name atom is specified, write the FONT property.
393 | if (_nameAtom != null) {
394 | Atom a = _xServer.findAtom ("FONT");
395 |
396 | io.writeInt (a.getId ()); // Name.
397 | io.writeInt (_nameAtom.getId ()); // Value.
398 | }
399 |
400 | for (int i = 0; i < numCharInfos; i++) {
401 | _paint.getTextBounds (s, i, i + 1, bounds);
402 | io.writeShort ((short) bounds.left); // Left side bearing.
403 | io.writeShort ((short) bounds.right); // Right side bearing.
404 | io.writeShort ((short) widths[i]); // Character width.
405 | io.writeShort ((short) -bounds.top); // Ascent.
406 | io.writeShort ((short) bounds.bottom); // Descent.
407 | io.writeShort ((short) 0); // Attributes.
408 | }
409 | }
410 | io.flush ();
411 | }
412 |
413 | /**
414 | * Process a QueryTextExtents request.
415 | *
416 | * @param client The remote client.
417 | * @param s The string whose extents are being queried.
418 | * @throws IOException
419 | */
420 | private void
421 | processQueryTextExtentsRequest (
422 | Client client,
423 | String s
424 | ) throws IOException {
425 | InputOutput io = client.getInputOutput ();
426 | int width = (int) _paint.measureText (s);
427 | Rect bounds = new Rect ();
428 |
429 | _paint.getTextBounds (s, 0, s.length (), bounds);
430 |
431 | synchronized (io) {
432 | Util.writeReplyHeader (client, (byte) 0);
433 | io.writeInt (0); // Reply length.
434 | io.writeShort (_ascent); // Font ascent.
435 | io.writeShort (_descent); // Font descent.
436 | io.writeShort ((short) -bounds.top); // Overall ascent.
437 | io.writeShort ((short) bounds.bottom); // Overall descent.
438 | io.writeInt (width); // Overall width.
439 | io.writeInt (bounds.left); // Overall left.
440 | io.writeInt (bounds.right); // Overall right.
441 | io.writePadBytes (4); // Unused.
442 | }
443 | io.flush ();
444 | }
445 |
446 | /**
447 | * Process a GetFontPath request.
448 | *
449 | * @param xServer The X server.
450 | * @param client The remote client.
451 | * @throws IOException
452 | */
453 | public static void
454 | processGetFontPath (
455 | XServer xServer,
456 | Client client
457 | ) throws IOException {
458 | InputOutput io = client.getInputOutput ();
459 | String[] fontPaths = xServer.getFontPath ();
460 | int numPaths = 0;
461 | int length = 0;
462 |
463 | if (fontPaths != null)
464 | numPaths = fontPaths.length;
465 |
466 | for (int i = 0; i < numPaths; i++)
467 | length += fontPaths[i].length () + 1;
468 |
469 | int pad = -length & 3;
470 |
471 | synchronized (io) {
472 | Util.writeReplyHeader (client, (byte) 0);
473 | io.writeInt ((length + pad) / 4); // Reply length.
474 | io.writeShort ((short) numPaths); // Number of STRs in path.
475 | io.writePadBytes (22); // Unused.
476 |
477 | for (int i = 0; i < numPaths; i++) {
478 | byte[] ba = fontPaths[i].getBytes ();
479 |
480 | io.writeByte ((byte) ba.length);
481 | io.writeBytes (ba, 0, ba.length);
482 | }
483 | io.writePadBytes (pad); // Unused.
484 | }
485 | io.flush ();
486 | }
487 |
488 | /**
489 | * Process a SetFontPath request.
490 | *
491 | * @param xServer The X server.
492 | * @param client The remote client.
493 | * @param bytesRemaining Bytes yet to be read in the request.
494 | * @throws IOException
495 | */
496 | public static void
497 | processSetFontPath (
498 | XServer xServer,
499 | Client client,
500 | int bytesRemaining
501 | ) throws IOException {
502 | InputOutput io = client.getInputOutput ();
503 |
504 | if (bytesRemaining < 4) {
505 | io.readSkip (bytesRemaining);
506 | ErrorCode.write (client, ErrorCode.Length,
507 | RequestCode.SetFontPath, 0);
508 | return;
509 | }
510 |
511 | int numPaths = io.readShort (); // Number of STRs in path.
512 | String[] fontPaths = (numPaths > 0) ? new String[numPaths] : null;
513 | boolean lengthError = false;
514 |
515 | io.readSkip (2); // Unused.
516 | bytesRemaining -= 4;
517 |
518 | for (int i = 0; i < numPaths; i++) {
519 | if (bytesRemaining < 1) {
520 | lengthError = true;
521 | break;
522 | }
523 |
524 | int length = io.readByte ();
525 | byte[] ba = new byte[length];
526 |
527 | bytesRemaining--;
528 | if (bytesRemaining < length) {
529 | lengthError = true;
530 | break;
531 | }
532 |
533 | io.readBytes (ba, 0, length);
534 | bytesRemaining -= length + 1;
535 | fontPaths[i] = new String (ba);
536 | }
537 |
538 | if (bytesRemaining >= 4)
539 | lengthError = true;
540 |
541 | io.readSkip (bytesRemaining);
542 | if (lengthError)
543 | ErrorCode.write (client, ErrorCode.Length,
544 | RequestCode.SetFontPath, 0);
545 | else
546 | xServer.setFontPath (fontPaths);
547 | }
548 |
549 | /**
550 | * Does the font name match the pattern?
551 | *
552 | * @param idx The index of the font being matched.
553 | * @param pattern The pattern being matched.
554 | * @param pfields The pattern, broken into its components.
555 | * @return The name of the matching font, or null if it doesn't match.
556 | */
557 | private static String
558 | fontMatchesPattern (
559 | int idx,
560 | String pattern,
561 | String[] pfields
562 | ) {
563 | String font = _allFonts[idx];
564 |
565 | if (pattern.equals ("*"))
566 | return font;
567 |
568 | String[] fields;
569 |
570 | if (_allFontFields == null)
571 | _allFontFields = new String[_allFonts.length][];
572 |
573 | if (_allFontFields[idx] == null)
574 | fields = _allFontFields[idx] = font.split ("-");
575 | else
576 | fields = _allFontFields[idx];
577 |
578 | if (fields.length < pfields.length)
579 | return null;
580 |
581 | if (fields.length == 1)
582 | return pattern.equalsIgnoreCase (font) ? font : null;
583 |
584 | int offset = 0;
585 | boolean rescale = false;
586 |
587 | if (pfields[0].equals ("*"))
588 | offset = fields.length - pfields.length;
589 |
590 | for (int i = 0; i < pfields.length; i++) {
591 | if (pfields[i].equals ("*"))
592 | continue;
593 |
594 | int foff = offset + i;
595 |
596 | if (foff == 0 || foff == 9 || foff == 10)
597 | continue; // First field not used. And ignore resolution.
598 | else if (fields[foff].equalsIgnoreCase (pfields[i]))
599 | continue;
600 | // else if (fields[foff].matches (pfields[i]))
601 | // continue; // Pattern matching.
602 | else if (foff >= 7 && foff <= 8) // Pixel and point size.
603 | rescale = true;
604 | else
605 | return null;
606 | }
607 |
608 | if (rescale) {
609 | int pixels = 0;
610 | int points = 0;
611 |
612 | if (offset <= 7) {
613 | try {
614 | pixels = Integer.parseInt (pfields[7 - offset]);
615 | } catch (Exception e) {
616 | }
617 | }
618 |
619 | if (offset <= 8) {
620 | try {
621 | points = Integer.parseInt (pfields[8 - offset]);
622 | } catch (Exception e) {
623 | }
624 | }
625 |
626 | if (pixels == 0 && points == 0)
627 | return font;
628 | else if (pixels == 0 && points != 0)
629 | pixels = (int) Math.round (points * _dpi / 722.7);
630 | else if (pixels != 0 && points == 0)
631 | points = (int) Math.round (pixels * 722.7 / _dpi);
632 |
633 | return "-" + fields[1] + "-" + fields[2]
634 | + "-" + fields[3] + "-" + fields[4]
635 | + "-" + fields[5] + "-" + fields[6]
636 | + "-" + pixels + "-" + points + "-" + _dpi + "-" + _dpi
637 | + "-" + fields[11] + "-" + fields[12]
638 | + "-" + fields[13] + "-" + fields[14];
639 | }
640 |
641 | return font;
642 | }
643 |
644 | /**
645 | * Process a ListFonts or ListFontsWithInfo request.
646 | *
647 | * @param client The remote client.
648 | * @param opcode The request's opcode.
649 | * @param bytesRemaining Bytes yet to be read in the request.
650 | * @throws IOException
651 | */
652 | public static void
653 | processListFonts (
654 | Client client,
655 | byte opcode,
656 | int bytesRemaining
657 | ) throws IOException {
658 | InputOutput io = client.getInputOutput ();
659 |
660 | if (bytesRemaining < 4) {
661 | io.readSkip (bytesRemaining);
662 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
663 | return;
664 | }
665 |
666 | int maxNames = io.readShort (); // Max names.
667 | int length = io.readShort (); // Length of pattern.
668 | int pad = -length & 3;
669 |
670 | bytesRemaining -= 4;
671 | if (bytesRemaining != length + pad) {
672 | io.readSkip (bytesRemaining);
673 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
674 | return;
675 | }
676 |
677 | byte[] bytes = new byte[length];
678 |
679 | io.readBytes (bytes, 0, length); // Pattern.
680 | io.readSkip (pad); // Unused.
681 |
682 | String pattern = new String (bytes);
683 | String[] pfields = pattern.split ("-");
684 | Vector fonts = new Vector();
685 |
686 | for (int i = 0; i < _allFonts.length; i++) {
687 | String f = fontMatchesPattern (i, pattern, pfields);
688 |
689 | if (f != null) {
690 | fonts.add (f);
691 | if (fonts.size () >= maxNames)
692 | break;
693 | }
694 | }
695 |
696 | if (opcode == RequestCode.ListFonts) {
697 | length = 0;
698 | for (String s: fonts)
699 | length += s.length () + 1;
700 |
701 | pad = -length & 3;
702 |
703 | synchronized (io) {
704 | Util.writeReplyHeader (client, (byte) 0);
705 | io.writeInt ((length + pad) / 4); // Reply length.
706 | io.writeShort ((short) fonts.size ()); // Number of names.
707 | io.writePadBytes (22); // Unused.
708 |
709 | for (String s: fonts) {
710 | byte[] ba = s.getBytes ();
711 |
712 | io.writeByte ((byte) ba.length);
713 | io.writeBytes (ba, 0, ba.length);
714 | }
715 |
716 | io.writePadBytes (pad); // Unused.
717 | }
718 | io.flush ();
719 | } else {
720 | int remaining = fonts.size ();
721 |
722 | for (String s: fonts)
723 | writeFontWithInfo (client, s, remaining--);
724 |
725 | // Last in series indicator.
726 | synchronized (io) {
727 | Util.writeReplyHeader (client, (byte) 0);
728 | io.writeInt (7); // Reply length.
729 | io.writePadBytes (52); // Unused.
730 | }
731 | io.flush ();
732 | }
733 | }
734 |
735 | /**
736 | * Write information about a named font.
737 | * This is one of multiple replies to a ListFontsWithInfo request.
738 | *
739 | * @param client The remote client.
740 | * @param name The name of the font.
741 | * @param fontsRemaining Number of replies before request is complete.
742 | * @throws IOException
743 | */
744 | private static void
745 | writeFontWithInfo (
746 | Client client,
747 | String name,
748 | int fontsRemaining
749 | ) throws IOException {
750 | InputOutput io = client.getInputOutput ();
751 | Font font = new Font (0, null, null, name);
752 | int numFontProperties = 0;
753 | byte nameLength = (byte) name.length ();
754 | int pad = -nameLength & 3;
755 | Paint.FontMetricsInt metrics = font._paint.getFontMetricsInt ();
756 |
757 | synchronized (io) {
758 | Util.writeReplyHeader (client, nameLength);
759 | // Reply length.
760 | io.writeInt (7 + numFontProperties * 2 + (nameLength + pad) / 4);
761 |
762 | // Min bounds.
763 | io.writeShort ((short) 0); // Left side bearing.
764 | io.writeShort ((short) 0); // Right side bearing.
765 | io.writeShort ((short) font._minWidth); // Character width.
766 | io.writeShort ((short) 0); // Ascent.
767 | io.writeShort ((short) 0); // Descent.
768 | io.writeShort ((short) 0); // Attributes.
769 | io.writePadBytes (4); // Unused.
770 |
771 | // Max bounds.
772 | io.writeShort ((short) 0); // Left side bearing.
773 | io.writeShort ((short) font._maxWidth); // Right side bearing.
774 | io.writeShort ((short) font._maxWidth); // Character width.
775 | io.writeShort ((short) -metrics.top); // Ascent.
776 | io.writeShort ((short) metrics.bottom); // Descent.
777 | io.writeShort ((short) 0); // Attributes.
778 | io.writePadBytes (4); // Unused.
779 |
780 | io.writeShort ((short) 32); // Min char or byte2.
781 | io.writeShort ((short) font._maxChar); // Max char or byte2.
782 | io.writeShort ((short) 32); // Default char.
783 | io.writeShort ((short) numFontProperties);
784 | io.writeByte ((byte) 0); // Draw direction = left-to-right.
785 | io.writeByte ((byte) 0); // Min byte 1.
786 | io.writeByte ((byte) 0); // Max byte 1.
787 | io.writeByte ((byte) 0); // All chars exist = false.
788 | io.writeShort ((short) -metrics.ascent); // Font ascent.
789 | io.writeShort ((short) metrics.descent); // Font descent.
790 | io.writeInt (fontsRemaining); // Replies hint.
791 | // No font properties.
792 | io.writeBytes (name.getBytes (), 0, nameLength); // Name.
793 | io.writePadBytes (pad); // Unused.
794 | }
795 | io.flush ();
796 | }
797 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Format.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class stores details of a pixmap format.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 |
9 | /**
10 | * @author Matthew Kwan
11 | *
12 | * This class stores details of a pixmap format.
13 | */
14 | public class Format {
15 | private final byte _depth;
16 | private final byte _bitsPerPixel;
17 | private final byte _scanlinePad;
18 |
19 | /**
20 | * Constructor.
21 | *
22 | * @param depth The depth in bits.
23 | * @param bitsPerPixel Number of bits per pixel.
24 | * @param scanlinePad Number of bits to pad each scan line.
25 | */
26 | public Format (
27 | byte depth,
28 | byte bitsPerPixel,
29 | byte scanlinePad
30 | ) {
31 | _depth = depth;
32 | _bitsPerPixel = bitsPerPixel;
33 | _scanlinePad = scanlinePad;
34 | }
35 |
36 | /**
37 | * Write details of the format.
38 | *
39 | * @param io The input/output stream.
40 | * @throws IOException
41 | */
42 | public void
43 | write (
44 | InputOutput io
45 | ) throws IOException {
46 | io.writeByte (_depth); // Depth.
47 | io.writeByte (_bitsPerPixel); // Bits per pixel.
48 | io.writeByte (_scanlinePad); // Scanline pad.
49 | io.writePadBytes (5); // Unused.
50 | }
51 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/GContext.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class implements an X graphics context.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 | import android.graphics.Canvas;
9 | import android.graphics.Paint;
10 | import android.graphics.Path;
11 | import android.graphics.PixelXorXfermode;
12 | import android.graphics.Rect;
13 | import android.graphics.Region;
14 |
15 |
16 | /**
17 | * @author Matthew Kwan
18 | *
19 | * This class implements an X graphics context.
20 | */
21 | public class GContext extends Resource {
22 | private Paint _paint;
23 | private Font _font = null;
24 | private Path.FillType _fillType;
25 | private int[] _attributes;
26 | private Rect[] _clipRectangles = null;
27 | private int _foregroundColor = 0xff000000;
28 | private int _backgroundColor = 0xffffffff;
29 |
30 | private static final int AttrFunction = 0;
31 | private static final int AttrPlaneMask = 1;
32 | private static final int AttrForeground = 2;
33 | private static final int AttrBackground = 3;
34 | private static final int AttrLineWidth = 4;
35 | private static final int AttrLineStyle = 5;
36 | private static final int AttrCapStyle = 6;
37 | private static final int AttrJoinStyle = 7;
38 | private static final int AttrFillStyle = 8;
39 | private static final int AttrFillRule = 9;
40 | private static final int AttrTile = 10;
41 | private static final int AttrStipple = 11;
42 | private static final int AttrTileStippleXOrigin = 12;
43 | private static final int AttrTileStippleYOrigin = 13;
44 | private static final int AttrFont = 14;
45 | private static final int AttrSubwindowMode = 15;
46 | private static final int AttrGraphicsExposures = 16;
47 | private static final int AttrClipXOrigin = 17;
48 | private static final int AttrClipYOrigin = 18;
49 | private static final int AttrClipMask = 19;
50 | private static final int AttrDashOffset = 20;
51 | private static final int AttrDashes = 21;
52 | private static final int AttrArcMode = 22;
53 |
54 | /**
55 | * Constructor.
56 | *
57 | * @param id The graphics context's ID.
58 | * @param xServer The X server.
59 | * @param client The client issuing the request.
60 | */
61 | public GContext (
62 | int id,
63 | XServer xServer,
64 | Client client
65 | ) {
66 | super (GCONTEXT, id, xServer, client);
67 |
68 | _paint = new Paint ();
69 | _attributes = new int[] {
70 | 3, // function = Copy
71 | 0xffffffff, // plane-mask = all ones
72 | 0, // foreground = 0
73 | 1, // background = 1
74 | 0, // line-width = 0
75 | 0, // line-style = Solid
76 | 1, // cap-style = Butt
77 | 0, // join-style = Miter
78 | 0, // fill-style = Solid
79 | 0, // fill-rule = EvenOdd
80 | 0, // tile = foreground-filled pixmap
81 | 0, // stipple = pixmap filled with ones
82 | 0, // tile-stipple-x-origin = 0
83 | 0, // tile-stipple-y-origin = 0
84 | 0, // font = server-dependent
85 | 0, // subwindow-mode = ClipByChildren
86 | 1, // graphics-exposures = True
87 | 0, // clip-x-origin = 0
88 | 0, // clip-y-origin = 0
89 | 0, // clip-mask = None
90 | 0, // dash-offset = 0
91 | 4, // dashes = 4 (i.e. the list [4,4])
92 | 1 // arc-mode = PieSlice
93 | };
94 | }
95 |
96 | /**
97 | * Return the GContext's Paint handle.
98 | *
99 | * @return The GContext's Paint handle.
100 | */
101 | public Paint
102 | getPaint () {
103 | return _paint;
104 | }
105 |
106 | /**
107 | * Return the GContext's background color.
108 | *
109 | * @return The GContext's background color.
110 | */
111 | public int
112 | getBackgroundColor () {
113 | return _backgroundColor;
114 | }
115 |
116 | /**
117 | * Return the GContext's foreground color.
118 | *
119 | * @return The GContext's foreground color.
120 | */
121 | public int
122 | getForegroundColor () {
123 | return _foregroundColor;
124 | }
125 |
126 | /**
127 | * Return the fill type.
128 | *
129 | * @return The fill type.
130 | */
131 | public Path.FillType
132 | getFillType () {
133 | return _fillType;
134 | }
135 |
136 | /**
137 | * Return the arc mode.
138 | * 0 = chord, 1 = pie slice.
139 | *
140 | * @return The arc mode.
141 | */
142 | public int
143 | getArcMode () {
144 | return _attributes[AttrArcMode];
145 | }
146 |
147 | /**
148 | * Return whether to generate graphics exposure events.
149 | *
150 | * @return Whether to generate graphics exposure events.
151 | */
152 | public boolean
153 | getGraphicsExposure () {
154 | return (_attributes[AttrGraphicsExposures] != 0);
155 | }
156 |
157 | /**
158 | * Return the GContext's font.
159 | *
160 | * @return The GContext's font.
161 | */
162 | public Font
163 | getFont () {
164 | return _font;
165 | }
166 |
167 | /**
168 | * Set the GContext's font.
169 | *
170 | * @param id The ID of the font.
171 | * @return True if the ID refers to a valid font.
172 | */
173 | public boolean
174 | setFont (
175 | int id
176 | ) {
177 | Resource r = _xServer.getResource (id);
178 |
179 | if (r == null || r.getType () != Resource.FONT)
180 | return false;
181 |
182 | _font = (Font) r;
183 | _paint.setTypeface (_font.getTypeface ());
184 | _paint.setTextSize (_font.getSize ());
185 |
186 | return true;
187 | }
188 |
189 | /**
190 | * Apply the GContext's clip rectangles to the canvas.
191 | *
192 | * @param canvas The canvas to apply the rectangles to.
193 | */
194 | public void
195 | applyClipRectangles (
196 | Canvas canvas
197 | ) {
198 | if (_clipRectangles == null)
199 | return;
200 |
201 | if (_clipRectangles.length == 0)
202 | canvas.clipRect (0, 0, 0, 0);
203 | else
204 | for (Rect r: _clipRectangles)
205 | canvas.clipRect (r, Region.Op.UNION);
206 | }
207 |
208 | /**
209 | * Process an X request relating to this graphics context.
210 | *
211 | * @param client The remote client.
212 | * @param opcode The request's opcode.
213 | * @param arg Optional first argument.
214 | * @param bytesRemaining Bytes yet to be read in the request.
215 | * @throws IOException
216 | */
217 | @Override
218 | public void
219 | processRequest (
220 | Client client,
221 | byte opcode,
222 | byte arg,
223 | int bytesRemaining
224 | ) throws IOException {
225 | InputOutput io = client.getInputOutput ();
226 |
227 | switch (opcode) {
228 | case RequestCode.QueryFont:
229 | case RequestCode.QueryTextExtents:
230 | _font.processRequest (client, opcode, arg, bytesRemaining);
231 | return;
232 | case RequestCode.ChangeGC:
233 | processValues (client, opcode, bytesRemaining);
234 | break;
235 | case RequestCode.CopyGC:
236 | if (bytesRemaining != 8) {
237 | io.readSkip (bytesRemaining);
238 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
239 | } else {
240 | int id = io.readInt (); // Destination GContext.
241 | int mask = io.readInt (); // Value mask.
242 | Resource r = _xServer.getResource (id);
243 |
244 | if (r == null || r.getType () != Resource.GCONTEXT) {
245 | ErrorCode.write (client, ErrorCode.GContext, opcode,
246 | id);
247 | } else {
248 | GContext gc = (GContext) r;
249 |
250 | for (int i = 0; i < 23; i++)
251 | if ((mask & (1 << i)) != 0)
252 | gc._attributes[i] = _attributes[i];
253 |
254 | gc.applyValues (null, opcode);
255 | }
256 | }
257 | break;
258 | case RequestCode.SetDashes:
259 | if (bytesRemaining < 4) {
260 | io.readSkip (bytesRemaining);
261 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
262 | } else {
263 | io.readShort (); // Dash offset.
264 |
265 | int n = io.readShort (); // Length of dashes.
266 | int pad = -n & 3;
267 |
268 | bytesRemaining -= 4;
269 | if (bytesRemaining != n + pad)
270 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
271 |
272 | io.readSkip (n + pad); // Ignore the dash information.
273 | }
274 | case RequestCode.SetClipRectangles:
275 | if (bytesRemaining < 4) {
276 | io.readSkip (bytesRemaining);
277 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
278 | } else {
279 | int clipXOrigin = (short) io.readShort ();
280 | int clipYOrigin = (short) io.readShort ();
281 |
282 | bytesRemaining -= 4;
283 | if ((bytesRemaining & 7) != 0) {
284 | io.readSkip (bytesRemaining);
285 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
286 | } else {
287 | int i = 0;
288 |
289 | _clipRectangles = new Rect[bytesRemaining / 8];
290 | while (bytesRemaining > 0) {
291 | int x = (short) io.readShort ();
292 | int y = (short) io.readShort ();
293 | int width = io.readShort ();
294 | int height = io.readShort ();
295 |
296 | bytesRemaining -= 8;
297 | _clipRectangles[i++] = new Rect (x + clipXOrigin,
298 | y + clipYOrigin, x + clipXOrigin + width,
299 | y + clipYOrigin + height);
300 | }
301 | }
302 | }
303 | break;
304 | case RequestCode.FreeGC:
305 | if (bytesRemaining != 0) {
306 | io.readSkip (bytesRemaining);
307 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
308 | } else {
309 | _xServer.freeResource (_id);
310 | if (_client != null)
311 | _client.freeResource (this);
312 | break;
313 | }
314 | default:
315 | io.readSkip (bytesRemaining);
316 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
317 | break;
318 | }
319 | }
320 |
321 | /**
322 | * Process a CreateGC request.
323 | *
324 | * @param xServer The X server.
325 | * @param client The client issuing the request.
326 | * @param id The ID of the GContext to create.
327 | * @param bytesRemaining Bytes yet to be read in the request.
328 | * @throws IOException
329 | */
330 | public static void
331 | processCreateGCRequest (
332 | XServer xServer,
333 | Client client,
334 | int id,
335 | int bytesRemaining
336 | ) throws IOException {
337 | GContext gc = new GContext (id, xServer, client);
338 |
339 | if (gc.processValues (client, RequestCode.CreateGC, bytesRemaining)) {
340 | xServer.addResource (gc);
341 | client.addResource (gc);
342 | }
343 | }
344 |
345 | /**
346 | * Process a list of GContext attribute values.
347 | *
348 | * @param client The remote client.
349 | * @param opcode The opcode being processed.
350 | * @param bytesRemaining Bytes yet to be read in the request.
351 | * @return True if the values are all valid.
352 | * @throws IOException
353 | */
354 | private boolean
355 | processValues (
356 | Client client,
357 | byte opcode,
358 | int bytesRemaining
359 | ) throws IOException {
360 | InputOutput io = client.getInputOutput ();
361 |
362 | if (bytesRemaining < 4) {
363 | io.readSkip (bytesRemaining);
364 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
365 | return false;
366 | }
367 |
368 | int valueMask = io.readInt (); // Value mask.
369 | int n = Util.bitcount (valueMask);
370 |
371 | bytesRemaining -= 4;
372 | if (bytesRemaining != n * 4) {
373 | io.readSkip (bytesRemaining);
374 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
375 | return false;
376 | }
377 |
378 | for (int i = 0; i < 23; i++)
379 | if ((valueMask & (1 << i)) != 0)
380 | processValue (io, i);
381 |
382 | return applyValues (client, opcode);
383 | }
384 |
385 | /**
386 | * Process a single GContext attribute value.
387 | *
388 | * @param io The input/output stream.
389 | * @param maskBit The mask bit of the attribute.
390 | * @throws IOException
391 | */
392 | private void
393 | processValue (
394 | InputOutput io,
395 | int maskBit
396 | ) throws IOException {
397 | switch (maskBit) {
398 | case AttrFunction:
399 | case AttrLineStyle:
400 | case AttrCapStyle:
401 | case AttrJoinStyle:
402 | case AttrFillStyle:
403 | case AttrFillRule:
404 | case AttrSubwindowMode:
405 | case AttrGraphicsExposures:
406 | case AttrDashes:
407 | case AttrArcMode:
408 | _attributes[maskBit] = io.readByte ();
409 | io.readSkip (3);
410 | break;
411 | case AttrPlaneMask:
412 | case AttrForeground:
413 | case AttrBackground:
414 | case AttrTile:
415 | case AttrStipple:
416 | case AttrFont:
417 | case AttrClipMask:
418 | _attributes[maskBit] = io.readInt ();
419 | break;
420 | case AttrLineWidth:
421 | case AttrDashOffset:
422 | _attributes[maskBit] = io.readShort ();
423 | io.readSkip (2);
424 | break;
425 | case AttrTileStippleXOrigin:
426 | case AttrTileStippleYOrigin:
427 | case AttrClipXOrigin:
428 | case AttrClipYOrigin:
429 | _attributes[maskBit] = (short) io.readShort ();
430 | io.readSkip (2);
431 | break;
432 | }
433 | }
434 |
435 | /**
436 | * Apply the attribute values to the Paint.
437 | *
438 | * @param client The remote client.
439 | * @param opcode The opcode being processed.
440 | * @return True if the values are all valid.
441 | * @throws IOException
442 | */
443 | private boolean
444 | applyValues (
445 | Client client,
446 | byte opcode
447 | ) throws IOException {
448 | boolean ok = true;
449 |
450 | _foregroundColor = _attributes[AttrForeground] | 0xff000000;
451 | _backgroundColor = _attributes[AttrBackground] | 0xff000000;
452 |
453 | _paint.setColor (_foregroundColor);
454 | _paint.setStrokeWidth (_attributes[AttrLineWidth]);
455 |
456 | if (_attributes[AttrFunction] == 6) // XOR.
457 | _paint.setXfermode (new PixelXorXfermode (0xffffffff));
458 | else
459 | _paint.setXfermode (null);
460 |
461 | switch (_attributes[AttrCapStyle]) {
462 | case 0: // NotLast
463 | case 1: // Butt
464 | _paint.setStrokeCap (Paint.Cap.BUTT);
465 | break;
466 | case 2: // Round
467 | _paint.setStrokeCap (Paint.Cap.ROUND);
468 | break;
469 | case 3: // Projecting
470 | _paint.setStrokeCap (Paint.Cap.SQUARE);
471 | break;
472 | }
473 |
474 | switch (_attributes[AttrJoinStyle]) {
475 | case 0: // Miter
476 | _paint.setStrokeJoin (Paint.Join.MITER);
477 | break;
478 | case 1: // Round
479 | _paint.setStrokeJoin (Paint.Join.ROUND);
480 | break;
481 | case 2: // Bevel
482 | _paint.setStrokeJoin (Paint.Join.BEVEL);
483 | break;
484 | }
485 |
486 | if (_attributes[AttrFillRule] == 1) // Winding.
487 | _fillType = Path.FillType.WINDING;
488 | else // Defaults to even-odd.
489 | _fillType = Path.FillType.EVEN_ODD;
490 |
491 | int fid = _attributes[AttrFont];
492 |
493 | if (_font == null || fid == 0)
494 | _font = _xServer.getDefaultFont ();
495 |
496 | if (fid != 0 && !setFont (fid)) {
497 | ok = false;
498 | ErrorCode.write (client, ErrorCode.Font, opcode, fid);
499 | }
500 |
501 | return ok;
502 | }
503 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/InputOutput.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class handles buffered bi-directional communications.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.BufferedInputStream;
7 | import java.io.BufferedOutputStream;
8 | import java.io.IOException;
9 | import java.net.Socket;
10 |
11 | /**
12 | * @author Matthew Kwan
13 | *
14 | * This class handles buffered bi-directional communications.
15 | */
16 | public class InputOutput {
17 | private final BufferedInputStream _inStream;
18 | private final BufferedOutputStream _outStream;
19 | private boolean _msb = true;
20 | private static final byte[] PadBytes = new byte[] {
21 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
23 | };
24 |
25 | /**
26 | * Constructor.
27 | *
28 | * @param socket Communicate via this socket.
29 | * @throws IOException
30 | */
31 | public InputOutput (
32 | Socket socket
33 | ) throws IOException {
34 | _inStream = new BufferedInputStream (socket.getInputStream (), 16384);
35 | _outStream = new BufferedOutputStream (socket.getOutputStream (),
36 | 16384);
37 | }
38 |
39 | /**
40 | * Set whether the most significant byte comes first.
41 | *
42 | * @param msb
43 | */
44 | public void
45 | setMSB (
46 | boolean msb
47 | ) {
48 | _msb = msb;
49 | }
50 |
51 | /**
52 | * Read an 8-bit integer from the input stream.
53 | *
54 | * @return An 8-bit integer in the range 0 to 255.
55 | * @throws IOException
56 | */
57 | public int
58 | readByte () throws IOException {
59 | int n = _inStream.read ();
60 |
61 | if (n < 0)
62 | throw new IOException ();
63 | else
64 | return n;
65 | }
66 |
67 | /**
68 | * Read bytes from the input stream.
69 | *
70 | * @param ba The array to store the bytes to.
71 | * @param offset The start position in the array to store the bytes.
72 | * @param length The maximum number of bytes to store.
73 | * @throws IOException
74 | */
75 | public void
76 | readBytes (
77 | byte[] ba,
78 | int offset,
79 | int length
80 | ) throws IOException {
81 | while (length > 0) {
82 | int n = _inStream.read (ba, offset, length);
83 |
84 | if (n < 0) {
85 | throw new IOException ();
86 | } else {
87 | length -= n;
88 | offset += n;
89 | }
90 | }
91 | }
92 |
93 | /**
94 | * Read bits from the input stream as an array of booleans.
95 | *
96 | * @param bits The array to store the bits to.
97 | * @param offset The start position in the array to store the bits.
98 | * @param length The maximum number of bits to store.
99 | * @throws IOException
100 | */
101 | public void
102 | readBits (
103 | boolean[] bits,
104 | int offset,
105 | int length
106 | ) throws IOException {
107 | for (int i = 0; i < length; i += 8) {
108 | int x = readByte ();
109 | int n = length - i;
110 |
111 | if (n > 8)
112 | n = 8;
113 |
114 | for (int j = 0; j < n; j++)
115 | bits[offset + i + j] = ((x & (1 << j)) != 0);
116 | }
117 | }
118 |
119 | /**
120 | * Read a shape mask from the input stream as an array of booleans.
121 | *
122 | * @param bits The array to store the mask to.
123 | * @param width Width of the pixmap.
124 | * @param height Height of the pixmap.
125 | * @throws IOException
126 | */
127 | public void
128 | readShapeMask (
129 | boolean[] bits,
130 | int width,
131 | int height
132 | ) throws IOException {
133 | int count = 0;
134 | int bytesPerRow = (width + 1) / 2;
135 |
136 | for (int row = 0; row < height; row++) {
137 | int col = 0;
138 |
139 | for (int i = 0; i < bytesPerRow; i++) {
140 | int b = readByte ();
141 | int mask = 0x80;
142 |
143 | for (int j = 0; j < 8; j++) {
144 | bits[count++] = ((b & mask) != 0);
145 | mask >>= 1;
146 |
147 | if (++col == width)
148 | break;
149 | }
150 |
151 | if (col == width) {
152 | readSkip (bytesPerRow - i - 1);
153 | break;
154 | }
155 | }
156 | }
157 | }
158 |
159 | /**
160 | * Read a 16-bit integer from the output stream.
161 | *
162 | * @return A 16-bit integer in the range 0 to 65535.
163 | * @throws IOException
164 | */
165 | public int
166 | readShort () throws IOException {
167 | if (_msb) {
168 | int n = readByte ();
169 |
170 | return (n << 8) | readByte ();
171 | } else {
172 | int n = readByte ();
173 |
174 | return n | (readByte () << 8);
175 | }
176 | }
177 |
178 | /**
179 | * Read a 32-bit integer from the input stream.
180 | *
181 | * @return A 32-bit signed integer.
182 | * @throws IOException
183 | */
184 | public int
185 | readInt () throws IOException {
186 | int n = readByte ();
187 |
188 | if (_msb) {
189 | n = (n << 8) | readByte ();
190 | n = (n << 8) | readByte ();
191 | n = (n << 8) | readByte ();
192 | } else {
193 | n |= readByte () << 8;
194 | n |= readByte () << 16;
195 | n |= readByte () << 24;
196 | }
197 |
198 | return n;
199 | }
200 |
201 | /**
202 | * Read a 64-bit integer from the input stream.
203 | *
204 | * @return A 64-bit signed integer.
205 | * @throws IOException
206 | */
207 | public long
208 | readLong () throws IOException {
209 | long n = readByte ();
210 |
211 | if (_msb) {
212 | n = (n << 8) | readByte ();
213 | n = (n << 8) | readByte ();
214 | n = (n << 8) | readByte ();
215 | n = (n << 8) | readByte ();
216 | n = (n << 8) | readByte ();
217 | n = (n << 8) | readByte ();
218 | n = (n << 8) | readByte ();
219 | } else {
220 | n |= readByte () << 8;
221 | n |= readByte () << 16;
222 | n |= readByte () << 24;
223 | n |= readByte () << 32;
224 | n |= readByte () << 40;
225 | n |= readByte () << 48;
226 | n |= readByte () << 56;
227 | }
228 |
229 | return n;
230 | }
231 |
232 | /**
233 | * Skip bytes from the input stream.
234 | *
235 | * @param n The number of bytes to skip.
236 | * @throws IOException
237 | */
238 | public void
239 | readSkip (
240 | int n
241 | ) throws IOException {
242 | while (n > 0)
243 | n -= _inStream.skip (n);
244 | }
245 |
246 | /**
247 | * Write an 8-bit integer to the output stream.
248 | *
249 | * @param n The byte to write.
250 | * @throws IOException
251 | */
252 | public void
253 | writeByte (
254 | byte n
255 | ) throws IOException {
256 | _outStream.write (n);
257 | }
258 |
259 | /**
260 | * Write bytes to the output stream.
261 | *
262 | * @param ba The array to be written.
263 | * @param offset The start position in the array to write from.
264 | * @param length The number of bytes to write.
265 | * @throws IOException
266 | */
267 | public void
268 | writeBytes (
269 | byte[] ba,
270 | int offset,
271 | int length
272 | ) throws IOException {
273 | _outStream.write (ba, offset, length);
274 | }
275 |
276 | /**
277 | * Write a 16-bit integer to the output stream.
278 | *
279 | * @param n The short to write.
280 | * @throws IOException
281 | */
282 | public void
283 | writeShort (
284 | short n
285 | ) throws IOException {
286 | if (_msb) {
287 | _outStream.write ((byte) ((n >> 8) & 0xff));
288 | _outStream.write ((byte) (n & 0xff));
289 | } else {
290 | _outStream.write ((byte) (n & 0xff));
291 | _outStream.write ((byte) ((n >> 8) & 0xff));
292 | }
293 | }
294 |
295 | /**
296 | * Write a 32-bit integer to the output stream.
297 | *
298 | * @param n The integer to write.
299 | * @throws IOException
300 | */
301 | public void
302 | writeInt (
303 | int n
304 | ) throws IOException {
305 | if (_msb) {
306 | _outStream.write ((byte) ((n >> 24) & 0xff));
307 | _outStream.write ((byte) ((n >> 16) & 0xff));
308 | _outStream.write ((byte) ((n >> 8) & 0xff));
309 | _outStream.write ((byte) (n & 0xff));
310 | } else {
311 | _outStream.write ((byte) ((n) & 0xff));
312 | _outStream.write ((byte) ((n >> 8) & 0xff));
313 | _outStream.write ((byte) ((n >> 16) & 0xff));
314 | _outStream.write ((byte) ((n >> 24) & 0xff));
315 | }
316 | }
317 |
318 | /**
319 | * Write a 64-bit integer to the output stream.
320 | *
321 | * @param n The integer to write.
322 | * @throws IOException
323 | */
324 | public void
325 | writeLong (
326 | long n
327 | ) throws IOException{
328 | if (_msb) {
329 | _outStream.write ((byte) ((n >> 56) & 0xff));
330 | _outStream.write ((byte) ((n >> 48) & 0xff));
331 | _outStream.write ((byte) ((n >> 40) & 0xff));
332 | _outStream.write ((byte) ((n >> 32) & 0xff));
333 | _outStream.write ((byte) ((n >> 24) & 0xff));
334 | _outStream.write ((byte) ((n >> 16) & 0xff));
335 | _outStream.write ((byte) ((n >> 8) & 0xff));
336 | _outStream.write ((byte) (n & 0xff));
337 | } else {
338 | _outStream.write ((byte) ((n) & 0xff));
339 | _outStream.write ((byte) ((n >> 8) & 0xff));
340 | _outStream.write ((byte) ((n >> 16) & 0xff));
341 | _outStream.write ((byte) ((n >> 24) & 0xff));
342 | _outStream.write ((byte) ((n >> 32) & 0xff));
343 | _outStream.write ((byte) ((n >> 40) & 0xff));
344 | _outStream.write ((byte) ((n >> 48) & 0xff));
345 | _outStream.write ((byte) ((n >> 56) & 0xff));
346 | }
347 | }
348 |
349 | /**
350 | * Write padding byte 0 to the output stream multiple times.
351 | *
352 | * @param n The number of bytes to write.
353 | * @throws IOException
354 | */
355 | public void
356 | writePadBytes (
357 | int n
358 | ) throws IOException {
359 | final int max = PadBytes.length;
360 |
361 | while (n > max) {
362 | _outStream.write (PadBytes, 0, max);
363 | n -= max;
364 | }
365 |
366 | if (n > 0)
367 | _outStream.write (PadBytes, 0, n);
368 | }
369 |
370 | /**
371 | * Flush all unwritten output bytes.
372 | *
373 | * @throws IOException
374 | */
375 | public void
376 | flush () throws IOException {
377 | _outStream.flush ();
378 | }
379 |
380 | /**
381 | * Close the input and output streams.
382 | *
383 | * @throws IOException
384 | */
385 | public void
386 | close () throws IOException {
387 | _inStream.close ();
388 | _outStream.close ();
389 | }
390 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Keyboard.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class handles an X keyboard.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 | import android.media.AudioFormat;
9 | import android.media.AudioManager;
10 | import android.media.AudioTrack;
11 | import android.view.KeyCharacterMap;
12 | import android.view.KeyEvent;
13 |
14 | /**
15 | * @author Matthew Kwan
16 | *
17 | * This class handles an X keyboard.
18 | */
19 | public class Keyboard {
20 | private int _minimumKeycode;
21 | private int _numKeycodes;
22 | private byte _keysymsPerKeycode = 3;
23 | private int[] _keyboardMapping = null;
24 | private byte _keycodesPerModifier = 2;
25 | private byte[] _keymap = new byte[32];
26 | private byte[] _modifierMapping = new byte[] {
27 | KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SHIFT_RIGHT,
28 | 0, 0, 0, 0,
29 | KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_SHIFT_RIGHT,
30 | 0, 0, 0, 0, 0, 0, 0, 0
31 | };
32 |
33 | private static final int DefaultBellPercent = 50;
34 | private int _bellPercent = DefaultBellPercent;
35 | private static final int DefaultBellPitch = 400;
36 | private int _bellPitch = DefaultBellPitch;
37 | private static final int DefaultBellDuration = 100;
38 | private int _bellDuration = DefaultBellDuration;
39 | private short[] _bellBuffer = null;
40 | private boolean _bellBufferFilled = false;
41 | private AudioTrack _audioTrack = null;
42 |
43 | private static final int SAMPLE_RATE = 11025;
44 | private static final int AttrKeyClickPercent = 0;
45 | private static final int AttrBellPercent = 1;
46 | private static final int AttrBellPitch = 2;
47 | private static final int AttrBellDuration = 3;
48 | private static final int AttrLed = 4;
49 | private static final int AttrLedMode = 5;
50 | private static final int AttrKey = 6;
51 | private static final int AttrAutoRepeatMode = 7;
52 |
53 | /**
54 | * Constructor.
55 | */
56 | Keyboard () {
57 | final byte kpk = _keysymsPerKeycode;
58 | int min = 255;
59 | int max = 0;
60 | int idx = 0;
61 | int[] map = new int[256 * kpk];
62 | KeyCharacterMap kcm = KeyCharacterMap.load (
63 | KeyCharacterMap.BUILT_IN_KEYBOARD);
64 |
65 | for (int i = 0; i < 256; i++) {
66 | int c1 = kcm.get (i, 0);
67 | int c2 = kcm.get (i, KeyEvent.META_SHIFT_ON);
68 | int c3 = kcm.get (i, KeyEvent.META_ALT_ON);
69 |
70 | map[idx++] = c1;
71 | map[idx++] = c2;
72 | map[idx++] = c3;
73 |
74 | if (c1 != 0 || c2 != 0 || c3 != 0) {
75 | if (i < min)
76 | min = i;
77 | if (i > max)
78 | max = i;
79 | }
80 | }
81 |
82 | if (max == 0)
83 | min = 0;
84 |
85 | if (max < KeyEvent.KEYCODE_DEL)
86 | max = KeyEvent.KEYCODE_DEL;
87 |
88 | _minimumKeycode = min;
89 | _numKeycodes = max - min + 1;
90 | if (_numKeycodes > 248)
91 | _numKeycodes = 248;
92 |
93 | _keyboardMapping = new int[kpk * _numKeycodes];
94 | System.arraycopy (map, min * kpk, _keyboardMapping, 0,
95 | _keyboardMapping.length);
96 |
97 | _keyboardMapping[(KeyEvent.KEYCODE_DEL - min) * kpk] = 127;
98 | _keyboardMapping[(KeyEvent.KEYCODE_ALT_LEFT - min) * kpk] = 0xff7e;
99 | _keyboardMapping[(KeyEvent.KEYCODE_ALT_RIGHT - min) * kpk] = 0xff7e;
100 | }
101 |
102 | /**
103 | * Translate an Android keycode to an X keycode.
104 | *
105 | * @param keycode The Android keycode.
106 | * @return The corresponding X keycode.
107 | */
108 | public int
109 | translateToXKeycode (
110 | int keycode
111 | ) {
112 | if (_minimumKeycode < 8)
113 | return keycode + 8 - _minimumKeycode;
114 | else
115 | return keycode;
116 | }
117 |
118 | /**
119 | * Return the minimum keycode.
120 | *
121 | * @return The minimum keycode.
122 | */
123 | public int
124 | getMinimumKeycode () {
125 | if (_minimumKeycode < 8)
126 | return 8;
127 | else
128 | return _minimumKeycode;
129 | }
130 |
131 | /**
132 | * Return the minimum keycode diff.
133 | *
134 | * @return The minimum keycode.
135 | */
136 | private int
137 | getMinimumKeycodeDiff () {
138 | if (_minimumKeycode < 8)
139 | return 8 - _minimumKeycode;
140 | else
141 | return 0;
142 | }
143 |
144 | /**
145 | * Return the maximum keycode.
146 | *
147 | * @return The maximum keycode.
148 | */
149 | public int
150 | getMaximumKeycode () {
151 | return getMinimumKeycode () + _numKeycodes - 1;
152 | }
153 |
154 | /**
155 | * Return the keymap for keycodes 8-255.
156 | *
157 | * @return The keymap for keycodes 8-255.
158 | */
159 | public byte[]
160 | getKeymap () {
161 | byte[] keymap = new byte[31];
162 |
163 | System.arraycopy (_keymap, 1, keymap, 0, 31);
164 |
165 | return keymap;
166 | }
167 |
168 | /**
169 | * Update the keymap when a key is pressed or released.
170 | *
171 | * @param keycode The keycode of the key.
172 | * @param pressed True if pressed, false if released.
173 | */
174 | public void
175 | updateKeymap (
176 | int keycode,
177 | boolean pressed
178 | ) {
179 | if (keycode < 0 || keycode > 255)
180 | return;
181 |
182 | int offset = keycode / 8;
183 | byte mask = (byte) (1 << (keycode & 7));
184 |
185 | if (pressed)
186 | _keymap[offset] |= mask;
187 | else
188 | _keymap[offset] &= ~mask;
189 | }
190 |
191 | /**
192 | * Process an X request relating to this keyboard.
193 | *
194 | * @param xServer The X server.
195 | * @param client The remote client.
196 | * @param opcode The request's opcode.
197 | * @param arg Optional first argument.
198 | * @param bytesRemaining Bytes yet to be read in the request.
199 | * @throws IOException
200 | */
201 | public void
202 | processRequest (
203 | XServer xServer,
204 | Client client,
205 | byte opcode,
206 | byte arg,
207 | int bytesRemaining
208 | ) throws IOException {
209 | InputOutput io = client.getInputOutput ();
210 |
211 | switch (opcode) {
212 | case RequestCode.QueryKeymap:
213 | if (bytesRemaining != 0) {
214 | io.readSkip (bytesRemaining);
215 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
216 | } else {
217 | synchronized (io) {
218 | Util.writeReplyHeader (client, (byte) 0);
219 | io.writeInt (2); // Reply length.
220 | io.writeBytes (_keymap, 0, 32); // Keys.
221 | }
222 | io.flush ();
223 | }
224 | break;
225 | case RequestCode.ChangeKeyboardMapping:
226 | if (bytesRemaining < 4) {
227 | io.readSkip (bytesRemaining);
228 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
229 | } else {
230 | byte keycodeCount = arg;
231 | byte keycode = (byte) io.readByte (); // First code.
232 | byte kspkc = (byte) io.readByte (); // Keysyms per code.
233 |
234 | io.readSkip (2); // Unused.
235 | bytesRemaining -= 4;
236 |
237 | if (bytesRemaining != keycodeCount * kspkc * 4) {
238 | io.readSkip (bytesRemaining);
239 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
240 | } else {
241 | _minimumKeycode = keycode;
242 | _numKeycodes = keycodeCount;
243 | _keysymsPerKeycode = kspkc;
244 | _keyboardMapping = new int[keycodeCount * kspkc];
245 | for (int i = 0; i < _keyboardMapping.length; i++)
246 | _keyboardMapping[i] = io.readInt (); // Keysyms.
247 |
248 | xServer.sendMappingNotify (1, keycode, keycodeCount);
249 | }
250 | }
251 | break;
252 | case RequestCode.GetKeyboardMapping:
253 | if (bytesRemaining != 4) {
254 | io.readSkip (bytesRemaining);
255 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
256 | } else {
257 | int keycode = io.readByte (); // First code.
258 | int count = io.readByte (); // Count.
259 | int length = count * _keysymsPerKeycode;
260 | int offset = (keycode - getMinimumKeycode ())
261 | * _keysymsPerKeycode;
262 |
263 | io.readSkip (2); // Unused.
264 |
265 | synchronized (io) {
266 | Util.writeReplyHeader (client , _keysymsPerKeycode);
267 | io.writeInt (length); // Reply length.
268 | io.writePadBytes (24); // Unused.
269 |
270 | for (int i = 0; i < length; i++) {
271 | int n = i + offset;
272 |
273 | if (n < 0 || n >= _keyboardMapping.length)
274 | io.writeInt (0); // No symbol.
275 | else
276 | io.writeInt (_keyboardMapping[n]);
277 | }
278 | }
279 | io.flush ();
280 | }
281 | break;
282 | case RequestCode.ChangeKeyboardControl:
283 | if (bytesRemaining < 4) {
284 | io.readSkip (bytesRemaining);
285 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
286 | } else {
287 | int valueMask = io.readInt (); // Value mask.
288 | int nbits = Util.bitcount (valueMask);
289 |
290 | bytesRemaining -= 4;
291 | if (bytesRemaining != nbits * 4) {
292 | io.readSkip (bytesRemaining);
293 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
294 | } else {
295 | for (int i = 0; i < 23; i++)
296 | if ((valueMask & (1 << i)) != 0)
297 | processValue (io, i);
298 | }
299 | }
300 | break;
301 | case RequestCode.GetKeyboardControl:
302 | if (bytesRemaining != 0) {
303 | io.readSkip (bytesRemaining);
304 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
305 | } else {
306 | synchronized (io) {
307 | Util.writeReplyHeader (client, _keysymsPerKeycode);
308 | io.writeInt (5); // Reply length.
309 | io.writeInt (0); // LED mask.
310 | io.writeByte ((byte) 0); // Key click percent.
311 | io.writeByte ((byte) _bellPercent); // Bell volume.
312 | io.writeShort ((short) _bellPitch); // Bell pitch Hz.
313 | io.writeShort ((short) _bellDuration);
314 | io.writePadBytes (2); // Unused.
315 | io.writePadBytes (32); // Auto repeats. Ignored.
316 | }
317 | io.flush ();
318 | }
319 | break;
320 | case RequestCode.SetModifierMapping:
321 | if (bytesRemaining != 8 * arg) {
322 | io.readSkip (bytesRemaining);
323 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
324 | } else { // Not supported. Always fails.
325 | io.readSkip (bytesRemaining);
326 | synchronized (io) {
327 | Util.writeReplyHeader (client, (byte) 2);
328 | io.writeInt (0); // Reply length.
329 | io.writePadBytes (24); // Unused.
330 | }
331 | io.flush ();
332 | }
333 | break;
334 | case RequestCode.GetModifierMapping:
335 | if (bytesRemaining != 0) {
336 | io.readSkip (bytesRemaining);
337 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
338 | } else {
339 | final byte kpm = _keycodesPerModifier;
340 | byte[] map = null;
341 |
342 | if (kpm > 0) {
343 | int diff = getMinimumKeycodeDiff ();
344 |
345 | map = new byte[kpm * 8];
346 | for (int i = 0; i < map.length; i++)
347 | if (_modifierMapping[i] == 0)
348 | map[i] = 0;
349 | else
350 | map[i] = (byte) (_modifierMapping[i] + diff);
351 | }
352 |
353 | synchronized (io) {
354 | Util.writeReplyHeader (client, kpm);
355 | io.writeInt (kpm * 2); // Reply length.
356 | io.writePadBytes (24); // Unused.
357 |
358 | if (map != null)
359 | io.writeBytes (map, 0, map.length);
360 | }
361 | io.flush ();
362 | }
363 | break;
364 | case RequestCode.Bell:
365 | if (bytesRemaining != 0) {
366 | io.readSkip (bytesRemaining);
367 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
368 | } else {
369 | playBell ((byte) arg);
370 | }
371 | break;
372 | default:
373 | io.readSkip (bytesRemaining);
374 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
375 | break;
376 | }
377 | }
378 |
379 | /**
380 | * Play a beep.
381 | *
382 | * @param percent Volume relative to base volume, [-100, 100]
383 | */
384 | private void
385 | playBell (
386 | int percent
387 | ) {
388 | int volume;
389 |
390 | if (percent < 0) {
391 | volume = _bellPercent + _bellPercent * percent / 100;
392 | _bellBufferFilled = false;
393 | } else if (percent > 0){
394 | volume = _bellPercent - _bellPercent * percent / 100 + percent;
395 | _bellBufferFilled = false;
396 | } else {
397 | volume = _bellPercent;
398 | }
399 |
400 | if (_bellBuffer == null) {
401 | _bellBuffer = new short[SAMPLE_RATE * _bellDuration / 1000];
402 | _bellBufferFilled = false;
403 |
404 | }
405 |
406 | if (!_bellBufferFilled) {
407 | double vol = 32767.0 * (double) volume / 100.0;
408 | double dt = _bellPitch * 2.0 * Math.PI / SAMPLE_RATE;
409 |
410 | for (int i = 0; i < _bellBuffer.length; i++)
411 | _bellBuffer[i] = (short) (vol * Math.sin ((double) i * dt));
412 |
413 | _bellBufferFilled = true;
414 | }
415 |
416 | if (_audioTrack != null) {
417 | _audioTrack.stop ();
418 | _audioTrack.release ();
419 | }
420 |
421 | _audioTrack = new AudioTrack (AudioManager.STREAM_SYSTEM,
422 | SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO,
423 | AudioFormat.ENCODING_PCM_16BIT, 2 * _bellBuffer.length,
424 | AudioTrack.MODE_STATIC);
425 |
426 | _audioTrack.write (_bellBuffer, 0, _bellBuffer.length);
427 | _audioTrack.play ();
428 | }
429 |
430 | /**
431 | * Process a single keyboard attribute value.
432 | *
433 | * @param io The input/output stream.
434 | * @param maskBit The mask bit of the attribute.
435 | * @throws IOException
436 | */
437 | private void
438 | processValue (
439 | InputOutput io,
440 | int maskBit
441 | ) throws IOException {
442 | switch (maskBit) {
443 | case AttrKeyClickPercent:
444 | io.readByte (); // Not implemented.
445 | io.readSkip (3);
446 | break;
447 | case AttrBellPercent:
448 | _bellPercent = (byte) io.readByte ();
449 | if (_bellPercent < 0)
450 | _bellPercent = DefaultBellPercent;
451 | io.readSkip (3);
452 | _bellBufferFilled = false;
453 | break;
454 | case AttrBellPitch:
455 | _bellPitch = (short) io.readShort ();
456 | if (_bellPitch < 0)
457 | _bellPitch = DefaultBellPitch;
458 | io.readSkip (2);
459 | _bellBufferFilled = false;
460 | break;
461 | case AttrBellDuration:
462 | _bellDuration = (short) io.readShort ();
463 | if (_bellDuration < 0)
464 | _bellDuration = DefaultBellDuration;
465 | io.readSkip (2);
466 | _bellBuffer = null;
467 | break;
468 | case AttrLed:
469 | io.readByte (); // Not implemented.
470 | io.readSkip (3);
471 | break;
472 | case AttrLedMode:
473 | io.readByte (); // Not implemented.
474 | io.readSkip (3);
475 | break;
476 | case AttrKey:
477 | io.readByte (); // Not implemented.
478 | io.readSkip (3);
479 | break;
480 | case AttrAutoRepeatMode:
481 | io.readByte (); // Not implemented.
482 | io.readSkip (3);
483 | break;
484 | }
485 | }
486 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/PassiveButtonGrab.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class records details of a passive button grab.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | /**
7 | * @author Matthew Kwan
8 | *
9 | * This class records details of a passive button grab.
10 | */
11 | public class PassiveButtonGrab {
12 | private final Client _grabClient;
13 | private final Window _grabWindow;
14 | private final byte _button;
15 | private final int _modifiers;
16 | private final boolean _ownerEvents;
17 | private final int _eventMask;
18 | private final boolean _pointerSynchronous;
19 | private final boolean _keyboardSynchronous;
20 | private final Window _confineWindow;
21 | private final Cursor _cursor;
22 |
23 | /**
24 | * Constructor.
25 | *
26 | * @param grabClient The grabbing client.
27 | * @param grabWindow The grab window.
28 | * @param button The button being grabbed, or 0 for any.
29 | * @param modifiers The modifier mask, or 0x8000 for any.
30 | * @param ownerEvents Owner-events flag.
31 | * @param eventMask Selected pointer events.
32 | * @param pointerSynchronous Are pointer events synchronous?
33 | * @param keyboardSynchronous Are keyboard events synchronous?
34 | * @param confineWindow Confine the cursor to this window. Can be null.
35 | * @param cursor The cursor to use during the grab. Can be null.
36 | */
37 | public PassiveButtonGrab (
38 | Client grabClient,
39 | Window grabWindow,
40 | byte button,
41 | int modifiers,
42 | boolean ownerEvents,
43 | int eventMask,
44 | boolean pointerSynchronous,
45 | boolean keyboardSynchronous,
46 | Window confineWindow,
47 | Cursor cursor
48 | ) {
49 | _grabClient = grabClient;
50 | _grabWindow = grabWindow;
51 | _button = button;
52 | _modifiers = modifiers;
53 | _ownerEvents = ownerEvents;
54 | _eventMask = eventMask;
55 | _pointerSynchronous = pointerSynchronous;
56 | _keyboardSynchronous = keyboardSynchronous;
57 | _confineWindow = confineWindow;
58 | _cursor = cursor;
59 | }
60 |
61 | /**
62 | * Does the event trigger the passive grab?
63 | *
64 | * @param button Currently-pressed buttons and modifiers.
65 | * @return True if the event matches.
66 | */
67 | public boolean
68 | matchesEvent (
69 | int buttons
70 | ) {
71 | if (_button != 0 && (buttons & 0xff00) != (0x80 << _button))
72 | return false;
73 |
74 | if (_modifiers != 0x8000 && (buttons & 0xff) != _modifiers)
75 | return false;
76 |
77 | return true;
78 | }
79 |
80 | /**
81 | * Does this match the parameters of the grab?
82 | *
83 | * @param button The button being grabbed, or 0 for any.
84 | * @param modifiers The modifier mask, or 0x8000 for any.
85 | * @return True if it matches the parameters.
86 | */
87 | public boolean
88 | matchesGrab (
89 | int button,
90 | int modifiers
91 | ) {
92 | if (button != 0 && _button != 0 && button != _button)
93 | return false;
94 |
95 | if (modifiers != 0x8000 && _modifiers != 0x8000
96 | && modifiers != _modifiers)
97 | return false;
98 |
99 | return true;
100 | }
101 |
102 | /**
103 | * Return the button.
104 | *
105 | * @return The button.
106 | */
107 | public byte
108 | getButton () {
109 | return _button;
110 | }
111 |
112 | /**
113 | * Return the modifier mask.
114 | *
115 | * @return The modifier mask.
116 | */
117 | public int
118 | getModifiers () {
119 | return _modifiers;
120 | }
121 |
122 | /**
123 | * Return the grab client.
124 | *
125 | * @return The grab client.
126 | */
127 | public Client
128 | getGrabClient () {
129 | return _grabClient;
130 | }
131 |
132 | /**
133 | * Return the grab window.
134 | *
135 | * @return The grab window.
136 | */
137 | public Window
138 | getGrabWindow () {
139 | return _grabWindow;
140 | }
141 |
142 | /**
143 | * Return the owner-events flag.
144 | *
145 | * @return The owner-events flag.
146 | */
147 | public boolean
148 | getOwnerEvents () {
149 | return _ownerEvents;
150 | }
151 |
152 | /**
153 | * Return the pointer events mask.
154 | *
155 | * @return The pointer events mask.
156 | */
157 | public int
158 | getEventMask () {
159 | return _eventMask;
160 | }
161 |
162 | /**
163 | * Return whether pointer events are synchronous.
164 | *
165 | * @return Whether pointer events are synchronous.
166 | */
167 | public boolean
168 | getPointerSynchronous () {
169 | return _pointerSynchronous;
170 | }
171 |
172 | /**
173 | * Return whether pointer events are synchronous.
174 | *
175 | * @return Whether pointer events are synchronous.
176 | */
177 | public boolean
178 | getKeyboardSynchronous () {
179 | return _keyboardSynchronous;
180 | }
181 |
182 | /**
183 | * Return the confine window.
184 | *
185 | * @return The confine window.
186 | */
187 | public Window
188 | getConfineWindow () {
189 | return _confineWindow;
190 | }
191 |
192 | /**
193 | * Return the cursor.
194 | *
195 | * @return The cursor.
196 | */
197 | public Cursor
198 | getCursor () {
199 | return _cursor;
200 | }
201 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/PassiveKeyGrab.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class records details of a passive key grab.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | /**
7 | * @author Matthew Kwan
8 | *
9 | * This class records details of a passive key grab.
10 | */
11 | public class PassiveKeyGrab {
12 | private final Client _grabClient;
13 | private final Window _grabWindow;
14 | private final byte _key;
15 | private final int _modifiers;
16 | private final boolean _ownerEvents;
17 | private final boolean _pointerSynchronous;
18 | private final boolean _keyboardSynchronous;
19 |
20 | /**
21 | * Constructor.
22 | *
23 | * @param grabClient The grabbing client.
24 | * @param grabWindow The grab window.
25 | * @param key The key being grabbed, or 0 for any.
26 | * @param modifiers The modifier mask, or 0x8000 for any.
27 | * @param ownerEvents Owner-events flag.
28 | * @param pointerSynchronous Are pointer events synchronous?
29 | * @param keyboardSynchronous Are keyboard events synchronous?
30 | */
31 | public PassiveKeyGrab (
32 | Client grabClient,
33 | Window grabWindow,
34 | byte key,
35 | int modifiers,
36 | boolean ownerEvents,
37 | boolean pointerSynchronous,
38 | boolean keyboardSynchronous
39 | ) {
40 | _grabClient = grabClient;
41 | _grabWindow = grabWindow;
42 | _key = key;
43 | _modifiers = modifiers;
44 | _ownerEvents = ownerEvents;
45 | _pointerSynchronous = pointerSynchronous;
46 | _keyboardSynchronous = keyboardSynchronous;
47 | }
48 |
49 | /**
50 | * Does the event trigger the passive grab?
51 | *
52 | * @param key The key that was pressed.
53 | * @param modifiers The current state of the modifiers.
54 | * @return True if the event matches.
55 | */
56 | public boolean
57 | matchesEvent (
58 | int key,
59 | int modifiers
60 | ) {
61 | if (_key != 0 && _key != key)
62 | return false;
63 |
64 | if (_modifiers != 0x8000 && _modifiers != modifiers)
65 | return false;
66 |
67 | return true;
68 | }
69 |
70 | /**
71 | * Does this match the parameters of the grab?
72 | *
73 | * @param key The key being grabbed, or 0 for any.
74 | * @param modifiers The modifier mask, or 0x8000 for any.
75 | * @return True if it matches the parameters.
76 | */
77 | public boolean
78 | matchesGrab (
79 | int key,
80 | int modifiers
81 | ) {
82 | if (key != 0 && _key != 0 && key != _key)
83 | return false;
84 |
85 | if (modifiers != 0x8000 && _modifiers != 0x8000
86 | && modifiers != _modifiers)
87 | return false;
88 |
89 | return true;
90 | }
91 |
92 | /**
93 | * Return the key code.
94 | *
95 | * @return The key code.
96 | */
97 | public byte
98 | getKey () {
99 | return _key;
100 | }
101 |
102 | /**
103 | * Return the modifier mask.
104 | *
105 | * @return The modifier mask.
106 | */
107 | public int
108 | getModifiers () {
109 | return _modifiers;
110 | }
111 |
112 | /**
113 | * Return the grab client.
114 | *
115 | * @return The grab client.
116 | */
117 | public Client
118 | getGrabClient () {
119 | return _grabClient;
120 | }
121 |
122 | /**
123 | * Return the grab window.
124 | *
125 | * @return The grab window.
126 | */
127 | public Window
128 | getGrabWindow () {
129 | return _grabWindow;
130 | }
131 |
132 | /**
133 | * Return the owner-events flag.
134 | *
135 | * @return The owner-events flag.
136 | */
137 | public boolean
138 | getOwnerEvents () {
139 | return _ownerEvents;
140 | }
141 |
142 | /**
143 | * Return whether pointer events are synchronous.
144 | *
145 | * @return Whether pointer events are synchronous.
146 | */
147 | public boolean
148 | getPointerSynchronous () {
149 | return _pointerSynchronous;
150 | }
151 |
152 | /**
153 | * Return whether pointer events are synchronous.
154 | *
155 | * @return Whether pointer events are synchronous.
156 | */
157 | public boolean
158 | getKeyboardSynchronous () {
159 | return _keyboardSynchronous;
160 | }
161 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Pixmap.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class implements an X pixmap.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 |
9 | /**
10 | * @author Matthew Kwan
11 | *
12 | * This class implements an X pixmap.
13 | */
14 | public class Pixmap extends Resource {
15 | private final Drawable _drawable;
16 | public final ScreenView _screen;
17 |
18 | /**
19 | * Constructor.
20 | *
21 | * @param id The pixmap's ID.
22 | * @param xServer The X server.
23 | * @param client The client issuing the request.
24 | * @param screen The screen.
25 | * @param width The pixmap width.
26 | * @param height The pixmap height.
27 | * @param depth The pixmap depth.
28 | */
29 | public Pixmap (
30 | int id,
31 | XServer xServer,
32 | Client client,
33 | ScreenView screen,
34 | int width,
35 | int height,
36 | int depth
37 | ) {
38 | super (PIXMAP, id, xServer, client);
39 |
40 | _drawable = new Drawable (width, height, depth, null, 0xff000000);
41 | _screen = screen;
42 | }
43 |
44 | /**
45 | * Return the pixmap's screen.
46 | *
47 | * @return The pixmap's screen.
48 | */
49 | public ScreenView
50 | getScreen () {
51 | return _screen;
52 | }
53 |
54 | /**
55 | * Return the pixmap's drawable.
56 | *
57 | * @return The pixmap's drawable.
58 | */
59 | public Drawable
60 | getDrawable () {
61 | return _drawable;
62 | }
63 |
64 | /**
65 | * Return the pixmap's depth.
66 | *
67 | * @return The pixmap's depth.
68 | */
69 | public int
70 | getDepth () {
71 | return _drawable.getDepth ();
72 | }
73 |
74 | /**
75 | * Process an X request relating to this pixmap.
76 | *
77 | * @param client The remote client.
78 | * @param opcode The request's opcode.
79 | * @param arg Optional first argument.
80 | * @param bytesRemaining Bytes yet to be read in the request.
81 | * @throws IOException
82 | */
83 | @Override
84 | public void
85 | processRequest (
86 | Client client,
87 | byte opcode,
88 | byte arg,
89 | int bytesRemaining
90 | ) throws IOException {
91 | InputOutput io = client.getInputOutput ();
92 |
93 | switch (opcode) {
94 | case RequestCode.FreePixmap:
95 | if (bytesRemaining != 0) {
96 | io.readSkip (bytesRemaining);
97 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
98 | } else {
99 | _xServer.freeResource (_id);
100 | if (_client != null)
101 | _client.freeResource (this);
102 | _drawable.getBitmap().recycle ();
103 | }
104 | break;
105 | case RequestCode.GetGeometry:
106 | if (bytesRemaining != 0) {
107 | io.readSkip (bytesRemaining);
108 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
109 | } else {
110 | writeGeometry (client);
111 | }
112 | break;
113 | case RequestCode.CopyArea:
114 | case RequestCode.CopyPlane:
115 | case RequestCode.PolyPoint:
116 | case RequestCode.PolyLine:
117 | case RequestCode.PolySegment:
118 | case RequestCode.PolyRectangle:
119 | case RequestCode.PolyArc:
120 | case RequestCode.FillPoly:
121 | case RequestCode.PolyFillRectangle:
122 | case RequestCode.PolyFillArc:
123 | case RequestCode.PutImage:
124 | case RequestCode.GetImage:
125 | case RequestCode.PolyText8:
126 | case RequestCode.PolyText16:
127 | case RequestCode.ImageText8:
128 | case RequestCode.ImageText16:
129 | case RequestCode.QueryBestSize:
130 | _drawable.processRequest (_xServer, client, _id, opcode, arg,
131 | bytesRemaining);
132 | return;
133 | default:
134 | io.readSkip (bytesRemaining);
135 | bytesRemaining = 0;
136 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
137 | break;
138 | }
139 | }
140 |
141 | /**
142 | * Write details of the pixmap's geometry in response to a GetGeometry
143 | * request.
144 | *
145 | * @param client The remote client.
146 | * @throws IOException
147 | */
148 | private void
149 | writeGeometry (
150 | Client client
151 | ) throws IOException {
152 | InputOutput io = client.getInputOutput ();
153 |
154 | synchronized (io) {
155 | Util.writeReplyHeader (client, (byte) 32);
156 | io.writeInt (0); // Reply length.
157 | io.writeInt (_screen.getRootWindow().getId ()); // Root window.
158 | io.writeShort ((short) 0); // X.
159 | io.writeShort ((short) 0); // Y.
160 | io.writeShort ((short) _drawable.getWidth ()); // Width.
161 | io.writeShort ((short) _drawable.getHeight ()); // Height.
162 | io.writeShort ((short) 0); // Border width.
163 | io.writePadBytes (10); // Unused.
164 | }
165 | io.flush ();
166 | }
167 |
168 | /**
169 | * Process a CreatePixmap request.
170 | *
171 | * @param xServer The X server.
172 | * @param client The client issuing the request.
173 | * @param id The ID of the pixmap to create.
174 | * @param depth The depth of the pixmap.
175 | * @param drawable The drawable whose depth it must match.
176 | * @throws IOException
177 | */
178 | public static void
179 | processCreatePixmapRequest (
180 | XServer xServer,
181 | Client client,
182 | int id,
183 | int width,
184 | int height,
185 | int depth,
186 | Resource drawable
187 | ) throws IOException {
188 | ScreenView screen;
189 | Pixmap p;
190 |
191 | if (drawable.getType () == Resource.PIXMAP)
192 | screen = ((Pixmap) drawable).getScreen ();
193 | else
194 | screen = ((Window) drawable).getScreen ();
195 |
196 | try {
197 | p = new Pixmap (id, xServer, client, screen, width, height, depth);
198 | } catch (OutOfMemoryError e) {
199 | ErrorCode.write (client, ErrorCode.Alloc,
200 | RequestCode.CreatePixmap, 0);
201 | return;
202 | }
203 |
204 | xServer.addResource (p);
205 | client.addResource (p);
206 | }
207 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Pointer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class handles an X pointer.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 | import android.graphics.Rect;
9 |
10 |
11 | /**
12 | * @author Matthew Kwan
13 | *
14 | * This class handles an X pointer.
15 | */
16 | public class Pointer {
17 | private byte[] _buttonMap = {1, 2, 3};
18 |
19 | /**
20 | * Return the virtual button that a physical button has been mapped to.
21 | * Zero indicates the button has been disabled.
22 | *
23 | * @param button The physical button: 1, 2, or 3.
24 | * @return The virtual button, or 0 for disabled.
25 | */
26 | public int
27 | mapButton (
28 | int button
29 | ) {
30 | if (button < 1 || button > _buttonMap.length)
31 | return 0;
32 |
33 | return _buttonMap[button - 1];
34 | }
35 |
36 | /**
37 | * Process a WarpPointer request.
38 | *
39 | * @param xServer The X server.
40 | * @param client The remote client.
41 | * @throws IOException
42 | */
43 | public void
44 | processWarpPointer (
45 | XServer xServer,
46 | Client client
47 | ) throws IOException {
48 | InputOutput io = client.getInputOutput ();
49 | int swin = io.readInt (); // Source window.
50 | int dwin = io.readInt (); // Destination window.
51 | int sx = io.readShort (); // Source X.
52 | int sy = io.readShort (); // Source Y.
53 | int width = io.readShort (); // Source width.
54 | int height = io.readShort (); // Source height.
55 | int dx = io.readShort (); // Destination X.
56 | int dy = io.readShort (); // Destination Y.
57 | ScreenView screen = xServer.getScreen ();
58 | boolean ok = true;
59 | int x, y;
60 |
61 | if (dwin == 0) {
62 | x = screen.getPointerX () + dx;
63 | y = screen.getPointerY () + dy;
64 | } else {
65 | Resource r = xServer.getResource (dwin);
66 |
67 | if (r == null || r.getType () != Resource.WINDOW) {
68 | ErrorCode.write (client, ErrorCode.Window,
69 | RequestCode.WarpPointer, dwin);
70 | ok = false;
71 | }
72 |
73 | Rect rect = ((Window) r).getIRect ();
74 |
75 | x = rect.left + dx;
76 | y = rect.top + dy;
77 | }
78 |
79 | if (swin != 0) {
80 | Resource r = xServer.getResource (swin);
81 |
82 | if (r == null || r.getType () != Resource.WINDOW) {
83 | ErrorCode.write (client, ErrorCode.Window,
84 | RequestCode.WarpPointer, swin);
85 | ok = false;
86 | } else {
87 | Window w = (Window) r;
88 | Rect rect = w.getIRect ();
89 |
90 | sx += rect.left;
91 | sy += rect.top;
92 |
93 | if (width == 0)
94 | width = rect.right - sx;
95 | if (height == 0)
96 | height = rect.bottom - sy;
97 |
98 | if (x < sx || x >= sx + width || y < sy || y >= sy + height)
99 | ok = false;
100 | }
101 | }
102 |
103 | if (ok)
104 | screen.updatePointerPosition (x, y, 0);
105 | }
106 |
107 | /**
108 | * Process an X request relating to the pointers.
109 | *
110 | * @param xServer The X server.
111 | * @param client The remote client.
112 | * @param opcode The request's opcode.
113 | * @param arg Optional first argument.
114 | * @param bytesRemaining Bytes yet to be read in the request.
115 | * @throws IOException
116 | */
117 | public void
118 | processRequest (
119 | XServer xServer,
120 | Client client,
121 | byte opcode,
122 | byte arg,
123 | int bytesRemaining
124 | ) throws IOException {
125 | InputOutput io = client.getInputOutput ();
126 |
127 | switch (opcode) {
128 | case RequestCode.WarpPointer:
129 | if (bytesRemaining != 20) {
130 | io.readSkip (bytesRemaining);
131 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
132 | } else {
133 | processWarpPointer (xServer, client);
134 | }
135 | break;
136 | case RequestCode.ChangePointerControl:
137 | if (bytesRemaining != 8)
138 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
139 | io.readSkip (bytesRemaining);
140 | break; // Do nothing.
141 | case RequestCode.GetPointerControl:
142 | if (bytesRemaining != 0) {
143 | io.readSkip (bytesRemaining);
144 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
145 | } else {
146 | synchronized (io) {
147 | Util.writeReplyHeader (client, (byte) 0);
148 | io.writeInt (0); // Reply length.
149 | io.writeShort ((short) 1); // Acceleration numerator.
150 | io.writeShort ((short) 1); // Acceleration denom.
151 | io.writeShort ((short) 1); // Threshold.
152 | io.writePadBytes (18); // Unused.
153 | }
154 | io.flush ();
155 | }
156 | break;
157 | case RequestCode.SetPointerMapping:
158 | if (bytesRemaining != arg + (-arg & 3)) {
159 | io.readSkip (bytesRemaining);
160 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
161 | } else if (arg != _buttonMap.length) {
162 | ErrorCode.write (client, ErrorCode.Value, opcode, 0);
163 | } else {
164 | io.readBytes (_buttonMap, 0, arg);
165 | io.readSkip (-arg & 3); // Unused.
166 |
167 | synchronized (io) {
168 | Util.writeReplyHeader (client, (byte) 0);
169 | io.writeInt (0); // Reply length.
170 | io.writePadBytes (24); // Unused.
171 | }
172 | io.flush ();
173 |
174 | xServer.sendMappingNotify (2, 0, 0);
175 | }
176 | break;
177 | case RequestCode.GetPointerMapping:
178 | if (bytesRemaining != 0) {
179 | io.readSkip (bytesRemaining);
180 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
181 | } else {
182 | byte n = (byte) _buttonMap.length;
183 | int pad = -n & 3;
184 |
185 | synchronized (io) {
186 | Util.writeReplyHeader (client, n);
187 | io.writeInt ((n + pad) / 4); // Reply length.
188 | io.writePadBytes (24); // Unused.
189 |
190 | io.writeBytes (_buttonMap, 0, n); // Map.
191 | io.writePadBytes (pad); // Unused.
192 | }
193 | io.flush ();
194 | }
195 | break;
196 | default:
197 | io.readSkip (bytesRemaining);
198 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
199 | break;
200 | }
201 | }
202 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Property.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class implements a selection.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 | import java.util.Hashtable;
8 | import java.util.Vector;
9 |
10 |
11 | /**
12 | * @author Matthew KWan
13 | *
14 | * This class implements a selection.
15 | */
16 | public class Property {
17 | private final int _id;
18 | private int _type;
19 | private byte _format;
20 | private byte[] _data = null;
21 |
22 | /**
23 | * Constructor.
24 | *
25 | * @param id The property's ID.
26 | * @param type The ID of the property's type atom.
27 | * @param format Data format = 8, 16, or 32.
28 | */
29 | public Property (
30 | int id,
31 | int type,
32 | byte format
33 | ) {
34 | _id = id;
35 | _type = type;
36 | _format = format;
37 | }
38 |
39 | /**
40 | * Constructor.
41 | *
42 | * @param p The property to copy.
43 | */
44 | private Property (
45 | final Property p
46 | ) {
47 | _id = p._id;
48 | _type = p._type;
49 | _format = p._format;
50 | _data = p._data;
51 | }
52 |
53 | /**
54 | * Return the property's atom ID.
55 | *
56 | * @return The property's atom ID.
57 | */
58 | public int
59 | getId () {
60 | return _id;
61 | }
62 |
63 | /**
64 | * Process an X request relating to properties.
65 | *
66 | * @param xServer The X server.
67 | * @param client The remote client.
68 | * @param arg Optional first argument.
69 | * @param opcode The request's opcode.
70 | * @param bytesRemaining Bytes yet to be read in the request.
71 | * @param w The window containing the properties.
72 | * @param properties Hash table of the window's properties.
73 | * @throws IOException
74 | */
75 | public static void
76 | processRequest (
77 | XServer xServer,
78 | Client client,
79 | byte arg,
80 | byte opcode,
81 | int bytesRemaining,
82 | Window w,
83 | Hashtable properties
84 | ) throws IOException {
85 | switch (opcode) {
86 | case RequestCode.ChangeProperty:
87 | processChangePropertyRequest (xServer, client, arg,
88 | bytesRemaining, w, properties);
89 | break;
90 | case RequestCode.GetProperty:
91 | processGetPropertyRequest (xServer, client, arg == 1,
92 | bytesRemaining, w, properties);
93 | break;
94 | case RequestCode.RotateProperties:
95 | processRotatePropertiesRequest (xServer, client,
96 | bytesRemaining, w, properties);
97 | break;
98 | default:
99 | InputOutput io = client.getInputOutput ();
100 |
101 | io.readSkip (bytesRemaining);
102 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
103 | break;
104 | }
105 | }
106 |
107 | /**
108 | * Process a ChangeProperty request.
109 | * Change the owner of the specified selection.
110 | *
111 | * @param xServer The X server.
112 | * @param client The remote client.
113 | * @param mode 0=Replace 1=Prepend 2=Append.
114 | * @param bytesRemaining Bytes yet to be read in the request.
115 | * @param w The window containing the properties.
116 | * @param properties Hash table of the window's properties.
117 | * @throws IOException
118 | */
119 | public static void
120 | processChangePropertyRequest (
121 | XServer xServer,
122 | Client client,
123 | byte mode,
124 | int bytesRemaining,
125 | Window w,
126 | Hashtable properties
127 | ) throws IOException {
128 | InputOutput io = client.getInputOutput ();
129 |
130 | if (bytesRemaining < 16) {
131 | io.readSkip (bytesRemaining);
132 | ErrorCode.write (client, ErrorCode.Length,
133 | RequestCode.ChangeProperty, 0);
134 | return;
135 | }
136 |
137 | int pid = io.readInt (); // Property atom.
138 | int tid = io.readInt (); // Type atom.
139 | byte format = (byte) io.readByte (); // Format.
140 |
141 | io.readSkip (3); // Unused.
142 |
143 | int length = io.readInt (); // Length of data.
144 | int n, pad;
145 |
146 | if (format == 8)
147 | n = length;
148 | else if (format == 16)
149 | n = length * 2;
150 | else
151 | n = length * 4;
152 |
153 | pad = -n & 3;
154 |
155 | bytesRemaining -= 16;
156 | if (bytesRemaining != n + pad) {
157 | io.readSkip (bytesRemaining);
158 | ErrorCode.write (client, ErrorCode.Length,
159 | RequestCode.ChangeProperty, 0);
160 | return;
161 | }
162 |
163 | byte[] data = new byte[n];
164 |
165 | io.readBytes (data, 0, n);
166 | io.readSkip (pad); // Unused.
167 |
168 | Atom property = xServer.getAtom (pid);
169 |
170 | if (property == null) {
171 | ErrorCode.write (client, ErrorCode.Atom,
172 | RequestCode.ChangeProperty, pid);
173 | return;
174 | }
175 |
176 | if (!xServer.atomExists (tid)) {
177 | ErrorCode.write (client, ErrorCode.Atom,
178 | RequestCode.ChangeProperty, tid);
179 | return;
180 | }
181 |
182 | Property p;
183 |
184 | if (properties.containsKey (pid)) {
185 | p = properties.get (pid);
186 | } else {
187 | p = new Property (pid, tid, format);
188 | properties.put (pid, p);
189 | }
190 |
191 | if (mode == 0) { // Replace.
192 | p._type = tid;
193 | p._format = format;
194 | p._data = data;
195 | } else {
196 | if (tid != p._type || format != p._format) {
197 | ErrorCode.write (client, ErrorCode.Match,
198 | RequestCode.ChangeProperty, 0);
199 | return;
200 | }
201 |
202 | if (p._data == null) {
203 | p._data = data;
204 | } else {
205 | byte[] d1, d2;
206 |
207 | if (mode == 1) { // Prepend.
208 | d1 = data;
209 | d2 = p._data;
210 | } else { // Append.
211 | d1 = p._data;
212 | d2 = data;
213 | }
214 |
215 | p._data = new byte[d1.length + d2.length];
216 | System.arraycopy (d1, 0, p._data, 0, d1.length);
217 | System.arraycopy (d2, 0, p._data, d1.length, d2.length);
218 | }
219 | }
220 |
221 | Vector sc;
222 |
223 | if ((sc = w.getSelectingClients (EventCode.MaskPropertyChange))
224 | != null) {
225 | for (Client c: sc)
226 | EventCode.sendPropertyNotify (c, w, property,
227 | xServer.getTimestamp (), 0);
228 | }
229 | }
230 |
231 | /**
232 | * Process a GetProperty request.
233 | *
234 | * @param xServer The X server.
235 | * @param client The remote client.
236 | * @param delete Delete flag.
237 | * @param bytesRemaining Bytes yet to be read in the request.
238 | * @param w The window containing the properties.
239 | * @param properties Hash table of the window's properties.
240 | * @throws IOException
241 | */
242 | public static void
243 | processGetPropertyRequest (
244 | XServer xServer,
245 | Client client,
246 | boolean delete,
247 | int bytesRemaining,
248 | Window w,
249 | Hashtable properties
250 | ) throws IOException {
251 | InputOutput io = client.getInputOutput ();
252 |
253 | if (bytesRemaining != 16) {
254 | io.readSkip (bytesRemaining);
255 | ErrorCode.write (client, ErrorCode.Length,
256 | RequestCode.GetProperty, 0);
257 | return;
258 | }
259 |
260 | int pid = io.readInt (); // Property.
261 | int tid = io.readInt (); // Type.
262 | int longOffset = io.readInt (); // Long offset.
263 | int longLength = io.readInt (); // Long length.
264 | Atom property = xServer.getAtom (pid);
265 |
266 | if (property == null) {
267 | ErrorCode.write (client, ErrorCode.Atom,
268 | RequestCode.GetProperty, pid);
269 | return;
270 | } else if (tid != 0 && !xServer.atomExists (tid)) {
271 | ErrorCode.write (client, ErrorCode.Atom,
272 | RequestCode.GetProperty, tid);
273 | return;
274 | }
275 |
276 | byte format = 0;
277 | int bytesAfter = 0;
278 | byte[] value = null;
279 | boolean generateNotify = false;
280 |
281 | if (properties.containsKey (pid)) {
282 | Property p = properties.get (pid);
283 |
284 | tid = p._type;
285 | format = p._format;
286 |
287 | if (tid != 0 && tid != p._type) {
288 | bytesAfter = (p._data == null) ? 0 : p._data.length;
289 | } else {
290 | int n, i, t, l;
291 |
292 | n = (p._data == null) ? 0 : p._data.length;
293 | i = 4 * longOffset;
294 | t = n - i;
295 |
296 | if (longLength < 0 || longLength > 536870911)
297 | longLength = 536870911; // Prevent overflow.
298 |
299 | if (t < longLength * 4)
300 | l = t;
301 | else
302 | l = longLength * 4;
303 |
304 | bytesAfter = n - (i + l);
305 |
306 | if (l < 0) {
307 | ErrorCode.write (client, ErrorCode.Value,
308 | RequestCode.GetProperty, 0);
309 | return;
310 | }
311 |
312 | if (l > 0) {
313 | value = new byte[l];
314 | System.arraycopy (p._data, i, value, 0, l);
315 | }
316 |
317 | if (delete && bytesAfter == 0) {
318 | properties.remove (pid);
319 | generateNotify = true;
320 | }
321 | }
322 | } else {
323 | tid = 0;
324 | }
325 |
326 | int length = (value == null) ? 0 : value.length;
327 | int pad = -length & 3;
328 | int valueLength;
329 |
330 | if (format == 8)
331 | valueLength = length;
332 | else if (format == 16)
333 | valueLength = length / 2;
334 | else if (format == 32)
335 | valueLength = length / 4;
336 | else
337 | valueLength = 0;
338 |
339 | synchronized (io) {
340 | Util.writeReplyHeader (client, format);
341 | io.writeInt ((length + pad) / 4); // Reply length.
342 | io.writeInt (tid); // Type.
343 | io.writeInt (bytesAfter); // Bytes after.
344 | io.writeInt (valueLength); // Value length.
345 | io.writePadBytes (12); // Unused.
346 |
347 | if (value != null) {
348 | io.writeBytes (value, 0, value.length); // Value.
349 | io.writePadBytes (pad); // Unused.
350 | }
351 | }
352 | io.flush ();
353 |
354 | if (generateNotify) {
355 | Vector sc;
356 |
357 | if ((sc = w.getSelectingClients (EventCode.MaskPropertyChange))
358 | != null) {
359 | for (Client c: sc)
360 | EventCode.sendPropertyNotify (c, w, property,
361 | xServer.getTimestamp (), 1);
362 | }
363 | }
364 | }
365 |
366 | /**
367 | * Process a RotateProperties request.
368 | *
369 | * @param xServer The X server.
370 | * @param client The remote client.
371 | * @param bytesRemaining Bytes yet to be read in the request.
372 | * @param w The window containing the properties.
373 | * @param properties Hash table of the window's properties.
374 | * @throws IOException
375 | */
376 | public static void
377 | processRotatePropertiesRequest (
378 | XServer xServer,
379 | Client client,
380 | int bytesRemaining,
381 | Window w,
382 | Hashtable properties
383 | ) throws IOException {
384 | InputOutput io = client.getInputOutput ();
385 |
386 | if (bytesRemaining < 4) {
387 | io.readSkip (bytesRemaining);
388 | ErrorCode.write (client, ErrorCode.Length,
389 | RequestCode.RotateProperties, 0);
390 | return;
391 | }
392 |
393 | int n = io.readShort (); // Num properties.
394 | int delta = io.readShort (); // Delta.
395 |
396 | bytesRemaining -= 4;
397 | if (bytesRemaining != n * 4) {
398 | io.readSkip (bytesRemaining);
399 | ErrorCode.write (client, ErrorCode.Length,
400 | RequestCode.RotateProperties, 0);
401 | return;
402 | }
403 |
404 | if (n == 0 || (delta % n) == 0)
405 | return;
406 |
407 | int[] aids = new int[n];
408 | Property[] props = new Property[n];
409 | Property[] pcopy = new Property[n];
410 |
411 | for (int i = 0; i < n; i++)
412 | aids[i] = io.readInt ();
413 |
414 | for (int i = 0; i < n; i++) {
415 | if (!xServer.atomExists (aids[i])) {
416 | ErrorCode.write (client, ErrorCode.Atom,
417 | RequestCode.RotateProperties, aids[i]);
418 | return;
419 | } else if (!properties.containsKey (aids[i])) {
420 | ErrorCode.write (client, ErrorCode.Match,
421 | RequestCode.RotateProperties, aids[i]);
422 | return;
423 | } else {
424 | props[i] = properties.get (aids[i]);
425 | pcopy[i] = new Property (props[i]);
426 | }
427 | }
428 |
429 | for (int i = 0; i < n; i++) {
430 | Property p = props[i];
431 | Property pc = pcopy[(i + delta) % n];
432 |
433 | p._type = pc._type;
434 | p._format = pc._format;
435 | p._data = pc._data;
436 | }
437 |
438 | Vector sc;
439 |
440 | if ((sc = w.getSelectingClients (EventCode.MaskPropertyChange))
441 | != null) {
442 | for (int i = 0; i < n; i++) {
443 | for (Client c: sc)
444 | EventCode.sendPropertyNotify (c, w,
445 | xServer.getAtom (aids[i]),
446 | xServer.getTimestamp (), 0);
447 | }
448 | }
449 | }
450 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/RequestCode.java:
--------------------------------------------------------------------------------
1 | /**
2 | * All the X request codes.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | /**
7 | * @author Matthew Kwan
8 | *
9 | * All the X request codes.
10 | */
11 | public class RequestCode {
12 | public static final byte CreateWindow = 1;
13 | public static final byte ChangeWindowAttributes = 2;
14 | public static final byte GetWindowAttributes = 3;
15 | public static final byte DestroyWindow = 4;
16 | public static final byte DestroySubwindows = 5;
17 | public static final byte ChangeSaveSet = 6;
18 | public static final byte ReparentWindow = 7;
19 | public static final byte MapWindow = 8;
20 | public static final byte MapSubwindows = 9;
21 | public static final byte UnmapWindow = 10;
22 | public static final byte UnmapSubwindows = 11;
23 | public static final byte ConfigureWindow = 12;
24 | public static final byte CirculateWindow = 13;
25 | public static final byte GetGeometry = 14;
26 | public static final byte QueryTree = 15;
27 | public static final byte InternAtom = 16;
28 | public static final byte GetAtomName = 17;
29 | public static final byte ChangeProperty = 18;
30 | public static final byte DeleteProperty = 19;
31 | public static final byte GetProperty = 20;
32 | public static final byte ListProperties = 21;
33 | public static final byte SetSelectionOwner = 22;
34 | public static final byte GetSelectionOwner = 23;
35 | public static final byte ConvertSelection = 24;
36 | public static final byte SendEvent = 25;
37 | public static final byte GrabPointer = 26;
38 | public static final byte UngrabPointer = 27;
39 | public static final byte GrabButton = 28;
40 | public static final byte UngrabButton = 29;
41 | public static final byte ChangeActivePointerGrab = 30;
42 | public static final byte GrabKeyboard = 31;
43 | public static final byte UngrabKeyboard = 32;
44 | public static final byte GrabKey = 33;
45 | public static final byte UngrabKey = 34;
46 | public static final byte AllowEvents = 35;
47 | public static final byte GrabServer = 36;
48 | public static final byte UngrabServer = 37;
49 | public static final byte QueryPointer = 38;
50 | public static final byte GetMotionEvents = 39;
51 | public static final byte TranslateCoordinates = 40;
52 | public static final byte WarpPointer = 41;
53 | public static final byte SetInputFocus = 42;
54 | public static final byte GetInputFocus = 43;
55 | public static final byte QueryKeymap = 44;
56 | public static final byte OpenFont = 45;
57 | public static final byte CloseFont = 46;
58 | public static final byte QueryFont = 47;
59 | public static final byte QueryTextExtents = 48;
60 | public static final byte ListFonts = 49;
61 | public static final byte ListFontsWithInfo = 50;
62 | public static final byte SetFontPath = 51;
63 | public static final byte GetFontPath = 52;
64 | public static final byte CreatePixmap = 53;
65 | public static final byte FreePixmap = 54;
66 | public static final byte CreateGC = 55;
67 | public static final byte ChangeGC = 56;
68 | public static final byte CopyGC = 57;
69 | public static final byte SetDashes = 58;
70 | public static final byte SetClipRectangles = 59;
71 | public static final byte FreeGC = 60;
72 | public static final byte ClearArea = 61;
73 | public static final byte CopyArea = 62;
74 | public static final byte CopyPlane = 63;
75 | public static final byte PolyPoint = 64;
76 | public static final byte PolyLine = 65;
77 | public static final byte PolySegment = 66;
78 | public static final byte PolyRectangle = 67;
79 | public static final byte PolyArc = 68;
80 | public static final byte FillPoly = 69;
81 | public static final byte PolyFillRectangle = 70;
82 | public static final byte PolyFillArc = 71;
83 | public static final byte PutImage = 72;
84 | public static final byte GetImage = 73;
85 | public static final byte PolyText8 = 74;
86 | public static final byte PolyText16 = 75;
87 | public static final byte ImageText8 = 76;
88 | public static final byte ImageText16 = 77;
89 | public static final byte CreateColormap = 78;
90 | public static final byte FreeColormap = 79;
91 | public static final byte CopyColormapAndFree = 80;
92 | public static final byte InstallColormap = 81;
93 | public static final byte UninstallColormap = 82;
94 | public static final byte ListInstalledColormaps = 83;
95 | public static final byte AllocColor = 84;
96 | public static final byte AllocNamedColor = 85;
97 | public static final byte AllocColorCells = 86;
98 | public static final byte AllocColorPlanes = 87;
99 | public static final byte FreeColors = 88;
100 | public static final byte StoreColors = 89;
101 | public static final byte StoreNamedColor = 90;
102 | public static final byte QueryColors = 91;
103 | public static final byte LookupColor = 92;
104 | public static final byte CreateCursor = 93;
105 | public static final byte CreateGlyphCursor = 94;
106 | public static final byte FreeCursor = 95;
107 | public static final byte RecolorCursor = 96;
108 | public static final byte QueryBestSize = 97;
109 | public static final byte QueryExtension = 98;
110 | public static final byte ListExtensions = 99;
111 | public static final byte ChangeKeyboardMapping = 100;
112 | public static final byte GetKeyboardMapping = 101;
113 | public static final byte ChangeKeyboardControl = 102;
114 | public static final byte GetKeyboardControl = 103;
115 | public static final byte Bell = 104;
116 | public static final byte ChangePointerControl = 105;
117 | public static final byte GetPointerControl = 106;
118 | public static final byte SetScreenSaver = 107;
119 | public static final byte GetScreenSaver = 108;
120 | public static final byte ChangeHosts = 109;
121 | public static final byte ListHosts = 110;
122 | public static final byte SetAccessControl = 111;
123 | public static final byte SetCloseDownMode = 112;
124 | public static final byte KillClient = 113;
125 | public static final byte RotateProperties = 114;
126 | public static final byte ForceScreenSaver = 115;
127 | public static final byte SetPointerMapping = 116;
128 | public static final byte GetPointerMapping = 117;
129 | public static final byte SetModifierMapping = 118;
130 | public static final byte GetModifierMapping = 119;
131 | public static final byte NoOperation = 127;
132 | public static final byte ExtensionStart = -128;
133 | public static final byte ExtensionEnd = -1;
134 | }
135 |
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Resource.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class handles details of a server resource.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 | /**
9 | * @author Matthew Kwan
10 | *
11 | * This class handles details of a server resource.
12 | */
13 | public class Resource {
14 | public static final int WINDOW = 1;
15 | public static final int PIXMAP = 2;
16 | public static final int CURSOR = 3;
17 | public static final int FONT = 4;
18 | public static final int GCONTEXT = 5;
19 | public static final int COLORMAP = 6;
20 |
21 | private final int _type;
22 | protected final int _id;
23 | protected final XServer _xServer;
24 | protected Client _client;
25 | private int _closeDownMode = Client.Destroy;
26 |
27 | /**
28 | * Constructor.
29 | *
30 | * @param type The resource type.
31 | * @param id The resource ID.
32 | * @param xServer The X server.
33 | * @param client The client issuing the request.
34 | */
35 | protected Resource (
36 | int type,
37 | int id,
38 | XServer xServer,
39 | Client client
40 | ) {
41 | _type = type;
42 | _id = id;
43 | _xServer = xServer;
44 | _client = client;
45 | }
46 |
47 | /**
48 | * Return the resource type.
49 | *
50 | * @return The resource type.
51 | */
52 | public int
53 | getType () {
54 | return _type;
55 | }
56 |
57 | /**
58 | * Return the resource ID.
59 | *
60 | * @return The resource ID.
61 | */
62 | public int
63 | getId () {
64 | return _id;
65 | }
66 |
67 | /**
68 | * Return the client that created the resource.
69 | *
70 | * @return The client that created the resource.
71 | */
72 | public Client
73 | getClient () {
74 | return _client;
75 | }
76 |
77 | /**
78 | * Return the resource's close down mode.
79 | *
80 | * @return The resource's close down mode.
81 | */
82 | public int
83 | getCloseDownMode () {
84 | return _closeDownMode;
85 | }
86 |
87 | /**
88 | * Set the close down mode of the resource.
89 | *
90 | * @param mode The mode used to destroy the resource.
91 | */
92 | public void
93 | setCloseDownMode (
94 | int mode
95 | ) {
96 | _closeDownMode = mode;
97 | }
98 |
99 | /**
100 | * Is the resource a drawable? (Window or Pixmap)
101 | *
102 | * @return Whether the resource is a drawable.
103 | */
104 | public boolean
105 | isDrawable () {
106 | return (_type == WINDOW || _type == PIXMAP);
107 | }
108 |
109 | /**
110 | * Is the resource a fontable? (Font or GContext)
111 | *
112 | * @return Whether the resource is a fontable.
113 | */
114 | public boolean
115 | isFontable () {
116 | return (_type == FONT || _type == GCONTEXT);
117 | }
118 |
119 | /**
120 | * Destroy the resource.
121 | * Remove it from the X server's resources, and override this function
122 | * to handle object-specific removals.
123 | */
124 | public void
125 | delete () {
126 | _xServer.freeResource (_id);
127 | }
128 |
129 | /**
130 | * Process an X request relating to this resource.
131 | * This is a fallback function that does nothing.
132 | *
133 | * @param client The remote client.
134 | * @param opcode The request's opcode.
135 | * @param arg Optional first argument.
136 | * @param bytesRemaining Bytes yet to be read in the request.
137 | * @throws IOException
138 | */
139 | public void
140 | processRequest (
141 | Client client,
142 | byte opcode,
143 | byte arg,
144 | int bytesRemaining
145 | ) throws IOException {
146 | }
147 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Selection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class implements a selection.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 |
9 | /**
10 | * @author Matthew KWan
11 | *
12 | * This class implements a selection.
13 | */
14 | public class Selection {
15 | private final int _id;
16 | private Client _owner = null;
17 | private Window _ownerWindow = null;
18 | private int _lastChangeTime = 0;
19 |
20 | /**
21 | * Constructor.
22 | *
23 | * @param id The selection's ID.
24 | */
25 | public Selection (
26 | int id
27 | ) {
28 | _id = id;
29 | }
30 |
31 | /**
32 | * Return the selection's atom ID.
33 | *
34 | * @return The selection's atom ID.
35 | */
36 | public int
37 | getId () {
38 | return _id;
39 | }
40 |
41 | /**
42 | * If the selection is owned by the client, clear it.
43 | * This occurs when a client disconnects.
44 | *
45 | * @param client The disconnecting client.
46 | */
47 | public void
48 | clearClient (
49 | Client client
50 | ) {
51 | if (_owner == client) {
52 | _owner = null;
53 | _ownerWindow = null;
54 | }
55 | }
56 |
57 | /**
58 | * Process an X request relating to selections.
59 | *
60 | * @param xServer The X server.
61 | * @param client The client issuing the request.
62 | * @param opcode The request's opcode.
63 | * @param bytesRemaining Bytes yet to be read in the request.
64 | * @throws IOException
65 | */
66 | public static void
67 | processRequest (
68 | XServer xServer,
69 | Client client,
70 | byte opcode,
71 | int bytesRemaining
72 | ) throws IOException {
73 | InputOutput io = client.getInputOutput ();
74 |
75 | switch (opcode) {
76 | case RequestCode.SetSelectionOwner:
77 | processSetSelectionOwnerRequest (xServer, client,
78 | bytesRemaining);
79 | break;
80 | case RequestCode.GetSelectionOwner:
81 | if (bytesRemaining != 4) {
82 | io.readSkip (bytesRemaining);
83 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
84 | } else {
85 | int aid = io.readInt (); // Selection atom.
86 |
87 | if (!xServer.atomExists (aid)) {
88 | ErrorCode.write (client, ErrorCode.Atom,
89 | RequestCode.SetSelectionOwner, aid);
90 | } else {
91 | int wid = 0;
92 | Selection sel = xServer.getSelection (aid);
93 |
94 | if (sel != null && sel._ownerWindow != null)
95 | wid = sel._ownerWindow.getId ();
96 |
97 | synchronized (io) {
98 | Util.writeReplyHeader (client, (byte) 0);
99 | io.writeInt (0); // Reply length.
100 | io.writeInt (wid); // Owner.
101 | io.writePadBytes (20); // Unused.
102 | }
103 | io.flush ();
104 | }
105 | }
106 | break;
107 | case RequestCode.ConvertSelection:
108 | processConvertSelectionRequest (xServer, client,
109 | bytesRemaining);
110 | break;
111 | default:
112 | io.readSkip (bytesRemaining);
113 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
114 | break;
115 | }
116 | }
117 |
118 | /**
119 | * Process a SetSelectionOwner request.
120 | * Change the owner of the specified selection.
121 | *
122 | * @param xServer The X server.
123 | * @param client The client issuing the request.
124 | * @param bytesRemaining Bytes yet to be read in the request.
125 | * @throws IOException
126 | */
127 | public static void
128 | processSetSelectionOwnerRequest (
129 | XServer xServer,
130 | Client client,
131 | int bytesRemaining
132 | ) throws IOException {
133 | InputOutput io = client.getInputOutput ();
134 |
135 | if (bytesRemaining != 12) {
136 | io.readSkip (bytesRemaining);
137 | ErrorCode.write (client, ErrorCode.Length,
138 | RequestCode.SetSelectionOwner, 0);
139 | return;
140 | }
141 |
142 | int wid = io.readInt (); // Owner window.
143 | int aid = io.readInt (); // Selection atom.
144 | int time = io.readInt (); // Timestamp.
145 | Window w = null;
146 |
147 | if (wid != 0) {
148 | Resource r = xServer.getResource (wid);
149 |
150 | if (r == null || r.getType () != Resource.WINDOW) {
151 | ErrorCode.write (client, ErrorCode.Window,
152 | RequestCode.SetSelectionOwner, wid);
153 | return;
154 | }
155 |
156 | w = (Window) r;
157 | }
158 |
159 | Atom a = xServer.getAtom (aid);
160 |
161 | if (a == null) {
162 | ErrorCode.write (client, ErrorCode.Atom,
163 | RequestCode.SetSelectionOwner, aid);
164 | return;
165 | }
166 |
167 | Selection sel = xServer.getSelection (aid);
168 |
169 | if (sel == null) {
170 | sel = new Selection (aid);
171 | xServer.addSelection (sel);
172 | }
173 |
174 | int now = xServer.getTimestamp ();
175 |
176 | if (time != 0) {
177 | if (time < sel._lastChangeTime || time >= now)
178 | return;
179 | } else {
180 | time = now;
181 | }
182 |
183 | sel._lastChangeTime = time;
184 | sel._ownerWindow = w;
185 |
186 | if (sel._owner != null && sel._owner != client)
187 | EventCode.sendSelectionClear (sel._owner, time, w, a);
188 |
189 | sel._owner = (w != null) ? client : null;
190 | }
191 |
192 | /**
193 | * Process a ConvertSelection request.
194 | *
195 | * @param xServer The X server.
196 | * @param client The client issuing the request.
197 | * @param bytesRemaining Bytes yet to be read in the request.
198 | * @throws IOException
199 | */
200 | public static void
201 | processConvertSelectionRequest (
202 | XServer xServer,
203 | Client client,
204 | int bytesRemaining
205 | ) throws IOException {
206 | InputOutput io = client.getInputOutput ();
207 |
208 | if (bytesRemaining != 20) {
209 | io.readSkip (bytesRemaining);
210 | ErrorCode.write (client, ErrorCode.Length,
211 | RequestCode.ConvertSelection, 0);
212 | return;
213 | }
214 |
215 | int wid = io.readInt (); // Requestor.
216 | int sid = io.readInt (); // Selection.
217 | int tid = io.readInt (); // Target.
218 | int pid = io.readInt (); // Property.
219 | int time = io.readInt (); // Time.
220 | Resource r = xServer.getResource (wid);
221 | Window w;
222 | Atom selectionAtom, targetAtom, propertyAtom;
223 |
224 | if (r == null || r.getType () != Resource.WINDOW) {
225 | ErrorCode.write (client, ErrorCode.Window,
226 | RequestCode.ConvertSelection, wid);
227 | return;
228 | } else {
229 | w = (Window) r;
230 | }
231 |
232 | selectionAtom = xServer.getAtom (sid);
233 | if (selectionAtom == null) {
234 | ErrorCode.write (client, ErrorCode.Atom,
235 | RequestCode.ConvertSelection, sid);
236 | return;
237 | }
238 |
239 | targetAtom = xServer.getAtom (tid);
240 | if (targetAtom == null) {
241 | ErrorCode.write (client, ErrorCode.Atom,
242 | RequestCode.ConvertSelection, tid);
243 | return;
244 | }
245 |
246 | propertyAtom = null;
247 | if (pid != 0 && (propertyAtom = xServer.getAtom (pid)) == null) {
248 | ErrorCode.write (client, ErrorCode.Atom,
249 | RequestCode.ConvertSelection, pid);
250 | return;
251 | }
252 |
253 | Client owner = null;
254 | Selection sel = xServer.getSelection (sid);
255 |
256 | if (sel != null)
257 | owner = sel._owner;
258 |
259 | if (owner != null) {
260 | try {
261 | EventCode.sendSelectionRequest (owner, time, sel._ownerWindow,
262 | w, selectionAtom, targetAtom, propertyAtom);
263 | } catch (IOException e) {
264 | }
265 | } else {
266 | EventCode.sendSelectionNotify (client, time, w, selectionAtom,
267 | targetAtom, propertyAtom);
268 | }
269 | }
270 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Util.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Utility functions.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 | /**
9 | * @author Matthew Kwan
10 | *
11 | * Utility functions.
12 | */
13 | public class Util {
14 | /**
15 | * Count the number of bits in an integer.
16 | *
17 | * @param n The integer containing the bits.
18 | * @return The number of bits in the integer.
19 | */
20 | public static int
21 | bitcount (
22 | int n
23 | ) {
24 | int c = 0;
25 |
26 | while (n != 0) {
27 | c += n & 1;
28 | n >>= 1;
29 | }
30 |
31 | return c;
32 | }
33 |
34 | /**
35 | * Write the header of a reply.
36 | *
37 | * @param client The remote client.
38 | * @param arg Optional argument.
39 | * @throws IOException
40 | */
41 | public static void
42 | writeReplyHeader (
43 | Client client,
44 | byte arg
45 | ) throws IOException {
46 | InputOutput io = client.getInputOutput ();
47 | short sn = (short) (client.getSequenceNumber () & 0xffff);
48 |
49 | io.writeByte ((byte) 1); // Reply.
50 | io.writeByte (arg);
51 | io.writeShort (sn);
52 | }
53 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Visual.java:
--------------------------------------------------------------------------------
1 | /**
2 | * An X visual.
3 | */
4 | package au.com.darkside.XServer;
5 |
6 | import java.io.IOException;
7 |
8 |
9 | /**
10 | * @author Matthew Kwan
11 | *
12 | * An X visual. This is always 32-bit TrueColor.
13 | */
14 | public class Visual {
15 | public final static byte BackingStoreNever = 0;
16 | public final static byte BackingStoreWhenMapped = 1;
17 | public final static byte BackingStoreAlways = 2;
18 |
19 | public final static byte StaticGray = 0;
20 | public final static byte GrayScale = 1;
21 | public final static byte StaticColor = 2;
22 | public final static byte PseudoColor = 3;
23 | public final static byte TrueColor = 4;
24 | public final static byte DirectColor = 5;
25 |
26 | private final int _id;
27 |
28 | /**
29 | * Constructor.
30 | *
31 | * @param id The visual ID.
32 | */
33 | public Visual (
34 | int id
35 | ) {
36 | _id = id;
37 | }
38 |
39 | /**
40 | * Return the visual's ID.
41 | *
42 | * @return The visual's ID.
43 | */
44 | public int
45 | getId () {
46 | return _id;
47 | }
48 |
49 | /**
50 | * Return whether the visual supports a backing store.
51 | *
52 | * @return Whether a backing store is supported.
53 | */
54 | public byte
55 | getBackingStoreInfo () {
56 | return BackingStoreAlways;
57 | }
58 |
59 | /**
60 | * Return whether the visual supports save-under.
61 | *
62 | * @return Whether save-under is supported.
63 | */
64 | public boolean
65 | getSaveUnder () {
66 | return false;
67 | }
68 |
69 | /**
70 | * Return the depth of the visual.
71 | * Under Android this is always 32.
72 | *
73 | * @return The depth of the visual, in bits.
74 | */
75 | public byte
76 | getDepth () {
77 | return 32;
78 | }
79 |
80 | /**
81 | * Write details of the visual.
82 | *
83 | * @param io The input/output stream.
84 | * @throws IOException
85 | */
86 | public void
87 | write (
88 | InputOutput io
89 | ) throws IOException {
90 | io.writeInt (_id); // Visual ID.
91 | io.writeByte (TrueColor); // Class.
92 | io.writeByte ((byte) 8); // Bits per RGB value.
93 | io.writeShort ((short) (1 << 8)); // Colormap entries.
94 | io.writeInt (0x00ff0000); // Red mask.
95 | io.writeInt (0x0000ff00); // Green mask.
96 | io.writeInt (0x000000ff); // Blue mask.
97 | io.writePadBytes (4); // Unused.
98 | }
99 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Xext/Extensions.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This class handles requests relating to extensions.
3 | */
4 | package au.com.darkside.XServer.Xext;
5 |
6 | import java.io.IOException;
7 |
8 | import au.com.darkside.XServer.Client;
9 | import au.com.darkside.XServer.ErrorCode;
10 | import au.com.darkside.XServer.InputOutput;
11 | import au.com.darkside.XServer.Util;
12 | import au.com.darkside.XServer.XServer;
13 |
14 |
15 | /**
16 | * @author mkwan
17 | *
18 | * This class handles requests relating to extensions.
19 | */
20 | public class Extensions {
21 | public static final byte XGE = -128;
22 | public static final byte XTEST = -127;
23 | public static final byte BigRequests = -126;
24 | public static final byte Shape = -125;
25 |
26 | /**
27 | * Process a request relating to an X extension.
28 | *
29 | * @param xServer The X server.
30 | * @param client The remote client.
31 | * @param opcode The request's opcode.
32 | * @param arg Optional first argument.
33 | * @param bytesRemaining Bytes yet to be read in the request.
34 | * @throws IOException
35 | */
36 | public static void
37 | processRequest (
38 | XServer xServer,
39 | Client client,
40 | byte opcode,
41 | byte arg,
42 | int bytesRemaining
43 | ) throws IOException {
44 | InputOutput io = client.getInputOutput ();
45 |
46 | switch (opcode) {
47 | case XGE:
48 | if (bytesRemaining != 4) {
49 | io.readSkip (bytesRemaining);
50 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
51 | } else { // Assume arg == 0 (GEQueryVersion).
52 | short xgeMajor = (short) io.readShort ();
53 | short xgeMinor = (short) io.readShort ();
54 |
55 | synchronized (io) {
56 | Util.writeReplyHeader (client, arg);
57 | io.writeInt (0); // Reply length.
58 | io.writeShort (xgeMajor);
59 | io.writeShort (xgeMinor);
60 | io.writePadBytes (20);
61 | }
62 | io.flush ();
63 | }
64 | break;
65 | case XTEST:
66 | XTest.processRequest (xServer, client, opcode, arg,
67 | bytesRemaining);
68 | break;
69 | case BigRequests:
70 | if (bytesRemaining != 0) {
71 | io.readSkip (bytesRemaining);
72 | ErrorCode.write (client, ErrorCode.Length, opcode, 0);
73 | } else { // Assume arg == 0 (BigReqEnable).
74 | synchronized (io) {
75 | Util.writeReplyHeader (client, arg);
76 | io.writeInt (0);
77 | io.writeInt (Integer.MAX_VALUE);
78 | io.writePadBytes (20);
79 | }
80 | io.flush ();
81 | }
82 | break;
83 | case Shape:
84 | XShape.processRequest (xServer, client, opcode, arg,
85 | bytesRemaining);
86 | break;
87 | default:
88 | io.readSkip (bytesRemaining); // Not implemented.
89 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
90 | break;
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Xext/XShape.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Handles requests relating to the X SHAPE extension.
3 | */
4 | package au.com.darkside.XServer.Xext;
5 |
6 | import java.io.IOException;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import android.graphics.Bitmap;
11 | import android.graphics.Rect;
12 | import android.graphics.Region;
13 | import au.com.darkside.XServer.Client;
14 | import au.com.darkside.XServer.Drawable;
15 | import au.com.darkside.XServer.ErrorCode;
16 | import au.com.darkside.XServer.InputOutput;
17 | import au.com.darkside.XServer.Pixmap;
18 | import au.com.darkside.XServer.Util;
19 | import au.com.darkside.XServer.Window;
20 | import au.com.darkside.XServer.XServer;
21 |
22 | /**
23 | * @author mkwan
24 | *
25 | * Handles requests related to the X SHAPE extension.
26 | */
27 | public class XShape {
28 | public static final byte EventBase = 76;
29 | public static final byte KindBounding = 0;
30 | public static final byte KindClip = 1;
31 | public static final byte KindInput = 2;
32 |
33 | private static final byte ShapeQueryVersion = 0;
34 | private static final byte ShapeRectangles = 1;
35 | private static final byte ShapeMask = 2;
36 | private static final byte ShapeCombine = 3;
37 | private static final byte ShapeOffset = 4;
38 | private static final byte ShapeQueryExtents = 5;
39 | private static final byte ShapeSelectInput = 6;
40 | private static final byte ShapeInputSelected = 7;
41 | private static final byte ShapeGetRectangles = 8;
42 |
43 | private static final byte OpSet = 0;
44 | private static final byte OpUnion = 1;
45 | private static final byte OpIntersect = 2;
46 | private static final byte OpSubtract = 3;
47 | private static final byte OpInvert = 4;
48 |
49 | /**
50 | * Process a request relating to the X SHAPE extension.
51 | *
52 | * @param xServer The X server.
53 | * @param client The remote client.
54 | * @param opcode The request's opcode.
55 | * @param arg Optional first argument.
56 | * @param bytesRemaining Bytes yet to be read in the request.
57 | * @param sequenceNumber Request sequence number.
58 | * @throws IOException
59 | */
60 | public static void
61 | processRequest (
62 | XServer xServer,
63 | Client client,
64 | byte opcode,
65 | byte arg,
66 | int bytesRemaining
67 | ) throws java.io.IOException {
68 | InputOutput io = client.getInputOutput ();
69 |
70 | switch (arg) {
71 | case ShapeQueryVersion:
72 | if (bytesRemaining != 0) {
73 | io.readSkip (bytesRemaining);
74 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
75 | arg, opcode, 0);
76 | } else {
77 | synchronized (io) {
78 | Util.writeReplyHeader (client, arg);
79 | io.writeInt (0); // Reply length.
80 | io.writeShort ((short) 1); // Shape major.
81 | io.writeShort ((short) 1); // Shape minor.
82 | io.writePadBytes (20);
83 | }
84 | io.flush ();
85 | }
86 | break;
87 | case ShapeRectangles:
88 | if (bytesRemaining < 12) {
89 | io.readSkip (bytesRemaining);
90 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
91 | arg, opcode, 0);
92 | } else {
93 | byte shapeOp = (byte) io.readByte ();
94 | byte shapeKind = (byte) io.readByte ();
95 |
96 | io.readByte (); // Ordering.
97 | io.readSkip (1);
98 |
99 | int wid = io.readInt ();
100 | int x = io.readShort ();
101 | int y = io.readShort ();
102 | Window w = (Window) xServer.getResource (wid);
103 |
104 | bytesRemaining -= 12;
105 |
106 | int nr = bytesRemaining / 8;
107 | Region r = (nr == 0) ? null : new Region ();
108 |
109 | for (int i = 0; i < nr; i++) {
110 | int rx = io.readShort ();
111 | int ry = io.readShort ();
112 | int rw = io.readShort ();
113 | int rh = io.readShort ();
114 |
115 | r.op (new Rect (rx, ry, rx + rw, ry + rh),
116 | Region.Op.UNION);
117 | bytesRemaining -= 8;
118 | }
119 |
120 | if (bytesRemaining != 0) // Oops!
121 | io.readSkip (bytesRemaining);
122 |
123 | regionOperate (w, shapeKind, r, shapeOp, x, y);
124 | if (shapeKind != KindInput && w.isViewable ())
125 | w.invalidate ();
126 | }
127 | break;
128 | case ShapeMask:
129 | if (bytesRemaining != 16) {
130 | io.readSkip (bytesRemaining);
131 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
132 | arg, opcode, 0);
133 | } else {
134 | byte shapeOp = (byte) io.readByte ();
135 | byte shapeKind = (byte) io.readByte ();
136 |
137 | io.readSkip (2);
138 |
139 | int wid = io.readInt ();
140 | int x = io.readShort ();
141 | int y = io.readShort ();
142 | int pid = io.readInt (); // Pixmap ID.
143 | Window w = (Window) xServer.getResource (wid);
144 | Pixmap p = (pid == 0) ? null :
145 | (Pixmap) xServer.getResource (pid);
146 | Region r = (p == null) ? null : createRegion (p);
147 |
148 | regionOperate (w, shapeKind, r, shapeOp, x, y);
149 | if (shapeKind != KindInput && w.isViewable ())
150 | w.invalidate ();
151 | }
152 | break;
153 | case ShapeCombine:
154 | if (bytesRemaining != 16) {
155 | io.readSkip (bytesRemaining);
156 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
157 | arg, opcode, 0);
158 | } else {
159 | byte shapeOp = (byte) io.readByte ();
160 | byte dstKind = (byte) io.readByte ();
161 | byte srcKind = (byte) io.readByte ();
162 |
163 | io.readSkip (1);
164 |
165 | int dwid = io.readInt ();
166 | int x = io.readShort ();
167 | int y = io.readShort ();
168 | int swid = io.readInt ();
169 | Window sw = (Window) xServer.getResource (swid);
170 | Window dw = (Window) xServer.getResource (dwid);
171 | Region sr = sw.getShapeRegion (srcKind);
172 | Rect irect = sw.getIRect ();
173 |
174 | x -= irect.left; // Make region coordinates relative.
175 | y -= irect.top;
176 |
177 | regionOperate (dw, dstKind, sr, shapeOp, x, y);
178 | if (dstKind != KindInput && dw.isViewable ())
179 | dw.invalidate ();
180 | }
181 | break;
182 | case ShapeOffset:
183 | if (bytesRemaining != 12) {
184 | io.readSkip (bytesRemaining);
185 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
186 | arg, opcode, 0);
187 | } else {
188 | byte shapeKind = (byte) io.readByte ();
189 |
190 | io.readSkip (3);
191 |
192 | int wid = io.readInt ();
193 | int x = io.readShort ();
194 | int y = io.readShort ();
195 | Window w = (Window) xServer.getResource (wid);
196 | Region r = w.getShapeRegion (shapeKind);
197 |
198 | if (r != null && (x != 0 || y != 0)) {
199 | r.translate (x, y);
200 | w.sendShapeNotify (shapeKind);
201 | if (shapeKind != KindInput && w.isViewable ())
202 | w.invalidate ();
203 | }
204 | }
205 | break;
206 | case ShapeQueryExtents:
207 | if (bytesRemaining != 4) {
208 | io.readSkip (bytesRemaining);
209 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
210 | arg, opcode, 0);
211 | } else {
212 | int wid = io.readInt ();
213 | Window w = (Window) xServer.getResource (wid);
214 | boolean bs = w.isBoundingShaped ();
215 | boolean cs = w.isClipShaped ();
216 | Rect orect;
217 | Rect irect;
218 |
219 | if (bs)
220 | orect = w.getShapeRegion(KindBounding).getBounds ();
221 | else
222 | orect = w.getORect ();
223 |
224 | if (cs)
225 | irect = w.getShapeRegion(KindClip).getBounds ();
226 | else
227 | irect = w.getIRect ();
228 |
229 | synchronized (io) {
230 | Util.writeReplyHeader (client, arg);
231 | io.writeInt (0);
232 | io.writeByte ((byte) (bs ? 1 : 0)); // Bounding shaped?
233 | io.writeByte ((byte) (cs ? 1 : 0)); // Clip shaped?
234 | io.writePadBytes (2);
235 | io.writeShort ((short) orect.left);
236 | io.writeShort ((short) orect.top);
237 | io.writeShort ((short) orect.width ());
238 | io.writeShort ((short) orect.height ());
239 | io.writeShort ((short) irect.left);
240 | io.writeShort ((short) irect.top);
241 | io.writeShort ((short) irect.width ());
242 | io.writeShort ((short) irect.height ());
243 | io.writePadBytes (4);
244 | }
245 | io.flush ();
246 | }
247 | break;
248 | case ShapeSelectInput:
249 | if (bytesRemaining != 8) {
250 | io.readSkip (bytesRemaining);
251 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
252 | arg, opcode, 0);
253 | } else {
254 | int wid = io.readInt ();
255 | boolean enable = (io.readByte() == 1);
256 |
257 | io.readSkip (3);
258 |
259 | Window w = (Window) xServer.getResource (wid);
260 |
261 | if (enable)
262 | w.addShapeSelectInput (client);
263 | else
264 | w.removeShapeSelectInput (client);
265 | }
266 | break;
267 | case ShapeInputSelected:
268 | if (bytesRemaining != 4) {
269 | io.readSkip (bytesRemaining);
270 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
271 | arg, opcode, 0);
272 | } else {
273 | int wid = io.readInt ();
274 | Window w = (Window) xServer.getResource (wid);
275 | boolean enabled = w.shapeSelectInputEnabled (client);
276 |
277 | synchronized (io) {
278 | Util.writeReplyHeader (client,
279 | (byte) (enabled ? 1 : 0));
280 | io.writeInt (0); // Reply length.
281 | io.writePadBytes (24);
282 | }
283 | io.flush ();
284 | }
285 | break;
286 | case ShapeGetRectangles:
287 | if (bytesRemaining != 8) {
288 | io.readSkip (bytesRemaining);
289 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
290 | arg, opcode, 0);
291 | } else {
292 | int wid = io.readInt ();
293 | byte shapeKind = (byte) io.readByte ();
294 |
295 | io.readSkip (3);
296 |
297 | Window w = (Window) xServer.getResource (wid);
298 | Region r = w.getShapeRegion (shapeKind);
299 | Rect irect = w.getIRect ();
300 | byte ordering = 0; // Unsorted.
301 | List rectangles = rectanglesFromRegion (r);
302 | int nr = rectangles.size ();
303 |
304 | synchronized (io) {
305 | Util.writeReplyHeader (client, ordering);
306 | io.writeInt (2 * nr); // Reply length.
307 | io.writeInt (nr);
308 | io.writePadBytes (20);
309 |
310 | for (Rect rect: rectangles) {
311 | io.writeShort ((short) (rect.left - irect.left));
312 | io.writeShort ((short) (rect.top - irect.top));
313 | io.writeShort ((short) rect.width ());
314 | io.writeShort ((short) rect.height ());
315 | }
316 | }
317 |
318 | io.flush ();
319 | }
320 | break;
321 | default:
322 | io.readSkip (bytesRemaining);
323 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
324 | break;
325 | }
326 | }
327 |
328 | /**
329 | * Carry out a shape operation on a region.
330 | *
331 | * @param w The destination window to operate on.
332 | * @param shapeKind The type of shape in the destination window.
333 | * @param sr Source region.
334 | * @param shapeOp Operation to carry out on the regions.
335 | * @param x X offset to apply to the source region.
336 | * @param y Y offset to apply to the source region.
337 | */
338 | private static void
339 | regionOperate (
340 | Window w,
341 | byte shapeKind,
342 | Region sr,
343 | byte shapeOp,
344 | int x,
345 | int y
346 | ) {
347 | if (sr != null) { // Apply (x, y) offset.
348 | Region r = new Region ();
349 | Rect irect = w.getIRect ();
350 |
351 | sr.translate (x + irect.left, y + irect.top, r);
352 | sr = r;
353 | }
354 |
355 | Region dr = w.getShapeRegion (shapeKind);
356 |
357 | switch (shapeOp) {
358 | case OpSet:
359 | break;
360 | case OpUnion:
361 | if (sr == null || dr == null)
362 | sr = null;
363 | else
364 | sr.op (dr, Region.Op.UNION);
365 | break;
366 | case OpIntersect:
367 | if (sr == null)
368 | sr = dr;
369 | else if (dr != null)
370 | sr.op (dr, Region.Op.INTERSECT);
371 | break;
372 | case OpSubtract: // Subtract source region from dest region.
373 | if (sr == null)
374 | sr = new Region (); // Empty region.
375 | else if (dr == null)
376 | sr.op (w.getORect (), Region.Op.DIFFERENCE);
377 | else
378 | sr.op (dr, Region.Op.DIFFERENCE);
379 | break;
380 | case OpInvert: // Subtract dest region from source region.
381 | if (dr == null) {
382 | sr = new Region (); // Empty region.
383 | } else if (sr == null) {
384 | sr = new Region (w.getORect ());
385 | sr.op (dr, Region.Op.REVERSE_DIFFERENCE);
386 | } else {
387 | sr.op (dr, Region.Op.REVERSE_DIFFERENCE);
388 | }
389 | break;
390 | default:
391 | return;
392 | }
393 |
394 | w.setShapeRegion (shapeKind, sr);
395 | w.sendShapeNotify (shapeKind);
396 | }
397 |
398 | /**
399 | * Return a list of rectangles that when combined make up the region.
400 | *
401 | * @param r The region.
402 | * @return
403 | */
404 | private static List
405 | rectanglesFromRegion (
406 | Region r
407 | ) {
408 | ArrayList rl = new ArrayList ();
409 |
410 | if (r != null && !r.isEmpty ()) {
411 | if (r.isRect ())
412 | rl.add (r.getBounds ());
413 | else
414 | extractRectangles (r, r.getBounds (), rl);
415 | }
416 |
417 | return rl;
418 | }
419 |
420 | /**
421 | * Recursively break the region contained in the rectangle into
422 | * rectangles entirely contained in the rectangle.
423 | *
424 | * @param r Region being broken into rectangles.
425 | * @param rect Part of the region being analyzed..
426 | * @param rl Return list of rectangles.
427 | */
428 | private static void
429 | extractRectangles (
430 | Region r,
431 | Rect rect,
432 | ArrayList rl
433 | ) {
434 | int rs = regionRectIntersection (r, rect);
435 |
436 | if (rs == 0) // No intersection with rect.
437 | return;
438 |
439 | if (rs == 1) { // Full intersection with rect.
440 | rl.add (rect);
441 | return;
442 | }
443 |
444 | int rw = rect.width ();
445 | int rh = rect.height ();
446 |
447 | if (rw > rh) { // Split the rectangle horizontally.
448 | int cx = rect.left + rw / 2;
449 |
450 | extractRectangles (r,
451 | new Rect (rect.left, rect.top, cx, rect.bottom), rl);
452 | extractRectangles (r,
453 | new Rect (cx, rect.top, rect.right, rect.bottom), rl);
454 | } else { // Split it vertically.
455 | int cy = rect.top + rh / 2;
456 |
457 | extractRectangles (r,
458 | new Rect (rect.left, rect.top, rect.right, cy), rl);
459 | extractRectangles (r,
460 | new Rect (rect.left, cy, rect.right, rect.bottom), rl);
461 | }
462 | }
463 |
464 | /**
465 | * Check how a region intersects with a rectangle.
466 | *
467 | * @param r The region.
468 | * @param rect The rectangle.
469 | * @return 0 = no overlap; 1 = full overlap; -1 = partial overlap.
470 | */
471 | private static int
472 | regionRectIntersection (
473 | final Region r,
474 | final Rect rect
475 | ) {
476 | if (r.quickReject (rect))
477 | return 0;
478 |
479 | int icount = 0;
480 | int ocount = 0;
481 |
482 | for (int y = rect.top; y < rect.bottom; y++) {
483 | for (int x = rect.left; x < rect.right; x++)
484 | if (r.contains (x, y))
485 | icount++;
486 | else
487 | ocount++;
488 |
489 | if (icount > 0 && ocount > 0)
490 | return -1;
491 | }
492 |
493 | if (icount == 0)
494 | return 0;
495 | else if (ocount == 0)
496 | return 1;
497 |
498 | return -1;
499 | }
500 |
501 | /**
502 | * Create a region using the non-zero pixels in the pixmap.
503 | *
504 | * @param p The pixmap.
505 | * @return A region equivalent to the non-zero pixels.
506 | */
507 | private static Region
508 | createRegion (
509 | Pixmap p
510 | ) {
511 | Drawable d = p.getDrawable ();
512 | Region r = new Region ();
513 |
514 | extractRegion (r, d.getBitmap (),
515 | new Rect (0, 0, d.getWidth (), d.getHeight ()));
516 |
517 | return r;
518 | }
519 |
520 | /**
521 | * Recursively break the image contained in the rectangle into
522 | * rectangles containing non-zero pixels.
523 | *
524 | * @param region Returned region.
525 | * @param bitmap Bitmap where the pixels appear.
526 | * @param rect Rectangle containing the pixels.
527 | */
528 | private static void
529 | extractRegion (
530 | Region region,
531 | Bitmap bitmap,
532 | Rect rect
533 | ) {
534 | int nzp = checkNonZeroPixels (bitmap, rect);
535 |
536 | if (nzp == 1) // Empty.
537 | return;
538 |
539 | int rw = rect.width ();
540 | int rh = rect.height ();
541 |
542 | if (nzp == 2) { // All non-zero. We have a rectangle.
543 | region.op (rect, Region.Op.UNION);
544 | return;
545 | }
546 |
547 | if (rw > rh) { // Split the rectangle horizontally.
548 | int cx = rect.left + rw / 2;
549 |
550 | extractRegion (region, bitmap,
551 | new Rect (rect.left, rect.top, cx, rect.bottom));
552 | extractRegion (region, bitmap,
553 | new Rect (cx, rect.top, rect.right, rect.bottom));
554 | } else { // Split it vertically.
555 | int cy = rect.top + rh / 2;
556 |
557 | extractRegion (region, bitmap,
558 | new Rect (rect.left, rect.top, rect.right, cy));
559 | extractRegion (region, bitmap,
560 | new Rect (rect.left, cy, rect.right, rect.bottom));
561 | }
562 | }
563 |
564 | /**
565 | * Check the number of non-zero pixels contained in the rectangle.
566 | * Return a bit mask indicating whether all the pixels are non-zero,
567 | * none of them, or a mix.
568 | *
569 | * @param bitmap The bitmap containing the pixels.
570 | * @param rect The rectangle.
571 | * @return 1 = no pixels set; 2 = all pixels set; 0 = some pixels set
572 | */
573 | private static int
574 | checkNonZeroPixels (
575 | Bitmap bitmap,
576 | Rect rect
577 | ) {
578 | final int width = rect.width ();
579 | final int height = rect.height ();
580 | int[] pixels = new int[width];
581 | int mask = 3;
582 |
583 | for (int i = 0; i < height; i++) {
584 | bitmap.getPixels (pixels, 0, width, rect.left, rect.top + i,
585 | width, 1);
586 |
587 | for (int p: pixels) {
588 | mask &= (p != 0xff000000) ? 2 : 1;
589 | if (mask == 0)
590 | return 0;
591 | }
592 | }
593 |
594 | return mask;
595 | }
596 | }
--------------------------------------------------------------------------------
/XServer/src/au/com/darkside/XServer/Xext/XTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Handles requests relating to the XTEST extension.
3 | */
4 | package au.com.darkside.XServer.Xext;
5 |
6 | import java.io.IOException;
7 |
8 | import au.com.darkside.XServer.Client;
9 | import au.com.darkside.XServer.Cursor;
10 | import au.com.darkside.XServer.ErrorCode;
11 | import au.com.darkside.XServer.InputOutput;
12 | import au.com.darkside.XServer.Resource;
13 | import au.com.darkside.XServer.ScreenView;
14 | import au.com.darkside.XServer.Util;
15 | import au.com.darkside.XServer.Window;
16 | import au.com.darkside.XServer.XServer;
17 |
18 | /**
19 | * @author mkwan
20 | *
21 | * Handles requests related to the XTEST extension.
22 | */
23 | public class XTest {
24 | private static final byte XTestGetVersion = 0;
25 | private static final byte XTestCompareCursor = 1;
26 | private static final byte XTestFakeInput = 2;
27 | private static final byte XTestGrabControl = 3;
28 |
29 | private static final byte KeyPress = 2;
30 | private static final byte KeyRelease = 3;
31 | private static final byte ButtonPress = 4;
32 | private static final byte ButtonRelease = 5;
33 | private static final byte MotionNotify = 6;
34 |
35 | /**
36 | * Process a request relating to the X SHAPE extension.
37 | *
38 | * @param xServer The X server.
39 | * @param client The remote client.
40 | * @param opcode The request's opcode.
41 | * @param arg Optional first argument.
42 | * @param bytesRemaining Bytes yet to be read in the request.
43 | * @param sequenceNumber Request sequence number.
44 | * @throws IOException
45 | */
46 | public static void
47 | processRequest (
48 | XServer xServer,
49 | Client client,
50 | byte opcode,
51 | byte arg,
52 | int bytesRemaining
53 | ) throws java.io.IOException {
54 | InputOutput io = client.getInputOutput ();
55 |
56 | switch (arg) {
57 | case XTestGetVersion:
58 | if (bytesRemaining != 4) {
59 | io.readSkip (bytesRemaining);
60 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
61 | arg, opcode, 0);
62 | } else {
63 | io.readSkip (4); // Skip client major/minor version.
64 |
65 | final byte serverMajorVersion = 2;
66 | final int serverMinorVersion = 1;
67 |
68 | synchronized (io) {
69 | Util.writeReplyHeader (client, serverMajorVersion);
70 | io.writeInt (0); // Reply length.
71 | io.writeShort ((short) serverMinorVersion);
72 | io.writePadBytes (22);
73 | }
74 | io.flush ();
75 | }
76 | break;
77 | case XTestCompareCursor:
78 | if (bytesRemaining != 8) {
79 | io.readSkip (bytesRemaining);
80 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
81 | arg, opcode, 0);
82 | } else {
83 | int wid = io.readInt ();
84 | int cid = io.readInt ();
85 | Resource r = xServer.getResource (wid);
86 |
87 | if (r == null || r.getType () != Resource.WINDOW) {
88 | ErrorCode.writeWithMinorOpcode (client,
89 | ErrorCode.Window, arg, opcode, wid);
90 | return;
91 | }
92 |
93 | Window w = (Window) r;
94 | Cursor c = w.getCursor ();
95 | boolean same;
96 |
97 | if (cid == 0) // No cursor.
98 | same = (c == null);
99 | else if (cid == 1) // CurrentCursor.
100 | same = (c == xServer.getScreen().getCurrentCursor());
101 | else
102 | same = (cid == c.getId ());
103 |
104 | synchronized (io) {
105 | Util.writeReplyHeader (client, (byte) (same ? 1 : 0));
106 | io.writeInt (0); // Reply length.
107 | io.writePadBytes (24);
108 | }
109 | io.flush ();
110 | }
111 | break;
112 | case XTestFakeInput:
113 | if (bytesRemaining != 32) {
114 | io.readSkip (bytesRemaining);
115 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
116 | arg, opcode, 0);
117 | } else {
118 | byte type = (byte) io.readByte ();
119 | int detail = io.readByte ();
120 |
121 | io.readSkip (2);
122 |
123 | int delay = io.readInt ();
124 | int wid = io.readInt ();
125 |
126 | io.readSkip (8);
127 |
128 | int x = io.readShort ();
129 | int y = io.readShort ();
130 |
131 | io.readSkip (8);
132 |
133 | Window root;
134 |
135 | if (wid == 0) {
136 | root = xServer.getScreen().getRootWindow ();
137 | } else {
138 | Resource r = (Window) xServer.getResource (wid);
139 |
140 | if (r == null || r.getType () != Resource.WINDOW) {
141 | ErrorCode.writeWithMinorOpcode (client,
142 | ErrorCode.Window, arg, opcode, wid);
143 | return;
144 | } else {
145 | root = (Window) r;
146 | }
147 | }
148 | testFakeInput (xServer, client, opcode, arg, type, detail,
149 | delay, root, x, y);
150 | }
151 | break;
152 | case XTestGrabControl:
153 | if (bytesRemaining != 4) {
154 | io.readSkip (bytesRemaining);
155 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Length,
156 | arg, opcode, 0);
157 | } else {
158 | boolean impervious = (io.readByte () != 0);
159 |
160 | io.readSkip (3);
161 | client.setImperviousToServerGrabs (impervious);
162 | }
163 | break;
164 | default:
165 | io.readSkip (bytesRemaining);
166 | ErrorCode.write (client, ErrorCode.Implementation, opcode, 0);
167 | break;
168 | }
169 | }
170 |
171 | /**
172 | * Inject a fake event.
173 | *
174 | * @param xServer The X server.
175 | * @param client The remote client.
176 | * @param opcode The request opcode, used for error reporting.
177 | * @param minorOpcode The minor opcode, used for error reporting.
178 | * @param type The event type.
179 | * @param detail Meaning depends on event type.
180 | * @param delay Millisecond delay.
181 | * @param root The root window in which motion takes place.
182 | * @param x The X coordinate of a motion event.
183 | * @param y The Y coordinate of a motion event.
184 | * @throws java.io.IOException
185 | */
186 | private static void
187 | testFakeInput (
188 | XServer xServer,
189 | Client client,
190 | byte opcode,
191 | byte minorOpcode,
192 | byte type,
193 | int detail,
194 | int delay,
195 | Window root,
196 | int x,
197 | int y
198 | ) throws java.io.IOException {
199 | if (delay != 0) {
200 | try {
201 | Thread.sleep (delay);
202 | } catch (InterruptedException e) {
203 | }
204 | }
205 |
206 | ScreenView sv = xServer.getScreen ();
207 |
208 | switch (type) {
209 | case KeyPress:
210 | sv.notifyKeyPressedReleased (detail, true);
211 | break;
212 | case KeyRelease:
213 | sv.notifyKeyPressedReleased (detail, false);
214 | break;
215 | case ButtonPress:
216 | sv.updatePointerButtons (detail, true);
217 | break;
218 | case ButtonRelease:
219 | sv.updatePointerButtons (detail, false);
220 | break;
221 | case MotionNotify:
222 | if (root != null)
223 | sv = root.getScreen ();
224 |
225 | if (detail != 0) { // Relative position.
226 | x += sv.getPointerX ();
227 | y += sv.getPointerY ();
228 | }
229 |
230 | if (x < 0)
231 | x = 0;
232 | else if (x >= sv.getWidth ())
233 | x = sv.getWidth () - 1;
234 |
235 | if (y < 0)
236 | y = 0;
237 | else if (y >= sv.getHeight ())
238 | y = sv.getHeight () - 1;
239 |
240 | sv.updatePointerPosition (x, y, 0);
241 | break;
242 | default:
243 | ErrorCode.writeWithMinorOpcode (client, ErrorCode.Value,
244 | minorOpcode, opcode, type);
245 | break;
246 | }
247 | }
248 | }
--------------------------------------------------------------------------------