openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

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 }