257 lines
5.0 KiB
C++
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;
|
|
}
|
|
|