⛏️ index : haiku.git

/*
 * Copyright 2002-2009, Haiku. All Rights Reserved.
 * Copyright 2002-2005,
 *		Marcus Overhagen,
 *		Stefano Ceccherini (stefano.ceccherini@gmail.com),
 *		Carwyn Jones (turok2@currantbun.com)
 *		All rights reserved.
 *
 * Distributed under the terms of the MIT License.
 */


#include <WindowScreen.h>

#include <new>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <Application.h>
#include <Screen.h>
#include <String.h>

#include <AppServerLink.h>
#include <input_globals.h>
#include <InputServerTypes.h>
#include <InterfacePrivate.h>
#include <ServerProtocol.h>
#include <WindowPrivate.h>


using BPrivate::AppServerLink;


//#define TRACE_WINDOWSCREEN 1
#if TRACE_WINDOWSCREEN
#	define CALLED() printf("%s\n", __PRETTY_FUNCTION__);
#else
#	define CALLED() ;
#endif


// Acceleration hooks pointers
static fill_rectangle sFillRectHook;
static screen_to_screen_blit sBlitRectHook;
static screen_to_screen_transparent_blit sTransparentBlitHook;
static screen_to_screen_scaled_filtered_blit sScaledFilteredBlitHook;
static wait_engine_idle sWaitIdleHook;
static acquire_engine sAcquireEngineHook;
static release_engine sReleaseEngineHook;

static engine_token *sEngineToken;


// Helper methods which translates the pre r5 graphics methods to r5 ones
static int32
card_sync()
{
	sWaitIdleHook();
	return 0;
}


static int32
blit(int32 sx, int32 sy, int32 dx, int32 dy, int32 width, int32 height)
{
	blit_params param;
	param.src_left = sx;
	param.src_top = sy;
	param.dest_left = dx;
	param.dest_top = dy;
	param.width = width;
	param.height = height;

	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
	sBlitRectHook(sEngineToken, &param, 1);
	sReleaseEngineHook(sEngineToken, NULL);
	return 0;
}


// TODO: This function seems not to be exported through CardHookAt().
// At least, nothing I've tried uses it.
#if 0
static int32
transparent_blit(int32 sx, int32 sy, int32 dx, int32 dy, int32 width,
	int32 height, uint32 transparent_color)
{
	blit_params param;
	param.src_left = sx;
	param.src_top = sy;
	param.dest_left = dx;
	param.dest_top = dy;
	param.width = width;
	param.height = height;

	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, 0, &sEngineToken);
	sTransparentBlitHook(sEngineToken, transparent_color, &param, 1);
	sReleaseEngineHook(sEngineToken, 0);
	return 0;
}
#endif


static int32
scaled_filtered_blit(int32 sx, int32 sy, int32 sw, int32 sh, int32 dx, int32 dy,
	int32 dw, int32 dh)
{
	scaled_blit_params param;
	param.src_left = sx;
	param.src_top = sy;
	param.src_width = sw;
	param.src_height = sh;
	param.dest_left = dx;
	param.dest_top = dy;
	param.dest_width = dw;
	param.dest_height = dh;

	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
	sScaledFilteredBlitHook(sEngineToken, &param, 1);
	sReleaseEngineHook(sEngineToken, NULL);
	return 0;
}


static int32
draw_rect_8(int32 sx, int32 sy, int32 sw, int32 sh, uint8 color_index)
{
	fill_rect_params param;
	param.left = sx;
	param.top = sy;
	param.right = sw;
	param.bottom = sh;

	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
	sFillRectHook(sEngineToken, color_index, &param, 1);
	sReleaseEngineHook(sEngineToken, NULL);
	return 0;
}


static int32
draw_rect_16(int32 sx, int32 sy, int32 sw, int32 sh, uint16 color)
{
	fill_rect_params param;
	param.left = sx;
	param.top = sy;
	param.right = sw;
	param.bottom = sh;

	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
	sFillRectHook(sEngineToken, color, &param, 1);
	sReleaseEngineHook(sEngineToken, NULL);
	return 0;
}


static int32
draw_rect_32(int32 sx, int32 sy, int32 sw, int32 sh, uint32 color)
{
	fill_rect_params param;
	param.left = sx;
	param.top = sy;
	param.right = sw;
	param.bottom = sh;

	sAcquireEngineHook(B_2D_ACCELERATION, 0xff, NULL, &sEngineToken);
	sFillRectHook(sEngineToken, color, &param, 1);
	sReleaseEngineHook(sEngineToken, NULL);
	return 0;
}


