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