WindowManager.cpp (12748B)
1 #include <blt/os.h> 2 #include <blt/syscall.h> 3 #include <blt/namer.h> 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <string.h> 7 #include <win/Event.h> 8 9 #include "WindowManager.h" 10 #include "Renderer.h" 11 #include "Window.h" 12 #include "protocol.h" 13 #include "SerialMouse.h" 14 #include "Renderer_vga.h" 15 16 const int kReceiveBufferSize = 16384; 17 const int kMaxStrLen = 256; 18 19 WindowManager::WindowManager(Renderer *screenRenderer) 20 : fNextWindowID(1), 21 fReceiveBufferSize(0), 22 fReceiveBufferPos(0), 23 fCurrentMouseFocus(0), 24 fMouseFocusLocked(false), 25 fInFocusLockedWindow(false), 26 fScreenRenderer(screenRenderer) 27 { 28 fReceiveBuffer = (char*) malloc(kReceiveBufferSize); 29 for (int i = 0; i < kMaxWindows; i++) 30 fWindowArray[i] = 0; 31 32 // Create the root window, which has an id of 0. 33 fWindowArray[0] = new Window(0, -1, screenRenderer); 34 Region screen; 35 screen.Include(screenRenderer->Bounds()); 36 fWindowArray[0]->SetVisibleRegion(screen); 37 38 fCursorLock = qsem_create(1); 39 40 thr_create((void*) StartDispatchThread, this, "draw_thread"); 41 thr_create((void*) StartMouseThread, this, "mouse_thread"); 42 } 43 44 WindowManager::~WindowManager() 45 { 46 qsem_destroy(fCursorLock); 47 } 48 49 Window* WindowManager::CreateWindow(Window *parent, const Rect &rect, int eventPort) 50 { 51 while (fWindowArray[fNextWindowID % kMaxWindows] != 0) 52 fNextWindowID++; 53 54 Window *window = new Window(fNextWindowID, eventPort); 55 fWindowArray[fNextWindowID % kMaxWindows] = window; 56 fNextWindowID++; 57 58 parent->AddChild(rect, window); 59 return window; 60 } 61 62 void WindowManager::InvalidateMouseBoundries() 63 { 64 fMouseBoundries.SetTo(-1, -1, -1, -1); 65 } 66 67 68 void WindowManager::DestroyWindow(Window *window) 69 { 70 fWindowArray[window->ID() % kMaxWindows] = 0; 71 delete window; 72 } 73 74 Window* WindowManager::LookupWindow(int id) 75 { 76 Window *window = fWindowArray[id % kMaxWindows]; 77 if (window && window->ID() == id) 78 return window; 79 80 return 0; 81 } 82 83 Window* WindowManager::WindowAtPoint(int x, int y) 84 { 85 Window *root = LookupWindow(0); 86 return root->ChildAtPoint(x, y); 87 } 88 89 int WindowManager::StartDispatchThread(void *windowManager) 90 { 91 ((WindowManager*) windowManager)->DispatchThread(); 92 return 0; 93 } 94 95 void WindowManager::ReadServicePort(void *data, int size) 96 { 97 int sizeRead = 0; 98 while (sizeRead < size) { 99 int sizeToRead = size - sizeRead; 100 101 if (fReceiveBufferSize - fReceiveBufferPos < sizeToRead) 102 sizeToRead = fReceiveBufferSize - fReceiveBufferPos; 103 104 if (sizeToRead == 0) { 105 msg_hdr_t header; 106 header.src = 0; 107 header.dst = fServicePort; 108 header.data = fReceiveBuffer; 109 header.size = kReceiveBufferSize; 110 111 fReceiveBufferSize = old_port_recv(&header); 112 fReceiveBufferPos = 0; 113 fRequestorPort = header.src; 114 continue; 115 } 116 117 memcpy((void*) ((char*) data + sizeRead), 118 (void*) (fReceiveBuffer + fReceiveBufferPos), sizeToRead); 119 fReceiveBufferPos += sizeToRead; 120 sizeRead += sizeToRead; 121 } 122 } 123 124 void WindowManager::Respond(void *data, int size) 125 { 126 msg_hdr_t header; 127 header.src = fServicePort; 128 header.dst = RequestorPort(); 129 header.data = data; 130 header.size = size; 131 old_port_send(&header); 132 } 133 134 int WindowManager::ReadInt32() 135 { 136 int outval; 137 ReadServicePort(&outval, 4); 138 return outval; 139 } 140 141 short WindowManager::ReadInt16() 142 { 143 short outval; 144 ReadServicePort(&outval, 2); 145 return outval; 146 } 147 148 char WindowManager::ReadInt8() 149 { 150 char outval; 151 ReadServicePort(&outval, 1); 152 return outval; 153 } 154 155 int WindowManager::RequestorPort() const 156 { 157 return fRequestorPort; 158 } 159 160 void WindowManager::LockCursor() 161 { 162 qsem_acquire(fCursorLock); 163 } 164 165 void WindowManager::UnlockCursor() 166 { 167 qsem_release(fCursorLock); 168 } 169 170 void WindowManager::DispatchThread() 171 { 172 fServicePort = port_create(0, "window_server"); 173 174 namer_register(fServicePort, "window_server"); 175 176 while (true) { 177 int opcode = ReadInt8(); 178 switch (opcode) { 179 case OP_DRAW_LINE: { 180 long windowID = ReadInt32(); 181 long x1 = ReadInt32(); 182 long y1 = ReadInt32(); 183 long x2 = ReadInt32(); 184 long y2 = ReadInt32(); 185 186 Window *targetWindow = LookupWindow(windowID); 187 LockCursor(); 188 if (targetWindow) 189 targetWindow->GC().DrawLine(x1, y1, x2, y2); 190 UnlockCursor(); 191 192 break; 193 } 194 195 case OP_FILL_RECT: { 196 long windowID = ReadInt32(); 197 long x1 = ReadInt32(); 198 long y1 = ReadInt32(); 199 long x2 = ReadInt32(); 200 long y2 = ReadInt32(); 201 Window *targetWindow = LookupWindow(windowID); 202 LockCursor(); 203 if (targetWindow) 204 targetWindow->GC().FillRect(x1, y1, x2, y2); 205 UnlockCursor(); 206 207 break; 208 } 209 210 case OP_SET_PEN_COLOR: { 211 long windowID = ReadInt32(); 212 char color = ReadInt8(); 213 Window *targetWindow = LookupWindow(windowID); 214 if (targetWindow) 215 targetWindow->GC().SetColor(color); 216 217 break; 218 } 219 220 case OP_SET_BG_COLOR: { 221 long windowID = ReadInt32(); 222 char color = ReadInt8(); 223 Window *targetWindow = LookupWindow(windowID); 224 if (targetWindow) { 225 targetWindow->SetColor(color); 226 targetWindow->Invalidate(targetWindow->Bounds()); 227 } 228 229 break; 230 } 231 232 case OP_DRAW_STRING: { 233 // Draw string 234 long windowID = ReadInt32(); 235 long x = ReadInt32(); 236 long y = ReadInt32(); 237 238 char buf[kMaxStrLen + 1]; 239 char c; 240 int index = 0; 241 while (true) { 242 c = ReadInt8(); 243 if (c == 0) 244 break; 245 246 if (index < kMaxStrLen) 247 buf[index++] = c; 248 } 249 250 buf[index] = 0; 251 Window *targetWindow = LookupWindow(windowID); 252 LockCursor(); 253 if (targetWindow) 254 targetWindow->GC().DrawString(x, y, buf); 255 256 UnlockCursor(); 257 } 258 259 case OP_DESTROY_WINDOW: { 260 long windowID = ReadInt32(); 261 Window *targetWindow = LookupWindow(windowID); 262 if (targetWindow) 263 DestroyWindow(targetWindow); 264 265 InvalidateMouseBoundries(); 266 break; 267 } 268 269 case OP_SHOW_WINDOW: { 270 long windowID = ReadInt32(); 271 Window *targetWindow = LookupWindow(windowID); 272 if (targetWindow) 273 targetWindow->Show(); 274 275 InvalidateMouseBoundries(); 276 break; 277 } 278 279 case OP_HIDE_WINDOW: { 280 long windowID = ReadInt32(); 281 Window *targetWindow = LookupWindow(windowID); 282 if (targetWindow) 283 targetWindow->Hide(); 284 285 InvalidateMouseBoundries(); 286 break; 287 } 288 289 case OP_MAKE_FOCUS: { 290 long windowID = ReadInt32(); 291 Window *targetWindow = LookupWindow(windowID); 292 if (targetWindow) 293 targetWindow->MoveToFront(); 294 295 InvalidateMouseBoundries(); 296 break; 297 } 298 299 case OP_BEGIN_PAINT: { 300 long windowID = ReadInt32(); 301 Rect rect; 302 Window *targetWindow = LookupWindow(windowID); 303 if (targetWindow) 304 targetWindow->BeginPaint(rect); 305 306 Respond(&rect, sizeof(rect)); 307 break; 308 } 309 310 case OP_END_PAINT: { 311 long windowID = ReadInt32(); 312 Window *targetWindow = LookupWindow(windowID); 313 if (targetWindow) 314 targetWindow->EndPaint(); 315 316 break; 317 } 318 319 case OP_CREATE_WINDOW: { 320 long parentWindow = ReadInt32(); 321 Rect rect; 322 rect.left = ReadInt32(); 323 rect.top = ReadInt32(); 324 rect.right = ReadInt32(); 325 rect.bottom = ReadInt32(); 326 long eventPort = ReadInt32(); 327 328 Window *parent = LookupWindow(parentWindow); 329 int id = -1; 330 LockCursor(); 331 if (parent) 332 id = CreateWindow(parent, rect, eventPort)->ID(); 333 UnlockCursor(); 334 335 Respond(&id, sizeof(id)); 336 InvalidateMouseBoundries(); 337 break; 338 } 339 340 case OP_COPY_RECT: { 341 long windowID = ReadInt32(); 342 Rect sourceRect; 343 sourceRect.left = ReadInt32(); 344 sourceRect.top = ReadInt32(); 345 sourceRect.right = ReadInt32(); 346 sourceRect.bottom = ReadInt32(); 347 348 long destX = ReadInt32(); 349 long destY = ReadInt32(); 350 Rect destRect(sourceRect); 351 destRect.OffsetTo(destX, destY); 352 353 Window *targetWindow = LookupWindow(windowID); 354 LockCursor(); 355 if (targetWindow) { 356 Region invalidateRegion; 357 if (targetWindow->InvalidRegion().Valid()) { 358 // Parts of the window are damaged and can't be copied. 359 Region copyRegion = targetWindow->ClipRegion(); 360 copyRegion.Exclude(targetWindow->InvalidRegion()); 361 targetWindow->GC().CopyRect(sourceRect, destRect, 362 copyRegion, invalidateRegion); 363 } else { 364 targetWindow->GC().CopyRect(sourceRect, destRect, 365 targetWindow->ClipRegion(), invalidateRegion); 366 } 367 368 // Draw parts of the window which have been "copied" 369 // out from under another window. 370 targetWindow->Invalidate(invalidateRegion); 371 } 372 UnlockCursor(); 373 374 break; 375 } 376 377 case OP_INVALIDATE: { 378 long windowID = ReadInt32(); 379 Rect rect; 380 rect.left = ReadInt32(); 381 rect.top = ReadInt32(); 382 rect.right = ReadInt32(); 383 rect.bottom = ReadInt32(); 384 385 Window *targetWindow = LookupWindow(windowID); 386 LockCursor(); 387 if (targetWindow) 388 targetWindow->Invalidate(rect); 389 UnlockCursor(); 390 391 break; 392 } 393 394 case OP_LOCK_MOUSE_FOCUS: 395 fMouseFocusLocked = true; 396 break; 397 398 default: 399 printf("unrecognized drawing command %d\n", opcode); 400 } 401 } 402 } 403 404 void WindowManager::SetCursorPos(int x, int y) 405 { 406 LockCursor(); 407 // a bit of a hack for now 408 ((Renderer_vga*)fScreenRenderer)->SetCursorPosition(x, y); 409 UnlockCursor(); 410 } 411 412 int WindowManager::StartMouseThread(void *_wm) 413 { 414 ((WindowManager*) _wm)->MouseThread(); 415 return 0; 416 } 417 418 void WindowManager::MouseThread() 419 { 420 SerialMouse *mouse = new SerialMouse(fScreenRenderer->BufferWidth() - 1, fScreenRenderer->BufferHeight() 421 - 1); 422 int cx = 160, cy = 100, buttons = 0; 423 int last_cx = cx; 424 int last_cy = cy; 425 int last_buttons = buttons; 426 while (true) { 427 mouse->GetPos(&cx, &cy, &buttons); 428 429 if (last_cx != cx || last_cy != cy) { 430 SetCursorPos(cx, cy); 431 last_cx = cx; 432 last_cy = cy; 433 434 Window *oldMouseFocus = fCurrentMouseFocus; 435 if (fCurrentMouseFocus == 0 || !fMouseBoundries.Contains(cx, cy)) { 436 // Either there is no focus window, or we have moved out 437 // of the current rectangle that is known to be in this window. 438 // Check to see what window we are over. 439 Window *focusWindow = WindowAtPoint(cx, cy); 440 if (fMouseFocusLocked) { 441 // Mouse focus is locked, don't actually switch focus windows 442 if (focusWindow == fCurrentMouseFocus && !fInFocusLockedWindow) { 443 // Inform the window with locked focus that the mouse has entered 444 Rect screenFrame = fCurrentMouseFocus->LocalToScreen( 445 fCurrentMouseFocus->Bounds()); 446 Event evt; 447 evt.what = EVT_MOUSE_ENTER; 448 evt.target = fCurrentMouseFocus->ID(); 449 evt.x = cx - screenFrame.left; 450 evt.y = cy - screenFrame.top; 451 fCurrentMouseFocus->PostEvent(&evt); 452 fInFocusLockedWindow = true; 453 } else if (focusWindow != fCurrentMouseFocus && fInFocusLockedWindow) { 454 // Inform the window with the locked focus that the mouse has left. 455 Event evt; 456 evt.what = EVT_MOUSE_LEAVE; 457 evt.target = oldMouseFocus->ID(); 458 fCurrentMouseFocus->PostEvent(&evt); 459 fInFocusLockedWindow = false; 460 } 461 462 focusWindow->ClipRegion().FindRect(cx, cy, fMouseBoundries); 463 } else { 464 fCurrentMouseFocus = focusWindow; 465 fCurrentMouseFocus->ClipRegion().FindRect(cx, cy, fMouseBoundries); 466 } 467 } 468 469 if (oldMouseFocus == fCurrentMouseFocus) { 470 // Post a mouse moved message to the current focus window 471 Rect screenFrame = fCurrentMouseFocus->LocalToScreen( 472 fCurrentMouseFocus->Bounds()); 473 474 Event evt; 475 evt.what = EVT_MOUSE_MOVED; 476 evt.target = fCurrentMouseFocus->ID(); 477 evt.x = cx - screenFrame.left; 478 evt.y = cy - screenFrame.top; 479 fCurrentMouseFocus->PostEvent(&evt); 480 } else { 481 // Inform the old window (if there is one), that the mouse is leaving 482 if (oldMouseFocus) { 483 Event evt; 484 evt.what = EVT_MOUSE_LEAVE; 485 evt.target = oldMouseFocus->ID(); 486 oldMouseFocus->PostEvent(&evt); 487 } 488 489 // Inform the new window that the mouse has entered 490 Rect screenFrame = fCurrentMouseFocus->LocalToScreen( 491 fCurrentMouseFocus->Bounds()); 492 493 Event evt; 494 evt.what = EVT_MOUSE_ENTER; 495 evt.target = fCurrentMouseFocus->ID(); 496 evt.x = cx - screenFrame.left; 497 evt.y = cy - screenFrame.top; 498 fCurrentMouseFocus->PostEvent(&evt); 499 } 500 } 501 502 if (buttons != last_buttons && fCurrentMouseFocus) { 503 // If the user has released the buttons, unlock the mouse focus 504 if (buttons == 0 && fMouseFocusLocked) { 505 InvalidateMouseBoundries(); 506 fMouseFocusLocked = false; 507 } 508 509 // Send a button message to the window 510 Rect screenFrame = fCurrentMouseFocus->LocalToScreen( 511 fCurrentMouseFocus->Bounds()); 512 513 Event evt; 514 evt.what = buttons != 0 ? EVT_MOUSE_DOWN : EVT_MOUSE_UP; 515 evt.target = fCurrentMouseFocus->ID(); 516 evt.x = cx - screenFrame.left; 517 evt.y = cy - screenFrame.top; 518 fCurrentMouseFocus->PostEvent(&evt); 519 last_buttons = buttons; 520 } 521 522 os_sleep(1); 523 } 524 }