1 /* 2 * Copyright 2005-2013, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "VirtualScreen.h" 11 12 #include "HWInterface.h" 13 #include "Desktop.h" 14 15 #include <new> 16 17 18 VirtualScreen::VirtualScreen() 19 : 20 fScreenList(4, true), 21 fDrawingEngine(NULL), 22 fHWInterface(NULL) 23 { 24 } 25 26 27 VirtualScreen::~VirtualScreen() 28 { 29 _Reset(); 30 } 31 32 33 void 34 VirtualScreen::_Reset() 35 { 36 ScreenList list; 37 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 38 screen_item* item = fScreenList.ItemAt(i); 39 40 list.AddItem(item->screen); 41 } 42 43 gScreenManager->ReleaseScreens(list); 44 fScreenList.MakeEmpty(); 45 46 fFrame.Set(0, 0, 0, 0); 47 fDrawingEngine = NULL; 48 fHWInterface = NULL; 49 } 50 51 52 status_t 53 VirtualScreen::SetConfiguration(Desktop& desktop, 54 ScreenConfigurations& configurations, uint32* _changedScreens) 55 { 56 // Remember previous screen modes 57 58 typedef std::map<Screen*, display_mode> ScreenModeMap; 59 ScreenModeMap previousModes; 60 bool previousModesFailed = false; 61 62 if (_changedScreens != NULL) { 63 *_changedScreens = 0; 64 65 try { 66 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 67 Screen* screen = fScreenList.ItemAt(i)->screen; 68 69 display_mode mode; 70 screen->GetMode(mode); 71 72 previousModes.insert(std::make_pair(screen, mode)); 73 } 74 } catch (...) { 75 previousModesFailed = true; 76 *_changedScreens = ~0L; 77 } 78 } 79 80 _Reset(); 81 82 ScreenList list; 83 status_t status = gScreenManager->AcquireScreens(&desktop, NULL, 0, 84 desktop.TargetScreen(), false, list); 85 if (status != B_OK) { 86 // TODO: we would try again here with force == true 87 return status; 88 } 89 90 for (int32 i = 0; i < list.CountItems(); i++) { 91 Screen* screen = list.ItemAt(i); 92 93 AddScreen(screen, configurations); 94 95 if (!previousModesFailed && _changedScreens != NULL) { 96 // Figure out which screens have changed their mode 97 display_mode mode; 98 screen->GetMode(mode); 99 100 ScreenModeMap::const_iterator found = previousModes.find(screen); 101 if (found != previousModes.end() 102 && memcmp(&mode, &found->second, sizeof(display_mode))) 103 *_changedScreens |= 1 << i; 104 } 105 } 106 107 UpdateFrame(); 108 return B_OK; 109 } 110 111 112 status_t 113 VirtualScreen::AddScreen(Screen* screen, ScreenConfigurations& configurations) 114 { 115 screen_item* item = new(std::nothrow) screen_item; 116 if (item == NULL) 117 return B_NO_MEMORY; 118 119 item->screen = screen; 120 121 status_t status = B_ERROR; 122 display_mode mode; 123 if (_GetMode(screen, configurations, mode) == B_OK) { 124 // we found settings for this screen, and try to apply them now 125 status = screen->SetMode(mode); 126 } 127 128 if (status != B_OK) { 129 // We found no configuration or it wasn't valid, try to fallback to 130 // sane values 131 status = screen->SetPreferredMode(); 132 if (status == B_OK) { 133 monitor_info info; 134 bool hasInfo = screen->GetMonitorInfo(info) == B_OK; 135 screen->GetMode(mode); 136 configurations.Set(screen->ID(), hasInfo ? &info : NULL, screen->Frame(), mode); 137 } 138 if (status != B_OK) 139 status = screen->SetBestMode(1024, 768, B_RGB32, 60.f); 140 if (status != B_OK) 141 status = screen->SetBestMode(800, 600, B_RGB32, 60.f, false); 142 if (status != B_OK) { 143 debug_printf("app_server: Failed to set mode: %s\n", 144 strerror(status)); 145 146 delete item; 147 return status; 148 } 149 } 150 151 // TODO: this works only for single screen configurations 152 fDrawingEngine = screen->GetDrawingEngine(); 153 fHWInterface = screen->HWInterface(); 154 fFrame = screen->Frame(); 155 item->frame = fFrame; 156 157 fScreenList.AddItem(item); 158 159 return B_OK; 160 } 161 162 163 status_t 164 VirtualScreen::RemoveScreen(Screen* screen) 165 { 166 // not implemented yet (config changes when running) 167 return B_ERROR; 168 } 169 170 171 void 172 VirtualScreen::UpdateFrame() 173 { 174 int32 virtualWidth = 0, virtualHeight = 0; 175 176 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 177 Screen* screen = fScreenList.ItemAt(i)->screen; 178 179 uint16 width, height; 180 uint32 colorSpace; 181 float frequency; 182 screen->GetMode(width, height, colorSpace, frequency); 183 184 // TODO: compute virtual size depending on the actual screen position! 185 virtualWidth += width; 186 virtualHeight = max_c(virtualHeight, height); 187 } 188 189 fFrame.Set(0, 0, virtualWidth - 1, virtualHeight - 1); 190 } 191 192 193 /*! Returns the smallest frame that spans over all screens 194 */ 195 BRect 196 VirtualScreen::Frame() const 197 { 198 return fFrame; 199 } 200 201 202 Screen* 203 VirtualScreen::ScreenAt(int32 index) const 204 { 205 screen_item* item = fScreenList.ItemAt(index); 206 if (item != NULL) 207 return item->screen; 208 209 return NULL; 210 } 211 212 213 Screen* 214 VirtualScreen::ScreenByID(int32 id) const 215 { 216 for (int32 i = fScreenList.CountItems(); i-- > 0;) { 217 screen_item* item = fScreenList.ItemAt(i); 218 219 if (item->screen->ID() == id || id == B_MAIN_SCREEN_ID.id) 220 return item->screen; 221 } 222 223 return NULL; 224 } 225 226 227 BRect 228 VirtualScreen::ScreenFrameAt(int32 index) const 229 { 230 screen_item* item = fScreenList.ItemAt(index); 231 if (item != NULL) 232 return item->frame; 233 234 return BRect(0, 0, 0, 0); 235 } 236 237 238 int32 239 VirtualScreen::CountScreens() const 240 { 241 return fScreenList.CountItems(); 242 } 243 244 245 status_t 246 VirtualScreen::_GetMode(Screen* screen, ScreenConfigurations& configurations, 247 display_mode& mode) const 248 { 249 monitor_info info; 250 bool hasInfo = screen->GetMonitorInfo(info) == B_OK; 251 252 screen_configuration* configuration = configurations.BestFit(screen->ID(), 253 hasInfo ? &info : NULL); 254 if (configuration == NULL) 255 return B_NAME_NOT_FOUND; 256 257 mode = configuration->mode; 258 configuration->is_current = true; 259 260 return B_OK; 261 } 262 263