1/* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6#include "TerminalBuffer.h" 7 8#include <algorithm> 9 10#include <Message.h> 11 12#include "TermConst.h" 13 14 15// #pragma mark - public methods 16 17 18TerminalBuffer::TerminalBuffer() 19 : 20 BLocker("terminal buffer"), 21 fEncoding(M_UTF8), 22 fAlternateScreen(NULL), 23 fAlternateHistory(NULL), 24 fAlternateScreenOffset(0), 25 fListenerValid(false) 26{ 27} 28 29 30TerminalBuffer::~TerminalBuffer() 31{ 32 delete fAlternateScreen; 33 delete fAlternateHistory; 34} 35 36 37status_t 38TerminalBuffer::Init(int32 width, int32 height, int32 historySize) 39{ 40 if (Sem() < 0) 41 return Sem(); 42 43 fAlternateScreen = _AllocateLines(width, height); 44 if (fAlternateScreen == NULL) 45 return B_NO_MEMORY; 46 47 for (int32 i = 0; i < height; i++) 48 fAlternateScreen[i]->Clear(); 49 50 return BasicTerminalBuffer::Init(width, height, historySize); 51} 52 53 54void 55TerminalBuffer::SetListener(BMessenger listener) 56{ 57 fListener = listener; 58 fListenerValid = true; 59} 60 61 62void 63TerminalBuffer::UnsetListener() 64{ 65 fListenerValid = false; 66} 67 68 69int 70TerminalBuffer::Encoding() const 71{ 72 return fEncoding; 73} 74 75 76void 77TerminalBuffer::ReportX10MouseEvent(bool reportX10MouseEvent) 78{ 79 if (fListenerValid) { 80 BMessage message(MSG_REPORT_MOUSE_EVENT); 81 message.AddBool("reportX10MouseEvent", reportX10MouseEvent); 82 fListener.SendMessage(&message); 83 } 84} 85 86 87void 88TerminalBuffer::ReportNormalMouseEvent(bool reportNormalMouseEvent) 89{ 90 if (fListenerValid) { 91 BMessage message(MSG_REPORT_MOUSE_EVENT); 92 message.AddBool("reportNormalMouseEvent", reportNormalMouseEvent); 93 fListener.SendMessage(&message); 94 } 95} 96 97 98void 99TerminalBuffer::ReportButtonMouseEvent(bool report) 100{ 101 if (fListenerValid) { 102 BMessage message(MSG_REPORT_MOUSE_EVENT); 103 message.AddBool("reportButtonMouseEvent", report); 104 fListener.SendMessage(&message); 105 } 106} 107 108 109void 110TerminalBuffer::ReportAnyMouseEvent(bool reportAnyMouseEvent) 111{ 112 if (fListenerValid) { 113 BMessage message(MSG_REPORT_MOUSE_EVENT); 114 message.AddBool("reportAnyMouseEvent", reportAnyMouseEvent); 115 fListener.SendMessage(&message); 116 } 117} 118 119 120void 121TerminalBuffer::SetEncoding(int encoding) 122{ 123 fEncoding = encoding; 124} 125 126 127void 128TerminalBuffer::SetTitle(const char* title) 129{ 130 if (fListenerValid) { 131 BMessage message(MSG_SET_TERMNAL_TITLE); 132 message.AddString("title", title); 133 fListener.SendMessage(&message); 134 } 135} 136 137 138void 139TerminalBuffer::NotifyQuit(int32 reason) 140{ 141 if (fListenerValid) { 142 BMessage message(MSG_QUIT_TERMNAL); 143 message.AddInt32("reason", reason); 144 fListener.SendMessage(&message); 145 } 146} 147 148 149void 150TerminalBuffer::NotifyListener() 151{ 152 if (fListenerValid) 153 fListener.SendMessage(MSG_TERMINAL_BUFFER_CHANGED); 154} 155 156 157status_t 158TerminalBuffer::ResizeTo(int32 width, int32 height) 159{ 160 int32 historyCapacity = 0; 161 if (!fAlternateScreenActive) 162 historyCapacity = HistoryCapacity(); 163 else if (fAlternateHistory != NULL) 164 historyCapacity = fAlternateHistory->Capacity(); 165 166 return ResizeTo(width, height, historyCapacity); 167} 168 169 170status_t 171TerminalBuffer::ResizeTo(int32 width, int32 height, int32 historyCapacity) 172{ 173 // switch to the normal screen buffer first 174 bool alternateScreenActive = fAlternateScreenActive; 175 if (alternateScreenActive) 176 _SwitchScreenBuffer(); 177 178 int32 oldWidth = fWidth; 179 int32 oldHeight = fHeight; 180 181 // Resize the normal screen buffer/history. 182 status_t error = BasicTerminalBuffer::ResizeTo(width, height, 183 historyCapacity); 184 if (error != B_OK) { 185 if (alternateScreenActive) 186 _SwitchScreenBuffer(); 187 return error; 188 } 189 190 // Switch to the alternate screen buffer and resize it. 191 if (fAlternateScreen != NULL) { 192 TermPos cursor = fCursor; 193 fCursor.SetTo(0, 0); 194 fWidth = oldWidth; 195 fHeight = oldHeight; 196 197 _SwitchScreenBuffer(); 198 199 error = BasicTerminalBuffer::ResizeTo(width, height, 0); 200 201 fWidth = width; 202 fHeight = height; 203 fCursor = cursor; 204 205 // Switch back. 206 if (!alternateScreenActive) 207 _SwitchScreenBuffer(); 208 209 if (error != B_OK) { 210 // This sucks -- we can't do anything about it. Delete the 211 // alternate screen buffer. 212 _FreeLines(fAlternateScreen, oldHeight); 213 fAlternateScreen = NULL; 214 } 215 } 216 217 return error; 218} 219 220 221void 222TerminalBuffer::UseAlternateScreenBuffer(bool clear) 223{ 224 if (fAlternateScreenActive || fAlternateScreen == NULL) 225 return; 226 227 _SwitchScreenBuffer(); 228 229 if (clear) 230 Clear(false); 231 232 _InvalidateAll(); 233} 234 235 236void 237TerminalBuffer::UseNormalScreenBuffer() 238{ 239 if (!fAlternateScreenActive) 240 return; 241 242 _SwitchScreenBuffer(); 243 _InvalidateAll(); 244} 245 246 247void 248TerminalBuffer::_SwitchScreenBuffer() 249{ 250 std::swap(fScreen, fAlternateScreen); 251 std::swap(fHistory, fAlternateHistory); 252 std::swap(fScreenOffset, fAlternateScreenOffset); 253 fAlternateScreenActive = !fAlternateScreenActive; 254} 255