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