Home | History | Annotate | Download | only in terminal
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.terminal;
     18 
     19 import android.graphics.Color;
     20 
     21 /**
     22  * Single terminal session backed by a pseudo terminal on the local device.
     23  */
     24 public class Terminal {
     25     public static final String TAG = "Terminal";
     26 
     27     public final int key;
     28 
     29     private static int sNumber = 0;
     30 
     31     static {
     32         System.loadLibrary("jni_terminal");
     33     }
     34 
     35     /**
     36      * Represents a run of one or more {@code VTermScreenCell} which all have
     37      * the same formatting.
     38      */
     39     public static class CellRun {
     40         char[] data;
     41         int dataSize;
     42         int colSize;
     43 
     44         boolean bold;
     45         int underline;
     46         boolean blink;
     47         boolean reverse;
     48         boolean strike;
     49         int font;
     50 
     51         int fg = Color.CYAN;
     52         int bg = Color.DKGRAY;
     53     }
     54 
     55     // NOTE: clients must not call back into terminal while handling a callback,
     56     // since native mutex isn't reentrant.
     57     public interface TerminalClient {
     58         public void onDamage(int startRow, int endRow, int startCol, int endCol);
     59         public void onMoveRect(int destStartRow, int destEndRow, int destStartCol, int destEndCol,
     60                 int srcStartRow, int srcEndRow, int srcStartCol, int srcEndCol);
     61         public void onMoveCursor(int posRow, int posCol, int oldPosRow, int oldPosCol, int visible);
     62         public void onBell();
     63     }
     64 
     65     private final long mNativePtr;
     66     private final Thread mThread;
     67 
     68     private String mTitle;
     69 
     70     private TerminalClient mClient;
     71 
     72     private boolean mCursorVisible;
     73     private int mCursorRow;
     74     private int mCursorCol;
     75 
     76     private final TerminalCallbacks mCallbacks = new TerminalCallbacks() {
     77         @Override
     78         public int damage(int startRow, int endRow, int startCol, int endCol) {
     79             if (mClient != null) {
     80                 mClient.onDamage(startRow, endRow, startCol, endCol);
     81             }
     82             return 1;
     83         }
     84 
     85         @Override
     86         public int moveRect(int destStartRow, int destEndRow, int destStartCol, int destEndCol,
     87                 int srcStartRow, int srcEndRow, int srcStartCol, int srcEndCol) {
     88             if (mClient != null) {
     89                 mClient.onMoveRect(destStartRow, destEndRow, destStartCol, destEndCol, srcStartRow,
     90                         srcEndRow, srcStartCol, srcEndCol);
     91             }
     92             return 1;
     93         }
     94 
     95         @Override
     96         public int moveCursor(int posRow, int posCol, int oldPosRow, int oldPosCol, int visible) {
     97             mCursorVisible = (visible != 0);
     98             mCursorRow = posRow;
     99             mCursorCol = posCol;
    100             if (mClient != null) {
    101                 mClient.onMoveCursor(posRow, posCol, oldPosRow, oldPosCol, visible);
    102             }
    103             return 1;
    104         }
    105 
    106         @Override
    107         public int bell() {
    108             if (mClient != null) {
    109                 mClient.onBell();
    110             }
    111             return 1;
    112         }
    113     };
    114 
    115     public Terminal() {
    116         mNativePtr = nativeInit(mCallbacks);
    117         key = sNumber++;
    118         mTitle = TAG + " " + key;
    119         mThread = new Thread(mTitle) {
    120             @Override
    121             public void run() {
    122                 nativeRun(mNativePtr);
    123             }
    124         };
    125     }
    126 
    127     /**
    128      * Start thread which internally forks and manages the pseudo terminal.
    129      */
    130     public void start() {
    131         mThread.start();
    132     }
    133 
    134     public void destroy() {
    135         if (nativeDestroy(mNativePtr) != 0) {
    136             throw new IllegalStateException("destroy failed");
    137         }
    138     }
    139 
    140     public void setClient(TerminalClient client) {
    141         mClient = client;
    142     }
    143 
    144     public void resize(int rows, int cols, int scrollRows) {
    145         if (nativeResize(mNativePtr, rows, cols, scrollRows) != 0) {
    146             throw new IllegalStateException("resize failed");
    147         }
    148     }
    149 
    150     public int getRows() {
    151         return nativeGetRows(mNativePtr);
    152     }
    153 
    154     public int getCols() {
    155         return nativeGetCols(mNativePtr);
    156     }
    157 
    158     public int getScrollRows() {
    159         return nativeGetScrollRows(mNativePtr);
    160     }
    161 
    162     public void getCellRun(int row, int col, CellRun run) {
    163         if (nativeGetCellRun(mNativePtr, row, col, run) != 0) {
    164             throw new IllegalStateException("getCell failed");
    165         }
    166     }
    167 
    168     public boolean getCursorVisible() {
    169         return mCursorVisible;
    170     }
    171 
    172     public int getCursorRow() {
    173         return mCursorRow;
    174     }
    175 
    176     public int getCursorCol() {
    177         return mCursorCol;
    178     }
    179 
    180     public String getTitle() {
    181         // TODO: hook up to title passed through termprop
    182         return mTitle;
    183     }
    184 
    185     public boolean dispatchKey(int modifiers, int key) {
    186         return nativeDispatchKey(mNativePtr, modifiers, key);
    187     }
    188 
    189     public boolean dispatchCharacter(int modifiers, int character) {
    190         return nativeDispatchCharacter(mNativePtr, modifiers, character);
    191     }
    192 
    193     private static native long nativeInit(TerminalCallbacks callbacks);
    194     private static native int nativeDestroy(long ptr);
    195 
    196     private static native int nativeRun(long ptr);
    197     private static native int nativeResize(long ptr, int rows, int cols, int scrollRows);
    198     private static native int nativeGetCellRun(long ptr, int row, int col, CellRun run);
    199     private static native int nativeGetRows(long ptr);
    200     private static native int nativeGetCols(long ptr);
    201     private static native int nativeGetScrollRows(long ptr);
    202 
    203     private static native boolean nativeDispatchKey(long ptr, int modifiers, int key);
    204     private static native boolean nativeDispatchCharacter(long ptr, int modifiers, int character);
    205 }
    206