//	#pragma mark - public API calls


void
set_mouse_position(int32 x, int32 y)
{
	BMessage command(IS_SET_MOUSE_POSITION);
	BMessage reply;

	command.AddPoint("where", BPoint(x, y));
	_control_input_server_(&command, &reply);
}


//	#pragma mark -


BWindowScreen::BWindowScreen(const char *title, uint32 space, status_t *error,
		bool debugEnable)
	:
	BWindow(BScreen().Frame(), title, B_NO_BORDER_WINDOW_LOOK,
		kWindowScreenFeel, kWindowScreenFlag | B_NOT_MINIMIZABLE
			| B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MOVABLE | B_NOT_RESIZABLE,
		B_CURRENT_WORKSPACE)
{
	CALLED();
	uint32 attributes = 0;
	if (debugEnable)
		attributes |= B_ENABLE_DEBUGGER;

	status_t status = _InitData(space, attributes);
	if (error)
		*error = status;
}


BWindowScreen::BWindowScreen(const char *title, uint32 space,
		uint32 attributes, status_t *error)
	:
	BWindow(BScreen().Frame(), title, B_NO_BORDER_WINDOW_LOOK,
		kWindowScreenFeel, kWindowScreenFlag | B_NOT_MINIMIZABLE
			| B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MOVABLE | B_NOT_RESIZABLE,
		B_CURRENT_WORKSPACE)
{
	CALLED();
	status_t status = _InitData(space, attributes);
	if (error)
		*error = status;
}


BWindowScreen::~BWindowScreen()
{
	CALLED();
	_DisposeData();
}


void
BWindowScreen::Quit(void)
{
	CALLED();
	Disconnect();
	BWindow::Quit();
}


void
BWindowScreen::ScreenConnected(bool active)
{
	// Implemented in subclasses
}


void
BWindowScreen::Disconnect()
{
	CALLED();
	if (fLockState == 1) {
		if (fDebugState)
			fDebugFirst = true;
		_Deactivate();
	}

	be_app->ShowCursor();
}


void
BWindowScreen::WindowActivated(bool active)
{
	CALLED();
	fWindowState = active;
	if (active && fLockState == 0 && fWorkState)
		_Activate();
}


void
BWindowScreen::WorkspaceActivated(int32 workspace, bool state)
{
	CALLED();
	fWorkState = state;

	if (state) {
		if (fLockState == 0 && fWindowState) {
			_Activate();
			if (!IsHidden()) {
				Activate(true);
				WindowActivated(true);
			}
		}
	} else if (fLockState)
		_Deactivate();
}


void
BWindowScreen::ScreenChanged(BRect screenFrame, color_space depth)
{
	// Implemented in subclasses
}


void
BWindowScreen::Hide()
{
	CALLED();

	Disconnect();
	BWindow::Hide();
}


void
BWindowScreen::Show()
{
	CALLED();

	BWindow::Show();
}


void
BWindowScreen::SetColorList(rgb_color *list, int32 firstIndex, int32 lastIndex)
{
	CALLED();
	if (firstIndex < 0 || lastIndex > 255 || firstIndex > lastIndex)
		return;

	if (!Lock())
		return;

	if (!fActivateState) {
		// If we aren't active, we just change our local palette
		for (int32 x = firstIndex; x <= lastIndex; x++) {
			fPalette[x] = list[x - firstIndex];
		}
	} else {
		uint8 colors[3 * 256];
			// the color table has 3 bytes per color
		int32 j = 0;

		for (int32 x = firstIndex; x <= lastIndex; x++) {
			fPalette[x] = list[x - firstIndex];
				// update our local palette as well

			colors[j++] = fPalette[x].red;
			colors[j++] = fPalette[x].green;
			colors[j++] = fPalette[x].blue;
		}

		if (fAddonImage >= 0) {
			set_indexed_colors setIndexedColors
				= (set_indexed_colors)fGetAccelerantHook(B_SET_INDEXED_COLORS,
					NULL);
			if (setIndexedColors != NULL) {
				setIndexedColors(255, 0,
					colors, 0);
			}
		}

		// TODO: Tell the app_server about our changes

		BScreen screen(this);
		screen.WaitForRetrace();
	}

	Unlock();
}


status_t
BWindowScreen::SetSpace(uint32 space)
{
	CALLED();

	display_mode mode;
	status_t status = _GetModeFromSpace(space, &mode);
	if (status == B_OK)
		status = _AssertDisplayMode(&mode);

	return status;
}


