1 /*
2 * Copyright 2013-2023, Haiku, Inc. All rights reserved.
3 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 *
6 * Authors:
7 * Ingo Weinhold, ingo_weinhold@gmx.de
8 * Simon South, simon@simonsouth.net
9 * Siarzhuk Zharski, zharik@gmx.li
10 */
11
12 #include "TerminalBuffer.h"
13
14 #include <algorithm>
15
16 #include <Message.h>
17
18 #include "Colors.h"
19 #include "TermApp.h"
20 #include "TermConst.h"
21
22
23 // #pragma mark - public methods
24
25
TerminalBuffer()26 TerminalBuffer::TerminalBuffer()
27 :
28 BLocker("terminal buffer"),
29 fEncoding(M_UTF8),
30 fAlternateScreen(NULL),
31 fAlternateHistory(NULL),
32 fAlternateScreenOffset(0),
33 fAlternateAttributes(),
34 fColorsPalette(NULL),
35 fListenerValid(false)
36 {
37 }
38
39
~TerminalBuffer()40 TerminalBuffer::~TerminalBuffer()
41 {
42 free(fAlternateScreen);
43 delete fAlternateHistory;
44 delete[] fColorsPalette;
45 }
46
47
48 status_t
Init(int32 width,int32 height,int32 historySize)49 TerminalBuffer::Init(int32 width, int32 height, int32 historySize)
50 {
51 if (BLocker::InitCheck() < 0)
52 return BLocker::InitCheck();
53
54 fAlternateScreen = _AllocateLines(width, height);
55 if (fAlternateScreen == NULL)
56 return B_NO_MEMORY;
57
58 for (int32 i = 0; i < height; i++)
59 fAlternateScreen[i]->Clear();
60
61 fColorsPalette = new(std::nothrow) rgb_color[kTermColorCount];
62 if (fColorsPalette == NULL)
63 return B_NO_MEMORY;
64
65 for (uint i = 0; i < kTermColorCount; i++)
66 fColorsPalette[i] = TermApp::DefaultPalette()[i];
67
68 return BasicTerminalBuffer::Init(width, height, historySize);
69 }
70
71
72 void
SetListener(BMessenger listener)73 TerminalBuffer::SetListener(BMessenger listener)
74 {
75 fListener = listener;
76 fListenerValid = true;
77 }
78
79
80 void
UnsetListener()81 TerminalBuffer::UnsetListener()
82 {
83 fListenerValid = false;
84 }
85
86
87 int
Encoding() const88 TerminalBuffer::Encoding() const
89 {
90 return fEncoding;
91 }
92
93
94 void
EnableInterpretMetaKey(bool enable)95 TerminalBuffer::EnableInterpretMetaKey(bool enable)
96 {
97 if (fListenerValid) {
98 BMessage message(MSG_ENABLE_META_KEY);
99 message.AddBool("enableInterpretMetaKey", enable);
100 fListener.SendMessage(&message);
101 }
102 }
103
104
105 void
EnableMetaKeySendsEscape(bool enable)106 TerminalBuffer::EnableMetaKeySendsEscape(bool enable)
107 {
108 if (fListenerValid) {
109 BMessage message(MSG_ENABLE_META_KEY);
110 message.AddBool("enableMetaKeySendsEscape", enable);
111 fListener.SendMessage(&message);
112 }
113 }
114
115
116 void
EnableBracketedPasteMode(bool enable)117 TerminalBuffer::EnableBracketedPasteMode(bool enable)
118 {
119 if (fListenerValid) {
120 BMessage message(MSG_ENABLE_BRACKETED_PASTE);
121 message.AddBool("enableBracketedPaste", enable);
122 fListener.SendMessage(&message);
123 }
124 }
125
126
127 void
ReportX10MouseEvent(bool reportX10MouseEvent)128 TerminalBuffer::ReportX10MouseEvent(bool reportX10MouseEvent)
129 {
130 if (fListenerValid) {
131 BMessage message(MSG_REPORT_MOUSE_EVENT);
132 message.AddBool("reportX10MouseEvent", reportX10MouseEvent);
133 fListener.SendMessage(&message);
134 }
135 }
136
137
138 void
ReportNormalMouseEvent(bool reportNormalMouseEvent)139 TerminalBuffer::ReportNormalMouseEvent(bool reportNormalMouseEvent)
140 {
141 if (fListenerValid) {
142 BMessage message(MSG_REPORT_MOUSE_EVENT);
143 message.AddBool("reportNormalMouseEvent", reportNormalMouseEvent);
144 fListener.SendMessage(&message);
145 }
146 }
147
148
149 void
ReportButtonMouseEvent(bool report)150 TerminalBuffer::ReportButtonMouseEvent(bool report)
151 {
152 if (fListenerValid) {
153 BMessage message(MSG_REPORT_MOUSE_EVENT);
154 message.AddBool("reportButtonMouseEvent", report);
155 fListener.SendMessage(&message);
156 }
157 }
158
159
160 void
ReportAnyMouseEvent(bool reportAnyMouseEvent)161 TerminalBuffer::ReportAnyMouseEvent(bool reportAnyMouseEvent)
162 {
163 if (fListenerValid) {
164 BMessage message(MSG_REPORT_MOUSE_EVENT);
165 message.AddBool("reportAnyMouseEvent", reportAnyMouseEvent);
166 fListener.SendMessage(&message);
167 }
168 }
169
170
171 void
EnableExtendedMouseCoordinates(bool enable)172 TerminalBuffer::EnableExtendedMouseCoordinates(bool enable)
173 {
174 if (fListenerValid) {
175 BMessage message(MSG_REPORT_MOUSE_EVENT);
176 message.AddBool("enableExtendedMouseCoordinates", enable);
177 fListener.SendMessage(&message);
178 }
179 }
180
181
182 void
SetEncoding(int encoding)183 TerminalBuffer::SetEncoding(int encoding)
184 {
185 fEncoding = encoding;
186 }
187
188
189 void
SetTitle(const char * title)190 TerminalBuffer::SetTitle(const char* title)
191 {
192 if (fListenerValid) {
193 BMessage message(MSG_SET_TERMINAL_TITLE);
194 message.AddString("title", title);
195 fListener.SendMessage(&message);
196 }
197 }
198
199
200 void
SetColors(uint8 * indexes,rgb_color * colors,int32 count,bool dynamic)201 TerminalBuffer::SetColors(uint8* indexes, rgb_color* colors,
202 int32 count, bool dynamic)
203 {
204 if (fListenerValid) {
205 BMessage message(MSG_SET_TERMINAL_COLORS);
206 message.AddInt32("count", count);
207 message.AddBool("dynamic", dynamic);
208 message.AddData("index", B_UINT8_TYPE,
209 indexes, sizeof(uint8), true, count);
210 message.AddData("color", B_RGB_COLOR_TYPE,
211 colors, sizeof(rgb_color), true, count);
212
213 for (int i = 1; i < count; i++) {
214 message.AddData("index", B_UINT8_TYPE, &indexes[i], sizeof(uint8));
215 message.AddData("color", B_RGB_COLOR_TYPE, &colors[i],
216 sizeof(rgb_color));
217 }
218
219 fListener.SendMessage(&message);
220 }
221 }
222
223
224 void
ResetColors(uint8 * indexes,int32 count,bool dynamic)225 TerminalBuffer::ResetColors(uint8* indexes, int32 count, bool dynamic)
226 {
227 if (fListenerValid) {
228 BMessage message(MSG_RESET_TERMINAL_COLORS);
229 message.AddInt32("count", count);
230 message.AddBool("dynamic", dynamic);
231 message.AddData("index", B_UINT8_TYPE,
232 indexes, sizeof(uint8), true, count);
233
234 for (int i = 1; i < count; i++)
235 message.AddData("index", B_UINT8_TYPE, &indexes[i], sizeof(uint8));
236
237 fListener.SendMessage(&message);
238 }
239 }
240
241
242 void
GetColor(uint8 index)243 TerminalBuffer::GetColor(uint8 index)
244 {
245 if (fListenerValid) {
246 BMessage message(MSG_GET_TERMINAL_COLOR);
247 message.AddUInt8("index", index);
248 fListener.SendMessage(&message);
249 }
250 }
251
252
253 void
SetCursorStyle(int32 style,bool blinking)254 TerminalBuffer::SetCursorStyle(int32 style, bool blinking)
255 {
256 if (fListenerValid) {
257 BMessage message(MSG_SET_CURSOR_STYLE);
258 message.AddInt32("style", style);
259 message.AddBool("blinking", blinking);
260 fListener.SendMessage(&message);
261 }
262 }
263
264
265 void
SetCursorBlinking(bool blinking)266 TerminalBuffer::SetCursorBlinking(bool blinking)
267 {
268 if (fListenerValid) {
269 BMessage message(MSG_SET_CURSOR_STYLE);
270 message.AddBool("blinking", blinking);
271 fListener.SendMessage(&message);
272 }
273 }
274
275
276 void
SetCursorHidden(bool hidden)277 TerminalBuffer::SetCursorHidden(bool hidden)
278 {
279 if (fListenerValid) {
280 BMessage message(MSG_SET_CURSOR_STYLE);
281 message.AddBool("hidden", hidden);
282 fListener.SendMessage(&message);
283 }
284 }
285
286
287 void
SetPaletteColor(uint8 index,rgb_color color)288 TerminalBuffer::SetPaletteColor(uint8 index, rgb_color color)
289 {
290 fColorsPalette[index] = color;
291 }
292
293
294 void
NotifyQuit(int32 reason)295 TerminalBuffer::NotifyQuit(int32 reason)
296 {
297 if (fListenerValid) {
298 BMessage message(MSG_QUIT_TERMNAL);
299 message.AddInt32("reason", reason);
300 fListener.SendMessage(&message);
301 }
302 }
303
304
305 void
NotifyListener()306 TerminalBuffer::NotifyListener()
307 {
308 if (fListenerValid)
309 fListener.SendMessage(MSG_TERMINAL_BUFFER_CHANGED);
310 }
311
312
313 status_t
ResizeTo(int32 width,int32 height)314 TerminalBuffer::ResizeTo(int32 width, int32 height)
315 {
316 int32 historyCapacity = 0;
317 if (!fAlternateScreenActive)
318 historyCapacity = HistoryCapacity();
319 else if (fAlternateHistory != NULL)
320 historyCapacity = fAlternateHistory->Capacity();
321
322 return ResizeTo(width, height, historyCapacity);
323 }
324
325
326 status_t
ResizeTo(int32 width,int32 height,int32 historyCapacity)327 TerminalBuffer::ResizeTo(int32 width, int32 height, int32 historyCapacity)
328 {
329 // switch to the normal screen buffer first
330 bool alternateScreenActive = fAlternateScreenActive;
331 if (alternateScreenActive)
332 _SwitchScreenBuffer();
333
334 int32 oldWidth = fWidth;
335 int32 oldHeight = fHeight;
336
337 // Resize the normal screen buffer/history.
338 status_t error = BasicTerminalBuffer::ResizeTo(width, height,
339 historyCapacity);
340 if (error != B_OK) {
341 if (alternateScreenActive)
342 _SwitchScreenBuffer();
343 return error;
344 }
345
346 // Switch to the alternate screen buffer and resize it.
347 if (fAlternateScreen != NULL) {
348 TermPos cursor = fCursor;
349 fCursor.SetTo(0, 0);
350 fWidth = oldWidth;
351 fHeight = oldHeight;
352
353 _SwitchScreenBuffer();
354
355 error = BasicTerminalBuffer::ResizeTo(width, height, 0);
356
357 fWidth = width;
358 fHeight = height;
359 fCursor = cursor;
360
361 // Switch back.
362 if (!alternateScreenActive)
363 _SwitchScreenBuffer();
364
365 if (error != B_OK) {
366 // This sucks -- we can't do anything about it. Delete the
367 // alternate screen buffer.
368 _FreeLines(fAlternateScreen, oldHeight);
369 fAlternateScreen = NULL;
370 }
371 }
372
373 return error;
374 }
375
376
377 void
UseAlternateScreenBuffer(bool clear)378 TerminalBuffer::UseAlternateScreenBuffer(bool clear)
379 {
380 if (fAlternateScreenActive || fAlternateScreen == NULL)
381 return;
382
383 _SwitchScreenBuffer();
384
385 if (clear)
386 Clear(false);
387
388 _InvalidateAll();
389 }
390
391
392 void
UseNormalScreenBuffer()393 TerminalBuffer::UseNormalScreenBuffer()
394 {
395 if (!fAlternateScreenActive)
396 return;
397
398 _SwitchScreenBuffer();
399 _InvalidateAll();
400 }
401
402
403 void
_SwitchScreenBuffer()404 TerminalBuffer::_SwitchScreenBuffer()
405 {
406 std::swap(fScreen, fAlternateScreen);
407 std::swap(fHistory, fAlternateHistory);
408 std::swap(fScreenOffset, fAlternateScreenOffset);
409 std::swap(fAttributes, fAlternateAttributes);
410 fAlternateScreenActive = !fAlternateScreenActive;
411 }
412