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