1ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey/*
2ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project
3ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey *
4ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * you may not use this file except in compliance with the License.
6ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * You may obtain a copy of the License at
7ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey *
8ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey *
10ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * See the License for the specific language governing permissions and
14ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * limitations under the License.
15ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey */
16ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
17ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#define LOG_TAG "Terminal"
18ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
19ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include <utils/Log.h>
2000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#include <utils/Mutex.h>
2100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#include "android_runtime/AndroidRuntime.h"
2200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
23ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include "jni.h"
24ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include "JNIHelp.h"
25479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey#include "ScopedLocalRef.h"
26479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey#include "ScopedPrimitiveArray.h"
27ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
289a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright#include <fcntl.h>
29ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes#include <pty.h>
309a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright#include <stdio.h>
315d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey#include <termios.h>
329a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright#include <unistd.h>
335d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey#include <util.h>
345d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey#include <utmp.h>
355d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
36ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include <vterm.h>
37ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
38ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey#include <string.h>
39ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
40c8be1790590605603a8dca8f9ee93327c916de3fMichael Wright#define USE_TEST_SHELL 0
41de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#define DEBUG_CALLBACKS 0
42de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#define DEBUG_IO 0
4300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#define DEBUG_SCROLLBACK 0
44a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey
45ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeynamespace android {
46ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
478c040334130cea6e44dda03516d86e774d18d376Kenny Root/*
488c040334130cea6e44dda03516d86e774d18d376Kenny Root * Callback class reference
498c040334130cea6e44dda03516d86e774d18d376Kenny Root */
508c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jclass terminalCallbacksClass;
518c040334130cea6e44dda03516d86e774d18d376Kenny Root
528c040334130cea6e44dda03516d86e774d18d376Kenny Root/*
538c040334130cea6e44dda03516d86e774d18d376Kenny Root * Callback methods
548c040334130cea6e44dda03516d86e774d18d376Kenny Root */
558c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID damageMethod;
568c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID moveRectMethod;
578c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID moveCursorMethod;
588c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID setTermPropBooleanMethod;
598c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID setTermPropIntMethod;
608c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID setTermPropStringMethod;
618c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID setTermPropColorMethod;
628c040334130cea6e44dda03516d86e774d18d376Kenny Rootstatic jmethodID bellMethod;
638c040334130cea6e44dda03516d86e774d18d376Kenny Root
64410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey/*
659cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey * CellRun class
66410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey */
679cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkeystatic jclass cellRunClass;
689cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkeystatic jfieldID cellRunDataField;
699cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkeystatic jfieldID cellRunDataSizeField;
709cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkeystatic jfieldID cellRunColSizeField;
71cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkeystatic jfieldID cellRunFgField;
72cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkeystatic jfieldID cellRunBgField;
73cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey
7400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeytypedef short unsigned int dimen_t;
7500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
7600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyclass ScrollbackLine {
7700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeypublic:
7800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    inline ScrollbackLine(dimen_t _cols) : cols(_cols) {
7900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        mCells = new VTermScreenCell[cols];
8000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    };
8100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    inline ~ScrollbackLine() {
8200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        delete mCells;
8300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
8400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
8500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    inline dimen_t copyFrom(dimen_t cols, const VTermScreenCell* cells) {
8600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        dimen_t n = this->cols > cols ? cols : this->cols;
8700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        memcpy(mCells, cells, sizeof(VTermScreenCell) * n);
8800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        return n;
8900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
9000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
9100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    inline dimen_t copyTo(dimen_t cols, VTermScreenCell* cells) {
9200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        dimen_t n = cols > this->cols ? this->cols : cols;
9300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        memcpy(cells, mCells, sizeof(VTermScreenCell) * n);
9400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        return n;
9500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
9600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
9700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    inline void getCell(dimen_t col, VTermScreenCell* cell) {
9800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        *cell = mCells[col];
9900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
10000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
10100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    const dimen_t cols;
10200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
10300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyprivate:
10400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    VTermScreenCell* mCells;
10500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey};
10600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
1078c040334130cea6e44dda03516d86e774d18d376Kenny Root/*
1088c040334130cea6e44dda03516d86e774d18d376Kenny Root * Terminal session
1098c040334130cea6e44dda03516d86e774d18d376Kenny Root */
1108c040334130cea6e44dda03516d86e774d18d376Kenny Rootclass Terminal {
1118c040334130cea6e44dda03516d86e774d18d376Kenny Rootpublic:
112d3090cb2c2ca1d6a2441c3bd1413da129ceadc38Tom Marshall    Terminal(jobject callbacks);
1138c040334130cea6e44dda03516d86e774d18d376Kenny Root    ~Terminal();
1148c040334130cea6e44dda03516d86e774d18d376Kenny Root
11500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    status_t run();
116479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey
1175d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    size_t write(const char *bytes, size_t len);
118410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
119c8be1790590605603a8dca8f9ee93327c916de3fMichael Wright    bool dispatchCharacter(int mod, int character);
120c8be1790590605603a8dca8f9ee93327c916de3fMichael Wright    bool dispatchKey(int mod, int key);
121c8be1790590605603a8dca8f9ee93327c916de3fMichael Wright    bool flushInput();
122007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright
12300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    status_t resize(dimen_t rows, dimen_t cols, dimen_t scrollRows);
12400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
12500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    status_t onPushline(dimen_t cols, const VTermScreenCell* cells);
12600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    status_t onPopline(dimen_t cols, VTermScreenCell* cells);
127a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey
12800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    void getCellLocked(VTermPos pos, VTermScreenCell* cell);
1295d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
13000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    dimen_t getRows() const;
13100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    dimen_t getCols() const;
13200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    dimen_t getScrollRows() const;
1338c040334130cea6e44dda03516d86e774d18d376Kenny Root
1348c040334130cea6e44dda03516d86e774d18d376Kenny Root    jobject getCallbacks() const;
1358c040334130cea6e44dda03516d86e774d18d376Kenny Root
13600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    // Lock protecting mutations of internal libvterm state
13700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    Mutex mLock;
13800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
1398c040334130cea6e44dda03516d86e774d18d376Kenny Rootprivate:
1405d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    int mMasterFd;
14100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    pid_t mChildPid;
1428c040334130cea6e44dda03516d86e774d18d376Kenny Root    VTerm *mVt;
1438c040334130cea6e44dda03516d86e774d18d376Kenny Root    VTermScreen *mVts;
1448c040334130cea6e44dda03516d86e774d18d376Kenny Root
145410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    jobject mCallbacks;
1468c040334130cea6e44dda03516d86e774d18d376Kenny Root
14700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    dimen_t mRows;
14800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    dimen_t mCols;
14900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    bool mKilled;
1508c040334130cea6e44dda03516d86e774d18d376Kenny Root
15100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    ScrollbackLine **mScroll;
15200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    dimen_t mScrollCur;
15300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    dimen_t mScrollSize;
1548c040334130cea6e44dda03516d86e774d18d376Kenny Root
15500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey};
156ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
157ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey/*
158ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * VTerm event handlers
159ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey */
160ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
161ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_damage(VTermRect rect, void *user) {
162ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
163de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if DEBUG_CALLBACKS
164ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_damage");
165de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#endif
1668c040334130cea6e44dda03516d86e774d18d376Kenny Root
16700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    JNIEnv* env = AndroidRuntime::getJNIEnv();
1688c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env->CallIntMethod(term->getCallbacks(), damageMethod, rect.start_row, rect.end_row,
1698c040334130cea6e44dda03516d86e774d18d376Kenny Root            rect.start_col, rect.end_col);
170ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
171ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
172ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_moverect(VTermRect dest, VTermRect src, void *user) {
173ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
174de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if DEBUG_CALLBACKS
175ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_moverect");
176de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#endif
1778c040334130cea6e44dda03516d86e774d18d376Kenny Root
17800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    JNIEnv* env = AndroidRuntime::getJNIEnv();
1796a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey    return env->CallIntMethod(term->getCallbacks(), moveRectMethod,
1806a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey            dest.start_row, dest.end_row, dest.start_col, dest.end_col,
1816a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey            src.start_row, src.end_row, src.start_col, src.end_col);
182ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
183ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
184ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) {
185ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
186de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if DEBUG_CALLBACKS
187ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_movecursor");
188de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#endif
1898c040334130cea6e44dda03516d86e774d18d376Kenny Root
19000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    JNIEnv* env = AndroidRuntime::getJNIEnv();
1916a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey    return env->CallIntMethod(term->getCallbacks(), moveCursorMethod, pos.row,
1926a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey            pos.col, oldpos.row, oldpos.col, visible);
193ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
194ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
195ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_settermprop(VTermProp prop, VTermValue *val, void *user) {
196ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
197de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if DEBUG_CALLBACKS
198ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_settermprop");
199de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#endif
2008c040334130cea6e44dda03516d86e774d18d376Kenny Root
20100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    JNIEnv* env = AndroidRuntime::getJNIEnv();
2028c040334130cea6e44dda03516d86e774d18d376Kenny Root    switch (vterm_get_prop_type(prop)) {
2038c040334130cea6e44dda03516d86e774d18d376Kenny Root    case VTERM_VALUETYPE_BOOL:
204ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes        return env->CallIntMethod(term->getCallbacks(), setTermPropBooleanMethod, prop,
205ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes                val->boolean ? JNI_TRUE : JNI_FALSE);
2068c040334130cea6e44dda03516d86e774d18d376Kenny Root    case VTERM_VALUETYPE_INT:
2078c040334130cea6e44dda03516d86e774d18d376Kenny Root        return env->CallIntMethod(term->getCallbacks(), setTermPropIntMethod, prop, val->number);
2088c040334130cea6e44dda03516d86e774d18d376Kenny Root    case VTERM_VALUETYPE_STRING:
2098c040334130cea6e44dda03516d86e774d18d376Kenny Root        return env->CallIntMethod(term->getCallbacks(), setTermPropStringMethod, prop,
2108c040334130cea6e44dda03516d86e774d18d376Kenny Root                env->NewStringUTF(val->string));
2118c040334130cea6e44dda03516d86e774d18d376Kenny Root    case VTERM_VALUETYPE_COLOR:
2128c040334130cea6e44dda03516d86e774d18d376Kenny Root        return env->CallIntMethod(term->getCallbacks(), setTermPropIntMethod, prop, val->color.red,
2138c040334130cea6e44dda03516d86e774d18d376Kenny Root                val->color.green, val->color.blue);
2148c040334130cea6e44dda03516d86e774d18d376Kenny Root    default:
2158c040334130cea6e44dda03516d86e774d18d376Kenny Root        ALOGE("unknown callback type");
2168c040334130cea6e44dda03516d86e774d18d376Kenny Root        return 0;
2178c040334130cea6e44dda03516d86e774d18d376Kenny Root    }
218ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
219ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
220ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_setmousefunc(VTermMouseFunc func, void *data, void *user) {
221ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
222de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if DEBUG_CALLBACKS
223ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_setmousefunc");
224de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#endif
225ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    return 1;
226ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
227ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
228ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic int term_bell(void *user) {
229ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
230de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if DEBUG_CALLBACKS
231ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    ALOGW("term_bell");
232de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#endif
2338c040334130cea6e44dda03516d86e774d18d376Kenny Root
23400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    JNIEnv* env = AndroidRuntime::getJNIEnv();
2358c040334130cea6e44dda03516d86e774d18d376Kenny Root    return env->CallIntMethod(term->getCallbacks(), bellMethod);
236ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
237ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
23800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeystatic int term_sb_pushline(int cols, const VTermScreenCell *cells, void *user) {
239ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
240de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if DEBUG_CALLBACKS
24100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    ALOGW("term_sb_pushline");
242de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#endif
2438c040334130cea6e44dda03516d86e774d18d376Kenny Root
24400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return term->onPushline(cols, cells);
24500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey}
2468c040334130cea6e44dda03516d86e774d18d376Kenny Root
24700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeystatic int term_sb_popline(int cols, VTermScreenCell *cells, void *user) {
24800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(user);
24900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#if DEBUG_CALLBACKS
25000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    ALOGW("term_sb_popline");
25100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#endif
25200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
25300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return term->onPopline(cols, cells);
254ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
255ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
256ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic VTermScreenCallbacks cb = {
257ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .damage = term_damage,
258ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .moverect = term_moverect,
259ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .movecursor = term_movecursor,
260ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .settermprop = term_settermprop,
261ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .setmousefunc = term_setmousefunc,
262ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    .bell = term_bell,
26300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    // Resize requests are applied immediately, so callback is ignored
26400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    .resize = NULL,
26500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    .sb_pushline = term_sb_pushline,
26600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    .sb_popline = term_sb_popline,
267ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey};
268ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
269d3090cb2c2ca1d6a2441c3bd1413da129ceadc38Tom MarshallTerminal::Terminal(jobject callbacks) :
270d3090cb2c2ca1d6a2441c3bd1413da129ceadc38Tom Marshall        mCallbacks(callbacks), mRows(25), mCols(80), mKilled(false),
27100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        mScrollCur(0), mScrollSize(100) {
27200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    JNIEnv* env = AndroidRuntime::getJNIEnv();
27300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    mCallbacks = env->NewGlobalRef(callbacks);
27400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
27500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    mScroll = new ScrollbackLine*[mScrollSize];
27600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    memset(mScroll, 0, sizeof(ScrollbackLine*) * mScrollSize);
27700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
278ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    /* Create VTerm */
279d3090cb2c2ca1d6a2441c3bd1413da129ceadc38Tom Marshall    mVt = vterm_new(mRows, mCols);
280ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    vterm_parser_set_utf8(mVt, 1);
281ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
282ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    /* Set up screen */
283ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    mVts = vterm_obtain_screen(mVt);
284ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    vterm_screen_enable_altscreen(mVts, 1);
285ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    vterm_screen_set_callbacks(mVts, &cb, this);
2866a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey    vterm_screen_set_damage_merge(mVts, VTERM_DAMAGE_SCROLL);
287479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey    vterm_screen_reset(mVts, 1);
288479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey}
289ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
290479bd643981271fb0edf756ae5915e44a7352c4dJeff SharkeyTerminal::~Terminal() {
291479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey    close(mMasterFd);
29200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    ::kill(mChildPid, SIGHUP);
29300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
294479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey    vterm_free(mVt);
29500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
29600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    delete mScroll;
29700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
29800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    JNIEnv *env = AndroidRuntime::getJNIEnv();
29900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    env->DeleteGlobalRef(mCallbacks);
300479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey}
301479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey
30200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeystatus_t Terminal::run() {
303ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes    struct termios termios;
304ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes    memset(&termios, 0, sizeof(termios));
305ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes    termios.c_iflag = ICRNL|IXON|IUTF8;
306ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes    termios.c_oflag = OPOST|ONLCR|NL0|CR0|TAB0|BS0|VT0|FF0;
307ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes    termios.c_cflag = CS8|CREAD;
308ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes    termios.c_lflag = ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK;
3095d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
3109a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    cfsetispeed(&termios, B38400);
3119a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    cfsetospeed(&termios, B38400);
3129a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright
3139a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VINTR]    = 0x1f & 'C';
3149a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VQUIT]    = 0x1f & '\\';
3159a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VERASE]   = 0x7f;
3169a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VKILL]    = 0x1f & 'U';
3179a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VEOF]     = 0x1f & 'D';
3189a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VSTART]   = 0x1f & 'Q';
3199a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VSTOP]    = 0x1f & 'S';
3209a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VSUSP]    = 0x1f & 'Z';
3219a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VREPRINT] = 0x1f & 'R';
3229a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VWERASE]  = 0x1f & 'W';
3239a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VLNEXT]   = 0x1f & 'V';
3249a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VMIN]     = 1;
3259a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    termios.c_cc[VTIME]    = 0;
3269a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright
3279a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    struct winsize size = { mRows, mCols, 0, 0 };
3289a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright
3299a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    int stderr_save_fd = dup(2);
3309a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    if (stderr_save_fd < 0) {
3319a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        ALOGE("failed to dup stderr - %s", strerror(errno));
3329a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    }
3339a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright
33400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    mChildPid = forkpty(&mMasterFd, NULL, &termios, &size);
33500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (mChildPid == 0) {
3369a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        /* Restore the ISIG signals back to defaults */
3379a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        signal(SIGINT, SIG_DFL);
3389a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        signal(SIGQUIT, SIG_DFL);
3399a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        signal(SIGSTOP, SIG_DFL);
3409a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        signal(SIGCONT, SIG_DFL);
3419a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright
3429a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        FILE *stderr_save = fdopen(stderr_save_fd, "a");
3439a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright
3449a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        if (!stderr_save) {
3459a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright            ALOGE("failed to open stderr - %s", strerror(errno));
3469a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        }
3479a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright
348ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes        // We know execvp(2) won't actually try to modify this.
349ffbad51da16422bab578c6616a714ad05ae20d73Elliott Hughes        char *shell = const_cast<char*>("/system/bin/sh");
350de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if USE_TEST_SHELL
35100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        char *args[4] = {shell, "-c", "x=1; c=0; while true; do echo -e \"stop \e[00;3${c}mechoing\e[00m yourself! ($x)\"; x=$(( $x + 1 )); c=$((($c+1)%7)); if [ $x -gt 110 ]; then sleep 0.5; fi; done", NULL};
352a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey#else
3539a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        char *args[2] = {shell, NULL};
354a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey#endif
355a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey
3569a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        execvp(shell, args);
3579a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        fprintf(stderr_save, "Cannot exec(%s) - %s\n", shell, strerror(errno));
3589a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright        _exit(1);
3599a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright    }
3609a0032b22232e66c29d49091dbdc6c8ea87a3785Michael Wright
361cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey    ALOGD("entering read() loop");
362d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey    while (1) {
363d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey        char buffer[4096];
364d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey        ssize_t bytes = ::read(mMasterFd, buffer, sizeof buffer);
365de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#if DEBUG_IO
366de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey        ALOGD("read() returned %d bytes", bytes);
367de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey#endif
368d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey
36900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        if (mKilled) {
37000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            ALOGD("kill() requested");
371de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey            break;
372de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey        }
373479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey        if (bytes == 0) {
374479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey            ALOGD("read() found EOF");
375479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey            break;
376d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey        }
377479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey        if (bytes == -1) {
378479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey            ALOGE("read() failed: %s", strerror(errno));
379d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey            return 1;
380d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey        }
381d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey
38200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        {
38300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            Mutex::Autolock lock(mLock);
38400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            vterm_push_bytes(mVt, buffer, bytes);
38500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            vterm_screen_flush_damage(mVts);
38600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        }
387d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey    }
388479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey
389de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey    return 0;
390de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey}
391de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey
392479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkeysize_t Terminal::write(const char *bytes, size_t len) {
393479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey    return ::write(mMasterFd, bytes, len);
394479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey}
395479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey
396c8be1790590605603a8dca8f9ee93327c916de3fMichael Wrightbool Terminal::dispatchCharacter(int mod, int character) {
39700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    Mutex::Autolock lock(mLock);
398303dab01fa211d0da20136049196e3321241cad8Michael Wright    vterm_input_push_char(mVt, static_cast<VTermModifier>(mod), character);
399c8be1790590605603a8dca8f9ee93327c916de3fMichael Wright    return flushInput();
400007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright}
401007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright
402c8be1790590605603a8dca8f9ee93327c916de3fMichael Wrightbool Terminal::dispatchKey(int mod, int key) {
40300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    Mutex::Autolock lock(mLock);
404007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright    vterm_input_push_key(mVt, static_cast<VTermModifier>(mod), static_cast<VTermKey>(key));
405c8be1790590605603a8dca8f9ee93327c916de3fMichael Wright    return flushInput();
406007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright}
407007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright
408c8be1790590605603a8dca8f9ee93327c916de3fMichael Wrightbool Terminal::flushInput() {
409007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright    size_t len = vterm_output_get_buffer_current(mVt);
410007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright    if (len) {
411007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright        char buf[len];
412007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright        len = vterm_output_bufferread(mVt, buf, len);
413c8be1790590605603a8dca8f9ee93327c916de3fMichael Wright        return len == write(buf, len);
414007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright    }
415c8be1790590605603a8dca8f9ee93327c916de3fMichael Wright    return true;
416007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright}
417007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright
41800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeystatus_t Terminal::resize(dimen_t rows, dimen_t cols, dimen_t scrollRows) {
41900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    Mutex::Autolock lock(mLock);
420a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey
42100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    ALOGD("resize(%d, %d, %d)", rows, cols, scrollRows);
422cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey
4235d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    mRows = rows;
4245d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    mCols = cols;
42500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    // TODO: resize scrollback
426cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey
4275d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    struct winsize size = { rows, cols, 0, 0 };
4285d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    ioctl(mMasterFd, TIOCSWINSZ, &size);
429cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey
430cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey    vterm_set_size(mVt, rows, cols);
431cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey    vterm_screen_flush_damage(mVts);
432cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey
433410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return 0;
434410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey}
435410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
43600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeystatus_t Terminal::onPushline(dimen_t cols, const VTermScreenCell* cells) {
43700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    ScrollbackLine* line = NULL;
43800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (mScrollCur == mScrollSize) {
43900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        /* Recycle old row if it's the right size */
44000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        if (mScroll[mScrollCur - 1]->cols == cols) {
44100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            line = mScroll[mScrollCur - 1];
44200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        } else {
44300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            delete mScroll[mScrollCur - 1];
44400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        }
44500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
44600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        memmove(mScroll + 1, mScroll, sizeof(ScrollbackLine*) * (mScrollCur - 1));
44700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    } else if (mScrollCur > 0) {
44800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        memmove(mScroll + 1, mScroll, sizeof(ScrollbackLine*) * mScrollCur);
44900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
45000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
45100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (line == NULL) {
45200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        line = new ScrollbackLine(cols);
45300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
45400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
45500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    mScroll[0] = line;
45600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
45700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (mScrollCur < mScrollSize) {
45800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        mScrollCur++;
45900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
46000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
46100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    line->copyFrom(cols, cells);
46200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return 1;
4635d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey}
4645d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
46500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeystatus_t Terminal::onPopline(dimen_t cols, VTermScreenCell* cells) {
46600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (mScrollCur == 0) {
46700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        return 0;
46800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
46900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
47000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    ScrollbackLine* line = mScroll[0];
47100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    mScrollCur--;
47200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    memmove(mScroll, mScroll + 1, sizeof(ScrollbackLine*) * mScrollCur);
47300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
47400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    dimen_t n = line->copyTo(cols, cells);
47500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    for (dimen_t col = n; col < cols; col++) {
47600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        cells[col].chars[0] = 0;
47700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        cells[col].width = 1;
47800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
47900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
48000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    delete line;
48100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return 1;
48200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey}
48300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
48400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeyvoid Terminal::getCellLocked(VTermPos pos, VTermScreenCell* cell) {
48500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    // The UI may be asking for cell data while the model is changing
48600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    // underneath it, so we always fill with meaningful data.
48700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
48800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (pos.row < 0) {
48900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        size_t scrollRow = -pos.row;
49000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        if (scrollRow > mScrollCur) {
49100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            // Invalid region above current scrollback
49200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            cell->width = 1;
49300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#if DEBUG_SCROLLBACK
49400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            cell->bg.red = 255;
49500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#endif
49600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            return;
49700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        }
49800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
49900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        ScrollbackLine* line = mScroll[scrollRow - 1];
50000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        if ((size_t) pos.col < line->cols) {
50100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            // Valid scrollback cell
50200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            line->getCell(pos.col, cell);
50300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            cell->width = 1;
50400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#if DEBUG_SCROLLBACK
50500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            cell->bg.blue = 255;
50600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#endif
50700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            return;
50800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        } else {
50900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            // Extend last scrollback cell into invalid region
51000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            line->getCell(line->cols - 1, cell);
51100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            cell->width = 1;
51200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            cell->chars[0] = ' ';
51300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#if DEBUG_SCROLLBACK
51400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            cell->bg.green = 255;
51500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#endif
51600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            return;
51700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        }
51800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
51900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
52000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if ((size_t) pos.row >= mRows) {
52100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        // Invalid region below screen
52200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        cell->width = 1;
52300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#if DEBUG_SCROLLBACK
52400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        cell->bg.red = 128;
52500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey#endif
52600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        return;
52700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    }
52800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
52900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    // Valid screen cell
53000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    vterm_screen_get_cell(mVts, pos, cell);
53100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey}
53200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
53300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeydimen_t Terminal::getRows() const {
534ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    return mRows;
535ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
536ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
53700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeydimen_t Terminal::getCols() const {
538410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return mCols;
539410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey}
540410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
54100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeydimen_t Terminal::getScrollRows() const {
54200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return mScrollSize;
54300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey}
54400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
5458c040334130cea6e44dda03516d86e774d18d376Kenny Rootjobject Terminal::getCallbacks() const {
5468c040334130cea6e44dda03516d86e774d18d376Kenny Root    return mCallbacks;
5478c040334130cea6e44dda03516d86e774d18d376Kenny Root}
5488c040334130cea6e44dda03516d86e774d18d376Kenny Root
549ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey/*
550ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey * JNI glue
551ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey */
552ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
553d3090cb2c2ca1d6a2441c3bd1413da129ceadc38Tom Marshallstatic jlong com_android_terminal_Terminal_nativeInit(JNIEnv* env, jclass clazz, jobject callbacks) {
554d3090cb2c2ca1d6a2441c3bd1413da129ceadc38Tom Marshall    return reinterpret_cast<jlong>(new Terminal(callbacks));
555d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey}
556d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey
55796403af9b78d4852f1ac86857a319e078e8fc93fColin Crossstatic jint com_android_terminal_Terminal_nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
558de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
55900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    delete term;
56000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return 0;
561de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey}
562de15e79aadde33fd8c880c19bd4fc6caca0bf795Jeff Sharkey
56396403af9b78d4852f1ac86857a319e078e8fc93fColin Crossstatic jint com_android_terminal_Terminal_nativeRun(JNIEnv* env, jclass clazz, jlong ptr) {
564a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
56500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return term->run();
566a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey}
567a76e33884c55bbd5db7e512b7687210cc3f635cfJeff Sharkey
568410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkeystatic jint com_android_terminal_Terminal_nativeResize(JNIEnv* env,
56996403af9b78d4852f1ac86857a319e078e8fc93fColin Cross        jclass clazz, jlong ptr, jint rows, jint cols, jint scrollRows) {
5705d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
57100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return term->resize(rows, cols, scrollRows);
572410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey}
573410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
57400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeystatic inline int toArgb(const VTermColor& color) {
57500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return (0xff << 24 | color.red << 16 | color.green << 8 | color.blue);
576cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey}
577cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey
57800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkeystatic inline bool isCellStyleEqual(const VTermScreenCell& a, const VTermScreenCell& b) {
57900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (toArgb(a.fg) != toArgb(b.fg)) return false;
58000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (toArgb(a.bg) != toArgb(b.bg)) return false;
58100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
58200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (a.attrs.bold != b.attrs.bold) return false;
58300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (a.attrs.underline != b.attrs.underline) return false;
58400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (a.attrs.italic != b.attrs.italic) return false;
58500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (a.attrs.blink != b.attrs.blink) return false;
58600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (a.attrs.reverse != b.attrs.reverse) return false;
58700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (a.attrs.strike != b.attrs.strike) return false;
58800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    if (a.attrs.font != b.attrs.font) return false;
58900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
590cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey    return true;
591cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey}
592cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey
5939cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkeystatic jint com_android_terminal_Terminal_nativeGetCellRun(JNIEnv* env,
59496403af9b78d4852f1ac86857a319e078e8fc93fColin Cross        jclass clazz, jlong ptr, jint row, jint col, jobject run) {
595410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
59600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    Mutex::Autolock lock(term->mLock);
597410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
5989cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    jcharArray dataArray = (jcharArray) env->GetObjectField(run, cellRunDataField);
599479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey    ScopedCharArrayRW data(env, dataArray);
600479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey    if (data.get() == NULL) {
601479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey        return -1;
602479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey    }
6039cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey
60400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    VTermScreenCell firstCell, cell;
6059cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey
606410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    VTermPos pos = {
607410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey        .row = row,
608410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey        .col = col,
609410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    };
610410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
61100b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    size_t dataSize = 0;
61200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    size_t colSize = 0;
61300b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    while ((size_t) pos.col < term->getCols()) {
61400b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        memset(&cell, 0, sizeof(VTermScreenCell));
61500b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        term->getCellLocked(pos, &cell);
616410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
617cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey        if (colSize == 0) {
61800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            env->SetIntField(run, cellRunFgField, toArgb(cell.fg));
61900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            env->SetIntField(run, cellRunBgField, toArgb(cell.bg));
62000b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            memcpy(&firstCell, &cell, sizeof(VTermScreenCell));
621cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey        } else {
62200b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey            if (!isCellStyleEqual(cell, firstCell)) {
623cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey                break;
624cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey            }
625cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey        }
626d439bacee510759728accb29ba93687a4e380eb6Jeff Sharkey
6279cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey        // Only include cell chars if they fit into run
628fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey        uint32_t rawCell = cell.chars[0];
62900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey        size_t size = (rawCell < 0x10000) ? 1 : 2;
630479bd643981271fb0edf756ae5915e44a7352c4dJeff Sharkey        if (dataSize + size <= data.size()) {
631fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey            if (rawCell < 0x10000) {
632fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey                data[dataSize++] = rawCell;
633fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey            } else {
634fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey                data[dataSize++] = (((rawCell - 0x10000) >> 10) & 0x3ff) + 0xd800;
635fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey                data[dataSize++] = ((rawCell - 0x10000) & 0x3ff) + 0xdc00;
636fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey            }
637fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey
638fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey            for (int i = 1; i < cell.width; i++) {
639fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey                data[dataSize++] = ' ';
640fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey            }
641fd6f0973405ce609964fc35b66ee355be596795dJeff Sharkey
6429cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey            colSize += cell.width;
6439cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey            pos.col += cell.width;
6449cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey        } else {
6459cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey            break;
6469cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey        }
6479cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    }
648410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
6499cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    env->SetIntField(run, cellRunDataSizeField, dataSize);
6509cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    env->SetIntField(run, cellRunColSizeField, colSize);
651410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
652410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return 0;
6535d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey}
6545d4b3955da5952d8ec2cb45e3aa5406294560798Jeff Sharkey
65596403af9b78d4852f1ac86857a319e078e8fc93fColin Crossstatic jint com_android_terminal_Terminal_nativeGetRows(JNIEnv* env, jclass clazz, jlong ptr) {
656ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
657ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    return term->getRows();
658ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
659ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
66096403af9b78d4852f1ac86857a319e078e8fc93fColin Crossstatic jint com_android_terminal_Terminal_nativeGetCols(JNIEnv* env, jclass clazz, jlong ptr) {
661410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
662410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey    return term->getCols();
663410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey}
664410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
66596403af9b78d4852f1ac86857a319e078e8fc93fColin Crossstatic jint com_android_terminal_Terminal_nativeGetScrollRows(JNIEnv* env, jclass clazz, jlong ptr) {
66600b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    Terminal* term = reinterpret_cast<Terminal*>(ptr);
66700b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey    return term->getScrollRows();
66800b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey}
66900b00812cd0c883c2380065d7fda29512d5477f0Jeff Sharkey
670c8be1790590605603a8dca8f9ee93327c916de3fMichael Wrightstatic jboolean com_android_terminal_Terminal_nativeDispatchCharacter(JNIEnv *env, jclass clazz,
67196403af9b78d4852f1ac86857a319e078e8fc93fColin Cross        jlong ptr, jint mod, jint c) {
672007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright    Terminal* term = reinterpret_cast<Terminal*>(ptr);
673007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright    return term->dispatchCharacter(mod, c);
674007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright}
675007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright
676c8be1790590605603a8dca8f9ee93327c916de3fMichael Wrightstatic jboolean com_android_terminal_Terminal_nativeDispatchKey(JNIEnv *env, jclass clazz,
67796403af9b78d4852f1ac86857a319e078e8fc93fColin Cross        jlong ptr, jint mod, jint c) {
678007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright    Terminal* term = reinterpret_cast<Terminal*>(ptr);
679007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright    return term->dispatchKey(mod, c);
680007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright}
681007efde8867b52cd5f3648173adb1a12069b6e0dMichael Wright
682ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeystatic JNINativeMethod gMethods[] = {
683d3090cb2c2ca1d6a2441c3bd1413da129ceadc38Tom Marshall    { "nativeInit", "(Lcom/android/terminal/TerminalCallbacks;)J", (void*)com_android_terminal_Terminal_nativeInit },
68496403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeDestroy", "(J)I", (void*)com_android_terminal_Terminal_nativeDestroy },
68596403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeRun", "(J)I", (void*)com_android_terminal_Terminal_nativeRun },
68696403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeResize", "(JIII)I", (void*)com_android_terminal_Terminal_nativeResize },
68796403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeGetCellRun", "(JIILcom/android/terminal/Terminal$CellRun;)I", (void*)com_android_terminal_Terminal_nativeGetCellRun },
68896403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeGetRows", "(J)I", (void*)com_android_terminal_Terminal_nativeGetRows },
68996403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeGetCols", "(J)I", (void*)com_android_terminal_Terminal_nativeGetCols },
69096403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeGetScrollRows", "(J)I", (void*)com_android_terminal_Terminal_nativeGetScrollRows },
69196403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeDispatchCharacter", "(JII)Z", (void*)com_android_terminal_Terminal_nativeDispatchCharacter},
69296403af9b78d4852f1ac86857a319e078e8fc93fColin Cross    { "nativeDispatchKey", "(JII)Z", (void*)com_android_terminal_Terminal_nativeDispatchKey },
693ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey};
694ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
695ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkeyint register_com_android_terminal_Terminal(JNIEnv* env) {
6968c040334130cea6e44dda03516d86e774d18d376Kenny Root    ScopedLocalRef<jclass> localClass(env,
6978c040334130cea6e44dda03516d86e774d18d376Kenny Root            env->FindClass("com/android/terminal/TerminalCallbacks"));
6988c040334130cea6e44dda03516d86e774d18d376Kenny Root
6998c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::terminalCallbacksClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
7008c040334130cea6e44dda03516d86e774d18d376Kenny Root
7018c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::damageMethod = env->GetMethodID(terminalCallbacksClass, "damage", "(IIII)I");
7028c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::moveRectMethod = env->GetMethodID(terminalCallbacksClass, "moveRect", "(IIIIIIII)I");
7038c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::moveCursorMethod = env->GetMethodID(terminalCallbacksClass, "moveCursor",
7046a142b6d4831c3841b6be1705fc97c9b75a7c9d1Jeff Sharkey            "(IIIII)I");
7058c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::setTermPropBooleanMethod = env->GetMethodID(terminalCallbacksClass,
7068c040334130cea6e44dda03516d86e774d18d376Kenny Root            "setTermPropBoolean", "(IZ)I");
7078c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::setTermPropIntMethod = env->GetMethodID(terminalCallbacksClass, "setTermPropInt",
7088c040334130cea6e44dda03516d86e774d18d376Kenny Root            "(II)I");
7098c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::setTermPropStringMethod = env->GetMethodID(terminalCallbacksClass, "setTermPropString",
7108c040334130cea6e44dda03516d86e774d18d376Kenny Root            "(ILjava/lang/String;)I");
7118c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::setTermPropColorMethod = env->GetMethodID(terminalCallbacksClass, "setTermPropColor",
7128c040334130cea6e44dda03516d86e774d18d376Kenny Root            "(IIII)I");
7138c040334130cea6e44dda03516d86e774d18d376Kenny Root    android::bellMethod = env->GetMethodID(terminalCallbacksClass, "bell", "()I");
7148c040334130cea6e44dda03516d86e774d18d376Kenny Root
7159cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    ScopedLocalRef<jclass> cellRunLocal(env,
7169cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey            env->FindClass("com/android/terminal/Terminal$CellRun"));
7179cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    cellRunClass = reinterpret_cast<jclass>(env->NewGlobalRef(cellRunLocal.get()));
7189cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    cellRunDataField = env->GetFieldID(cellRunClass, "data", "[C");
7199cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    cellRunDataSizeField = env->GetFieldID(cellRunClass, "dataSize", "I");
7209cae0a9616b1b71eac7e762d198fe1da47fea901Jeff Sharkey    cellRunColSizeField = env->GetFieldID(cellRunClass, "colSize", "I");
721cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey    cellRunFgField = env->GetFieldID(cellRunClass, "fg", "I");
722cedf158c17dc147163734ad1070032ff934d1b2eJeff Sharkey    cellRunBgField = env->GetFieldID(cellRunClass, "bg", "I");
723410e0da343fd581f3112037deb475db9fb0da850Jeff Sharkey
724ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey    return jniRegisterNativeMethods(env, "com/android/terminal/Terminal",
725ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey            gMethods, NELEM(gMethods));
726ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey}
727ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey
728ef946f3ae80556ab221265c0bf1c560683ea27f6Jeff Sharkey} /* namespace android */
729