xref: /haiku/src/kits/game/WindowScreen.cpp (revision 2ae568931fcac7deb9f1e6ff4e47213fbfe4029b)
1 /*
2  * Copyright 2002-2005,
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 #ifdef COMPILE_FOR_R5
11 #include "/boot/develop/headers/be/interface/Window.h"
12 #endif
13 
14 #include <Application.h>
15 #include <Screen.h>
16 #include <WindowScreen.h>
17 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include <input_globals.h>
23 #include <InputServerTypes.h> // For IS_SET_MOUSE_POSITION
24 #include <WindowPrivate.h>
25 
26 
27 #ifdef COMPILE_FOR_R5
28 #include <R5_AppServerLink.h>
29 #endif
30 
31 // WindowScreen commands
32 #define WS_MOVE_DISPLAY			0x00000108
33 #define WS_SET_FULLSCREEN 		0x00000881
34 #define WS_GET_FRAMEBUFFER 		0x00000eed
35 #define WS_GET_ACCELERANT_NAME 	0x00000ef4
36 #define WS_GET_DRIVER_NAME 		0x00000ef5
37 #define WS_DISPLAY_UTILS		0x00000ef9
38 #define WS_SET_LOCK_STATE		0x00000efb
39 #define WS_SET_DISPLAY_MODE 	0x00000efd
40 #define WS_SET_PALETTE			0x00000f27
41 
42 
43 #if TRACE_WINDOWSCREEN
44 #define CALLED() printf("%s\n", __PRETTY_FUNCTION__);
45 #else
46 #define CALLED() ;
47 #endif
48 
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(B_2D_ACCELERATION, 0xff, NULL, &et_global);
82 	blit_rect_global(et_global, &param, 1);
83 	release_engine_global(et_global, NULL);
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(B_2D_ACCELERATION, 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(B_2D_ACCELERATION, 0xff, NULL, &et_global);
123 	scaled_filtered_blit_rect_global(et_global, &param, 1);
124 	release_engine_global(et_global, NULL);
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(B_2D_ACCELERATION, 0xff, NULL, &et_global);
139 	fill_rect_global(et_global, color_index, &param, 1);
140 	release_engine_global(et_global, NULL);
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(B_2D_ACCELERATION, 0xff, NULL, &et_global);
155 	fill_rect_global(et_global, color, &param, 1);
156 	release_engine_global(et_global, NULL);
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(B_2D_ACCELERATION, 0xff, NULL, &et_global);
171 	fill_rect_global(et_global, color, &param, 1);
172 	release_engine_global(et_global, NULL);
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 void
283 set_mouse_position(int32 x, int32 y)
284 {
285 	BMessage command(IS_SET_MOUSE_POSITION);
286 	BMessage reply;
287 
288 	command.AddPoint("where", BPoint(x, y));
289 	_control_input_server_(&command, &reply);
290 }
291 
292 
293 BWindowScreen::BWindowScreen(const char *title, uint32 space, status_t *error, bool debug_enable)
294 	:
295 	BWindow(BScreen().Frame(), title, B_TITLED_WINDOW,
296 		kWindowScreenFlag | B_NOT_MINIMIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MOVABLE | B_NOT_RESIZABLE,
297 		B_CURRENT_WORKSPACE)
298 {
299 	CALLED();
300 	uint32 attributes = 0;
301 	if (debug_enable)
302 		attributes |= B_ENABLE_DEBUGGER;
303 
304 	status_t status = InitData(space, attributes);
305 	if (error)
306 		*error = status;
307 }
308 
309 
310 BWindowScreen::BWindowScreen(const char *title, uint32 space, uint32 attributes, status_t *error)
311 	:
312 	BWindow(BScreen().Frame(), title, B_TITLED_WINDOW,
313 		kWindowScreenFlag | B_NOT_MINIMIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MOVABLE | B_NOT_RESIZABLE,
314 		B_CURRENT_WORKSPACE)
315 {
316 	CALLED();
317 	status_t status = InitData(space, attributes);
318 	if (error)
319 		*error = status;
320 }
321 
322 
323 BWindowScreen::~BWindowScreen()
324 {
325 	Disconnect();
326 	if (addon_state == 1)
327 		unload_add_on(addon_image);
328 
329 	SetFullscreen(0);
330 
331 	delete_sem(activate_sem);
332 	delete_sem(debug_sem);
333 
334 	if (debug_state)
335 		activate_workspace(debug_workspace);
336 
337 	free(new_space);
338 	free(old_space);
339 	free(mode_list);
340 }
341 
342 
343 void
344 BWindowScreen::Quit(void)
345 {
346 	Disconnect();
347 	BWindow::Quit();
348 }
349 
350 
351 void
352 BWindowScreen::ScreenConnected(bool active)
353 {
354 	// Implemented in subclasses
355 }
356 
357 
358 void
359 BWindowScreen::Disconnect()
360 {
361 	if (lock_state == 1) {
362 		if (debug_state)
363 			debug_first = true;
364 		SetActiveState(0);
365 	}
366 }
367 
368 
369 void
370 BWindowScreen::WindowActivated(bool active)
371 {
372 	CALLED();
373 	window_state = active;
374 	if(active && lock_state == 0 && work_state)
375 		SetActiveState(1);
376 }
377 
378 
379 void
380 BWindowScreen::WorkspaceActivated(int32 ws, bool state)
381 {
382 	CALLED();
383 	work_state = state;
384 	if (state) {
385 		if (lock_state == 0 && window_state) {
386 			SetActiveState(1);
387 			if (!IsHidden()) {
388 				Activate(true);
389 				WindowActivated(true);
390 			}
391 		}
392 	} else {
393 		if (lock_state)
394 			SetActiveState(0);
395 	}
396 }
397 
398 
399 void
400 BWindowScreen::ScreenChanged(BRect screen_size, color_space depth)
401 {
402 	// Implemented in subclasses
403 }
404 
405 
406 void
407 BWindowScreen::Hide()
408 {
409 	if (lock_state == 1) {
410 		if (debug_state)
411 			debug_first = true;
412 		SetActiveState(0);
413 	}
414 
415 	BWindow::Hide();
416 }
417 
418 
419 void
420 BWindowScreen::Show()
421 {
422 	BWindow::Show();
423 	if (!activate_state) {
424 		release_sem(activate_sem);
425 		activate_state = true;
426 	}
427 }
428 
429 
430 void
431 BWindowScreen::SetColorList(rgb_color *list, int32 first_index, int32 last_index)
432 {
433 	if (first_index < 0 || last_index > 255 || first_index > last_index)
434 		return;
435 
436 	if (Lock()) {
437 		if (!activate_state) {
438 			//If we aren't active, we just change our local palette
439 			for (int32 x = first_index; x <= last_index; x++)
440 				colorList[x] = list[x];
441 		} else {
442 			uint32 colorCount = last_index - first_index + 1;
443 			if (addon_state == 1) {
444 				set_indexed_colors sic = (set_indexed_colors)m_gah(B_SET_INDEXED_COLORS, NULL);
445 				if (sic != NULL)
446 					sic(colorCount, first_index, (uint8*)colorList, 0);
447 			}
448 
449 			BScreen screen(this);
450 			screen.WaitForRetrace();
451 			// Update our local palette too. We're doing this between two
452 			// WaitForRetrace() calls so nobody will notice.
453 			for (int32 x = first_index; x <= last_index; x++)
454 				colorList[x] = list[x];
455 
456 			// Tell the app_server about our changes
457 #ifdef COMPILE_FOR_R5
458 			_BAppServerLink_ link;
459 			link.fSession->swrite_l(WS_SET_PALETTE);
460 			link.fSession->swrite_l(screen_index);
461 			link.fSession->swrite_l(first_index);
462 			link.fSession->swrite_l(last_index);
463 			link.fSession->swrite(colorCount * sizeof(rgb_color), colorList);
464 			link.fSession->sync();
465 #endif
466 			screen.WaitForRetrace();
467 		}
468 
469 		Unlock();
470 	}
471 }
472 
473 
474 status_t
475 BWindowScreen::SetSpace(uint32 space)
476 {
477 	display_mode mode;
478 	status_t status = GetModeFromSpace(space, &mode);
479 	if (status == B_OK)
480 		status = AssertDisplayMode(&mode);
481 	return status;
482 }
483 
484 
485 bool
486 BWindowScreen::CanControlFrameBuffer()
487 {
488 	return (addon_state <= 1 && (card_info.flags & B_FRAME_BUFFER_CONTROL));
489 }
490 
491 
492 status_t
493 BWindowScreen::SetFrameBuffer(int32 width, int32 height)
494 {
495 	display_mode highMode = *new_space;
496 
497 	highMode.virtual_height = (int16)height;
498 	highMode.virtual_width = (int16)width;
499 
500 	display_mode lowMode = highMode;
501 	display_mode mode = highMode;
502 
503 	BScreen screen(this);
504 	status_t status = screen.ProposeMode(&mode, &lowMode, &highMode);
505 
506 	// If the mode is supported, change the workspace
507 	// to that mode.
508 	if (status == B_OK)
509 		status = AssertDisplayMode(&mode);
510 
511 	return status;
512 }
513 
514 
515 status_t
516 BWindowScreen::MoveDisplayArea(int32 x, int32 y)
517 {
518 	status_t status = B_ERROR;
519 
520 #ifdef COMPILE_FOR_R5
521 	_BAppServerLink_ link;
522 	link.fSession->swrite_l(WS_DISPLAY_UTILS);
523 	link.fSession->swrite_l(screen_index);
524 	link.fSession->swrite_l(WS_MOVE_DISPLAY);
525 	link.fSession->swrite(sizeof(int16), (int16*)&x);
526 	link.fSession->swrite(sizeof(int16), (int16*)&y);
527 	link.fSession->sync();
528 	link.fSession->sread(sizeof(status), &status);
529 #endif
530 
531 	if (status == B_OK) {
532 		format_info.display_x = x;
533 		format_info.display_y = y;
534 		new_space->h_display_start = x;
535 		new_space->v_display_start = y;
536 	}
537 	return status;
538 }
539 
540 
541 void *
542 BWindowScreen::IOBase()
543 {
544 	// Not supported
545 	return NULL;
546 }
547 
548 
549 rgb_color *
550 BWindowScreen::ColorList()
551 {
552 	return colorList;
553 }
554 
555 
556 frame_buffer_info *
557 BWindowScreen::FrameBufferInfo()
558 {
559 	return &format_info;
560 }
561 
562 
563 graphics_card_hook
564 BWindowScreen::CardHookAt(int32 index)
565 {
566 	if (addon_state != 1)
567 		return 0;
568 
569 	graphics_card_hook hook = NULL;
570 
571 	switch (index) {
572 		case 5: // 8 bit fill rect
573 			hook = (graphics_card_hook)m_gah(B_FILL_RECTANGLE, 0);
574 			fill_rect = (fill_rectangle)hook;
575 			fill_rect_global = fill_rect;
576 			hook = (graphics_card_hook)draw_rect_8;
577 			break;
578 		case 6: // 32 bit fill rect
579 			hook = (graphics_card_hook)m_gah(B_FILL_RECTANGLE, 0);
580 			fill_rect = (fill_rectangle)hook;
581 			fill_rect_global = fill_rect;
582 			hook = (graphics_card_hook)draw_rect_32;
583 			break;
584 		case 7: // screen to screen blit
585 			hook = (graphics_card_hook)m_gah(B_SCREEN_TO_SCREEN_BLIT, 0);
586 			blit_rect = (screen_to_screen_blit)hook;
587 			blit_rect_global = blit_rect;
588 			hook = (graphics_card_hook)blit;
589 			break;
590 		case 8: // screen to screen scaled filtered blit
591 			hook = (graphics_card_hook)m_gah(B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT, 0);
592 			scaled_filtered_blit_rect = (screen_to_screen_scaled_filtered_blit)hook;
593 			scaled_filtered_blit_rect_global = scaled_filtered_blit_rect;
594 			hook = (graphics_card_hook)scaled_filtered_blit;
595 			break;
596 		case 10: // sync aka wait for graphics card idle
597 			hook = (graphics_card_hook)card_sync;
598 			break;
599 		case 13: // 16 bit fill rect
600 			hook = (graphics_card_hook)m_gah(B_FILL_RECTANGLE, 0);
601 			fill_rect = (fill_rectangle)hook;
602 			fill_rect_global = fill_rect;
603 			hook = (graphics_card_hook)draw_rect_16;
604 			break;
605 		default:
606 			break;
607 	}
608 
609 	return hook;
610 }
611 
612 
613 graphics_card_info *
614 BWindowScreen::CardInfo()
615 {
616 	return &card_info;
617 }
618 
619 
620 void
621 BWindowScreen::RegisterThread(thread_id id)
622 {
623 	CALLED();
624 	while (acquire_sem(debug_sem) == B_INTERRUPTED)
625 		;
626 	++debug_list_count;
627 	debug_list = (thread_id *)realloc(debug_list, debug_list_count * sizeof(thread_id));
628 	debug_list[debug_list_count - 1] = id;
629 
630 	release_sem(debug_sem);
631 }
632 
633 
634 void
635 BWindowScreen::SuspensionHook(bool active)
636 {
637 	// Implemented in subclasses
638 }
639 
640 
641 void
642 BWindowScreen::Suspend(char *label)
643 {
644 	CALLED();
645 	if (debug_state) {
646 		fprintf(stderr, "## Debugger(\"%s\").", label);
647 		fprintf(stderr, " Press Alt-F%ld or Cmd-F%ld to resume.\n", space0 + 1, space0 + 1);
648 
649 		if (IsLocked())
650 			Unlock();
651 
652 		activate_workspace(debug_workspace);
653 
654 		// Suspend ourself
655 		suspend_thread(find_thread(NULL));
656 
657 		Lock();
658 	}
659 }
660 
661 
662 status_t
663 BWindowScreen::Perform(perform_code d, void *arg)
664 {
665 	return inherited::Perform(d, arg);
666 }
667 
668 
669 // Reserved for future binary compatibility
670 void BWindowScreen::_ReservedWindowScreen1() {}
671 void BWindowScreen::_ReservedWindowScreen2() {}
672 void BWindowScreen::_ReservedWindowScreen3() {}
673 void BWindowScreen::_ReservedWindowScreen4() {}
674 
675 
676 /* unimplemented for protection of the user:
677  *
678  * BWindowScreen::BWindowScreen()
679  * BWindowScreen::BWindowScreen(BWindowScreen &)
680  * BWindowScreen &BWindowScreen::operator=(BWindowScreen &)
681  */
682 
683 
684 BRect
685 BWindowScreen::CalcFrame(int32 index, int32 space, display_mode *dmode)
686 {
687 	BScreen screen;
688 	if (dmode)
689 		screen.GetMode(dmode);
690 
691 	return screen.Frame();
692 }
693 
694 
695 int32
696 BWindowScreen::SetFullscreen(int32 enable)
697 {
698 	int32 retval = -1;
699 
700 #ifdef COMPILE_FOR_R5
701 	int32 result = -1;
702 
703 	a_session->swrite_l(WS_SET_FULLSCREEN);
704 	a_session->swrite_l(server_token);
705 	a_session->swrite_l(enable);
706 	a_session->sync();
707 	a_session->sread(sizeof(result), &result);
708 	a_session->sread(sizeof(retval), &retval);
709 #endif
710 
711 	return retval;
712 }
713 
714 
715 status_t
716 BWindowScreen::InitData(uint32 space, uint32 attributes)
717 {
718 	CALLED();
719 
720 	BScreen screen(this);
721 	debug_state = attributes & B_ENABLE_DEBUGGER;
722 	debug_list_count = 0;
723 	debug_list = 0;
724 	debug_first = true;
725 
726 	debug_sem = create_sem(1, "WindowScreen debug sem");
727 	old_space = (display_mode *)calloc(1, sizeof(display_mode));
728 	new_space = (display_mode *)calloc(1, sizeof(display_mode));
729 
730 	screen.GetModeList(&mode_list, &mode_count);
731 
732 	_attributes = attributes;
733 
734 	display_mode *n_space = new_space;
735 	screen_index = 0;
736 	lock_state = 0;
737 	addon_state = 0;
738 	direct_enable = 0;
739 	window_state = 0;
740 
741 	space_mode = 1;
742 
743 	GetModeFromSpace(space, n_space);
744 
745 	space0 = 0;
746 
747 	SetWorkspaces(B_CURRENT_WORKSPACE);
748 
749 	SetFullscreen(1);
750 	work_state = 1;
751 	debug_workspace = 0;
752 	const color_map *map = screen.ColorMap();
753 	memcpy(colorList, map->color_list, 256);
754 
755 	GetCardInfo();
756 	activate_sem = create_sem(0, "WindowScreen start lock");
757 	activate_state = 0;
758 
759 	return B_OK;
760 }
761 
762 
763 status_t
764 BWindowScreen::SetActiveState(int32 state)
765 {
766 	CALLED();
767 	status_t status = B_ERROR;
768 	if (state == 1) {
769 		be_app->HideCursor();
770 		if (be_app->IsCursorHidden()
771 			&& (status = SetLockState(1)) == B_OK) {
772 			status = AssertDisplayMode(new_space);
773 			if (status == B_OK) {
774 				if (!activate_state) {
775 					while (acquire_sem(activate_sem) == B_INTERRUPTED)
776 						;
777 				}
778 				SetColorList(colorList);
779 				if (debug_state && !debug_first) {
780 					SuspensionHook(true);
781 					Resume();
782 				} else {
783 					debug_first = true;
784 					ScreenConnected(true);
785 				}
786 				if (status == B_OK)
787 					return status;
788 
789 			} else
790 				SetLockState(0);
791 
792 			be_app->ShowCursor();
793 		}
794 	} else {
795 		if (debug_state && !debug_first) {
796 			Suspend();
797 			SuspensionHook(false);
798 		} else
799 			ScreenConnected(false);
800 
801 		status = SetLockState(0);
802 		if (status == B_OK) {
803 			be_app->ShowCursor();
804 			if (activate_state) {
805 #ifdef COMPILE_FOR_R5
806 				const color_map *colorMap = system_colors();
807 				_BAppServerLink_ link;
808 
809 				link.fSession->swrite_l(WS_SET_PALETTE);
810 				link.fSession->swrite_l(screen_index);
811 				link.fSession->swrite_l(0);
812 				link.fSession->swrite_l(255);
813 				link.fSession->swrite(256 * sizeof(rgb_color), const_cast<rgb_color *>(colorMap->color_list));
814 				link.fSession->sync();
815 #endif
816 			}
817 		}
818 	}
819 	return status;
820 }
821 
822 
823 status_t
824 BWindowScreen::SetLockState(int32 state)
825 {
826 	CALLED();
827 	if (addon_state == 1 && state == 1) {
828 		m_wei();
829 		fill_rect_global = NULL;
830 		blit_rect_global = NULL;
831 		trans_blit_rect_global = NULL;
832 		scaled_filtered_blit_rect_global = NULL;
833 		wait_idle_global = NULL;
834 		et_global = NULL;
835 		acquire_engine_global = NULL;
836 		release_engine_global = NULL;
837 	}
838 
839 	status_t status = B_ERROR;
840 
841 #ifdef COMPILE_FOR_R5
842 	_BAppServerLink_ link;
843 	link.fSession->swrite_l(WS_SET_LOCK_STATE);
844 	link.fSession->swrite_l(screen_index);
845 	link.fSession->swrite_l(state);
846 	link.fSession->swrite_l(server_token);
847 	link.fSession->sync();
848 	link.fSession->sread(sizeof(status), &status);
849 #endif
850 
851 	if (status == B_OK) {
852 		lock_state = state;
853 		if (state == 1) {
854 			if (addon_state == 0) {
855 				status = InitClone();
856 
857 				if (status == B_OK) {
858 					addon_state = 1;
859 					m_wei = (wait_engine_idle)m_gah(B_WAIT_ENGINE_IDLE, NULL);
860 					m_re = (release_engine)m_gah(B_RELEASE_ENGINE, NULL);
861 					m_ae = (acquire_engine)m_gah(B_ACQUIRE_ENGINE, NULL);
862 				} else
863 					addon_state = -1;
864 			}
865 
866 			if (addon_state == 1 && state == 1) {
867 				fill_rect_global = fill_rect;
868 				blit_rect_global = blit_rect;
869 				trans_blit_rect_global = trans_blit_rect;
870 				scaled_filtered_blit_rect_global = scaled_filtered_blit_rect;
871 				wait_idle_global = m_wei;
872 				et_global = et;
873 				acquire_engine_global = m_ae;
874 				release_engine_global = m_re;
875 				m_wei();
876 			}
877 		}
878 	}
879 
880 	return status;
881 }
882 
883 
884 void
885 BWindowScreen::GetCardInfo()
886 {
887 	CALLED();
888 
889 	BScreen screen(this);
890 	display_mode mode;
891 	if (screen.GetMode(&mode) < B_OK)
892 		return;
893 
894 	uint32 bits_per_pixel;
895 	switch(mode.space & 0x0fff) {
896 		case B_CMAP8:
897 			bits_per_pixel = 8;
898 			break;
899 		case B_RGB16:
900 			bits_per_pixel = 16;
901 			break;
902 		case B_RGB32:
903 			bits_per_pixel = 32;
904 			break;
905 		default:
906 			bits_per_pixel = 0;
907 			break;
908 	}
909 
910 	card_info.version = 2;
911 	card_info.id = 0;
912 	card_info.bits_per_pixel = bits_per_pixel;
913 	card_info.width = mode.virtual_width;
914 	card_info.height = mode.virtual_height;
915 
916 	if (mode.space & 0x10)
917 		strncpy(card_info.rgba_order, "rgba", 4);
918 	else
919 		strncpy(card_info.rgba_order, "bgra", 4);
920 
921 	card_info.flags = 0;
922 
923 	if (mode.flags & B_SCROLL)
924 		card_info.flags |= B_FRAME_BUFFER_CONTROL;
925 	if (mode.flags & B_PARALLEL_ACCESS)
926 		card_info.flags |= B_PARALLEL_BUFFER_ACCESS;
927 
928 	screen_id id = screen.ID();
929 
930 	status_t result = B_ERROR;
931 
932 	frame_buffer_config config;
933 
934 #ifdef COMPILE_FOR_R5
935 	_BAppServerLink_ link;
936 	link.fSession->swrite_l(WS_GET_FRAMEBUFFER);
937 	link.fSession->swrite_l(id.id);
938 	link.fSession->swrite_l(server_token);
939 	link.fSession->sync();
940 	link.fSession->sread(sizeof(result), &result);
941 	if (result == B_OK)
942 		link.fSession->sread(sizeof(frame_buffer_config), &config);
943 #endif
944 
945 	if (result == B_OK) {
946 		card_info.id = id.id;
947 		card_info.frame_buffer = config.frame_buffer;
948 		card_info.bytes_per_row = config.bytes_per_row;
949 	}
950 
951 	memcpy(&card_info_global, &card_info, sizeof(graphics_card_info));
952 
953 	CALLED();
954 }
955 
956 
957 void
958 BWindowScreen::Suspend()
959 {
960 	CALLED();
961 
962 	while (acquire_sem(debug_sem) == B_INTERRUPTED)
963 		;
964 
965 	// Suspend all the registered threads
966 	for (int i = 0; i < debug_list_count; i++) {
967 		snooze(10000);
968 		suspend_thread(debug_list[i]);
969 	}
970 
971 	graphics_card_info *info = CardInfo();
972 	size_t fbSize = info->bytes_per_row * info->height;
973 
974 	// Save the content of the frame buffer into the local buffer
975 	debug_buffer = (char *)malloc(fbSize);
976 	memcpy(debug_buffer, info->frame_buffer, fbSize);
977 }
978 
979 
980 void
981 BWindowScreen::Resume()
982 {
983 	CALLED();
984 	graphics_card_info *info = CardInfo();
985 
986 	// Copy the content of the debug_buffer back into the frame buffer.
987 	memcpy(info->frame_buffer, debug_buffer, info->bytes_per_row * info->height);
988 	free(debug_buffer);
989 
990 	// Resume all the registered threads
991 	for (int i = 0; i < debug_list_count; i++)
992 		resume_thread(debug_list[i]);
993 
994 	release_sem(debug_sem);
995 }
996 
997 
998 status_t
999 BWindowScreen::GetModeFromSpace(uint32 space, display_mode *dmode)
1000 {
1001 	CALLED();
1002 
1003 	uint32 out_space;
1004 	int32 width, height;
1005 	status_t ret = B_ERROR;
1006 
1007 	mode2parms(space, &out_space, &width, &height);
1008 	// mode2parms converts the space to actual width, height and color_space, e.g B_8_BIT_640x480
1009 
1010 	for (uint32 i = 0; i < mode_count; i++) {
1011 		if (mode_list[i].space == out_space && mode_list[i].virtual_width == width
1012 			&& mode_list[i].virtual_height == height) {
1013 
1014 			memcpy(dmode, &mode_list[i], sizeof(display_mode));
1015 			ret = B_OK;
1016 			break;
1017 		}
1018 	}
1019 
1020 	return ret;
1021 }
1022 
1023 
1024 status_t
1025 BWindowScreen::InitClone()
1026 {
1027 	CALLED();
1028 #ifndef COMPILE_FOR_R5
1029 	// TODO: Too much stuff to change, I'll just
1030 	return B_ERROR;
1031 	// for now
1032 #else
1033 	// TODO: Using BScreen::GetDeviceInfo() could do the job, I think,
1034 	// but it always returns B_ERROR on my system (Rudolf's Nvidia driver)
1035 	_BAppServerLink_ link;
1036 	link.fSession->swrite_l(WS_GET_ACCELERANT_NAME);
1037 	link.fSession->swrite_l(screen_index);
1038 	link.fSession->sync();
1039 
1040 	int32 result;
1041 	link.fSession->sread(sizeof(result), &result);
1042 	if (result != B_OK)
1043 		return result;
1044 
1045 	link.fSession->sread(sizeof(result), &result); // read length of accelerant's name
1046 
1047 	char *addonName = (char *)malloc((result + 1) * sizeof (char));
1048 	link.fSession->sread(result, addonName); // read the accelerant's name
1049 	addonName[result] = '\0';
1050 
1051 	link.fSession->swrite_l(WS_GET_DRIVER_NAME); // get driver's name without the /dev/
1052 	link.fSession->swrite_l(screen_index);
1053 	link.fSession->sync();
1054 
1055 	link.fSession->sread(sizeof(result), &result);
1056 	if (result != B_OK)
1057 		return result;
1058 
1059 	link.fSession->sread(sizeof(result), &result);
1060 	// result now contains the length of the buffer needed for the drivers path name
1061 
1062 	char *path = (char *)malloc((result + 1) * sizeof(char));
1063 	link.fSession->sread(result, path);
1064 	path[result] = '\0';
1065 	// path now contains the driver's name
1066 
1067 	// load the accelerant
1068 	addon_image = load_add_on(addonName);
1069 
1070 	free(addonName);
1071 
1072 	if (addon_image < 0)
1073 		return B_ERROR;
1074 
1075 	// now get the symbol for GetAccelerantHook m_gah
1076 	if (get_image_symbol(addon_image, "get_accelerant_hook",
1077 						B_SYMBOL_TYPE_ANY, (void **)&m_gah) < 0)
1078 		return B_ERROR;
1079 
1080 	// now use m_gah to get a pointer to the accelerant's clone accelerant
1081 	clone_accelerant clone = (clone_accelerant)m_gah(B_CLONE_ACCELERANT, 0);
1082 
1083 	if (!clone)
1084 		return B_ERROR;
1085 
1086 	// test if the driver supports cloning of the accelerant, using the path we got earlier
1087 	result = clone((void *)path);
1088 	free(path);
1089 
1090 	if (result != 0) {
1091 		unload_add_on(addon_image);
1092 		addon_image = -1;
1093 	}
1094 
1095 	return result;
1096 #endif
1097 }
1098 
1099 
1100 status_t
1101 BWindowScreen::AssertDisplayMode(display_mode *dmode)
1102 {
1103 	status_t result = B_ERROR;
1104 
1105 #ifdef COMPILE_FOR_R5
1106 	_BAppServerLink_ link;
1107 	link.fSession->swrite_l(WS_SET_DISPLAY_MODE); // check display_mode valid command
1108 	link.fSession->swrite_l(screen_index);
1109 	link.fSession->swrite(sizeof(display_mode), (void *)dmode);
1110 	link.fSession->sync();
1111 	link.fSession->sread(sizeof(result), &result);
1112 #endif
1113 
1114 	// if the result is B_OK, we copy the dmode to new_space
1115 	if (result == B_OK) {
1116 		memcpy(new_space, dmode, sizeof(display_mode));
1117 		space_mode = 1;
1118 	}
1119 	GetCardInfo();
1120 
1121 	format_info.bits_per_pixel = card_info.bits_per_pixel;
1122 	format_info.bytes_per_row = card_info.bytes_per_row;
1123 	format_info.width = card_info.width;
1124 	format_info.height = card_info.height;
1125 	format_info.display_width = card_info.width;
1126 	format_info.display_height = card_info.height;
1127 	format_info.display_x = 0;
1128 	format_info.display_y = 0;
1129 
1130 	return result;
1131 }
1132