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
17package com.android.terminal;
18
19import android.graphics.Color;
20
21/**
22 * Single terminal session backed by a pseudo terminal on the local device.
23 */
24public 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