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