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