xref: /haiku/src/servers/app/EventStream.cpp (revision 3e216965baa8d58a67bf7372e2bfa13d999f5a9d)
1 /*
2  * Copyright 2005, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include "EventStream.h"
11 
12 #include <InputServerTypes.h>
13 #include <ServerProtocol.h>
14 #include <shared_cursor_area.h>
15 
16 #include <new>
17 #include <stdio.h>
18 #include <string.h>
19 
20 
21 EventStream::EventStream()
22 {
23 }
24 
25 
26 EventStream::~EventStream()
27 {
28 }
29 
30 
31 bool
32 EventStream::SupportsCursorThread() const
33 {
34 	return false;
35 }
36 
37 
38 bool
39 EventStream::GetNextCursorPosition(BPoint& where)
40 {
41 	return false;
42 }
43 
44 
45 //	#pragma mark -
46 
47 
48 InputServerStream::InputServerStream(BMessenger& messenger)
49 	:
50 	fInputServer(messenger),
51 	fPort(-1),
52 	fQuitting(false),
53 	fLatestMouseMoved(NULL)
54 {
55 	BMessage message(IS_ACQUIRE_INPUT);
56 	fCursorArea = create_area("shared cursor", (void **)&fCursorBuffer, B_ANY_ADDRESS,
57 		B_PAGE_SIZE, B_LAZY_LOCK, B_READ_AREA | B_WRITE_AREA);
58 	if (fCursorArea >= B_OK)
59 		message.AddInt32("cursor area", fCursorArea);
60 
61 	BMessage reply;
62 	if (messenger.SendMessage(&message, &reply) != B_OK)
63 		return;
64 
65 	if (reply.FindInt32("event port", &fPort) != B_OK)
66 		fPort = -1;
67 	if (reply.FindInt32("cursor semaphore", &fCursorSemaphore) != B_OK)
68 		fCursorSemaphore = -1;
69 }
70 
71 
72 #if TEST_MODE
73 InputServerStream::InputServerStream()
74 	:
75 	fQuitting(false),
76 	fCursorSemaphore(-1),
77 	fLatestMouseMoved(NULL)
78 {
79 	fPort = find_port(SERVER_INPUT_PORT);
80 }
81 #endif
82 
83 
84 InputServerStream::~InputServerStream()
85 {
86 	delete_area(fCursorArea);
87 }
88 
89 
90 bool
91 InputServerStream::IsValid()
92 {
93 	port_info portInfo;
94 	if (fPort < B_OK || get_port_info(fPort, &portInfo) != B_OK)
95 		return false;
96 
97 	return true;
98 }
99 
100 
101 void
102 InputServerStream::SendQuit()
103 {
104 	fQuitting = true;
105 	write_port(fPort, 'quit', NULL, 0);
106 	release_sem(fCursorSemaphore);
107 }
108 
109 
110 void
111 InputServerStream::UpdateScreenBounds(BRect bounds)
112 {
113 	BMessage update(IS_SCREEN_BOUNDS_UPDATED);
114 	update.AddRect("screen_bounds", bounds);
115 
116 	fInputServer.SendMessage(&update);
117 }
118 
119 
120 bool
121 InputServerStream::GetNextEvent(BMessage** _event)
122 {
123 	if (fEvents.IsEmpty()) {
124 		// wait for new events
125 		BMessage* event;
126 		status_t status = _MessageFromPort(&event);
127 		if (status == B_OK) {
128 			if (event->what == B_MOUSE_MOVED)
129 				fLatestMouseMoved = event;
130 
131 			fEvents.AddMessage(event);
132 		} else if (status == B_BAD_PORT_ID) {
133 			// our port got deleted - the input_server must have died
134 			fPort = -1;
135 			return false;
136 		}
137 
138 		int32 count = port_count(fPort);
139 		if (count > 0) {
140 			// empty port queue completely while we're at it
141 			for (int32 i = 0; i < count; i++) {
142 				if (_MessageFromPort(&event, 0) == B_OK) {
143 					if (event->what == B_MOUSE_MOVED)
144 						fLatestMouseMoved = event;
145 					fEvents.AddMessage(event);
146 				}
147 			}
148 		}
149 	}
150 
151 	// there are items in our list, so just work through them
152 
153 	*_event = fEvents.NextMessage();
154 	return true;
155 }
156 
157 
158 bool
159 InputServerStream::GetNextCursorPosition(BPoint &where)
160 {
161 	status_t status;
162 	do {
163 		status = acquire_sem(fCursorSemaphore);
164 	} while (status == B_INTERRUPTED);
165 
166 	if (status == B_BAD_SEM_ID) {
167 		// the semaphore is no longer valid - the input_server must have died
168 		fCursorSemaphore = -1;
169 		return false;
170 	}
171 
172 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
173 	uint32 pos = atomic_get((int32*)&fCursorBuffer->pos);
174 #else
175 	uint32 pos = fCursorBuffer->pos;
176 #endif
177 
178 	where.x = pos >> 16UL;
179 	where.y = pos & 0xffff;
180 
181 	atomic_and(&fCursorBuffer->read, 0);
182 		// this tells the input_server that we've read the
183 		// cursor position and want to be notified if updated
184 
185 	if (fQuitting) {
186 		fQuitting = false;
187 		return false;
188 	}
189 
190 	return true;
191 }
192 
193 
194 BMessage*
195 InputServerStream::PeekLatestMouseMoved()
196 {
197 	return fLatestMouseMoved;
198 }
199 
200 
201 status_t
202 InputServerStream::_MessageFromPort(BMessage** _message, bigtime_t timeout)
203 {
204 	uint8 *buffer = NULL;
205 	ssize_t bufferSize;
206 
207 	// read message from port
208 
209 	do {
210 		bufferSize = port_buffer_size_etc(fPort, B_RELATIVE_TIMEOUT, timeout);
211 	} while (bufferSize == B_INTERRUPTED);
212 
213 	if (bufferSize < B_OK)
214 		return bufferSize;
215 
216 	if (bufferSize > 0) {
217 		buffer = new (std::nothrow) uint8[bufferSize];
218 		if (buffer == NULL)
219 			return B_NO_MEMORY;
220 	}
221 
222 	int32 code;
223 	bufferSize = read_port_etc(fPort, &code, buffer, bufferSize,
224 		B_RELATIVE_TIMEOUT, 0);
225 	if (bufferSize < B_OK) {
226 		delete[] buffer;
227 		return bufferSize;
228 	}
229 
230 	if (code == 'quit') {
231 		// this will cause GetNextEvent() to return false
232 		return B_BAD_PORT_ID;
233 	}
234 
235 	// we have the message, now let's unflatten it
236 
237 	BMessage* message = new BMessage(code);
238 	if (message == NULL)
239 		return B_NO_MEMORY;
240 
241 	if (buffer == NULL) {
242 		*_message = message;
243 		return B_OK;
244 	}
245 
246 	status_t status = message->Unflatten((const char*)buffer);
247 	delete[] buffer;
248 
249 	if (status != B_OK) {
250 		printf("Unflatten event failed: %s, port message code was: %ld - %c%c%c%c\n",
251 			strerror(status), code, (int8)(code >> 24), (int8)(code >> 16),
252 			(int8)(code >> 8), (int8)code);
253 		delete message;
254 		return status;
255 	}
256 
257 	*_message = message;
258 	return B_OK;
259 }
260 
261