bool
BWindowScreen::CanControlFrameBuffer()
{
	return (fCardInfo.flags & B_FRAME_BUFFER_CONTROL) != 0;
}


status_t
BWindowScreen::SetFrameBuffer(int32 width, int32 height)
{
	CALLED();
	display_mode highMode = *fDisplayMode;
	highMode.flags |= B_SCROLL;

	highMode.virtual_height = (int16)height;
	highMode.virtual_width = (int16)width;

	display_mode lowMode = highMode;
	display_mode mode = highMode;

	BScreen screen(this);
	status_t status = screen.ProposeMode(&mode, &lowMode, &highMode);
	if (status == B_OK)
		status = _AssertDisplayMode(&mode);

	return status;
}


status_t
BWindowScreen::MoveDisplayArea(int32 x, int32 y)
{
	CALLED();
	move_display_area moveDisplayArea
		= (move_display_area)fGetAccelerantHook(B_MOVE_DISPLAY, NULL);
	if (moveDisplayArea && moveDisplayArea((int16)x, (int16)y) == B_OK) {
		fFrameBufferInfo.display_x = x;
		fFrameBufferInfo.display_y = y;
		fDisplayMode->h_display_start = x;
		fDisplayMode->v_display_start = y;
		return B_OK;
	}
	return B_ERROR;
}


#if 0
void *
BWindowScreen::IOBase()
{
	// Not supported
	return NULL;
}
#endif


rgb_color *
BWindowScreen::ColorList()
{
	CALLED();
	return fPalette;
}


frame_buffer_info *
BWindowScreen::FrameBufferInfo()
{
	CALLED();
	return &fFrameBufferInfo;
}


graphics_card_hook
BWindowScreen::CardHookAt(int32 index)
{
	CALLED();
	if (fAddonImage < 0)
		return NULL;

	graphics_card_hook hook = NULL;

	switch (index) {
		case 5: // 8 bit fill rect
			if (sFillRectHook)
				hook = (graphics_card_hook)draw_rect_8;
			break;
		case 6: // 32 bit fill rect
			if (sFillRectHook)
				hook = (graphics_card_hook)draw_rect_32;
			break;
		case 7: // screen to screen blit
			if (sBlitRectHook)
				hook = (graphics_card_hook)blit;
			break;
		case 8: // screen to screen scaled filtered blit
			if (sScaledFilteredBlitHook)
				hook = (graphics_card_hook)scaled_filtered_blit;
			break;
		case 10: // sync aka wait for graphics card idle
			if (sWaitIdleHook)
				hook = (graphics_card_hook)card_sync;
			break;
		case 13: // 16 bit fill rect
			if (sFillRectHook)
				hook = (graphics_card_hook)draw_rect_16;
			break;
		default:
			break;
	}

	return hook;
}


graphics_card_info *
BWindowScreen::CardInfo()
{
	CALLED();
	return &fCardInfo;
}


void
BWindowScreen::RegisterThread(thread_id thread)
{
	CALLED();

	status_t status;
	do {
		status = acquire_sem(fDebugSem);
	} while (status == B_INTERRUPTED);

	if (status < B_OK)
		return;

	void *newDebugList = realloc(fDebugThreads,
		(fDebugThreadCount + 1) * sizeof(thread_id));
	if (newDebugList != NULL) {
		fDebugThreads = (thread_id *)newDebugList;
		fDebugThreads[fDebugThreadCount] = thread;
		fDebugThreadCount++;
	}
	release_sem(fDebugSem);
}


void
BWindowScreen::SuspensionHook(bool active)
{
	// Implemented in subclasses
}


void
BWindowScreen::Suspend(char* label)
{
	CALLED();
	if (fDebugState) {
		fprintf(stderr, "## Debugger(\"%s\").", label);
		fprintf(stderr, " Press Alt-F%" B_PRId32 " or Cmd-F%" B_PRId32 " to resume.\n",
			fWorkspaceIndex + 1, fWorkspaceIndex + 1);

		if (IsLocked())
			Unlock();

		activate_workspace(fDebugWorkspace);

		// Suspend ourself
		suspend_thread(find_thread(NULL));

		Lock();
	}
}


status_t
BWindowScreen::Perform(perform_code d, void* arg)
{
	return inherited::Perform(d, arg);
}


// Reserved for future binary compatibility
void BWindowScreen::_ReservedWindowScreen1() {}
void BWindowScreen::_ReservedWindowScreen2() {}
void BWindowScreen::_ReservedWindowScreen3() {}
void BWindowScreen::_ReservedWindowScreen4() {}


