Files
haiku-beta6/src/apps/terminal/TermView.cpp
T

2291 lines
42 KiB
C++
Raw Normal View History

2004-07-05 19:44:26 +00:00
/*
2005-08-12 18:00:37 +00:00
* Copyright (c) 2001-2005, Haiku, Inc.
2004-07-05 19:44:26 +00:00
* Copyright (c) 2003-4 Kian Duffy <[email protected]>
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
2005-08-12 18:00:37 +00:00
* Distributed under the terms of the MIT license.
2004-07-05 19:44:26 +00:00
*
2005-08-12 18:00:37 +00:00
* Authors:
* Kian Duffy <[email protected]>
2004-07-05 19:44:26 +00:00
*/
#include <support/Debug.h>
#include <PopUpMenu.h>
#include <ScrollBar.h>
#include <storage/Path.h>
#include <support/Beep.h>
#include <Input.h>
#include <String.h>
#include <Clipboard.h>
#include <Roster.h>
#include <Autolock.h>
#include <string.h>
#include <stdlib.h>
#include "TermView.h"
#include "TermWindow.h"
#include "TermApp.h"
#include "TermParse.h"
#include "TermBuffer.h"
#include "CodeConv.h"
#include "VTkeymap.h"
#include "TermConst.h"
#include "PrefHandler.h"
#include "MenuUtil.h"
#include "PrefView.h"
#include <termios.h>
#include <signal.h>
#include "spawn.h"
// defined VTKeyTbl.c
extern int function_keycode_table[];
extern char *function_key_char_table[];
extern int gNowCoding; /* defined TermParse.cpp */
rgb_color gTermColorTable[16] = {
{ 0, 0, 0, 0},
{255, 0, 0, 0},
{ 0, 255, 0, 0},
{255, 255, 0, 0},
{ 0, 0, 255, 0},
{255, 0, 255, 0},
{ 0, 255, 255, 0},
{255, 255, 255, 0},
};
2005-08-12 18:00:37 +00:00
// Global Preference Handler
extern PrefHandler *gTermPref;
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
TermView::TermView(BRect frame, CodeConv *inCodeConv)
:BView(frame, "termview",
2004-07-05 19:44:26 +00:00
B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS)
{
2005-08-12 18:00:37 +00:00
int rows, cols;
// Cursor reset.
fCurPos.Set(0, 0);
fCurStack.Set(0, 0);
fBufferStartPos = -1;
rows = gTermPref->getInt32(PREF_ROWS);
cols = gTermPref->getInt32(PREF_COLS);
fTermRows = rows;
fTermColumns = cols;
fCodeConv = inCodeConv;
// scroll pointer.
fTop = 0;
// create TermBuffer and CodeConv Class.
fTextBuffer = new TermBuffer(rows, cols);
// cursor Blinking and draw flag.
fCursorStatus = CURON;
fCursorDrawFlag = CURON;
fUpdateFlag = false;
fCursorBlinkingFlag = CURON;
fSelStart.Set(-1, -1);
fSelEnd.Set(-1, -1);
fSelected = false;
fMouseTracking = false;
// scroll bar varriables.
fScrollUpCount = 0;
fScrollBarRange = 0;
fScrRegionSet = 0;
fScrBufSize = gTermPref->getInt32(PREF_HISTORY_SIZE);
// resize flag.
fFrameResized = 0;
// terminal mode flag.
fInsertModeFlag = MODE_OVER;
fInverseFlag = fBoldFlag = fUnderlineFlag = 0;
// terminal scroll flag.
fScrTop = 0;
fScrBot = rows - 1;
fPopMenu = NULL;
SetMouseButton();
SetMouseCursor();
fPreviousMousePoint.Set(0, 0);
// SetIMAware(gTermPref->getInt32(PREF_IM_AWARE));
fIMflag = false;
fViewThread = -1;
fMouseThread = -1;
fQuitting = 1;
InitViewThread();
fDrawRect_p = 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
TermView::~TermView()
2004-07-05 19:44:26 +00:00
{
// delete InputMessenger;
delete fTextBuffer;
fQuitting = 0;
2005-08-12 18:00:37 +00:00
kill_thread(fViewThread);
kill_thread(fMouseThread);
delete_sem(fDrawRectSem);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Get width and height for terminal font
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::GetFontSize(int *width, int *height)
2004-07-05 19:44:26 +00:00
{
*width = fFontWidth;
*height = fFontHeight;
}
2005-08-12 18:00:37 +00:00
// Set number of rows and columns in terminal
2004-07-05 19:44:26 +00:00
BRect
2005-08-12 18:00:37 +00:00
TermView::SetTermSize(int rows, int cols, bool flag)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(rows)
fTermRows = rows;
if(cols)
fTermColumns = cols;
fTextBuffer->ResizeTo(fTermRows, fTermColumns, 0);
fScrTop = 0;
fScrBot = fTermRows - 1;
BRect r(0, 0,
fTermColumns * fFontWidth,
fTermRows * fFontHeight);
if(flag) {
ResizeTo(fTermColumns * fFontWidth -1,
fTermRows * fFontHeight -1);
}
Invalidate(Frame());
return r;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Set mouse button assignments
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetMouseButton(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
mSelectButton = SetupMouseButton(gTermPref->getString(PREF_SELECT_MBUTTON));
mSubMenuButton = SetupMouseButton(gTermPref->getString(PREF_SUBMENU_MBUTTON));
mPasteMenuButton = SetupMouseButton(gTermPref->getString(PREF_PASTE_MBUTTON));
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Sets the mouse cursor image
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetMouseCursor(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(!strcmp(gTermPref->getString(PREF_MOUSE_IMAGE), "Hand cursor"))
fMouseImage = false;
else
fMouseImage = true;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Sets colors for the terminal
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetTermColor(void)
{
fTextForeColor = gTermPref->getRGB(PREF_TEXT_FORE_COLOR);
fTextBackColor = gTermPref->getRGB(PREF_TEXT_BACK_COLOR);
fSelectForeColor = gTermPref->getRGB(PREF_SELECT_FORE_COLOR);
fSelectBackColor = gTermPref->getRGB(PREF_SELECT_BACK_COLOR);
fCursorForeColor = gTermPref->getRGB(PREF_CURSOR_FORE_COLOR);
fCursorBackColor = gTermPref->getRGB(PREF_CURSOR_BACK_COLOR);
SetLowColor(fTextBackColor);
SetViewColor(fTextBackColor);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Sets half and full fonts for terminal
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetTermFont(BFont *halfFont, BFont *fullFont)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
char buf[4];
int halfWidth = 0;
fHalfFont = halfFont;
fFullFont = fullFont;
// calculate half font's max width
// Not Bounding, check only A-Z(For case of fHalfFont is KanjiFont. )
for(int c = 0x20 ; c <= 0x7e; c++){
sprintf(buf, "%c", c);
int tmpWidth =(int)fHalfFont.StringWidth(buf);
if(tmpWidth > halfWidth)
halfWidth = tmpWidth;
}
// How to calculate FullWidth ?
fFontWidth = halfWidth;
// Second, Calc Font Height
font_height fh, hh;
fHalfFont.GetHeight(&hh);
fFullFont.GetHeight(&fh);
int font_ascent, font_descent,font_leading;
font_ascent =(int)((fh.ascent > hh.ascent) ? fh.ascent : hh.ascent);
font_descent =(int)((fh.descent > hh.descent) ? fh.descent : hh.descent);
font_leading =(int)((fh.leading > hh.leading) ? fh.leading : hh.leading);
if(font_leading == 0)
font_leading = 1;
if(fTop)
fTop = fTop / fFontHeight;
fFontHeight = font_ascent + font_descent + font_leading + 1;
fTop = fTop * fFontHeight;
fFontAscent = font_ascent;
fCursorHeight = font_ascent + font_descent + font_leading + 1;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// set scrollbar object to assigned value
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetScrollBar(BScrollBar *scrbar)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
fScrollBar = scrbar;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Print one character
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::PutChar(uchar *string, ushort attr, int width)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(width == FULL_WIDTH)
attr |= A_WIDTH;
// check column over flow.
if((fCurPos.x + width) > fTermColumns) {
UpdateLine();
fCurPos.x = 0;
if(fCurPos.y == fTermRows -1)
ScrollScreen();
else
fCurPos.y++;
}
if(fInsertModeFlag == MODE_INSERT)
fTextBuffer->InsertSpace(fCurPos, width);
fTextBuffer->WriteChar(fCurPos, string, attr);
if(fUpdateFlag == false)
fBufferStartPos = fCurPos.x;
fCurPos.x += width;
fUpdateFlag = true;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Print a CR and move the cursor
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::PutCR(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fTextBuffer->WriteCR(fCurPos);
fCurPos.x = 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Print a LF and move the cursor
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::PutLF(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
if(fScrRegionSet)
if(fCurPos.y == fScrBot) {
ScrollRegion(-1, -1, SCRUP, 1);
return;
}
if(fCurPos.x != fTermColumns){
if(fCurPos.y == fTermRows -1)
ScrollScreen();
else
fCurPos.y++;
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Print a NL and move the cursor
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::PutNL(int num)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
ScrollRegion(fCurPos.y, -1, SCRDOWN, num);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Print a space
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::InsertSpace(int num)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fTextBuffer->InsertSpace(fCurPos, num);
TermDraw(fCurPos, CurPos(fTermColumns - 1, fCurPos.y));
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Set or reset Insert mode
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetInsertMode(int flag)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fInsertModeFlag = flag;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Draw region
2004-07-05 19:44:26 +00:00
inline int
2005-08-12 18:00:37 +00:00
TermView::TermDraw(const CurPos &start, const CurPos &end)
{
int x1 = start.x;
int y1 = start.y;
int x2 = end.x;
int y2 = end.y;
// Send Draw Rectangle data to Draw Engine thread.
SendDataToDrawEngine(x1, y1 + fTop / fFontHeight,
x2, y2 + fTop / fFontHeight);
return 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Draw region
2004-07-05 19:44:26 +00:00
int
2005-08-12 18:00:37 +00:00
TermView::TermDrawSelectedRegion(CurPos start, CurPos end)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
CurPos inPos;
if(end < start) {
inPos = start;
start = end;
end = inPos;
}
if(start.y == end.y) {
SendDataToDrawEngine(start.x, start.y,
end.x, end.y);
} else {
SendDataToDrawEngine(start.x, start.y,
fTermColumns, start.y);
if(end.y - start.y > 0)
SendDataToDrawEngine(0, start.y + 1, fTermColumns, end.y - 1);
SendDataToDrawEngine(0, end.y,
end.x, end.y);
}
return 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Draw region
2004-07-05 19:44:26 +00:00
int
2005-08-12 18:00:37 +00:00
TermView::TermDrawRegion(CurPos start, CurPos end)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
CurPos inPos;
int top = fTop / fFontHeight;
if(end < start) {
inPos = start;
start = end;
end = inPos;
}
start.y += top;
end.y += top;
if(start.y == end.y) {
SendDataToDrawEngine(start.x, start.y,
end.x, end.y);
} else {
SendDataToDrawEngine(start.x, start.y,
fTermColumns - 1, start.y);
if(end.y - start.y > 0) {
SendDataToDrawEngine(0, start.y + 1,
fTermColumns - 1, end.y - 1);
}
SendDataToDrawEngine(0, end.y,
end.x, end.y);
}
return 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Erase below cursor below.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::EraseBelow(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fTextBuffer->EraseBelow(fCurPos);
TermDraw(fCurPos, CurPos(fTermColumns - 1, fCurPos.y));
if(fCurPos.y != fTermRows - 1)
TermDraw(CurPos(0, fCurPos.y + 1), CurPos(fTermColumns - 1, fTermRows - 1));
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Delete num characters from current position.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::DeleteChar(int num)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fTextBuffer->DeleteChar(fCurPos, num);
TermDraw(fCurPos, CurPos(fTermColumns - 1, fCurPos.y));
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Delete cursor right characters.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::DeleteColumns(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fTextBuffer->DeleteChar(fCurPos, fTermColumns - fCurPos.x);
TermDraw(fCurPos, CurPos(fTermColumns - 1, fCurPos.y));
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Delete 'num' lines from current position with scrolling.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::DeleteLine(int num)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
ScrollRegion(fCurPos.y, -1, SCRUP, num);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Sets cursor position
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetCurPos(int x, int y)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
if(x >= 0 && x < fTermColumns)
2004-07-05 19:44:26 +00:00
fCurPos.x = x;
2005-08-12 18:00:37 +00:00
if(y >= 0 && y < fTermRows)
2004-07-05 19:44:26 +00:00
fCurPos.y = y;
return;
}
2005-08-12 18:00:37 +00:00
// Sets cursor x position
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetCurX(int x)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(x >= 0 && x < fTermRows) {
UpdateLine();
fCurPos.x = x;
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Sets cursor y position
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetCurY(int y)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(y >= 0 && y < fTermColumns) {
UpdateLine();
fCurPos.y = y;
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Gets cursor position
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::GetCurPos(CurPos *inCurPos)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
inCurPos->x = fCurPos.x;
inCurPos->y = fCurPos.y;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Gets cursor x position
2004-07-05 19:44:26 +00:00
int
2005-08-12 18:00:37 +00:00
TermView::GetCurX(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
return fCurPos.x;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Gets cursor y position
2004-07-05 19:44:26 +00:00
int
2005-08-12 18:00:37 +00:00
TermView::GetCurY(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
return fCurPos.y;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Saves cursor position
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SaveCursor(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
fCurStack = fCurPos;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Restores cursor position
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::RestoreCursor(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fCurPos = fCurStack;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Move cursor right by 'num' steps.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::MoveCurRight(int num)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
if(fCurPos.x + num >= fTermColumns) {
// Wrap around
fCurPos.x = 0;
PutCR();
PutLF();
} else {
fCurPos.x += num;
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Move cursor left by 'num' steps.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::MoveCurLeft(int num)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fCurPos.x -= num;
if(fCurPos.x < 0)
fCurPos.x = 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Move cursor up by 'num' steps.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::MoveCurUp(int num)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fCurPos.y -= num;
if(fCurPos.y < 0)
fCurPos.y = 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Move cursor down by 'num' steps.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::MoveCurDown(int num)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
UpdateLine();
fCurPos.y += num;
if(fCurPos.y >= fTermRows)
fCurPos.y = fTermRows - 1;
2004-07-05 19:44:26 +00:00
}
void
2005-08-12 18:00:37 +00:00
TermView::DrawCursor(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
CURSOR_RECT;
uchar buf[4];
ushort attr;
int top = fTop / fFontHeight;
int m_flag = false;
m_flag = CheckSelectedRegion(CurPos(fCurPos.x,
fCurPos.y + fTop / fFontHeight));
if(fTextBuffer->
GetChar(fCurPos.y + top, fCurPos.x, buf, &attr) == A_CHAR) {
int width;
if(IS_WIDTH(attr))
width = 2;
else
width = 1;
DrawLines(fCurPos.x * fFontWidth,
fCurPos.y * fFontHeight + fTop,
attr, buf, width, m_flag, true, this);
} else {
if(m_flag)
SetHighColor(fSelectBackColor);
else
SetHighColor(fCursorBackColor);
FillRect(r);
}
Sync();
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::BlinkCursor(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(fCursorDrawFlag == CURON
&& fCursorBlinkingFlag == CURON
&& Window()->IsActive()) {
if(fCursorStatus == CURON)
TermDraw(fCurPos, fCurPos);
else
DrawCursor();
fCursorStatus =(fCursorStatus == CURON) ? CUROFF : CURON;
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Draw / Clear cursor.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetCurDraw(bool flag)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(flag == CUROFF) {
if(fCursorStatus == CURON)
TermDraw(fCurPos, fCurPos);
fCursorStatus = CUROFF;
fCursorDrawFlag = CUROFF;
} else {
if(fCursorDrawFlag == CUROFF) {
fCursorDrawFlag = CURON;
fCursorStatus = CURON;
if(LockLooper()) {
DrawCursor();
UnlockLooper();
}
}
}
}
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
// Sets cursor Blinking flag.
void
TermView::SetCurBlinking(bool flag)
{
fCursorBlinkingFlag = flag;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Scroll terminal dir directory by 'num' steps.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::ScrollRegion(int top, int bot, int dir, int num)
{
UpdateLine();
if(top == -1)
top = fScrTop;
if(bot == -1)
bot = fScrBot;
if(top < fScrTop)
top = fScrTop;
if(bot > fScrBot)
bot = fScrBot;
fTextBuffer->ScrollRegion(top, bot , dir ,num);
TermDraw(CurPos(0, top), CurPos(fTermColumns - 1, bot));
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Sets terminal scroll region.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetScrollRegion(int top, int bot)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(top >= 0 && top < fTermRows) {
if(bot >= 0 && bot < fTermRows) {
if(top > bot) {
fScrTop = bot;
fScrBot = top;
}
else if( top < bot ) {
fScrTop = top;
fScrBot = bot;
}
}
}
if(fScrTop != 0 || fScrBot != fTermRows -1 )
fScrRegionSet = 1;
else
fScrRegionSet = 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Scroll to cursor position.
void
TermView::ScrollAtCursor(void)
{
if(LockLooper()) {
ResizeScrBarRange();
fScrollUpCount = 0;
ScrollTo(0, fTop);
UnlockLooper();
}
}
2004-07-05 19:44:26 +00:00
thread_id
2005-08-12 18:00:37 +00:00
TermView::InitViewThread(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
// spwan Draw Engine thread.
if(fViewThread < 0) {
fViewThread = spawn_thread(ViewThread, "DrawEngine",
B_DISPLAY_PRIORITY, this);
}
else
return B_BAD_THREAD_ID;
fDrawRectSem = create_sem(0, "draw_engine_sem");
resume_thread(fViewThread);
// spawn Mouse Tracking thread.
if(fMouseThread < 0) {
fMouseThread = spawn_thread(MouseTracking, "MouseTracking",
B_NORMAL_PRIORITY,this);
}
else
return B_BAD_THREAD_ID;
resume_thread(fMouseThread);
return(fViewThread);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Thread of Draw Character to View.
2004-07-05 19:44:26 +00:00
int32
2005-08-12 18:00:37 +00:00
TermView::ViewThread(void *data)
{
int width, height;
sDrawRect pos;
//#define INVALIDATE
#ifndef INVALIDATE
int i, j, count;
int m_flag;
ushort attr;
uchar buf[256];
BRect eraseRect;
#endif
int inDrawRect_p = 0;
TermView *theObj =(TermView *)data;
while(theObj->fQuitting) {
// Wait semaphore
acquire_sem(theObj->fDrawRectSem);
pos = theObj->fDrawRectBuffer[inDrawRect_p];
inDrawRect_p++;
inDrawRect_p %= RECT_BUF_SIZE;
width = theObj->fFontWidth;
height = theObj->fFontHeight;
#ifdef INVALIDATE
BRect r(pos.x1 * width, pos.y1 * height,
(pos.x2 + 1) * width -1,(pos.y2 + 1) * height -1);
if(theObj->LockLooper()) {
theObj->Invalidate(r);
theObj->UnlockLooper();
}
#else
if(theObj->LockLooper()) {
for(j = pos.y1; j <= pos.y2; j++) {
for(i = pos.x1; i <= pos.x2;) {
count = theObj->fTextBuffer->GetString(j, i, pos.x2, buf, &attr);
m_flag = theObj->CheckSelectedRegion(CurPos(i, j));
if(count < 0) {
eraseRect.Set(width * i,
height * j,
width *(i - count) - 1,
height *(j + 1) - 1);
if(m_flag)
theObj->SetHighColor(theObj->fSelectBackColor);
else
theObj->SetHighColor(theObj->fTextBackColor);
theObj->FillRect(eraseRect);
count = -count;
} else {
theObj->DrawLines( width * i, height * j,
attr, buf, count, m_flag, false, theObj);
}
i += count;
}
}
theObj->UnlockLooper();
}
#endif
} // end while()
exit_thread(B_OK);
return 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Thread for tracking mouse.
2004-07-05 19:44:26 +00:00
int32
2005-08-12 18:00:37 +00:00
TermView::MouseTracking(void *data)
{
int32 code, selected = false;
uint32 button;
thread_id sender;
CurPos stpos, edpos;
BPoint stpoint, edpoint;
float scr_start, scr_end, scr_pos;
TermView *theObj =(TermView *)data;
while(theObj->fQuitting) {
if(1) {
2004-07-05 19:44:26 +00:00
#ifdef CHANGE_CURSOR_IMAGE
2005-08-12 18:00:37 +00:00
if(!has_data(find_thread(NULL))) {
BRect r;
if(theObj->fSelected
&& ( gTermPref->getInt32(PREF_DRAGN_COPY)
|| modifiers() & B_CONTROL_KEY)) {
if(theObj->LockLooper()) {
theObj->GetMouse(&stpoint, &button);
r = theObj->Bounds();
theObj->UnlockLooper();
}
if(r.Contains(stpoint)) {
CurPos tmppos = theObj->BPointToCurPos(stpoint);
if(theObj->fSelStart > theObj->fSelEnd) {
stpos = theObj->fSelEnd;
edpos = theObj->fSelStart;
} else {
stpos = theObj->fSelStart;
edpos = theObj->fSelEnd;
}
if(tmppos > stpos && tmppos < edpos)
be_app->SetCursor(M_ADD_CURSOR);
else
be_app->SetCursor(B_HAND_CURSOR);
}
}
snooze(50 * 1000);
continue;
}
else {
2004-07-05 19:44:26 +00:00
#endif
2005-08-12 18:00:37 +00:00
code = receive_data(&sender,(void *)&stpoint, sizeof(BPoint));
}
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
if(code != MOUSE_THR_CODE)
continue;
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
selected = theObj->fSelected;
edpoint.Set(-1, -1);
stpos = theObj->BPointToCurPos(stpoint);
do {
snooze(40 * 1000);
if(theObj->LockLooper()) {
theObj->GetMouse(&edpoint, &button);
theObj->UnlockLooper();
}
edpos = theObj->BPointToCurPos(edpoint);
if(stpoint == edpoint) {
continue;
} else {
if(!selected) {
theObj->Select(stpos, edpos);
selected = true;
} else {
// Align cursor point to text.
if(stpos == edpos)
continue;
if(edpos > stpos) {
edpoint.x -= theObj->fFontWidth / 2;
edpos = theObj->BPointToCurPos(edpoint);
//edpos.x--;
if(edpos.x < 0)
edpos.x = 0;
}
else
if(edpos < stpos) {
edpoint.x += theObj->fFontWidth / 2;
edpos = theObj->BPointToCurPos(edpoint);
//edpos.x++;
if(edpos.x > theObj->fTermColumns)
edpos.x = theObj->fTermColumns;
}
// Scroll check
if(theObj->LockLooper()) {
// Get now scroll point
theObj->fScrollBar->GetRange(&scr_start, &scr_end);
scr_pos = theObj->fScrollBar->Value();
if(edpoint.y < theObj->Bounds().LeftTop().y )
// mouse point left of window
if(scr_pos != scr_start)
theObj->ScrollTo(0, edpoint.y);
if(edpoint.y > theObj->Bounds().LeftBottom().y) {
// mouse point left of window
if(scr_pos != scr_end)
theObj->ScrollTo(0, edpoint.y);
}
theObj->UnlockLooper();
}
theObj->ResizeSelectRegion(edpos);
}
}
} while(button);
theObj->fMouseTracking = false;
}
exit_thread(B_OK);
return 0;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Draw character on offscreen bitmap.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::DrawLines(int x1, int y1, ushort attr, uchar *buf,
int width, int mouse, int cursor, BView *inView)
{
// int width;
int x2, y2;
int forecolor, backcolor;
rgb_color rgb_fore = fTextForeColor, rgb_back = fTextBackColor, rgb_tmp;
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
// Set Font.
if(IS_WIDTH(attr))
inView->SetFont(&fFullFont);
else
inView->SetFont(&fHalfFont);
// Set pen point
x2 = x1 + fFontWidth * width;
y2 = y1 + fFontHeight;
// color attribute
forecolor = IS_FORECOLOR(attr);
backcolor = IS_BACKCOLOR(attr);
if(IS_FORESET(attr))
rgb_fore = gTermColorTable[forecolor];
if(IS_BACKSET(attr))
rgb_back = gTermColorTable[backcolor];
// Selection check.
if(cursor) {
rgb_fore = fCursorForeColor;
rgb_back = fCursorBackColor;
}
else
if(mouse){
rgb_fore = fSelectForeColor;
rgb_back = fSelectBackColor;
} else {
// Reverse attribute(If selected area, don't reverse color).
if(IS_INVERSE(attr)) {
rgb_tmp = rgb_fore;
rgb_fore = rgb_back;
rgb_back = rgb_tmp;
}
}
// Fill color at Background color and set low color.
inView->SetHighColor(rgb_back);
inView->FillRect(BRect(x1, y1, x2 - 1, y2 - 1));
inView->SetLowColor(rgb_back);
inView->SetHighColor(rgb_fore);
// Draw character.
inView->MovePenTo(x1, y1 + fFontAscent);
inView->DrawString((char *) buf);
// bold attribute.
if(IS_BOLD(attr)) {
inView->MovePenTo(x1 + 1, y1 + fFontAscent);
inView->SetDrawingMode(B_OP_OVER);
inView->DrawString((char *)buf);
inView->SetDrawingMode(B_OP_COPY);
}
// underline attribute
if(IS_UNDER(attr)) {
inView->MovePenTo(x1, y1 + fFontAscent);
inView->StrokeLine(BPoint(x1 , y1 + fFontAscent),
BPoint(x2 , y1 + fFontAscent));
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Resize scroll bar range and knob size.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::ResizeScrBarRange(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
float viewheight, start_pos;
viewheight = fTermRows * fFontHeight;
start_pos = fTop -(fScrBufSize - fTermRows *2) * fFontHeight;
if(start_pos > 0) {
fScrollBar->SetRange(start_pos, viewheight + fTop - fFontHeight);
} else {
fScrollBar->SetRange(0, viewheight + fTop - fFontHeight);
fScrollBar->SetProportion( viewheight /(viewheight + fTop));
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Scrolls screen.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::ScrollScreen(void)
{
fTop += fFontHeight;
fScrollUpCount++;
fTextBuffer->ScrollLine();
if(fScrollUpCount > fTermRows ) {
if(LockLooper()) {
ResizeScrBarRange();
fScrollBarRange += fScrollUpCount;
fScrollUpCount = 0;
ScrollTo(0, fTop);
UnlockLooper();
}
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Scrolls screen.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::ScrollScreenDraw(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(fScrollUpCount){
if(LockLooper()) {
ResizeScrBarRange();
fScrollBarRange += fScrollUpCount;
fScrollUpCount = 0;
ScrollTo(0, fTop);
UnlockLooper();
}
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Handler for SIGWINCH
2004-07-05 19:44:26 +00:00
void
TermView::UpdateSIGWINCH()
{
2005-08-12 18:00:37 +00:00
struct winsize ws;
if(fFrameResized) {
if(fSelected)
TermDrawSelectedRegion(fSelStart, fSelEnd);
ScrollTo(0, fTop);
ResizeScrBarRange();
ws.ws_row = fTermRows;
ws.ws_col = fTermColumns;
ioctl(pfd, TIOCSWINSZ, &ws);
kill(-sh_pid, SIGWINCH);
fFrameResized = 0;
if(fScrRegionSet == 0)
fScrBot = fTermRows - 1;
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Device Status.
// Q & D hack by Y.Hayakawa([email protected])
2004-07-05 19:44:26 +00:00
// 21-JUL-99
void
TermView::DeviceStatusReport(int n)
{
2005-08-12 18:00:37 +00:00
char sbuf[16] ;
int len;
switch(n) {
case 5:
len = sprintf(sbuf,"\033[0n") ;
write(pfd, sbuf, len);
break ;
case 6:
len = sprintf(sbuf,"\033[%d;%dR",fTermRows,fTermColumns) ;
write(pfd, sbuf, len);
break ;
default:
return;
}
2004-07-05 19:44:26 +00:00
}
// Update line buffer.
void
2005-08-12 18:00:37 +00:00
TermView::UpdateLine(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(fUpdateFlag == true) {
if(fInsertModeFlag == MODE_INSERT) {
TermDraw(CurPos(fBufferStartPos, fCurPos.y),
CurPos(fTermColumns - 1, fCurPos.y));
} else {
TermDraw(CurPos(fBufferStartPos, fCurPos.y),
CurPos(fCurPos.x - 1, fCurPos.y));
}
fUpdateFlag = false;
}
2004-07-05 19:44:26 +00:00
}
void
2005-08-12 18:00:37 +00:00
TermView::AttachedToWindow(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
SetFont(&fHalfFont);
MakeFocus(true);
fScrollBar->SetSteps(fFontHeight, fFontHeight * fTermRows);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::Draw(BRect updateRect)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(IsPrinting()) {
DoPrint(updateRect);
return;
}
int x1, x2, y1, y2;
int i, j, k, count;
ushort attr;
uchar buf[256];
int m_flag;
BRect eraseRect;
x1 =(int)updateRect.left / fFontWidth;
x2 =(int)updateRect.right / fFontWidth;
y1 =(int)updateRect.top / fFontHeight;
y2 =(int)updateRect.bottom / fFontHeight;
Window()->BeginViewTransaction();
for(j = y1; j <= y2; j++) {
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
// If(x1, y1) Buffer is in string full width character,
// alignment start position.
k = x1;
if(fTextBuffer->GetChar(j, k, buf, &attr) == IN_STRING)
k--;
if(k < 0)
k = 0;
for(i = k; i <= x2;) {
count = fTextBuffer->GetString(j, i, x2, buf, &attr);
m_flag = CheckSelectedRegion(CurPos(i, j));
if(count < 0) {
if(m_flag) {
eraseRect.Set(fFontWidth * i,
fFontHeight * j,
fFontWidth *(i - count) -1,
fFontHeight *(j + 1) -1);
SetHighColor(fSelectBackColor);
FillRect(eraseRect);
}
i += abs(count);
continue;
}
DrawLines(fFontWidth * i, fFontHeight * j,
attr, buf, count, m_flag, false, this);
i += count;
if(i >= fTermColumns)
break;
}
}
if(fCursorStatus == CURON)
DrawCursor();
Window()->EndViewTransaction();
}
2004-07-05 19:44:26 +00:00
void
TermView::DoPrint(BRect updateRect)
{
2005-08-12 18:00:37 +00:00
ushort attr;
uchar buf[256];
const int numLines =(int)((updateRect.Height()) / fFontHeight);
int y1 =(int)updateRect.top / fFontHeight;
y1 = y1 -(fScrBufSize - numLines * 2);
if(y1 < 0)
y1 = 0;
const int y2 = y1 + numLines -1;
const int x1 =(int)updateRect.left / fFontWidth;
const int x2 =(int)updateRect.right / fFontWidth;
for(int j = y1; j <= y2; j++) {
// If(x1, y1) Buffer is in string full width character,
// alignment start position.
int k = x1;
if(fTextBuffer->GetChar(j, k, buf, &attr) == IN_STRING)
k--;
if(k < 0)
k = 0;
for(int i = k; i <= x2;) {
int count = fTextBuffer->GetString(j, i, x2, buf, &attr);
if(count < 0) {
i += abs(count);
continue;
}
DrawLines(fFontWidth * i, fFontHeight * j,
attr, buf, count, false, false, this);
i += count;
}
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::WindowActivated(bool active)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(active == false) {
// DoIMConfirm();
}
if(active && fMouseImage) {
be_app->SetCursor(B_I_BEAM_CURSOR);
}
2004-07-05 19:44:26 +00:00
}
void
2005-08-12 18:00:37 +00:00
TermView::KeyDown(const char *bytes, int32 numBytes)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
char c;
struct termios tio;
int32 key, mod;
uchar dstbuf[1024];
Looper()->CurrentMessage()->FindInt32("modifiers", &mod);
Looper()->CurrentMessage()->FindInt32("key", &key);
if(fIMflag)
return;
// If bytes[0] equal intr charactor,
// send signal to shell process group.
tcgetattr(pfd, &tio);
if(*bytes == tio.c_cc[VINTR]) {
if(tio.c_lflag & ISIG)
kill(-sh_pid, SIGINT);
}
// Terminal changes RET, ENTER, F1...F12, and ARROW key code.
if(numBytes == 1) {
if(mod & B_OPTION_KEY) {
c = *bytes;
c |= 0x80;
write(pfd, &c, 1);
return;
}
switch(*bytes) {
case B_RETURN:
c = 0x0d;
if(key == RETURN_KEY || key == ENTER_KEY) {
write(pfd, &c, 1);
return;
} else {
write(pfd, bytes, numBytes);
return;
}
break;
case B_LEFT_ARROW:
if(key == LEFT_ARROW_KEY) {
write(pfd, LEFT_ARROW_KEY_CODE, sizeof(LEFT_ARROW_KEY_CODE)-1);
return;
}
break;
case B_RIGHT_ARROW:
if(key == RIGHT_ARROW_KEY) {
write(pfd, RIGHT_ARROW_KEY_CODE, sizeof(RIGHT_ARROW_KEY_CODE)-1);
return;
}
break;
case B_UP_ARROW:
if(mod & B_SHIFT_KEY) {
if(Bounds().top <= 0)
return;
ScrollBy(0, -fFontHeight);
Window()->UpdateIfNeeded();
return;
}
if(key == UP_ARROW_KEY) {
write(pfd, UP_ARROW_KEY_CODE, sizeof(UP_ARROW_KEY_CODE)-1);
return;
}
break;
case B_DOWN_ARROW:
if(mod & B_SHIFT_KEY) {
ScrollBy(0, fFontHeight);
Window()->UpdateIfNeeded();
return;
}
if(key == DOWN_ARROW_KEY) {
write(pfd, DOWN_ARROW_KEY_CODE, sizeof(DOWN_ARROW_KEY_CODE)-1);
return;
}
break;
case B_INSERT:
if(key == INSERT_KEY) {
write(pfd, INSERT_KEY_CODE, sizeof(INSERT_KEY_CODE)-1);
return;
}
break;
case B_HOME:
if(key == HOME_KEY) {
write(pfd, HOME_KEY_CODE, sizeof(HOME_KEY_CODE)-1);
return;
}
break;
case B_PAGE_UP:
if(mod & B_SHIFT_KEY) {
if(Bounds().top <= 0)
return;
ScrollBy(0, -fFontHeight * fTermRows );
Window()->UpdateIfNeeded();
return;
}
if(key == PAGE_UP_KEY) {
write(pfd, PAGE_UP_KEY_CODE, sizeof(PAGE_UP_KEY_CODE)-1);
return;
}
break;
case B_PAGE_DOWN:
if(mod & B_SHIFT_KEY) {
ScrollBy(0, fFontHeight * fTermRows);
Window()->UpdateIfNeeded();
return;
}
if(key == PAGE_DOWN_KEY) {
write(pfd, PAGE_DOWN_KEY_CODE, sizeof(PAGE_DOWN_KEY_CODE)-1);
return;
}
break;
case B_END:
if(key == END_KEY) {
write(pfd, END_KEY_CODE, sizeof(END_KEY_CODE)-1);
return;
}
break;
case B_FUNCTION_KEY:
for(c = 0; c < 12; c++) {
if(key == function_keycode_table[c]) {
write(pfd, function_key_char_table[c], 5);
return;
}
}
break;
default:
break;
}
} else {
// input multibyte character
if(gNowCoding != M_UTF8) {
int cnum = fCodeConv->ConvertFromInternal
((uchar *)bytes, dstbuf, gNowCoding);
write(pfd, dstbuf, cnum);
return;
}
}
write(pfd, bytes, numBytes);
2004-07-05 19:44:26 +00:00
}
void
2005-08-12 18:00:37 +00:00
TermView::FrameResized(float width, float height)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
const int cols =((int)width + 1) / fFontWidth;
const int rows =((int)height + 1) / fFontHeight;
int offset = 0;
if(rows < fCurPos.y + 1) {
fTop +=(fCurPos.y + 1 - rows) * fFontHeight;
offset = fCurPos.y + 1 - rows;
fCurPos.y = rows - 1;
}
fTextBuffer->ResizeTo(rows, cols, offset);
fTermRows = rows;
fTermColumns = cols;
fFrameResized = 1;
2004-07-05 19:44:26 +00:00
}
void
TermView::MessageReceived(BMessage *msg)
{
entry_ref ref;
char *ctrl_l = " ";
switch(msg->what){
case B_SIMPLE_DATA:
{
int32 i=0;
if(msg->FindRef("refs", i++, &ref) == B_OK)
{
2005-08-12 18:00:37 +00:00
DoFileDrop(ref);
while(msg->FindRef("refs", i++, &ref) == B_OK)
2005-08-12 18:59:17 +00:00
{
WritePTY((const uchar*)" ",1);
2005-08-12 18:00:37 +00:00
DoFileDrop(ref);
2005-08-12 18:59:17 +00:00
}
}
else
{
BView::MessageReceived(msg);
}
break;
}
case B_MIME_DATA:
{
char *text;
int32 num_bytes;
status_t sts;
2005-08-12 18:00:37 +00:00
if(msg->WasDropped())
{
2005-08-12 18:00:37 +00:00
sts = msg->FindData((const char *)"text/plain",
(type_code)B_MIME_TYPE,
(const void **)&text, &num_bytes);
2005-08-12 18:00:37 +00:00
if(sts != B_OK)
break;
// Clipboard text doesn't attached EOF?
text[num_bytes] = '\0';
2005-08-12 18:00:37 +00:00
WritePTY((uchar *)text, num_bytes);
}
break;
}
case B_COPY:
{
2005-08-12 18:00:37 +00:00
DoCopy();
break;
}
case B_PASTE:
{
int32 code;
2005-08-12 18:00:37 +00:00
if(msg->FindInt32("index", &code) == B_OK)
DoPaste();
break;
}
case B_SELECT_ALL:
{
2005-08-12 18:00:37 +00:00
DoSelectAll();
break;
}
case MENU_CLEAR_ALL:
{
2005-08-12 18:00:37 +00:00
DoClearAll();
write(pfd, ctrl_l, 1);
break;
}
case MSGRUN_CURSOR:
{
2005-08-12 18:00:37 +00:00
BlinkCursor();
break;
}
2004-07-05 19:44:26 +00:00
// case B_INPUT_METHOD_EVENT:
// {
// int32 op;
// msg->FindInt32("be:opcode", &op);
// switch(op){
// case B_INPUT_METHOD_STARTED:
2005-08-12 18:00:37 +00:00
//DoIMStart(msg);
2004-07-05 19:44:26 +00:00
// break;
// case B_INPUT_METHOD_STOPPED:
2005-08-12 18:00:37 +00:00
// DoIMStop(msg);
2004-07-05 19:44:26 +00:00
// break;
// case B_INPUT_METHOD_CHANGED:
2005-08-12 18:00:37 +00:00
// DoIMChange(msg);
2004-07-05 19:44:26 +00:00
// break;
// case B_INPUT_METHOD_LOCATION_REQUEST:
2005-08-12 18:00:37 +00:00
// DoIMLocation(msg);
2004-07-05 19:44:26 +00:00
// break;
// }
// }
default:
{
BView::MessageReceived(msg);
break;
}
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Gets dropped file full path and display it at cursor position.
2004-07-05 19:44:26 +00:00
void
TermView::DoFileDrop(entry_ref &ref)
{
BEntry ent(&ref);
BPath path(&ent);
BString string(path.Path());
string.CharacterEscape(" ~`#$&*()\\|[]{};'\"<>?!",'\\');
2005-08-12 18:00:37 +00:00
WritePTY((const uchar *)string.String(), string.Length());
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Copy selected text to Clipboard.
2004-07-05 19:44:26 +00:00
void
TermView::DoCopy()
{
2005-08-12 18:00:37 +00:00
if(!fSelected)
return;
BString copyStr("");
fTextBuffer->GetStringFromRegion(copyStr);
if(be_clipboard->Lock()) {
BMessage *clipMsg = NULL;
be_clipboard->Clear();
if((clipMsg = be_clipboard->Data()) != NULL) {
clipMsg->AddData("text/plain", B_MIME_TYPE, copyStr.String(),
copyStr.Length());
be_clipboard->Commit();
}
be_clipboard->Unlock();
}
2005-05-07 16:20:06 +00:00
// Deselecting the current selection is not the behavior that
// R5's Terminal app displays. We want to mimic the behavior, so we will
// no longer do the deselection
2005-08-12 18:00:37 +00:00
// if(!fMouseTracking)
// DeSelect();
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Paste clipboard text at cursor position.
2004-07-05 19:44:26 +00:00
void
TermView::DoPaste(void)
{
2005-08-12 18:00:37 +00:00
if( be_clipboard->Lock() ) {
BMessage *clipMsg = be_clipboard->Data();
char *text;
ssize_t num_bytes;
if( clipMsg->FindData((const char *)"text/plain",
(type_code) B_MIME_TYPE,
(const void **)&text,
&num_bytes) == B_OK ) {
// Clipboard text doesn't attached EOF?
text[num_bytes] = '\0';
WritePTY((uchar *)text, num_bytes);
}
be_clipboard->Unlock();
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Select all displayed text and text /in buffer.
2004-07-05 19:44:26 +00:00
void
TermView::DoSelectAll(void)
{
2005-08-12 18:00:37 +00:00
CurPos start, end;
int screen_top;
int viewheight, start_pos;
screen_top = fTop / fFontHeight;
viewheight = fTermRows;
start_pos = screen_top -(fScrBufSize - viewheight * 2);
start.x = 0;
end.x = fTermColumns -1;
if(start_pos > 0)
start.y = start_pos;
else
start.y = 0;
end.y = fCurPos.y + screen_top;
Select(start, end);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Clear display and text buffer, then moves Cursorr at home position.
void
TermView::DoClearAll(void)
{
DeSelect();
fTextBuffer->ClearAll();
fTop = 0;
ScrollTo(0, 0);
if(LockLooper()) {
SetHighColor(fTextBackColor);
FillRect(Bounds());
SetHighColor(fTextForeColor);
UnlockLooper();
}
// reset cursor pos
SetCurPos(0, 0);
// reset selection.
fSelected = false;
fScrollBar->SetRange(0, 0);
fScrollBar->SetProportion(1);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Substitution meta character
2004-07-05 19:44:26 +00:00
int
2005-08-12 18:00:37 +00:00
TermView::SubstMetaChar(const char *p, char *q)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
char *metachar = " ~`#$&*()\\|[]{};'\"<>?!";
int num_char = 0;
while(*p) {
char *mp = metachar;
for(int i = 0; i < 22; i++){
if(*p == *mp++) {
*q++ = '\\';
num_char++;
break;
}
}
*q++ = *p++;
num_char++;
}
// Add null string
*q = *p;
return(num_char + 1);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Write strings to PTY device. If encoding system isn't UTF8, change
// encoding to UTF8 before writing PTY.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::WritePTY(const uchar *text, int num_bytes)
{
if(gNowCoding != M_UTF8) {
uchar *dstbuf =(uchar *)malloc(num_bytes * 3);
num_bytes = fCodeConv->ConvertFromInternal(text, dstbuf, gNowCoding);
write(pfd, dstbuf, num_bytes);
free(dstbuf);
} else {
write(pfd, text, num_bytes);
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Make encoding pop up menu (make copy of window's one.)
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::SetupPop(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
fPopMenu = new BPopUpMenu("");
MakeEncodingMenu(fPopMenu, gNowCoding, true);
fPopMenu->SetTargetForItems(Window());
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// convert button name to number.
2004-07-05 19:44:26 +00:00
int32
2005-08-12 18:00:37 +00:00
TermView::SetupMouseButton(const char *bname)
{
if(!strcmp(bname, "Disable")) {
return 0;
}
else if(!strcmp(bname, "Button 1")) {
return B_PRIMARY_MOUSE_BUTTON;
}
else if(!strcmp(bname, "Button 2")) {
return B_SECONDARY_MOUSE_BUTTON;
}
else if(!strcmp(bname, "Button 3")) {
return B_TERTIARY_MOUSE_BUTTON;
} else {
return 0; //Disable
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::MouseDown(BPoint where)
{
int32 buttons = 0, clicks = 0;
int32 mod;
BPoint inPoint;
ssize_t num_bytes;
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
// paste button
if(buttons == mPasteMenuButton) {
if(fSelected) {
// If selected region, copy text from region.
BString copyStr("");
fTextBuffer->GetStringFromRegion(copyStr);
num_bytes = copyStr.Length();
WritePTY((uchar *)copyStr.String(), num_bytes);
}
else {
// If don't selected, copy text from clipboard.
DoPaste();
}
return;
}
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
// Select Region
if(buttons == mSelectButton) {
Window()->CurrentMessage()->FindInt32("modifiers", &mod);
Window()->CurrentMessage()->FindInt32("clicks", &clicks);
if(fSelected) {
CurPos inPos, stPos, edPos;
if(fSelStart < fSelEnd) {
stPos = fSelStart;
edPos = fSelEnd;
} else {
stPos = fSelEnd;
edPos = fSelStart;
}
inPos = BPointToCurPos(where);
// If mouse pointer is avove selected Region, start Drag'n Copy.
if(inPos > stPos && inPos < edPos) {
if(mod & B_CONTROL_KEY || gTermPref->getInt32(PREF_DRAGN_COPY)) {
BPoint p;
uint32 bt;
do {
GetMouse(&p, &bt);
if(bt == 0) {
DeSelect();
return;
}
snooze(40 * 1000);
} while(abs((int)(where.x - p.x)) < 4
&& abs((int)(where.y - p.y)) < 4);
BString copyStr("");
fTextBuffer->GetStringFromRegion(copyStr);
BMessage msg(B_MIME_TYPE);
msg.AddData("text/plain",
B_MIME_TYPE,
copyStr.String(),
copyStr.Length());
BPoint st = CurPosToBPoint(stPos);
BPoint ed = CurPosToBPoint(edPos);
BRect r;
if(stPos.y == edPos.y) {
r.Set(st.x, st.y - fTop,
ed.x + fFontWidth, ed.y + fFontHeight - fTop);
} else {
r.Set(0, st.y - fTop,
fTermColumns * fFontWidth, ed.y + fFontHeight - fTop);
}
r = r & Bounds();
DragMessage(&msg, r);
return;
}
}
}
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
// If mouse has a lot of movement, disable double/triple click.
2004-07-05 19:44:26 +00:00
inPoint = fPreviousMousePoint - where;
2005-08-12 18:00:37 +00:00
if(abs((int)inPoint.x) > 16 || abs((int)inPoint.y) > 16) clicks = 1;
2004-07-05 19:44:26 +00:00
fPreviousMousePoint = where;
2005-08-12 18:00:37 +00:00
if(mod & B_SHIFT_KEY) {
AddSelectRegion(BPointToCurPos(where));
2004-07-05 19:44:26 +00:00
} else {
2005-08-12 18:00:37 +00:00
DeSelect();
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// If clicks larger than 3, reset mouse click counter.
2004-07-05 19:44:26 +00:00
clicks = clicks % 3;
2005-08-12 18:00:37 +00:00
if(clicks == 0) clicks = 3;
2004-07-05 19:44:26 +00:00
2005-08-12 18:00:37 +00:00
switch(clicks){
2004-07-05 19:44:26 +00:00
case 1:
fMouseTracking = true;
2005-08-12 18:00:37 +00:00
send_data(fMouseThread,
2004-07-05 19:44:26 +00:00
MOUSE_THR_CODE,
2005-08-12 18:00:37 +00:00
(void *)&where,
sizeof(BPoint));
2004-07-05 19:44:26 +00:00
break;
case 2:
SelectWord(where, mod);
break;
case 3:
SelectLine(where, mod);
break;
}
return;
}
2005-08-12 18:00:37 +00:00
// Sub menu(coding popup menu)
if(buttons == mSubMenuButton){
ConvertToScreen(&where);
SetupPop();
fPopMenu->Go(where, true);
delete fPopMenu;
return;
}
BView::MouseDown(where);
2004-07-05 19:44:26 +00:00
}
void
2005-08-12 18:00:37 +00:00
TermView::MouseMoved(BPoint, uint32 transit, const BMessage *)
{
if(fMouseImage && Window()->IsActive()) {
if(transit == B_ENTERED_VIEW)
be_app->SetCursor(B_I_BEAM_CURSOR);
if(transit == B_EXITED_VIEW)
be_app->SetCursor(B_HAND_CURSOR);
}
2004-07-05 19:44:26 +00:00
}
// Select a range of text
void
2005-08-12 18:00:37 +00:00
TermView::Select(CurPos start, CurPos end)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
uchar buf[4];
ushort attr;
if(start.x < 0)
start.x = 0;
if(end.x >= fTermColumns)
end.x = fTermColumns - 1;
if(fTextBuffer->GetChar(start.y, start.x, buf, &attr) == IN_STRING) {
start.x--;
if(start.x < 0) start.x = 0;
}
if(fTextBuffer->GetChar(end.y, end.x, buf, &attr) == IN_STRING) {
end.x++;
if(end.x >= fTermColumns) end.x = fTermColumns;
}
fSelStart = start;
fSelEnd = end;
fTextBuffer->Select(fSelStart, fSelEnd);
TermDrawSelectedRegion(fSelStart, fSelEnd);
fSelected = true;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Add select region(shift + mouse click)
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::AddSelectRegion(CurPos pos)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
uchar buf[4];
ushort attr;
CurPos start, end, inPos;
if(!fSelected)
return;
// error check, and if mouse point to a plase full width character,
// select point decliment.
if(pos.x >= fTermColumns)
pos.x = fTermColumns - 1;
else
if(pos.x < 0)
pos.x = 0;
if(pos.y < 0)
pos.y = 0;
if(fTextBuffer->GetChar(pos.y, pos.x, buf, &attr) == IN_STRING) {
pos.x++;
if(pos.x >= fTermColumns)
pos.x = fTermColumns - 1;
}
start = fSelStart;
end = fSelEnd;
// Mouse point is same as selected line.
if(pos.y == fSelStart.y && pos.y == fSelEnd.y) {
if(abs(pos.x - start.x) > abs(pos.x - end.x)) {
fSelStart = start;
fSelEnd = pos;
inPos = end;
} else {
fSelStart = end;
fSelEnd = pos;
inPos = start;
}
}
// else, End point set to near the start or end point.
else
if(abs(pos.y - start.y) > abs(pos.y - end.y)) {
fSelStart = start;
fSelEnd = pos;
inPos = end;
}
else if(abs(pos.y - start.y) > abs(pos.y - end.y)) {
fSelStart = end;
fSelEnd = pos;
inPos = start;
} else {
if(start > end) {
inPos = start;
start = end;
end = inPos;
}
if(pos.y < start.y) {
fSelStart = end;
fSelEnd = pos;
inPos = start;
} else {
fSelStart = start;
fSelEnd = pos;
inPos = end;
}
}
fTextBuffer->Select(fSelStart, fSelEnd);
TermDrawSelectedRegion(inPos, fSelEnd);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Resize select region (mouse drag)
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::ResizeSelectRegion(CurPos pos)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
CurPos inPos;
uchar buf[4];
ushort attr;
inPos = fSelEnd;
// error check, and if mouse point to a plase full width character,
// select point decliment.
if(pos.x >= fTermColumns)
pos.x = fTermColumns - 1;
else
if(pos.x < 0)
pos.x = 0;
if(pos.y < 0)
pos.y = 0;
if(fTextBuffer->GetChar(pos.y, pos.x, buf, &attr) == IN_STRING) {
pos.x++;
if(pos == inPos)
return;
if(pos.x >= fTermColumns)
pos.x = fTermColumns - 1;
}
fSelEnd = pos;
fTextBuffer->Select(fSelStart, pos);
TermDrawSelectedRegion(inPos, pos);
2004-07-05 19:44:26 +00:00
}
// DeSelect a range of text
void
2005-08-12 18:00:37 +00:00
TermView::DeSelect(void)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
CurPos start, end;
if(!fSelected)
return;
fTextBuffer->DeSelect();
start = fSelStart;
end = fSelEnd;
fSelStart.Set(-1, -1);
fSelEnd.Set(-1, -1);
TermDrawSelectedRegion(start, end);
fSelected = false;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
void
TermView::SelectWord(BPoint where, int mod)
{
2005-08-12 18:00:37 +00:00
CurPos start, end, pos;
bool flag;
pos = BPointToCurPos(where);
flag = fTextBuffer->FindWord(pos, &start, &end);
if(mod & B_SHIFT_KEY) {
if(flag) {
if(start < fSelStart) {
AddSelectRegion(start);
}
else
if(end > fSelEnd) {
AddSelectRegion(end);
}
} else {
AddSelectRegion(pos);
}
} else {
DeSelect();
if(flag)
Select(start, end);
}
2004-07-05 19:44:26 +00:00
}
void
TermView::SelectLine(BPoint where, int mod)
{
2005-08-12 18:00:37 +00:00
CurPos start, end, pos;
pos = BPointToCurPos(where);
if(mod & B_SHIFT_KEY) {
start = CurPos(0, pos.y);
end = CurPos(fTermColumns - 1, pos.y);
if(start < fSelStart) {
AddSelectRegion(start);
}
else
if(end > fSelEnd) {
AddSelectRegion(end);
}
} else {
DeSelect();
Select(CurPos(0, pos.y), CurPos(fTermColumns - 1, pos.y));
}
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
// Convert View visible area corrdination to cursor position.
CurPos
2005-08-12 18:00:37 +00:00
TermView::BPointToCurPos(const BPoint &p)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
return CurPos(p.x / fFontWidth, p.y / fFontHeight);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
// Convert cursor position to view coordination.
BPoint
2005-08-12 18:00:37 +00:00
TermView::CurPosToBPoint(const CurPos &pos)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
return BPoint(fFontWidth * pos.x, pos.y * fFontHeight + fTop);
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
bool
2005-08-12 18:00:37 +00:00
TermView::CheckSelectedRegion(const CurPos &pos)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
CurPos start, end;
if(fSelStart > fSelEnd) {
start = fSelEnd;
end = fSelStart;
} else {
start = fSelStart;
end = fSelEnd;
}
if(pos >= start && pos <= end)
return true;
return false;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::GetFrameSize(float *width, float *height)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
if(width != NULL)
*width = fTermColumns * fFontWidth;
if(height == NULL)
return;
if(!fTop){
*height = fTermRows * fFontHeight;
return;
}
if(fTop - fTermRows * fFontHeight > fScrBufSize * fFontHeight) {
*height = fScrBufSize * fFontHeight;
return;
}
*height = fTop + fTermRows * fFontHeight;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Sets terninal rows and cols.
2004-07-05 19:44:26 +00:00
void
2005-08-12 18:00:37 +00:00
TermView::GetFontInfo(int *width, int *height)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
*width = fFontWidth;
*height = fFontHeight;
2004-07-05 19:44:26 +00:00
}
2005-08-12 18:00:37 +00:00
// Send DrawRect data to Draw Engine thread.
2004-07-05 19:44:26 +00:00
inline void
2005-08-12 18:00:37 +00:00
TermView::SendDataToDrawEngine(int x1, int y1, int x2, int y2)
2004-07-05 19:44:26 +00:00
{
2005-08-12 18:00:37 +00:00
// TODO: remove the goto
sem_info info;
retry:
get_sem_info(fDrawRectSem, &info);
if((RECT_BUF_SIZE - info.count) < 2) {
snooze(10 * 1000);
goto retry;
}
fDrawRectBuffer[fDrawRect_p].x1 = x1;
fDrawRectBuffer[fDrawRect_p].x2 = x2;
fDrawRectBuffer[fDrawRect_p].y1 = y1;
fDrawRectBuffer[fDrawRect_p].y2 = y2;
fDrawRect_p++;
fDrawRect_p %= RECT_BUF_SIZE;
release_sem(fDrawRectSem);
2004-07-05 19:44:26 +00:00
}