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