status_t
BWindowScreen::_InitData(uint32 space, uint32 attributes)
{
	CALLED();

	fDebugState = attributes & B_ENABLE_DEBUGGER;
	fDebugThreadCount = 0;
	fDebugThreads = NULL;
	fDebugFirst = true;

	fAttributes = attributes;
		// TODO: not really used right now, but should probably be known by
		// the app_server

	fWorkspaceIndex = fDebugWorkspace = current_workspace();
	fLockState = 0;
	fAddonImage = -1;
	fWindowState = 0;
	fOriginalDisplayMode = NULL;
	fDisplayMode = NULL;
	fModeList = NULL;
	fModeCount = 0;
	fDebugSem = -1;
	fActivateState = false;
	fWorkState = false;

	status_t status = B_ERROR;
	try {
		fOriginalDisplayMode = new display_mode;
		fDisplayMode = new display_mode;

		BScreen screen(this);
		status = screen.GetMode(fOriginalDisplayMode);
		if (status < B_OK)
			throw status;

		status = screen.GetModeList(&fModeList, &fModeCount);
		if (status < B_OK)
			throw status;

		status = _GetModeFromSpace(space, fDisplayMode);
		if (status < B_OK)
			throw status;

		status = _GetCardInfo();
		if (status < B_OK)
			throw status;

		fDebugSem = create_sem(1, "WindowScreen debug sem");
		if (fDebugSem < B_OK)
			throw (status_t)fDebugSem;

		memcpy((void*)fPalette, screen.ColorMap()->color_list, sizeof(fPalette));
		fActivateState = false;
		fWorkState = true;

		status = B_OK;
	} catch (std::bad_alloc&) {
		status = B_NO_MEMORY;
	} catch (status_t error) {
		status = error;
	} catch (...) {
		status = B_ERROR;
	}

	if (status != B_OK)
		_DisposeData();

	return status;
}


void
BWindowScreen::_DisposeData()
{
	CALLED();
	Disconnect();
	if (fAddonImage >= 0) {
		unload_add_on(fAddonImage);
		fAddonImage = -1;
	}

	delete_sem(fDebugSem);
	fDebugSem = -1;

	if (fDebugState)
		activate_workspace(fDebugWorkspace);

	delete fDisplayMode;
	fDisplayMode = NULL;
	delete fOriginalDisplayMode;
	fOriginalDisplayMode = NULL;
	free(fModeList);
	fModeList = NULL;
	fModeCount = 0;

	fLockState = 0;
}


status_t
BWindowScreen::_LockScreen(bool lock)
{
	if (fActivateState == lock)
		return B_OK;

	// TODO: the BWindowScreen should use the same mechanism as BDirectWindows!
	BPrivate::AppServerLink link;

	link.StartMessage(AS_DIRECT_SCREEN_LOCK);
	link.Attach<bool>(lock);

	status_t status = B_ERROR;
	if (link.FlushWithReply(status) == B_OK && status == B_OK)
		fActivateState = lock;

	return status;
}


status_t
BWindowScreen::_Activate()
{
	CALLED();
	status_t status = _AssertDisplayMode(fDisplayMode);
	if (status < B_OK)
		return status;

	status = _SetupAccelerantHooks();
	if (status < B_OK)
		return status;

	if (!fActivateState) {
		status = _LockScreen(true);
		if (status != B_OK)
			return status;
	}

	be_app->HideCursor();

	SetColorList(fPalette);
	if (fDebugState && !fDebugFirst) {
		SuspensionHook(true);
		_Resume();
	} else {
		fDebugFirst = true;
		ScreenConnected(true);
	}

	return B_OK;
}


status_t
BWindowScreen::_Deactivate()
{
	CALLED();

	if (fDebugState && !fDebugFirst) {
		_Suspend();
		SuspensionHook(false);
	} else
		ScreenConnected(false);

	if (fActivateState) {
		status_t status = _LockScreen(false);
		if (status != B_OK)
			return status;

		BScreen screen(this);
		SetColorList((rgb_color *)screen.ColorMap()->color_list);
	}

	_AssertDisplayMode(fOriginalDisplayMode);
	_ResetAccelerantHooks();

	be_app->ShowCursor();

	return B_OK;
}


