xref: /haiku/src/apps/terminal/TerminalBuffer.cpp (revision 2231cbd5fe30db1df3dfedb02d912a19ddab530f)
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