xref: /haiku/src/kits/game/WindowScreen.cpp (revision 6a45488dd93a920bccd174756ad44613d844189c)
1 /*
2  * Copyright 2002-2007, Haiku. All Rights Reserved.
3  * Copyright 2002-2005,
4  *		Marcus Overhagen,
5  *		Stefano Ceccherini (stefano.ceccherini@gmail.com),
6  *		Carwyn Jones (turok2@currantbun.com)
7  *		All rights reserved.
8  *
9  * Distributed under the terms of the MIT License.
10  */
11 
12 
13 #include <Application.h>
14 #include <Screen.h>
15 #include <String.h>
16 #include <WindowScreen.h>
17 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include <new>
23 
24 #include <input_globals.h>
25 #include <InputServerTypes.h> // For IS_SET_MOUSE_POSITION
26 #include <WindowPrivate.h>
27 
28 #include <AppServerLink.h>
29 #include <ServerProtocol.h>
30 
31 using BPrivate::AppServerLink;
32 
33 
34 #define TRACE_WINDOWSCREEN 0
35 #if TRACE_WINDOWSCREEN
36 #define CALLED() printf("%s\n", __PRETTY_FUNCTION__);
37 #else
38 #define CALLED() ;
39 #endif
40 
41 
42 // Acceleration hooks pointers
43 static fill_rectangle sFillRectHook;
44 static screen_to_screen_blit sBlitRectHook;
45 static screen_to_screen_transparent_blit sTransparentBlitHook;
46 static screen_to_screen_scaled_filtered_blit sScaledFilteredBlitHook;
47 static wait_engine_idle sWaitIdleHook;
48 static acquire_engine sAcquireEngineHook;
49 static release_engine sReleaseEngineHook;
50 
51 static engine_token *sEngineToken;
52 
53 
54 // Helper methods which translates the pre r5 graphics methods to r5 ones
55 static int32
56 card_sync()
57 {
58 	sWaitIdleHook();
59 	return 0;
60 }
61 
62 
63 static int32
64 blit(int32 sx, int32 sy, int32 dx, int32 dy, int32 width, int32 height)
65 {
66 	blit_params param;
67 	param.src_left = sx;
68 	param.src_top = sy;
69 	param.dest_left = dx;
70 	param.dest_top = dy;
71 	param.width = width;
72 	param.height = height;
73 
74 	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
75 	sBlitRectHook(sEngineToken, &param, 1);
76 	sReleaseEngineHook(sEngineToken, NULL);
77 	return 0;
78 }
79 
80 // TODO: This function seems not to be exported through CardHookAt().
81 // At least, nothing I've tried uses it.
82 /*
83 static int32
84 transparent_blit(int32 sx, int32 sy, int32 dx, int32 dy,
85 			int32 width, int32 height, uint32 transparent_color)
86 {
87 	blit_params param;
88 	param.src_left = sx;
89 	param.src_top = sy;
90 	param.dest_left = dx;
91 	param.dest_top = dy;
92 	param.width = width;
93 	param.height = height;
94 
95 	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, 0, &sEngineToken);
96 	sTransparentBlitHook(sEngineToken, transparent_color, &param, 1);
97 	sReleaseEngineHook(sEngineToken, 0);
98 	return 0;
99 }
100 */
101 
102 static int32
103 scaled_filtered_blit(int32 sx, int32 sy, int32 sw, int32 sh, int32 dx, int32 dy, int32 dw, int32 dh)
104 {
105 	scaled_blit_params param;
106 	param.src_left = sx;
107 	param.src_top = sy;
108 	param.src_width = sw;
109 	param.src_height = sh;
110 	param.dest_left = dx;
111 	param.dest_top = dy;
112 	param.dest_width = dw;
113 	param.dest_height = dh;
114 
115 	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
116 	sScaledFilteredBlitHook(sEngineToken, &param, 1);
117 	sReleaseEngineHook(sEngineToken, NULL);
118 	return 0;
119 }
120 
121 
122 static int32
123 draw_rect_8(int32 sx, int32 sy, int32 sw, int32 sh, uint8 color_index)
124 {
125 	fill_rect_params param;
126 	param.left = sx;
127 	param.top = sy;
128 	param.right = sw;
129 	param.bottom = sh;
130 
131 	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
132 	sFillRectHook(sEngineToken, color_index, &param, 1);
133 	sReleaseEngineHook(sEngineToken, NULL);
134 	return 0;
135 }
136 
137 
138 static int32
139 draw_rect_16(int32 sx, int32 sy, int32 sw, int32 sh, uint16 color)
140 {
141 	fill_rect_params param;
142 	param.left = sx;
143 	param.top = sy;
144 	param.right = sw;
145 	param.bottom = sh;
146 
147 	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
148 	sFillRectHook(sEngineToken, color, &param, 1);
149 	sReleaseEngineHook(sEngineToken, NULL);
150 	return 0;
151 }
152 
153 
154 static int32
155 draw_rect_32(int32 sx, int32 sy, int32 sw, int32 sh, uint32 color)
156 {
157 	fill_rect_params param;
158 	param.left = sx;
159 	param.top = sy;
160 	param.right = sw;
161 	param.bottom = sh;
162 
163 	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
164 	sFillRectHook(sEngineToken, color, &param, 1);
165 	sReleaseEngineHook(sEngineToken, NULL);
166 	return 0;
167 }
168 
169 
170 /*!
171 	Fills the \a width, \a height, and \a colorSpace parameters according
172 	to the window screen's mode.
173 	Returns \c true if the mode is known.
174 */
175 static bool
176 get_mode_parameter(uint32 mode, int32& width, int32& height, uint32& colorSpace)
177 {
178 	switch (mode) {
179 		case B_8_BIT_640x480:
180 		case B_8_BIT_800x600:
181 		case B_8_BIT_1024x768:
182    		case B_8_BIT_1152x900:
183 		case B_8_BIT_1280x1024:
184 		case B_8_BIT_1600x1200:
185 			colorSpace = B_CMAP8;
186 			break;
187 
188 		case B_15_BIT_640x480:
189 		case B_15_BIT_800x600:
190 		case B_15_BIT_1024x768:
191    		case B_15_BIT_1152x900:
192 		case B_15_BIT_1280x1024:
193 		case B_15_BIT_1600x1200:
194    			colorSpace = B_RGB15;
195    			break;
196 
197 		case B_16_BIT_640x480:
198 		case B_16_BIT_800x600:
199 		case B_16_BIT_1024x768:
200    		case B_16_BIT_1152x900:
201 		case B_16_BIT_1280x1024:
202 		case B_16_BIT_1600x1200:
203 			colorSpace = B_RGB16;
204 			break;
205 
206 		case B_32_BIT_640x480:
207 		case B_32_BIT_800x600:
208 		case B_32_BIT_1024x768:
209    		case B_32_BIT_1152x900:
210 		case B_32_BIT_1280x1024:
211 		case B_32_BIT_1600x1200:
212 			colorSpace = B_RGB32;
213 			break;
214 
215 		default:
216 			return false;
217 	}
218 
219 	switch (mode) {
220 		case B_8_BIT_640x480:
221 		case B_15_BIT_640x480:
222 		case B_16_BIT_640x480:
223 		case B_32_BIT_640x480:
224 			width = 640; height = 480;
225 			break;
226 
227 		case B_8_BIT_800x600:
228 		case B_15_BIT_800x600:
229 		case B_16_BIT_800x600:
230 		case B_32_BIT_800x600:
231 			width = 800; height = 600;
232 			break;
233 
234 		case B_8_BIT_1024x768:
235 		case B_15_BIT_1024x768:
236 		case B_16_BIT_1024x768:
237 		case B_32_BIT_1024x768:
238 			width = 1024; height = 768;
239 			break;
240 
241    		case B_8_BIT_1152x900:
242    		case B_15_BIT_1152x900:
243    		case B_16_BIT_1152x900:
244    		case B_32_BIT_1152x900:
245    			width = 1152; height = 900;
246    			break;
247 
248 		case B_8_BIT_1280x1024:
249 		case B_15_BIT_1280x1024:
250 		case B_16_BIT_1280x1024:
251 		case B_32_BIT_1280x1024:
252 			width = 1280; height = 1024;
253 			break;
254 
255 		case B_8_BIT_1600x1200:
256 		case B_15_BIT_1600x1200:
257 		case B_16_BIT_1600x1200:
258 		case B_32_BIT_1600x1200:
259 			width = 1600; height = 1200;
260 			break;
261 	}
262 
263 	return true;
264 }
265 
266 
267 //	#pragma mark - public API calls
268 
269 
270 void
271 set_mouse_position(int32 x, int32 y)
272 {
273 	BMessage command(IS_SET_MOUSE_POSITION);
274 	BMessage reply;
275 
276 	command.AddPoint("where", BPoint(x, y));
277 	_control_input_server_(&command, &reply);
278 }
279 
280 
281 //	#pragma mark -
282 
283 
284 BWindowScreen::BWindowScreen(const char *title, uint32 space,
285 		status_t *error, bool debug_enable)
286 	: BWindow(BScreen().Frame(), title, B_TITLED_WINDOW,
287 		kWindowScreenFlag | B_NOT_MINIMIZABLE | B_NOT_CLOSABLE
288 			| B_NOT_ZOOMABLE | B_NOT_MOVABLE | B_NOT_RESIZABLE, B_CURRENT_WORKSPACE)
289 {
290 	CALLED();
291 	uint32 attributes = 0;
292 	if (debug_enable)
293 		attributes |= B_ENABLE_DEBUGGER;
294 
295 	status_t status = _InitData(space, attributes);
296 	if (error)
297 		*error = status;
298 }
299 
300 
301 BWindowScreen::BWindowScreen(const char *title, uint32 space,
302 		uint32 attributes, status_t *error)
303 	: BWindow(BScreen().Frame(), title, B_TITLED_WINDOW,
304 		kWindowScreenFlag | B_NOT_MINIMIZABLE | B_NOT_CLOSABLE
305 			| B_NOT_ZOOMABLE | B_NOT_MOVABLE | B_NOT_RESIZABLE, B_CURRENT_WORKSPACE)
306 {
307 	CALLED();
308 	status_t status = _InitData(space, attributes);
309 	if (error)
310 		*error = status;
311 }
312 
313 
314 BWindowScreen::~BWindowScreen()
315 {
316 	CALLED();
317 	_DisposeData();
318 }
319 
320 
321 void
322 BWindowScreen::Quit(void)
323 {
324 	CALLED();
325 	Disconnect();
326 	BWindow::Quit();
327 }
328 
329 
330 void
331 BWindowScreen::ScreenConnected(bool active)
332 {
333 	// Implemented in subclasses
334 }
335 
336 
337 void
338 BWindowScreen::Disconnect()
339 {
340 	CALLED();
341 	if (fLockState == 1) {
342 		if (fDebugState)
343 			fDebugFirst = true;
344 		_SetActiveState(0);
345 	}
346 
347 	be_app->ShowCursor();
348 }
349 
350 
351 void
352 BWindowScreen::WindowActivated(bool active)
353 {
354 	CALLED();
355 	fWindowState = active;
356 	if (active && fLockState == 0 && fWorkState)
357 		_SetActiveState(1);
358 }
359 
360 
361 void
362 BWindowScreen::WorkspaceActivated(int32 ws, bool state)
363 {
364 	CALLED();
365 	fWorkState = state;
366 	if (state) {
367 		if (fLockState == 0 && fWindowState) {
368 			_SetActiveState(1);
369 			if (!IsHidden()) {
370 				Activate(true);
371 				WindowActivated(true);
372 			}
373 		}
374 	} else if (fLockState)
375 		_SetActiveState(0);
376 }
377 
378 
379 void
380 BWindowScreen::ScreenChanged(BRect screen_size, color_space depth)
381 {
382 	// Implemented in subclasses
383 }
384 
385 
386 void
387 BWindowScreen::Hide()
388 {
389 	CALLED();
390 
391 	Disconnect();
392 	BWindow::Hide();
393 }
394 
395 
396 void
397 BWindowScreen::Show()
398 {
399 	CALLED();
400 
401 	BWindow::Show();
402 
403 	if (!fActivateState) {
404 		release_sem(fActivateSem);
405 		fActivateState = true;
406 		be_app->HideCursor();
407 	}
408 }
409 
410 
411 void
412 BWindowScreen::SetColorList(rgb_color *list, int32 firstIndex, int32 lastIndex)
413 {
414 	CALLED();
415 	if (firstIndex < 0 || lastIndex > 255 || firstIndex > lastIndex)
416 		return;
417 
418 	if (Lock()) {
419 		if (!fActivateState) {
420 			// If we aren't active, we just change our local palette
421 			for (int32 x = firstIndex; x <= lastIndex; x++) {
422 				fPalette[x] = list[x];
423 			}
424 		} else {
425 			uint8 colors[3 * 256];
426 				// the color table has 3 bytes per color
427 			int32 j = 0;
428 
429 			for (int32 x = firstIndex; x <= lastIndex; x++) {
430 				fPalette[x] = list[x];
431 					// update our local palette as well
432 
433 				colors[j++] = list[x].red;
434 				colors[j++] = list[x].green;
435 				colors[j++] = list[x].blue;
436 			}
437 
438 			if (fAddonImage >= 0) {
439 				set_indexed_colors setIndexedColors =
440 					(set_indexed_colors)fGetAccelerantHook(B_SET_INDEXED_COLORS, NULL);
441 				if (setIndexedColors != NULL)
442 					setIndexedColors(lastIndex - firstIndex + 1, firstIndex, colors, 0);
443 			}
444 
445 			// TODO: Tell the app_server about our changes
446 
447 			BScreen screen(this);
448 			screen.WaitForRetrace();
449 		}
450 
451 		Unlock();
452 	}
453 }
454 
455 
456 status_t
457 BWindowScreen::SetSpace(uint32 space)
458 {
459 	CALLED();
460 
461 	display_mode mode;
462 	status_t status = _GetModeFromSpace(space, &mode);
463 	if (status == B_OK)
464 		status = _AssertDisplayMode(&mode);
465 
466 	return status;
467 }
468 
469 
470 bool
471 BWindowScreen::CanControlFrameBuffer()
472 {
473 	return (fCardInfo.flags & B_FRAME_BUFFER_CONTROL) != 0;
474 }
475 
476 
477 status_t
478 BWindowScreen::SetFrameBuffer(int32 width, int32 height)
479 {
480 	CALLED();
481 	display_mode highMode = *fDisplayMode;
482 	highMode.flags |= B_SCROLL;
483 
484 	highMode.virtual_height = (int16)height;
485 	highMode.virtual_width = (int16)width;
486 
487 	display_mode lowMode = highMode;
488 	display_mode mode = highMode;
489 
490 	BScreen screen(this);
491 	status_t status = screen.ProposeMode(&mode, &lowMode, &highMode);
492 	if (status == B_OK)
493 		status = _AssertDisplayMode(&mode);
494 
495 	return status;
496 }
497 
498 
499 status_t
500 BWindowScreen::MoveDisplayArea(int32 x, int32 y)
501 {
502 	CALLED();
503 	move_display_area moveDisplayArea = (move_display_area)fGetAccelerantHook(B_MOVE_DISPLAY, NULL);
504 	if (moveDisplayArea && moveDisplayArea((int16)x, (int16)y) == B_OK) {
505 		fFrameBufferInfo.display_x = x;
506 		fFrameBufferInfo.display_y = y;
507 		fDisplayMode->h_display_start = x;
508 		fDisplayMode->v_display_start = y;
509 		return B_OK;
510 	}
511 	return B_ERROR;
512 }
513 
514 
515 #if 0
516 void *
517 BWindowScreen::IOBase()
518 {
519 	// Not supported
520 	return NULL;
521 }
522 #endif
523 
524 
525 rgb_color *
526 BWindowScreen::ColorList()
527 {
528 	CALLED();
529 	return fPalette;
530 }
531 
532 
533 frame_buffer_info *
534 BWindowScreen::FrameBufferInfo()
535 {
536 	CALLED();
537 	return &fFrameBufferInfo;
538 }
539 
540 
541 graphics_card_hook
542 BWindowScreen::CardHookAt(int32 index)
543 {
544 	CALLED();
545 	if (fAddonImage < 0)
546 		return NULL;
547 
548 	graphics_card_hook hook = NULL;
549 
550 	switch (index) {
551 		case 5: // 8 bit fill rect
552 			hook = (graphics_card_hook)draw_rect_8;
553 			break;
554 		case 6: // 32 bit fill rect
555 			hook = (graphics_card_hook)draw_rect_32;
556 			break;
557 		case 7: // screen to screen blit
558 			hook = (graphics_card_hook)blit;
559 			break;
560 		case 8: // screen to screen scaled filtered blit
561 			hook = (graphics_card_hook)scaled_filtered_blit;
562 			break;
563 		case 10: // sync aka wait for graphics card idle
564 			hook = (graphics_card_hook)card_sync;
565 			break;
566 		case 13: // 16 bit fill rect
567 			hook = (graphics_card_hook)draw_rect_16;
568 			break;
569 		default:
570 			break;
571 	}
572 
573 	return hook;
574 }
575 
576 
577 graphics_card_info *
578 BWindowScreen::CardInfo()
579 {
580 	CALLED();
581 	return &fCardInfo;
582 }
583 
584 
585 void
586 BWindowScreen::RegisterThread(thread_id thread)
587 {
588 	CALLED();
589 
590 	status_t status;
591 	do {
592 		status = acquire_sem(fDebugSem);
593 	} while (status == B_INTERRUPTED);
594 
595 	if (status < B_OK)
596 		return;
597 
598 	void *newDebugList = realloc(fDebugThreads, (fDebugThreadCount + 1) * sizeof(thread_id));
599 	if (newDebugList != NULL) {
600 		fDebugThreads = (thread_id *)newDebugList;
601 		fDebugThreads[fDebugThreadCount] = thread;
602 		fDebugThreadCount++;
603 	}
604 	release_sem(fDebugSem);
605 }
606 
607 
608 void
609 BWindowScreen::SuspensionHook(bool active)
610 {
611 	// Implemented in subclasses
612 }
613 
614 
615 void
616 BWindowScreen::Suspend(char* label)
617 {
618 	CALLED();
619 	if (fDebugState) {
620 		fprintf(stderr, "## Debugger(\"%s\").", label);
621 		fprintf(stderr, " Press Alt-F%ld or Cmd-F%ld to resume.\n", fWorkspaceIndex + 1,
622 			fWorkspaceIndex + 1);
623 
624 		if (IsLocked())
625 			Unlock();
626 
627 		activate_workspace(fDebugWorkspace);
628 
629 		// Suspend ourself
630 		suspend_thread(find_thread(NULL));
631 
632 		Lock();
633 	}
634 }
635 
636 
637 status_t
638 BWindowScreen::Perform(perform_code d, void* arg)
639 {
640 	return inherited::Perform(d, arg);
641 }
642 
643 
644 // Reserved for future binary compatibility
645 void BWindowScreen::_ReservedWindowScreen1() {}
646 void BWindowScreen::_ReservedWindowScreen2() {}
647 void BWindowScreen::_ReservedWindowScreen3() {}
648 void BWindowScreen::_ReservedWindowScreen4() {}
649 
650 
651 /* unimplemented for protection of the user:
652  *
653  * BWindowScreen::BWindowScreen()
654  * BWindowScreen::BWindowScreen(BWindowScreen &)
655  * BWindowScreen &BWindowScreen::operator=(BWindowScreen &)
656  */
657 
658 
659 status_t
660 BWindowScreen::_InitData(uint32 space, uint32 attributes)
661 {
662 	CALLED();
663 
664 	fDebugState = attributes & B_ENABLE_DEBUGGER;
665 	fDebugThreadCount = 0;
666 	fDebugThreads = NULL;
667 	fDebugFirst = true;
668 
669 	fAttributes = attributes;
670 		// TODO: not really used right now, but should probably be known by the app_server
671 
672 	fWorkspaceIndex = current_workspace();
673 	fDebugWorkspace = fWorkspaceIndex > 0 ? fWorkspaceIndex - 1 : 1;
674 	fLockState = 0;
675 	fAddonImage = -1;
676 	fWindowState = 0;
677 	fOriginalDisplayMode = NULL;
678 	fDisplayMode = NULL;
679 	fModeList = NULL;
680 	fModeCount = 0;
681 	fActivateSem = -1;
682 	fDebugSem = -1;
683 	fActivateState = 0;
684 	fWorkState = 0;
685 
686 	status_t status = B_ERROR;
687 	try {
688 		fOriginalDisplayMode = new display_mode;
689 		fDisplayMode = new display_mode;
690 
691 		BScreen screen(this);
692 		status = screen.GetMode(fOriginalDisplayMode);
693 		if (status < B_OK)
694 			throw status;
695 
696 		status = screen.GetModeList(&fModeList, &fModeCount);
697 		if (status < B_OK)
698 			throw status;
699 
700 		status = _GetModeFromSpace(space, fDisplayMode);
701 		if (status < B_OK)
702 			throw status;
703 
704 		status = _GetCardInfo();
705 		if (status < B_OK)
706 			throw status;
707 
708 		fActivateSem = create_sem(0, "WindowScreen start lock");
709 		if (fActivateSem < B_OK)
710 			throw fActivateSem;
711 
712 		fDebugSem = create_sem(1, "WindowScreen debug sem");
713 		if (fDebugSem < B_OK)
714 			throw fDebugSem;
715 
716 		memcpy(fPalette, screen.ColorMap()->color_list, 256);
717 		fActivateState = 0;
718 		fWorkState = 1;
719 
720 	} catch (std::bad_alloc) {
721 		status = B_NO_MEMORY;
722 	} catch (int error) {
723 		status = error;
724 	} catch (...) {
725 		status = B_ERROR;
726 	}
727 
728 	if (status != B_OK)
729 		_DisposeData();
730 
731 	return status;
732 }
733 
734 
735 void
736 BWindowScreen::_DisposeData()
737 {
738 	CALLED();
739 	Disconnect();
740 	if (fAddonImage >= 0) {
741 		unload_add_on(fAddonImage);
742 		fAddonImage = -1;
743 	}
744 
745 	delete_sem(fActivateSem);
746 	fActivateSem = -1;
747 	delete_sem(fDebugSem);
748 	fDebugSem = -1;
749 
750 	if (fDebugState)
751 		activate_workspace(fDebugWorkspace);
752 
753 	delete fDisplayMode;
754 	fDisplayMode = NULL;
755 	delete fOriginalDisplayMode;
756 	fOriginalDisplayMode = NULL;
757 	delete fModeList;
758 	fModeList = NULL;
759 	fModeCount = 0;
760 
761 	fLockState = 0;
762 }
763 
764 
765 status_t
766 BWindowScreen::_SetActiveState(int32 state)
767 {
768 	CALLED();
769 	status_t status = B_ERROR;
770 	if (state == 1) {
771 		status = _AssertDisplayMode(fDisplayMode);
772 		if (status == B_OK && (status = _SetupAccelerantHooks(true)) == B_OK) {
773 			if (!fActivateState) {
774 				do {
775 					status = acquire_sem(fActivateSem);
776 				} while (status == B_INTERRUPTED);
777 
778 				if (status < B_OK)
779 					return status;
780 			}
781 
782 			SetColorList(fPalette);
783 			if (fDebugState && !fDebugFirst) {
784 				SuspensionHook(true);
785 				_Resume();
786 			} else {
787 				fDebugFirst = true;
788 				ScreenConnected(true);
789 			}
790 
791 			if (status == B_OK)
792 				return status;
793 		} else
794 			_SetupAccelerantHooks(false);
795 	} else {
796 		_AssertDisplayMode(fOriginalDisplayMode);
797 
798 		if (fDebugState && !fDebugFirst) {
799 			_Suspend();
800 			SuspensionHook(false);
801 		} else
802 			ScreenConnected(false);
803 
804 		status = _SetupAccelerantHooks(false);
805 		if (status == B_OK) {
806 			be_app->ShowCursor();
807 			if (fActivateState) {
808 				// TODO: Set palette
809 			}
810 		}
811 	}
812 
813 	return status;
814 }
815 
816 
817 status_t
818 BWindowScreen::_SetupAccelerantHooks(bool enable)
819 {
820 	CALLED();
821 	if (fAddonImage >= 0) {
822 		fWaitEngineIdle();
823 		sFillRectHook = NULL;
824 		sBlitRectHook = NULL;
825 		sTransparentBlitHook = NULL;
826 		sScaledFilteredBlitHook = NULL;
827 		sWaitIdleHook = NULL;
828 		sEngineToken = NULL;
829 		sAcquireEngineHook = NULL;
830 		sReleaseEngineHook = NULL;
831 	}
832 
833 	fLockState = enable ? 1 : 0;
834 
835 	status_t status = B_OK;
836 	if (enable) {
837 		acquire_engine aquireEngine = NULL;
838 		release_engine releaseEngine = NULL;
839 		fill_rectangle fillRectangle = NULL;
840 		screen_to_screen_blit blit = NULL;
841 		screen_to_screen_transparent_blit transparentBlit = NULL;
842 		screen_to_screen_scaled_filtered_blit scaledFilteredBlit = NULL;
843 
844 		if (fAddonImage < 0) {
845 			status = _InitClone();
846 			if (status == B_OK) {
847 				fWaitEngineIdle = (wait_engine_idle)fGetAccelerantHook(B_WAIT_ENGINE_IDLE, NULL);
848 
849 				releaseEngine = (release_engine)fGetAccelerantHook(B_RELEASE_ENGINE, NULL);
850 				aquireEngine = (acquire_engine)fGetAccelerantHook(B_ACQUIRE_ENGINE, NULL);
851 				fillRectangle = (fill_rectangle)fGetAccelerantHook(B_FILL_RECTANGLE, NULL);
852 				blit = (screen_to_screen_blit)fGetAccelerantHook(B_SCREEN_TO_SCREEN_BLIT, NULL);
853 				transparentBlit = (screen_to_screen_transparent_blit)fGetAccelerantHook(B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT, NULL);
854 				scaledFilteredBlit = (screen_to_screen_scaled_filtered_blit)fGetAccelerantHook(B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT, NULL);
855 			}
856 		}
857 
858 		if (status == B_OK) {
859 			sFillRectHook = fillRectangle;
860 			sBlitRectHook = blit;
861 			sTransparentBlitHook = transparentBlit;
862 			sScaledFilteredBlitHook = scaledFilteredBlit;
863 			sWaitIdleHook = fWaitEngineIdle;
864 			sAcquireEngineHook = aquireEngine;
865 			sReleaseEngineHook = releaseEngine;
866 
867 			fWaitEngineIdle();
868 		}
869 	}
870 
871 	return status;
872 }
873 
874 
875 status_t
876 BWindowScreen::_GetCardInfo()
877 {
878 	CALLED();
879 
880 	BScreen screen(this);
881 	display_mode mode;
882 	status_t status = screen.GetMode(&mode);
883 	if (status < B_OK)
884 		return status;
885 
886 	uint32 bitsPerPixel;
887 	switch(mode.space & 0x0fff) {
888 		case B_CMAP8:
889 			bitsPerPixel = 8;
890 			break;
891 		case B_RGB15:
892 			bitsPerPixel = 15;
893 			break;
894 		case B_RGB16:
895 			bitsPerPixel = 16;
896 			break;
897 		case B_RGB32:
898 			bitsPerPixel = 32;
899 			break;
900 		default:
901 			bitsPerPixel = 0;
902 			break;
903 	}
904 
905 	fCardInfo.version = 2;
906 	fCardInfo.id = screen.ID().id;
907 	fCardInfo.bits_per_pixel = bitsPerPixel;
908 	fCardInfo.width = mode.virtual_width;
909 	fCardInfo.height = mode.virtual_height;
910 
911 	if (mode.space & 0x10)
912 		strncpy(fCardInfo.rgba_order, "rgba", 4);
913 	else
914 		strncpy(fCardInfo.rgba_order, "bgra", 4);
915 
916 	fCardInfo.flags = 0;
917 	if (mode.flags & B_SCROLL)
918 		fCardInfo.flags |= B_FRAME_BUFFER_CONTROL;
919 	if (mode.flags & B_PARALLEL_ACCESS)
920 		fCardInfo.flags |= B_PARALLEL_BUFFER_ACCESS;
921 
922 	AppServerLink link;
923 	link.StartMessage(AS_GET_FRAME_BUFFER_CONFIG);
924 	link.Attach<screen_id>(screen.ID());
925 
926 	status_t result = B_ERROR;
927 	if (link.FlushWithReply(result) < B_OK || result < B_OK)
928 		return result;
929 
930 	frame_buffer_config config;
931 	link.Read<frame_buffer_config>(&config);
932 
933 	fCardInfo.frame_buffer = config.frame_buffer;
934 	fCardInfo.bytes_per_row = config.bytes_per_row;
935 
936 	return B_OK;
937 }
938 
939 
940 void
941 BWindowScreen::_Suspend()
942 {
943 	CALLED();
944 
945 	status_t status;
946 	do {
947 		status = acquire_sem(fDebugSem);
948 	} while (status == B_INTERRUPTED);
949 
950 	if (status < B_OK)
951 		return;
952 
953 	// Suspend all the registered threads
954 	for (int32 i = 0; i < fDebugThreadCount; i++) {
955 		snooze(10000);
956 		suspend_thread(fDebugThreads[i]);
957 	}
958 
959 	graphics_card_info *info = CardInfo();
960 	size_t fbSize = info->bytes_per_row * info->height;
961 
962 	// Save the content of the frame buffer into the local buffer
963 	fDebugFrameBuffer = (char *)malloc(fbSize);
964 	memcpy(fDebugFrameBuffer, info->frame_buffer, fbSize);
965 }
966 
967 
968 void
969 BWindowScreen::_Resume()
970 {
971 	CALLED();
972 	graphics_card_info *info = CardInfo();
973 
974 	// Copy the content of the debug_buffer back into the frame buffer.
975 	memcpy(info->frame_buffer, fDebugFrameBuffer, info->bytes_per_row * info->height);
976 	free(fDebugFrameBuffer);
977 	fDebugFrameBuffer = NULL;
978 
979 	// Resume all the registered threads
980 	for (int32 i = 0; i < fDebugThreadCount; i++) {
981 		resume_thread(fDebugThreads[i]);
982 	}
983 
984 	release_sem(fDebugSem);
985 }
986 
987 
988 status_t
989 BWindowScreen::_GetModeFromSpace(uint32 space, display_mode *dmode)
990 {
991 	CALLED();
992 
993 	int32 width, height;
994 	uint32 colorSpace;
995 	if (!get_mode_parameter(space, width, height, colorSpace))
996 		return B_BAD_VALUE;
997 
998 	for (uint32 i = 0; i < fModeCount; i++) {
999 		if (fModeList[i].space == colorSpace && fModeList[i].virtual_width == width
1000 			&& fModeList[i].virtual_height == height) {
1001 			memcpy(dmode, &fModeList[i], sizeof(display_mode));
1002 			return B_OK;
1003 		}
1004 	}
1005 
1006 	return B_ERROR;
1007 }
1008 
1009 
1010 status_t
1011 BWindowScreen::_InitClone()
1012 {
1013 	CALLED();
1014 
1015 	if (fAddonImage >= 0)
1016 		return B_OK;
1017 
1018 	AppServerLink link;
1019 	link.StartMessage(AS_GET_ACCELERANT_PATH);
1020 	link.Attach<int32>(fWorkspaceIndex);
1021 
1022 	status_t status = B_ERROR;
1023 	if (link.FlushWithReply(status) < B_OK || status < B_OK)
1024 		return status;
1025 
1026 	BString accelerantPath;
1027 	link.ReadString(accelerantPath);
1028 	fAddonImage = load_add_on(accelerantPath.String());
1029 	if (fAddonImage < B_OK) {
1030 		fprintf(stderr, "InitClone: cannot load accelerant image\n");
1031 		return fAddonImage;
1032 	}
1033 
1034 	status = get_image_symbol(fAddonImage, B_ACCELERANT_ENTRY_POINT,
1035 		B_SYMBOL_TYPE_TEXT, (void **)&fGetAccelerantHook);
1036 	if (status < B_OK) {
1037 		fprintf(stderr, "InitClone: cannot get accelerant entry point\n");
1038 		unload_add_on(fAddonImage);
1039 		fAddonImage = -1;
1040 		return status;
1041 	}
1042 
1043 	accelerant_clone_info_size cloneInfoSizeHook;
1044 	get_accelerant_clone_info cloneInfoHook;
1045 	clone_accelerant cloneHook;
1046 	cloneInfoSizeHook = (accelerant_clone_info_size)fGetAccelerantHook(B_ACCELERANT_CLONE_INFO_SIZE, NULL);
1047 	cloneInfoHook = (get_accelerant_clone_info)fGetAccelerantHook(B_GET_ACCELERANT_CLONE_INFO, NULL);
1048 	cloneHook = (clone_accelerant)fGetAccelerantHook(B_CLONE_ACCELERANT, NULL);
1049 
1050 	status = B_ERROR;
1051 	if (!cloneInfoSizeHook || !cloneInfoHook || !cloneHook) {
1052 		fprintf(stderr, "InitClone: cannot get clone hook\n");
1053 		unload_add_on(fAddonImage);
1054 		fAddonImage = -1;
1055 		return status;
1056 	}
1057 
1058 	ssize_t cloneInfoSize = cloneInfoSizeHook();
1059 	void *cloneInfo = malloc(cloneInfoSize);
1060 	if (!cloneInfo) {
1061 		unload_add_on(fAddonImage);
1062 		fAddonImage = -1;
1063 		return B_NO_MEMORY;
1064 	}
1065 
1066 	cloneInfoHook(cloneInfo);
1067 		// no way to see if this call fails
1068 
1069 	status = cloneHook(cloneInfo);
1070 
1071 	free(cloneInfo);
1072 
1073 	if (status < B_OK) {
1074 		fprintf(stderr, "InitClone: cannot clone accelerant\n");
1075 		unload_add_on(fAddonImage);
1076 		fAddonImage = -1;
1077 	}
1078 
1079 	return status;
1080 }
1081 
1082 
1083 status_t
1084 BWindowScreen::_AssertDisplayMode(display_mode* displayMode)
1085 {
1086 	CALLED();
1087 
1088 	BScreen screen(this);
1089 
1090 	display_mode currentMode;
1091 	status_t status = screen.GetMode(&currentMode);
1092 	if (status < B_OK)
1093 		return status;
1094 
1095 	if (currentMode.virtual_height != displayMode->virtual_height
1096 		|| currentMode.virtual_width != displayMode->virtual_width
1097 		|| currentMode.space != displayMode->space
1098 		|| currentMode.flags != displayMode->flags) {
1099 		status = screen.SetMode(displayMode);
1100 		if (status < B_OK) {
1101 			printf("AssertDisplayMode: Setting mode failed: %s\n", strerror(status));
1102 			return status;
1103 		}
1104 
1105 		memcpy(fDisplayMode, displayMode, sizeof(display_mode));
1106 	}
1107 
1108 	status = _GetCardInfo();
1109 	if (status < B_OK)
1110 		return status;
1111 
1112 	fFrameBufferInfo.bits_per_pixel = fCardInfo.bits_per_pixel;
1113 	fFrameBufferInfo.bytes_per_row = fCardInfo.bytes_per_row;
1114 	fFrameBufferInfo.width = fCardInfo.width;
1115 	fFrameBufferInfo.height = fCardInfo.height;
1116 	fFrameBufferInfo.display_width = fCardInfo.width;
1117 	fFrameBufferInfo.display_height = fCardInfo.height;
1118 	fFrameBufferInfo.display_x = 0;
1119 	fFrameBufferInfo.display_y = 0;
1120 
1121 	return B_OK;
1122 }
1123