status_t
BWindowScreen::_SetupAccelerantHooks()
{
	CALLED();

	status_t status = B_OK;
	if (fAddonImage < 0)
		status = _InitClone();
	else
		_ResetAccelerantHooks();

	if (status == B_OK) {
		sWaitIdleHook = fWaitEngineIdle = (wait_engine_idle)
			fGetAccelerantHook(B_WAIT_ENGINE_IDLE, NULL);
		sReleaseEngineHook
			= (release_engine)fGetAccelerantHook(B_RELEASE_ENGINE, NULL);
		sAcquireEngineHook
			= (acquire_engine)fGetAccelerantHook(B_ACQUIRE_ENGINE, NULL);
		sFillRectHook
			= (fill_rectangle)fGetAccelerantHook(B_FILL_RECTANGLE, NULL);
		sBlitRectHook = (screen_to_screen_blit)
			fGetAccelerantHook(B_SCREEN_TO_SCREEN_BLIT, NULL);
		sTransparentBlitHook = (screen_to_screen_transparent_blit)
			fGetAccelerantHook(B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT, NULL);
		sScaledFilteredBlitHook = (screen_to_screen_scaled_filtered_blit)
			fGetAccelerantHook(B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT, NULL);

		if (fWaitEngineIdle)
			fWaitEngineIdle();

		fLockState = 1;
	}

	return status;
}


void
BWindowScreen::_ResetAccelerantHooks()
{
	CALLED();
	if (fWaitEngineIdle)
		fWaitEngineIdle();

	sFillRectHook = NULL;
	sBlitRectHook = NULL;
	sTransparentBlitHook = NULL;
	sScaledFilteredBlitHook = NULL;
	sWaitIdleHook = NULL;
	sEngineToken = NULL;
	sAcquireEngineHook = NULL;
	sReleaseEngineHook = NULL;

	fWaitEngineIdle = NULL;

	fLockState = 0;
}


status_t
BWindowScreen::_GetCardInfo()
{
	CALLED();

	BScreen screen(this);
	display_mode mode;
	status_t status = screen.GetMode(&mode);
	if (status < B_OK)
		return status;

	uint32 bitsPerPixel;
	switch(mode.space & 0x0fff) {
		case B_CMAP8:
			bitsPerPixel = 8;
			break;
		case B_RGB15:
			bitsPerPixel = 15;
			break;
		case B_RGB16:
			bitsPerPixel = 16;
			break;
		case B_RGB32:
			bitsPerPixel = 32;
			break;
		default:
			bitsPerPixel = 0;
			break;
	}

	fCardInfo.version = 2;
	fCardInfo.id = screen.ID().id;
	fCardInfo.bits_per_pixel = bitsPerPixel;
	fCardInfo.width = mode.virtual_width;
	fCardInfo.height = mode.virtual_height;

	if (mode.space & 0x10)
		memcpy(fCardInfo.rgba_order, "rgba", 4);
	else
		memcpy(fCardInfo.rgba_order, "bgra", 4);

	fCardInfo.flags = 0;
	if (mode.flags & B_SCROLL)
		fCardInfo.flags |= B_FRAME_BUFFER_CONTROL;
	if (mode.flags & B_PARALLEL_ACCESS)
		fCardInfo.flags |= B_PARALLEL_BUFFER_ACCESS;

	AppServerLink link;
	link.StartMessage(AS_GET_FRAME_BUFFER_CONFIG);
	link.Attach<screen_id>(screen.ID());

	status_t result = B_ERROR;
	if (link.FlushWithReply(result) < B_OK || result < B_OK)
		return result;

	frame_buffer_config config;
	link.Read<frame_buffer_config>(&config);

	fCardInfo.frame_buffer = config.frame_buffer;
	fCardInfo.bytes_per_row = config.bytes_per_row;

	return B_OK;
}


void
BWindowScreen::_Suspend()
{
	CALLED();

	status_t status;
	do {
		status = acquire_sem(fDebugSem);
	} while (status == B_INTERRUPTED);

	if (status != B_OK)
		return;

	// Suspend all the registered threads
	for (int32 i = 0; i < fDebugThreadCount; i++) {
		snooze(10000);
		suspend_thread(fDebugThreads[i]);
	}

	graphics_card_info *info = CardInfo();
	size_t fbSize = info->bytes_per_row * info->height;

	// Save the content of the frame buffer into the local buffer
	fDebugFrameBuffer = (char *)malloc(fbSize);
	memcpy(fDebugFrameBuffer, info->frame_buffer, fbSize);
}


