haiku/src/servers/app/VirtualScreen.cpp

257 lines
5.0 KiB
C++

/*
* Copyright 2005-2013, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#include "VirtualScreen.h"
#include "HWInterface.h"
#include "Desktop.h"
#include <new>
VirtualScreen::VirtualScreen()
:
fScreenList(4, true),
fDrawingEngine(NULL),
fHWInterface(NULL)
{
}
VirtualScreen::~VirtualScreen()
{
_Reset();
}
void
VirtualScreen::_Reset()
{
ScreenList list;
for (int32 i = 0; i < fScreenList.CountItems(); i++) {
screen_item* item = fScreenList.ItemAt(i);
list.AddItem(item->screen);
}
gScreenManager->ReleaseScreens(list);
fScreenList.MakeEmpty();
fFrame.Set(0, 0, 0, 0);
fDrawingEngine = NULL;
fHWInterface = NULL;
}
status_t
VirtualScreen::SetConfiguration(Desktop& desktop,
ScreenConfigurations& configurations, uint32* _changedScreens)
{
// Remember previous screen modes
typedef std::map<Screen*, display_mode> ScreenModeMap;
ScreenModeMap previousModes;
bool previousModesFailed = false;
if (_changedScreens != NULL) {
*_changedScreens = 0;
try {
for (int32 i = 0; i < fScreenList.CountItems(); i++) {
Screen* screen = fScreenList.ItemAt(i)->screen;
display_mode mode;
screen->GetMode(mode);
previousModes.insert(std::make_pair(screen, mode));
}
} catch (...) {
previousModesFailed = true;
*_changedScreens = ~0L;
}
}
_Reset();
ScreenList list;
status_t status = gScreenManager->AcquireScreens(&desktop, NULL, 0,
desktop.TargetScreen(), false, list);
if (status != B_OK) {
// TODO: we would try again here with force == true
return status;
}
for (int32 i = 0; i < list.CountItems(); i++) {
Screen* screen = list.ItemAt(i);
AddScreen(screen, configurations);
if (!previousModesFailed && _changedScreens != NULL) {
// Figure out which screens have changed their mode
display_mode mode;
screen->GetMode(mode);
ScreenModeMap::const_iterator found = previousModes.find(screen);
if (found != previousModes.end()
&& memcmp(&mode, &found->second, sizeof(display_mode)))
*_changedScreens |= 1 << i;
}
}
UpdateFrame();
return B_OK;
}
status_t
VirtualScreen::AddScreen(Screen* screen, ScreenConfigurations& configurations)
{
screen_item* item = new(std::nothrow) screen_item;
if (item == NULL)
return B_NO_MEMORY;
item->screen = screen;
status_t status = B_ERROR;
display_mode mode;
if (_GetMode(screen, configurations, mode) == B_OK) {
// we found settings for this screen, and try to apply them now
status = screen->SetMode(mode);
}
if (status != B_OK) {
// We found no configuration or it wasn't valid, try to fallback to
// sane values
status = screen->SetPreferredMode();
if (status != B_OK)
status = screen->SetBestMode(1024, 768, B_RGB32, 60.f);
if (status != B_OK)
status = screen->SetBestMode(800, 600, B_RGB32, 60.f, false);
if (status != B_OK) {
debug_printf("app_server: Failed to set mode: %s\n",
strerror(status));
delete item;
return status;
}
}
// TODO: this works only for single screen configurations
fDrawingEngine = screen->GetDrawingEngine();
fHWInterface = screen->HWInterface();
fFrame = screen->Frame();
item->frame = fFrame;
fScreenList.AddItem(item);
return B_OK;
}
status_t
VirtualScreen::RemoveScreen(Screen* screen)
{
// not implemented yet (config changes when running)
return B_ERROR;
}
void
VirtualScreen::UpdateFrame()
{
int32 virtualWidth = 0, virtualHeight = 0;
for (int32 i = 0; i < fScreenList.CountItems(); i++) {
Screen* screen = fScreenList.ItemAt(i)->screen;
uint16 width, height;
uint32 colorSpace;
float frequency;
screen->GetMode(width, height, colorSpace, frequency);
// TODO: compute virtual size depending on the actual screen position!
virtualWidth += width;
virtualHeight = max_c(virtualHeight, height);
}
fFrame.Set(0, 0, virtualWidth - 1, virtualHeight - 1);
}
/*! Returns the smallest frame that spans over all screens
*/
BRect
VirtualScreen::Frame() const
{
return fFrame;
}
Screen*
VirtualScreen::ScreenAt(int32 index) const
{
screen_item* item = fScreenList.ItemAt(index);
if (item != NULL)
return item->screen;
return NULL;
}
Screen*
VirtualScreen::ScreenByID(int32 id) const
{
for (int32 i = fScreenList.CountItems(); i-- > 0;) {
screen_item* item = fScreenList.ItemAt(i);
if (item->screen->ID() == id || id == B_MAIN_SCREEN_ID.id)
return item->screen;
}
return NULL;
}
BRect
VirtualScreen::ScreenFrameAt(int32 index) const
{
screen_item* item = fScreenList.ItemAt(index);
if (item != NULL)
return item->frame;
return BRect(0, 0, 0, 0);
}
int32
VirtualScreen::CountScreens() const
{
return fScreenList.CountItems();
}
status_t
VirtualScreen::_GetMode(Screen* screen, ScreenConfigurations& configurations,
display_mode& mode) const
{
monitor_info info;
bool hasInfo = screen->GetMonitorInfo(info) == B_OK;
screen_configuration* configuration = configurations.BestFit(screen->ID(),
hasInfo ? &info : NULL);
if (configuration == NULL)
return B_NAME_NOT_FOUND;
mode = configuration->mode;
configuration->is_current = true;
return B_OK;
}