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 status_t 39 EventStream::GetNextCursorPosition(BPoint& where, bigtime_t timeout) 40 { 41 return B_ERROR; 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 while (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 status_t 159 InputServerStream::GetNextCursorPosition(BPoint &where, bigtime_t timeout) 160 { 161 status_t status; 162 163 do { 164 status = acquire_sem_etc(fCursorSemaphore, 1, B_RELATIVE_TIMEOUT, 165 timeout); 166 } while (status == B_INTERRUPTED); 167 168 if (status == B_TIMED_OUT) 169 return status; 170 171 if (status == B_BAD_SEM_ID) { 172 // the semaphore is no longer valid - the input_server must have died 173 fCursorSemaphore = -1; 174 return B_ERROR; 175 } 176 177 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 178 uint32 pos = atomic_get((int32*)&fCursorBuffer->pos); 179 #else 180 uint32 pos = fCursorBuffer->pos; 181 #endif 182 183 where.x = pos >> 16UL; 184 where.y = pos & 0xffff; 185 186 atomic_and(&fCursorBuffer->read, 0); 187 // this tells the input_server that we've read the 188 // cursor position and want to be notified if updated 189 190 if (fQuitting) { 191 fQuitting = false; 192 return B_ERROR; 193 } 194 195 return B_OK; 196 } 197 198 199 status_t 200 InputServerStream::InsertEvent(BMessage* event) 201 { 202 fEvents.AddMessage(event); 203 status_t status = write_port_etc(fPort, 'insm', NULL, 0, B_RELATIVE_TIMEOUT, 204 0); 205 if (status == B_BAD_PORT_ID) 206 return status; 207 208 // If the port is full, we obviously don't care to report this, as we 209 // already placed our message. 210 return B_OK; 211 } 212 213 214 BMessage* 215 InputServerStream::PeekLatestMouseMoved() 216 { 217 return fLatestMouseMoved; 218 } 219 220 221 status_t 222 InputServerStream::_MessageFromPort(BMessage** _message, bigtime_t timeout) 223 { 224 uint8 *buffer = NULL; 225 ssize_t bufferSize; 226 227 // read message from port 228 229 do { 230 bufferSize = port_buffer_size_etc(fPort, B_RELATIVE_TIMEOUT, timeout); 231 } while (bufferSize == B_INTERRUPTED); 232 233 if (bufferSize < B_OK) 234 return bufferSize; 235 236 if (bufferSize > 0) { 237 buffer = new (std::nothrow) uint8[bufferSize]; 238 if (buffer == NULL) 239 return B_NO_MEMORY; 240 } 241 242 int32 code; 243 bufferSize = read_port_etc(fPort, &code, buffer, bufferSize, 244 B_RELATIVE_TIMEOUT, 0); 245 if (bufferSize < B_OK) { 246 delete[] buffer; 247 return bufferSize; 248 } 249 250 if (code == 'quit') { 251 // this will cause GetNextEvent() to return false 252 return B_BAD_PORT_ID; 253 } 254 if (code == 'insm') { 255 // a message has been inserted into our queue 256 return B_INTERRUPTED; 257 } 258 259 // we have the message, now let's unflatten it 260 261 BMessage* message = new BMessage(code); 262 if (message == NULL) 263 return B_NO_MEMORY; 264 265 if (buffer == NULL) { 266 *_message = message; 267 return B_OK; 268 } 269 270 status_t status = message->Unflatten((const char*)buffer); 271 delete[] buffer; 272 273 if (status != B_OK) { 274 printf("Unflatten event failed: %s, port message code was: %" B_PRId32 275 " - %c%c%c%c\n", strerror(status), code, (int8)(code >> 24), 276 (int8)(code >> 16), (int8)(code >> 8), (int8)code); 277 delete message; 278 return status; 279 } 280 281 *_message = message; 282 return B_OK; 283 } 284 285