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 "RemoteEventStream.h"
10
11#include "RemoteMessage.h"
12#include "StreamingRingBuffer.h"
13
14#include <Autolock.h>
15
16#include <new>
17
18
19RemoteEventStream::RemoteEventStream()
20	:
21	fEventList(10, true),
22	fEventListLocker("remote event list"),
23	fEventNotification(-1),
24	fWaitingOnEvent(false),
25	fLatestMouseMovedEvent(NULL),
26	fMousePosition(0, 0),
27	fMouseButtons(0),
28	fModifiers(0)
29{
30	fEventNotification = create_sem(0, "remote event notification");
31}
32
33
34RemoteEventStream::~RemoteEventStream()
35{
36	delete_sem(fEventNotification);
37}
38
39
40void
41RemoteEventStream::UpdateScreenBounds(BRect bounds)
42{
43}
44
45
46bool
47RemoteEventStream::GetNextEvent(BMessage** _event)
48{
49	BAutolock lock(fEventListLocker);
50	while (fEventList.CountItems() == 0) {
51		fWaitingOnEvent = true;
52		lock.Unlock();
53
54		status_t result;
55		do {
56			result = acquire_sem(fEventNotification);
57		} while (result == B_INTERRUPTED);
58
59		lock.Lock();
60		if (!lock.IsLocked())
61			return false;
62	}
63
64	*_event = fEventList.RemoveItemAt(0);
65	return true;
66}
67
68
69status_t
70RemoteEventStream::InsertEvent(BMessage* event)
71{
72	BAutolock lock(fEventListLocker);
73	if (!lock.IsLocked())
74		return B_ERROR;
75
76	if (!fEventList.AddItem(event))
77		return B_ERROR;
78
79	if (event->what == B_MOUSE_MOVED)
80		fLatestMouseMovedEvent = event;
81
82	return B_OK;
83}
84
85
86BMessage*
87RemoteEventStream::PeekLatestMouseMoved()
88{
89	return fLatestMouseMovedEvent;
90}
91
92
93bool
94RemoteEventStream::EventReceived(RemoteMessage& message)
95{
96	uint16 code = message.Code();
97	uint32 what = 0;
98	switch (code) {
99		case RP_MOUSE_MOVED:
100			what = B_MOUSE_MOVED;
101			break;
102		case RP_MOUSE_DOWN:
103			what = B_MOUSE_DOWN;
104			break;
105		case RP_MOUSE_UP:
106			what = B_MOUSE_UP;
107			break;
108		case RP_MOUSE_WHEEL_CHANGED:
109			what = B_MOUSE_WHEEL_CHANGED;
110			break;
111		case RP_KEY_DOWN:
112			what = B_KEY_DOWN;
113			break;
114		case RP_KEY_UP:
115			what = B_KEY_UP;
116			break;
117		case RP_MODIFIERS_CHANGED:
118			what = B_MODIFIERS_CHANGED;
119			break;
120	}
121
122	if (what == 0)
123		return false;
124
125	BMessage* event = new BMessage(what);
126	if (event == NULL)
127		return false;
128
129	event->AddInt64("when", system_time());
130
131	switch (code) {
132		case RP_MOUSE_MOVED:
133		case RP_MOUSE_DOWN:
134		case RP_MOUSE_UP:
135		{
136			message.Read(fMousePosition);
137			if (code != RP_MOUSE_MOVED)
138				message.Read(fMouseButtons);
139
140			event->AddPoint("where", fMousePosition);
141			event->AddInt32("buttons", fMouseButtons);
142			event->AddInt32("modifiers", fModifiers);
143
144			if (code == RP_MOUSE_DOWN) {
145				int32 clicks;
146				if (message.Read(clicks) == B_OK)
147					event->AddInt32("clicks", clicks);
148			}
149
150			if (code == RP_MOUSE_MOVED)
151				fLatestMouseMovedEvent = event;
152			break;
153		}
154
155		case RP_MOUSE_WHEEL_CHANGED:
156		{
157			float xDelta, yDelta;
158			message.Read(xDelta);
159			message.Read(yDelta);
160			event->AddFloat("be:wheel_delta_x", xDelta);
161			event->AddFloat("be:wheel_delta_y", yDelta);
162			break;
163		}
164
165		case RP_KEY_DOWN:
166		case RP_KEY_UP:
167		{
168			int32 numBytes;
169			if (message.Read(numBytes) != B_OK)
170				break;
171
172			char* bytes = (char*)malloc(numBytes + 1);
173			if (bytes == NULL)
174				break;
175
176			if (message.ReadList(bytes, numBytes) != B_OK) {
177				free(bytes);
178				break;
179			}
180
181			for (int32 i = 0; i < numBytes; i++)
182				event->AddInt8("byte", (int8)bytes[i]);
183
184			bytes[numBytes] = 0;
185			event->AddData("bytes", B_STRING_TYPE, bytes, numBytes + 1, false);
186			event->AddInt32("modifiers", fModifiers);
187
188			int32 rawChar;
189			if (message.Read(rawChar) == B_OK)
190				event->AddInt32("raw_char", rawChar);
191
192			int32 key;
193			if (message.Read(key) == B_OK)
194				event->AddInt32("key", key);
195
196			free(bytes);
197			break;
198		}
199
200		case RP_MODIFIERS_CHANGED:
201		{
202			event->AddInt32("be:old_modifiers", fModifiers);
203			message.Read(fModifiers);
204			event->AddInt32("modifiers", fModifiers);
205			break;
206		}
207	}
208
209	BAutolock lock(fEventListLocker);
210	fEventList.AddItem(event);
211	if (fWaitingOnEvent) {
212		fWaitingOnEvent = false;
213		lock.Unlock();
214		release_sem(fEventNotification);
215	}
216
217	return true;
218}
219