#include "DWindowHWInterface.h"
#include <malloc.h>
#include <new>
#include <stdio.h>
#include <Application.h>
#include <Bitmap.h>
#include <Cursor.h>
#include <DirectWindow.h>
#include <Locker.h>
#include <Message.h>
#include <MessageFilter.h>
#include <MessageRunner.h>
#include <Region.h>
#include <Screen.h>
#include <String.h>
#include <View.h>
#include <Accelerant.h>
#include <graphic_driver.h>
#include <FindDirectory.h>
#include <image.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <ServerProtocol.h>
#include "DWindowBuffer.h"
#include "PortLink.h"
#include "RGBColor.h"
#include "ServerConfig.h"
#include "ServerCursor.h"
#ifdef DEBUG_DRIVER_MODULE
# include <stdio.h>
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
const unsigned char kEmptyCursor[] = { 16, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static int32
run_app_thread(void* cookie)
{
if (BApplication* app = (BApplication*)cookie) {
app->Lock();
app->Run();
}
return 0;
}
class DView : public BView {
public:
DView(BRect bounds);
virtual ~DView();
void ForwardMessage(BMessage* message = NULL);
private:
port_id fInputPort;
};
class DWindow : public BWindow {
public:
DWindow(BRect frame,
DWindowHWInterface* interface,
DWindowBuffer* buffer);
virtual ~DWindow();
virtual bool QuitRequested();
virtual void FrameMoved(BPoint newOffset);
private:
DWindowHWInterface* fHWInterface;
DWindowBuffer* fBuffer;
};
class DirectMessageFilter : public BMessageFilter {
public:
DirectMessageFilter(DView* view);
virtual filter_result Filter(BMessage *message, BHandler** _target);
private:
DView* fView;
};
DView::DView(BRect bounds)
:
BView(bounds, "graphics card view", B_FOLLOW_ALL, 0)
{
SetViewColor(B_TRANSPARENT_COLOR);
#ifndef INPUTSERVER_TEST_MODE
fInputPort = create_port(200, SERVER_INPUT_PORT);
#else
fInputPort = create_port(100, "ViewInputDevice");
#endif
#ifdef ENABLE_INPUT_SERVER_EMULATION
AddFilter(new DirectMessageFilter(this));
#endif
}
DView::~DView()
{
}
void
DView::ForwardMessage(BMessage* message)
{
if (message == NULL)
message = Window()->CurrentMessage();
if (message == NULL)
return;
BMessage copy = *message;
copy.RemoveName("screen_where");
copy.RemoveName("be:transit");
copy.RemoveName("be:view_where");
copy.RemoveName("be:cursor_needed");
size_t length = copy.FlattenedSize();
char stream[length];
if (copy.Flatten(stream, length) == B_OK)
write_port(fInputPort, 0, stream, length);
}
DirectMessageFilter::DirectMessageFilter(DView* view)
:
BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
fView(view)
{
}
filter_result
DirectMessageFilter::Filter(BMessage* message, BHandler** target)
{
switch (message->what) {
case B_KEY_DOWN:
case B_UNMAPPED_KEY_DOWN:
case B_KEY_UP:
case B_UNMAPPED_KEY_UP:
case B_MOUSE_DOWN:
case B_MOUSE_UP:
case B_MOUSE_WHEEL_CHANGED:
fView->ForwardMessage(message);
return B_SKIP_MESSAGE;
case B_MOUSE_MOVED:
{
int32 transit;
if (message->FindInt32("be:transit", &transit) == B_OK
&& transit == B_ENTERED_VIEW) {
BCursor cursor(kEmptyCursor);
fView->SetViewCursor(&cursor, true);
}
fView->ForwardMessage(message);
return B_SKIP_MESSAGE;
}
}
return B_DISPATCH_MESSAGE;
}
DWindow::DWindow(BRect frame, DWindowHWInterface* interface,
DWindowBuffer* buffer)
:
BWindow(frame, "Haiku App Server", B_TITLED_WINDOW_LOOK,
B_NORMAL_WINDOW_FEEL,
B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NOT_MOVABLE),
fHWInterface(interface),
fBuffer(buffer)
{
DView* view = new DView(Bounds());
AddChild(view);
view->MakeFocus();
}
DWindow::~DWindow()
{
}
bool
DWindow::QuitRequested()
{
port_id serverport = find_port(SERVER_PORT_NAME);
if (serverport >= 0) {
BPrivate::PortLink link(serverport);
link.StartMessage(B_QUIT_REQUESTED);
link.Flush();
} else
printf("ERROR: couldn't find the app_server's main port!");
return false;
}
void
DWindow::FrameMoved(BPoint newOffset)
{
fHWInterface->SetOffset((int32)newOffset.x, (int32)newOffset.y);
}
const int32 kDefaultParamsCount = 64;
DWindowHWInterface::DWindowHWInterface()
:
HWInterface(),
fFrontBuffer(new DWindowBuffer()),
fWindow(NULL),
fXOffset(50),
fYOffset(50),
fCardFD(-1),
fAccelerantImage(-1),
fAccelerantHook(NULL),
fAccAcquireEngine(NULL),
fAccReleaseEngine(NULL),
fAccSyncToToken(NULL),
fAccGetModeCount(NULL),
fAccGetModeList(NULL),
fAccGetFrameBufferConfig(NULL),
fAccSetDisplayMode(NULL),
fAccGetDisplayMode(NULL),
fAccGetPixelClockLimits(NULL),
fAccGetTimingConstraints(NULL),
fAccProposeDisplayMode(NULL),
fAccFillRect(NULL),
fAccInvertRect(NULL),
fAccScreenBlit(NULL),
fAccSetCursorShape(NULL),
fAccMoveCursor(NULL),
fAccShowCursor(NULL)
{
fDisplayMode.virtual_width = 800;
fDisplayMode.virtual_height = 600;
fDisplayMode.space = B_RGBA32;
}
DWindowHWInterface::~DWindowHWInterface()
{
if (fWindow) {
fWindow->Lock();
fWindow->Quit();
}
be_app->Lock();
be_app->Quit();
delete be_app;
}
status_t
DWindowHWInterface::Initialize()
{
status_t ret = HWInterface::Initialize();
if (ret >= B_OK) {
for (int32 i = 1; fCardFD != B_ENTRY_NOT_FOUND; i++) {
fCardFD = _OpenGraphicsDevice(i);
if (fCardFD < 0) {
STRACE(("Failed to open graphics device\n"));
continue;
}
if (_OpenAccelerant(fCardFD) == B_OK)
break;
close(fCardFD);
}
return fCardFD >= 0 ? B_OK : fCardFD;
}
return ret;
}
int
DWindowHWInterface::_OpenGraphicsDevice(int deviceNumber)
{
DIR *directory = opendir("/dev/graphics");
if (!directory)
return B_ENTRY_NOT_FOUND;
int count = 0;
struct dirent *entry = NULL;
int current_card_fd = -1;
char path[PATH_MAX];
while (count < deviceNumber && (entry = readdir(directory)) != NULL) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")
|| !strcmp(entry->d_name, "vesa") || !strcmp(entry->d_name, "framebuffer"))
continue;
if (current_card_fd >= 0) {
close(current_card_fd);
current_card_fd = -1;
}
sprintf(path, "/dev/graphics/%s", entry->d_name);
current_card_fd = open(path, B_READ_WRITE);
if (current_card_fd >= 0)
count++;
}
if (count < deviceNumber) {
if (deviceNumber == 1) {
sprintf(path, "/dev/graphics/vesa");
current_card_fd = open(path, B_READ_WRITE);
if (current_card_fd < 0) {
sprintf(path, "/dev/graphics/framebuffer");
current_card_fd = open(path, B_READ_WRITE);
}
} else {
close(current_card_fd);
current_card_fd = B_ENTRY_NOT_FOUND;
}
}
if (entry)
fCardNameInDevFS = entry->d_name;
return current_card_fd;
}
status_t
DWindowHWInterface::_OpenAccelerant(int device)
{
char signature[1024];
if (ioctl(device, B_GET_ACCELERANT_SIGNATURE,
&signature, sizeof(signature)) != B_OK)
return B_ERROR;
STRACE(("accelerant signature is: %s\n", signature));
struct stat accelerant_stat;
const static directory_which dirs[] = {
B_USER_NONPACKAGED_ADDONS_DIRECTORY,
B_USER_ADDONS_DIRECTORY,
B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY
};
fAccelerantImage = -1;
for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) {
char path[PATH_MAX];
if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK)
continue;
strcat(path, "/accelerants/");
strcat(path, signature);
if (stat(path, &accelerant_stat) != 0)
continue;
fAccelerantImage = load_add_on(path);
if (fAccelerantImage >= 0) {
if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT,
B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) {
STRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n"));
unload_add_on(fAccelerantImage);
fAccelerantImage = -1;
return B_ERROR;
}
accelerant_clone_info_size cloneInfoSize;
cloneInfoSize = (accelerant_clone_info_size)fAccelerantHook(
B_ACCELERANT_CLONE_INFO_SIZE, NULL);
if (!cloneInfoSize) {
STRACE(("unable to get B_ACCELERANT_CLONE_INFO_SIZE (%s)\n", path));
unload_add_on(fAccelerantImage);
fAccelerantImage = -1;
return B_ERROR;
}
ssize_t cloneSize = cloneInfoSize();
void* cloneInfoData = malloc(cloneSize);
sprintf((char*)cloneInfoData, "graphics/%s", fCardNameInDevFS.String());
clone_accelerant cloneAccelerant;
cloneAccelerant = (clone_accelerant)fAccelerantHook(B_CLONE_ACCELERANT, NULL);
if (!cloneAccelerant) {
STRACE(("unable to get B_CLONE_ACCELERANT\n"));
unload_add_on(fAccelerantImage);
fAccelerantImage = -1;
free(cloneInfoData);
return B_ERROR;
}
status_t ret = cloneAccelerant(cloneInfoData);
if (ret != B_OK) {
STRACE(("Cloning accelerant unsuccessful: %s\n", strerror(ret)));
unload_add_on(fAccelerantImage);
fAccelerantImage = -1;
return B_ERROR;
}
break;
}
}
if (fAccelerantImage < B_OK)
return B_ERROR;
if (_SetupDefaultHooks() != B_OK) {
STRACE(("cannot setup default hooks\n"));
uninit_accelerant uninitAccelerant = (uninit_accelerant)
fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
if (uninitAccelerant != NULL)
uninitAccelerant();
unload_add_on(fAccelerantImage);
return B_ERROR;
} else {
_UpdateFrameBufferConfig();
}
return B_OK;
}
status_t
DWindowHWInterface::_SetupDefaultHooks()
{
fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL);
fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL);
fAccSyncToToken = (sync_to_token)fAccelerantHook(B_SYNC_TO_TOKEN, NULL);
fAccGetModeCount = (accelerant_mode_count)fAccelerantHook(
B_ACCELERANT_MODE_COUNT, NULL);
fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL);
fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook(
B_GET_FRAME_BUFFER_CONFIG, NULL);
fAccSetDisplayMode = (set_display_mode)fAccelerantHook(
B_SET_DISPLAY_MODE, NULL);
fAccGetDisplayMode = (get_display_mode)fAccelerantHook(
B_GET_DISPLAY_MODE, NULL);
fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook(
B_GET_PIXEL_CLOCK_LIMITS, NULL);
if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig
|| !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode
|| !fAccGetDisplayMode || !fAccGetPixelClockLimits) {
return B_ERROR;
}
fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook(
B_GET_TIMING_CONSTRAINTS, NULL);
fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook(
B_PROPOSE_DISPLAY_MODE, NULL);
fAccSetCursorShape = (set_cursor_shape)fAccelerantHook(
B_SET_CURSOR_SHAPE, NULL);
fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL);
fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL);
fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, NULL);
fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE, NULL);
fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook(
B_SCREEN_TO_SCREEN_BLIT, NULL);
return B_OK;
}
status_t
DWindowHWInterface::_UpdateFrameBufferConfig()
{
frame_buffer_config config;
if (fAccGetFrameBufferConfig(&config) != B_OK) {
STRACE(("unable to get frame buffer config\n"));
return B_ERROR;
}
fFrontBuffer->SetTo(&config, fXOffset, fYOffset, fDisplayMode.virtual_width,
fDisplayMode.virtual_height, (color_space)fDisplayMode.space);
return B_OK;
}
status_t
DWindowHWInterface::Shutdown()
{
printf("DWindowHWInterface::Shutdown()\n");
if (fAccelerantHook) {
uninit_accelerant UninitAccelerant
= (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
if (UninitAccelerant)
UninitAccelerant();
}
if (fAccelerantImage >= 0)
unload_add_on(fAccelerantImage);
if (fCardFD >= 0)
close(fCardFD);
return B_OK;
}
status_t
DWindowHWInterface::SetMode(const display_mode& mode)
{
AutoWriteLocker _(this);
status_t ret = B_OK;
if (fFrontBuffer.IsSet()
&& fDisplayMode.virtual_width == mode.virtual_width
&& fDisplayMode.virtual_height == mode.virtual_height
&& fDisplayMode.space == mode.space)
return ret;
display_mode *modes;
uint32 modeCount, i;
if (GetModeList(&modes, &modeCount) != B_OK)
return B_NO_MEMORY;
for (i = 0; i < modeCount; i++) {
if (modes[i].virtual_width == mode.virtual_width
&& modes[i].virtual_height == mode.virtual_height
&& modes[i].space == mode.space) {
fDisplayMode = modes[i];
break;
}
}
delete[] modes;
if (i == modeCount)
return B_BAD_VALUE;
BRect frame(0.0, 0.0,
fDisplayMode.virtual_width - 1,
fDisplayMode.virtual_height - 1);
if (!fWindow) {
BApplication* app = new BApplication(
"application/x-vnd.Haiku-test-app_server");
app->Unlock();
thread_id appThread = spawn_thread(run_app_thread, "app thread",
B_NORMAL_PRIORITY, app);
if (appThread >= B_OK)
ret = resume_thread(appThread);
else
ret = appThread;
if (ret < B_OK)
return ret;
fWindow = new DWindow(frame.OffsetByCopy(fXOffset, fYOffset), this,
fFrontBuffer.Get());
fWindow->Hide();
fWindow->Show();
}
if (fWindow->Lock()) {
if (ret >= B_OK) {
fWindow->ResizeTo(frame.Width(), frame.Height());
}
if (fWindow->IsHidden())
fWindow->Show();
fWindow->Unlock();
} else {
ret = B_ERROR;
}
_UpdateFrameBufferConfig();
_NotifyFrameBufferChanged();
return ret;
}
void
DWindowHWInterface::GetMode(display_mode* mode)
{
if (mode && ReadLock()) {
*mode = fDisplayMode;
ReadUnlock();
}
}
status_t
DWindowHWInterface::GetDeviceInfo(accelerant_device_info* info)
{
if (ReadLock()) {
info->version = 100;
sprintf(info->name, "Haiku, Inc. DWindowHWInterface");
sprintf(info->chipset, "Haiku, Inc. Chipset");
sprintf(info->serial_no, "3.14159265358979323846");
info->memory = 134217728;
info->dac_speed = 0xFFFFFFFF;
ReadUnlock();
}
return B_OK;
}
status_t
DWindowHWInterface::GetModeList(display_mode** _modes, uint32* _count)
{
AutoReadLocker _(this);
#if 1
const struct resolution { int32 width, height; } resolutions[] = {
{640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960},
{1280, 1024}, {1400, 1050}, {1600, 1200}
};
uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]);
uint32 count = resolutionCount;
display_mode* modes = new(std::nothrow) display_mode[count];
if (modes == NULL)
return B_NO_MEMORY;
*_modes = modes;
*_count = count;
int32 index = 0;
for (uint32 i = 0; i < resolutionCount; i++) {
modes[index].virtual_width = resolutions[i].width;
modes[index].virtual_height = resolutions[i].height;
modes[index].space = B_RGB32;
modes[index].h_display_start = 0;
modes[index].v_display_start = 0;
modes[index].timing.h_display = resolutions[i].width;
modes[index].timing.v_display = resolutions[i].height;
modes[index].timing.h_total = 22000;
modes[index].timing.v_total = 22000;
modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total
* modes[index].timing.v_total * 60) / 1000;
modes[index].flags = B_PARALLEL_ACCESS;
index++;
}
#else
display_mode *modes = new(std::nothrow) display_mode[1];
modes[0].virtual_width = 800;
modes[0].virtual_height = 600;
modes[0].space = B_BRGB32;
*_modes = modes;
*_count = 1;
#endif
return B_OK;
}
status_t
DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
uint32* high)
{
return B_ERROR;
}
status_t
DWindowHWInterface::GetTimingConstraints(
display_timing_constraints* constraints)
{
return B_ERROR;
}
status_t
DWindowHWInterface::ProposeMode(display_mode* candidate,
const display_mode* low, const display_mode* high)
{
return B_OK;
}
sem_id
DWindowHWInterface::RetraceSemaphore()
{
return -1;
}
status_t
DWindowHWInterface::WaitForRetrace(bigtime_t timeout)
{
BScreen screen;
return screen.WaitForRetrace(timeout);
}
status_t
DWindowHWInterface::SetDPMSMode(uint32 state)
{
AutoWriteLocker _(this);
return BScreen().SetDPMS(state);
}
uint32
DWindowHWInterface::DPMSMode()
{
AutoReadLocker _(this);
return BScreen().DPMSState();
}
uint32
DWindowHWInterface::DPMSCapabilities()
{
AutoReadLocker _(this);
return BScreen().DPMSCapabilites();
}
status_t
DWindowHWInterface::SetBrightness(float brightness)
{
AutoReadLocker _(this);
return BScreen().SetBrightness(brightness);
}
status_t
DWindowHWInterface::GetBrightness(float* brightness)
{
AutoReadLocker _(this);
return BScreen().GetBrightness(brightness);
}
RenderingBuffer*
DWindowHWInterface::FrontBuffer() const
{
return fFrontBuffer.Get();
}
RenderingBuffer*
DWindowHWInterface::BackBuffer() const
{
return fFrontBuffer.Get();
}
bool
DWindowHWInterface::IsDoubleBuffered() const
{
return false;
}
status_t
DWindowHWInterface::Invalidate(const BRect& frame)
{
return HWInterface::Invalidate(frame);
}
void
DWindowHWInterface::SetOffset(int32 left, int32 top)
{
if (!WriteLock())
return;
fXOffset = left;
fYOffset = top;
_UpdateFrameBufferConfig();
WriteUnlock();
}