void
BWindowScreen::_Resume()
{
	CALLED();
	graphics_card_info *info = CardInfo();

	// Copy the content of the debug_buffer back into the frame buffer.
	memcpy(info->frame_buffer, fDebugFrameBuffer,
		info->bytes_per_row * info->height);
	free(fDebugFrameBuffer);
	fDebugFrameBuffer = NULL;

	// Resume all the registered threads
	for (int32 i = 0; i < fDebugThreadCount; i++) {
		resume_thread(fDebugThreads[i]);
	}

	release_sem(fDebugSem);
}


status_t
BWindowScreen::_GetModeFromSpace(uint32 space, display_mode *dmode)
{
	CALLED();

	int32 width, height;
	uint32 colorSpace;
	if (!BPrivate::get_mode_parameter(space, width, height, colorSpace))
		return B_BAD_VALUE;

	for (uint32 i = 0; i < fModeCount; i++) {
		if (fModeList[i].space == colorSpace
			&& fModeList[i].virtual_width == width
			&& fModeList[i].virtual_height == height) {
			memcpy(dmode, &fModeList[i], sizeof(display_mode));
			return B_OK;
		}
	}

	return B_ERROR;
}


status_t
BWindowScreen::_InitClone()
{
	CALLED();

	if (fAddonImage >= 0)
		return B_OK;

	BScreen screen(this);

	AppServerLink link;
	link.StartMessage(AS_GET_ACCELERANT_PATH);
	link.Attach<screen_id>(screen.ID());

	status_t status = B_ERROR;
	if (link.FlushWithReply(status) < B_OK || status < B_OK)
		return status;

	BString accelerantPath;
	link.ReadString(accelerantPath);

	link.StartMessage(AS_GET_DRIVER_PATH);
	link.Attach<screen_id>(screen.ID());

	status = B_ERROR;
	if (link.FlushWithReply(status) < B_OK || status < B_OK)
		return status;

	BString driverPath;
	link.ReadString(driverPath);

	fAddonImage = load_add_on(accelerantPath.String());
	if (fAddonImage < B_OK) {
		fprintf(stderr, "InitClone: cannot load accelerant image\n");
		return fAddonImage;
	}

	status = get_image_symbol(fAddonImage, B_ACCELERANT_ENTRY_POINT,
		B_SYMBOL_TYPE_TEXT, (void**)&fGetAccelerantHook);
	if (status < B_OK) {
		fprintf(stderr, "InitClone: cannot get accelerant entry point\n");
		unload_add_on(fAddonImage);
		fAddonImage = -1;
		return B_NOT_SUPPORTED;
	}

	clone_accelerant cloneHook
		= (clone_accelerant)fGetAccelerantHook(B_CLONE_ACCELERANT, NULL);
	if (cloneHook == NULL) {
		fprintf(stderr, "InitClone: cannot get clone hook\n");
		unload_add_on(fAddonImage);
		fAddonImage = -1;
		return B_NOT_SUPPORTED;
	}

	status = cloneHook((void*)driverPath.String());
	if (status < B_OK) {
		fprintf(stderr, "InitClone: cannot clone accelerant\n");
		unload_add_on(fAddonImage);
		fAddonImage = -1;
	}

	return status;
}


status_t
BWindowScreen::_AssertDisplayMode(display_mode* displayMode)
{
	CALLED();

	BScreen screen(this);

	display_mode currentMode;
	status_t status = screen.GetMode(&currentMode);
	if (status != B_OK)
		return status;

	if (currentMode.virtual_height != displayMode->virtual_height
		|| currentMode.virtual_width != displayMode->virtual_width
		|| currentMode.space != displayMode->space
		|| currentMode.flags != displayMode->flags) {
		status = screen.SetMode(displayMode);
		if (status != B_OK) {
			fprintf(stderr, "AssertDisplayMode: Setting mode failed: %s\n",
				strerror(status));
			return status;
		}

		memcpy(fDisplayMode, displayMode, sizeof(display_mode));
	}

	status = _GetCardInfo();
	if (status != B_OK)
		return status;

	fFrameBufferInfo.bits_per_pixel = fCardInfo.bits_per_pixel;
	fFrameBufferInfo.bytes_per_row = fCardInfo.bytes_per_row;
	fFrameBufferInfo.width = fCardInfo.width;
	fFrameBufferInfo.height = fCardInfo.height;
	fFrameBufferInfo.display_width = fCardInfo.width;
	fFrameBufferInfo.display_height = fCardInfo.height;
	fFrameBufferInfo.display_x = 0;
	fFrameBufferInfo.display_y = 0;

	return B_OK;
}