xref: /haiku/src/servers/app/drawing/interface/remote/RemoteHWInterface.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
1 /*
2  * Copyright 2009, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include "RemoteHWInterface.h"
10 #include "RemoteDrawingEngine.h"
11 #include "RemoteEventStream.h"
12 #include "RemoteMessage.h"
13 
14 #include "NetReceiver.h"
15 #include "NetSender.h"
16 #include "StreamingRingBuffer.h"
17 
18 #include <Autolock.h>
19 #include <NetEndpoint.h>
20 
21 #include <new>
22 #include <string.h>
23 
24 
25 #define TRACE(x...)				/*debug_printf("RemoteHWInterface: "x)*/
26 #define TRACE_ALWAYS(x...)		debug_printf("RemoteHWInterface: "x)
27 #define TRACE_ERROR(x...)		debug_printf("RemoteHWInterface: "x)
28 
29 
30 struct callback_info {
31 	uint32				token;
32 	RemoteHWInterface::CallbackFunction	callback;
33 	void*				cookie;
34 };
35 
36 
37 RemoteHWInterface::RemoteHWInterface(const char* target)
38 	:
39 	HWInterface(),
40 	fTarget(target),
41 	fRemoteHost(NULL),
42 	fRemotePort(10900),
43 	fIsConnected(false),
44 	fProtocolVersion(100),
45 	fConnectionSpeed(0),
46 	fListenPort(10901),
47 	fSendEndpoint(NULL),
48 	fReceiveEndpoint(NULL),
49 	fSendBuffer(NULL),
50 	fReceiveBuffer(NULL),
51 	fSender(NULL),
52 	fReceiver(NULL),
53 	fEventThread(-1),
54 	fEventStream(NULL),
55 	fCallbackLocker("callback locker")
56 {
57 	fDisplayMode.virtual_width = 640;
58 	fDisplayMode.virtual_height = 480;
59 	fDisplayMode.space = B_RGB32;
60 
61 	fRemoteHost = strdup(fTarget);
62 	char *portStart = strchr(fRemoteHost, ':');
63 	if (portStart != NULL) {
64 		portStart[0] = 0;
65 		portStart++;
66 		if (sscanf(portStart, "%lu", &fRemotePort) != 1) {
67 			fInitStatus = B_BAD_VALUE;
68 			return;
69 		}
70 
71 		fListenPort = fRemotePort + 1;
72 	}
73 
74 	fSendEndpoint = new(std::nothrow) BNetEndpoint();
75 	if (fSendEndpoint == NULL) {
76 		fInitStatus = B_NO_MEMORY;
77 		return;
78 	}
79 
80 	fReceiveEndpoint = new(std::nothrow) BNetEndpoint();
81 	if (fReceiveEndpoint == NULL) {
82 		fInitStatus = B_NO_MEMORY;
83 		return;
84 	}
85 
86 	fInitStatus = fReceiveEndpoint->Bind(fListenPort);
87 	if (fInitStatus != B_OK)
88 		return;
89 
90 	fSendBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024);
91 	if (fSendBuffer == NULL) {
92 		fInitStatus = B_NO_MEMORY;
93 		return;
94 	}
95 
96 	fInitStatus = fSendBuffer->InitCheck();
97 	if (fInitStatus != B_OK)
98 		return;
99 
100 	fReceiveBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024);
101 	if (fReceiveBuffer == NULL) {
102 		fInitStatus = B_NO_MEMORY;
103 		return;
104 	}
105 
106 	fInitStatus = fReceiveBuffer->InitCheck();
107 	if (fInitStatus != B_OK)
108 		return;
109 
110 	fSender = new(std::nothrow) NetSender(fSendEndpoint, fSendBuffer);
111 	if (fSender == NULL) {
112 		fInitStatus = B_NO_MEMORY;
113 		return;
114 	}
115 
116 	fReceiver = new(std::nothrow) NetReceiver(fReceiveEndpoint, fReceiveBuffer);
117 	if (fReceiver == NULL) {
118 		fInitStatus = B_NO_MEMORY;
119 		return;
120 	}
121 
122 	fEventStream = new(std::nothrow) RemoteEventStream();
123 	if (fEventStream == NULL) {
124 		fInitStatus = B_NO_MEMORY;
125 		return;
126 	}
127 
128 	fSendEndpoint->SetTimeout(3 * 1000 * 1000);
129 	fInitStatus = _Connect();
130 	if (fInitStatus != B_OK)
131 		return;
132 
133 	fEventThread = spawn_thread(_EventThreadEntry, "remote event thread",
134 		B_NORMAL_PRIORITY, this);
135 	if (fEventThread < 0) {
136 		fInitStatus = fEventThread;
137 		return;
138 	}
139 
140 	resume_thread(fEventThread);
141 }
142 
143 
144 RemoteHWInterface::~RemoteHWInterface()
145 {
146 	delete fReceiver;
147 	delete fReceiveBuffer;
148 
149 	delete fSendBuffer;
150 	delete fSender;
151 
152 	delete fReceiveEndpoint;
153 	delete fSendEndpoint;
154 
155 	delete fEventStream;
156 
157 	free(fRemoteHost);
158 }
159 
160 
161 status_t
162 RemoteHWInterface::Initialize()
163 {
164 	return fInitStatus;
165 }
166 
167 
168 status_t
169 RemoteHWInterface::Shutdown()
170 {
171 	_Disconnect();
172 	return B_OK;
173 }
174 
175 
176 DrawingEngine*
177 RemoteHWInterface::CreateDrawingEngine()
178 {
179 	return new(std::nothrow) RemoteDrawingEngine(this);
180 }
181 
182 
183 EventStream*
184 RemoteHWInterface::CreateEventStream()
185 {
186 	return fEventStream;
187 }
188 
189 
190 status_t
191 RemoteHWInterface::AddCallback(uint32 token, CallbackFunction callback,
192 	void* cookie)
193 {
194 	BAutolock lock(fCallbackLocker);
195 	int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
196 	if (index >= 0)
197 		return B_NAME_IN_USE;
198 
199 	callback_info* info = new(std::nothrow) callback_info;
200 	if (info == NULL)
201 		return B_NO_MEMORY;
202 
203 	info->token = token;
204 	info->callback = callback;
205 	info->cookie = cookie;
206 
207 	fCallbacks.AddItem(info, -index - 1);
208 	return B_OK;
209 }
210 
211 
212 bool
213 RemoteHWInterface::RemoveCallback(uint32 token)
214 {
215 	BAutolock lock(fCallbackLocker);
216 	int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
217 	if (index < 0)
218 		return false;
219 
220 	delete fCallbacks.RemoveItemAt(index);
221 	return true;
222 }
223 
224 
225 callback_info*
226 RemoteHWInterface::_FindCallback(uint32 token)
227 {
228 	BAutolock lock(fCallbackLocker);
229 	return fCallbacks.BinarySearchByKey(token, &_CallbackCompare);
230 }
231 
232 
233 int
234 RemoteHWInterface::_CallbackCompare(const uint32* key,
235 	const callback_info* info)
236 {
237 	if (info->token == *key)
238 		return 0;
239 
240 	if (info->token < *key)
241 		return -1;
242 
243 	return 1;
244 }
245 
246 
247 int32
248 RemoteHWInterface::_EventThreadEntry(void* data)
249 {
250 	return ((RemoteHWInterface*)data)->_EventThread();
251 }
252 
253 
254 status_t
255 RemoteHWInterface::_EventThread()
256 {
257 	RemoteMessage message(fReceiveBuffer, fSendBuffer);
258 	while (true) {
259 		uint16 code;
260 		status_t result = message.NextMessage(code);
261 		if (result != B_OK) {
262 			TRACE_ERROR("failed to read message from receiver: %s\n",
263 				strerror(result));
264 			return result;
265 		}
266 
267 		TRACE("got message code %u with %lu bytes\n", code, message.DataLeft());
268 
269 		if (code >= RP_MOUSE_MOVED && code <= RP_MODIFIERS_CHANGED) {
270 			// an input event, dispatch to the event stream
271 			if (fEventStream->EventReceived(message))
272 				continue;
273 		}
274 
275 		switch (code) {
276 			case RP_UPDATE_DISPLAY_MODE:
277 			{
278 				// TODO: implement, we only handle it in the context of the
279 				// initial mode setup on connect
280 				break;
281 			}
282 
283 			default:
284 			{
285 				uint32 token;
286 				if (message.Read(token) == B_OK) {
287 					callback_info* info = _FindCallback(token);
288 					if (info != NULL && info->callback(info->cookie, message))
289 						break;
290 				}
291 
292 				TRACE_ERROR("unhandled remote event code %u\n", code);
293 				break;
294 			}
295 		}
296 	}
297 }
298 
299 
300 status_t
301 RemoteHWInterface::_Connect()
302 {
303 	TRACE("connecting to host \"%s\" port %lu\n", fRemoteHost, fRemotePort);
304 	status_t result = fSendEndpoint->Connect(fRemoteHost, (uint16)fRemotePort);
305 	if (result != B_OK) {
306 		TRACE_ERROR("failed to connect to host \"%s\" port %lu\n", fRemoteHost,
307 			fRemotePort);
308 		return result;
309 	}
310 
311 	RemoteMessage message(fReceiveBuffer, fSendBuffer);
312 	message.Start(RP_INIT_CONNECTION);
313 	message.Add(fListenPort);
314 	result = message.Flush();
315 	if (result != B_OK) {
316 		TRACE_ERROR("failed to send init connection message\n");
317 		return result;
318 	}
319 
320 	uint16 code;
321 	result = message.NextMessage(code);
322 	if (result != B_OK) {
323 		TRACE_ERROR("failed to read message from receiver: %s\n",
324 			strerror(result));
325 		return result;
326 	}
327 
328 	TRACE("code %u with %lu bytes of data\n", code, message.DataLeft());
329 	if (code != RP_UPDATE_DISPLAY_MODE) {
330 		TRACE_ERROR("invalid connection init code %u\n", code);
331 		return B_ERROR;
332 	}
333 
334 	int32 width, height;
335 	message.Read(width);
336 	result = message.Read(height);
337 	if (result != B_OK) {
338 		TRACE_ERROR("failed to get initial display mode\n");
339 		return result;
340 	}
341 
342 	fDisplayMode.virtual_width = width;
343 	fDisplayMode.virtual_height = height;
344 	return B_OK;
345 }
346 
347 
348 void
349 RemoteHWInterface::_Disconnect()
350 {
351 	if (fIsConnected) {
352 		RemoteMessage message(NULL, fSendBuffer);
353 		message.Start(RP_CLOSE_CONNECTION);
354 		message.Flush();
355 		fIsConnected = false;
356 	}
357 
358 	if (fSendEndpoint != NULL)
359 		fSendEndpoint->Close();
360 	if (fReceiveEndpoint != NULL)
361 		fReceiveEndpoint->Close();
362 }
363 
364 
365 status_t
366 RemoteHWInterface::SetMode(const display_mode& mode)
367 {
368 	// The display mode depends on the screen resolution of the client, we
369 	// don't allow to change it.
370 	return B_UNSUPPORTED;
371 }
372 
373 
374 void
375 RemoteHWInterface::GetMode(display_mode* mode)
376 {
377 	if (mode == NULL || !ReadLock())
378 		return;
379 
380 	*mode = fDisplayMode;
381 	ReadUnlock();
382 }
383 
384 
385 status_t
386 RemoteHWInterface::GetDeviceInfo(accelerant_device_info* info)
387 {
388 	if (!ReadLock())
389 		return B_ERROR;
390 
391 	info->version = fProtocolVersion;
392 	info->dac_speed = fConnectionSpeed;
393 	info->memory = 33554432; // 32MB
394 	snprintf(info->name, sizeof(info->name), "Haiku, Inc. RemoteHWInterface");
395 	snprintf(info->chipset, sizeof(info->chipset), "Haiku, Inc. Chipset");
396 	snprintf(info->serial_no, sizeof(info->serial_no), fTarget);
397 
398 	ReadUnlock();
399 	return B_OK;
400 }
401 
402 
403 status_t
404 RemoteHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
405 {
406 	// We don't actually have a frame buffer.
407 	return B_UNSUPPORTED;
408 }
409 
410 
411 status_t
412 RemoteHWInterface::GetModeList(display_mode** _modes, uint32* _count)
413 {
414 	AutoReadLocker _(this);
415 
416 	display_mode* modes = new(std::nothrow) display_mode[1];
417 	if (modes == NULL)
418 		return B_NO_MEMORY;
419 
420 	modes[0] = fDisplayMode;
421 	*_modes = modes;
422 	*_count = 1;
423 	return B_OK;
424 }
425 
426 
427 status_t
428 RemoteHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
429 	uint32* high)
430 {
431 	return B_UNSUPPORTED;
432 }
433 
434 
435 status_t
436 RemoteHWInterface::GetTimingConstraints(display_timing_constraints* constraints)
437 {
438 	return B_UNSUPPORTED;
439 }
440 
441 
442 status_t
443 RemoteHWInterface::ProposeMode(display_mode* candidate, const display_mode* low,
444 	const display_mode* high)
445 {
446 	return B_UNSUPPORTED;
447 }
448 
449 
450 status_t
451 RemoteHWInterface::SetDPMSMode(uint32 state)
452 {
453 	return B_UNSUPPORTED;
454 }
455 
456 
457 uint32
458 RemoteHWInterface::DPMSMode()
459 {
460 	return B_UNSUPPORTED;
461 }
462 
463 
464 uint32
465 RemoteHWInterface::DPMSCapabilities()
466 {
467 	return 0;
468 }
469 
470 
471 sem_id
472 RemoteHWInterface::RetraceSemaphore()
473 {
474 	return -1;
475 }
476 
477 
478 status_t
479 RemoteHWInterface::WaitForRetrace(bigtime_t timeout)
480 {
481 	return B_UNSUPPORTED;
482 }
483 
484 
485 void
486 RemoteHWInterface::SetCursor(ServerCursor* cursor)
487 {
488 	HWInterface::SetCursor(cursor);
489 	RemoteMessage message(NULL, fSendBuffer);
490 	message.Start(RP_SET_CURSOR);
491 	message.AddCursor(Cursor().Get());
492 }
493 
494 
495 void
496 RemoteHWInterface::SetCursorVisible(bool visible)
497 {
498 	HWInterface::SetCursorVisible(visible);
499 	RemoteMessage message(NULL, fSendBuffer);
500 	message.Start(RP_SET_CURSOR_VISIBLE);
501 	message.Add(visible);
502 }
503 
504 
505 void
506 RemoteHWInterface::MoveCursorTo(float x, float y)
507 {
508 	HWInterface::MoveCursorTo(x, y);
509 	RemoteMessage message(NULL, fSendBuffer);
510 	message.Start(RP_MOVE_CURSOR_TO);
511 	message.Add(x);
512 	message.Add(y);
513 }
514 
515 
516 void
517 RemoteHWInterface::SetDragBitmap(const ServerBitmap* bitmap,
518 	const BPoint& offsetFromCursor)
519 {
520 	HWInterface::SetDragBitmap(bitmap, offsetFromCursor);
521 	RemoteMessage message(NULL, fSendBuffer);
522 	message.Start(RP_SET_CURSOR);
523 	message.AddCursor(CursorAndDragBitmap().Get());
524 }
525 
526 
527 RenderingBuffer*
528 RemoteHWInterface::FrontBuffer() const
529 {
530 	return NULL;
531 }
532 
533 
534 RenderingBuffer*
535 RemoteHWInterface::BackBuffer() const
536 {
537 	return NULL;
538 }
539 
540 
541 bool
542 RemoteHWInterface::IsDoubleBuffered() const
543 {
544 	return false;
545 }
546 
547 
548 status_t
549 RemoteHWInterface::InvalidateRegion(BRegion& region)
550 {
551 	RemoteMessage message(NULL, fSendBuffer);
552 	message.Start(RP_INVALIDATE_REGION);
553 	message.AddRegion(region);
554 	return B_OK;
555 }
556 
557 
558 status_t
559 RemoteHWInterface::Invalidate(const BRect& frame)
560 {
561 	RemoteMessage message(NULL, fSendBuffer);
562 	message.Start(RP_INVALIDATE_RECT);
563 	message.Add(frame);
564 	return B_OK;
565 }
566 
567 
568 status_t
569 RemoteHWInterface::CopyBackToFront(const BRect& frame)
570 {
571 	return B_OK;
572 }
573