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 18 TerminalBuffer::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 30 TerminalBuffer::~TerminalBuffer() 31 { 32 delete fAlternateScreen; 33 delete fAlternateHistory; 34 } 35 36 37 status_t 38 TerminalBuffer::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 54 void 55 TerminalBuffer::SetListener(BMessenger listener) 56 { 57 fListener = listener; 58 fListenerValid = true; 59 } 60 61 62 void 63 TerminalBuffer::UnsetListener() 64 { 65 fListenerValid = false; 66 } 67 68 69 int 70 TerminalBuffer::Encoding() const 71 { 72 return fEncoding; 73 } 74 75 76 void 77 TerminalBuffer::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 87 void 88 TerminalBuffer::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 98 void 99 TerminalBuffer::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 109 void 110 TerminalBuffer::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 120 void 121 TerminalBuffer::SetEncoding(int encoding) 122 { 123 fEncoding = encoding; 124 } 125 126 127 void 128 TerminalBuffer::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 138 void 139 TerminalBuffer::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 149 void 150 TerminalBuffer::NotifyListener() 151 { 152 if (fListenerValid) 153 fListener.SendMessage(MSG_TERMINAL_BUFFER_CHANGED); 154 } 155 156 157 status_t 158 TerminalBuffer::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 170 status_t 171 TerminalBuffer::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 221 void 222 TerminalBuffer::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 236 void 237 TerminalBuffer::UseNormalScreenBuffer() 238 { 239 if (!fAlternateScreenActive) 240 return; 241 242 _SwitchScreenBuffer(); 243 _InvalidateAll(); 244 } 245 246 247 void 248 TerminalBuffer::_SwitchScreenBuffer() 249 { 250 std::swap(fScreen, fAlternateScreen); 251 std::swap(fHistory, fAlternateHistory); 252 std::swap(fScreenOffset, fAlternateScreenOffset); 253 fAlternateScreenActive = !fAlternateScreenActive; 254 } 255