1 /* 2 * Copyright 2005-2007, 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 using std::nothrow; 18 19 20 VirtualScreen::VirtualScreen() 21 : 22 fScreenList(4, true), 23 fDrawingEngine(NULL), 24 fHWInterface(NULL) 25 { 26 } 27 28 29 VirtualScreen::~VirtualScreen() 30 { 31 _Reset(); 32 } 33 34 35 void 36 VirtualScreen::_Reset() 37 { 38 ScreenList list; 39 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 40 screen_item* item = fScreenList.ItemAt(i); 41 42 list.AddItem(item->screen); 43 } 44 45 gScreenManager->ReleaseScreens(list); 46 fScreenList.MakeEmpty(); 47 fSettings.MakeEmpty(); 48 49 fFrame.Set(0, 0, 0, 0); 50 fDrawingEngine = NULL; 51 fHWInterface = NULL; 52 } 53 54 55 status_t 56 VirtualScreen::RestoreConfiguration(Desktop& desktop, const BMessage* settings) 57 { 58 _Reset(); 59 60 // Copy current Desktop workspace settings 61 if (settings) 62 fSettings = *settings; 63 64 ScreenList list; 65 status_t status = gScreenManager->AcquireScreens(&desktop, NULL, 0, false, 66 list); 67 if (status < B_OK) { 68 // TODO: we would try again here with force == true 69 return status; 70 } 71 72 for (int32 i = 0; i < list.CountItems(); i++) { 73 Screen* screen = list.ItemAt(i); 74 75 AddScreen(screen); 76 } 77 78 return B_OK; 79 } 80 81 82 status_t 83 VirtualScreen::StoreConfiguration(BMessage& settings) 84 { 85 // store the configuration of all current screens 86 87 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 88 screen_item* item = fScreenList.ItemAt(i); 89 Screen* screen = item->screen; 90 if (!screen->IsDefaultMode()) 91 continue; 92 93 BMessage screenSettings; 94 screenSettings.AddInt32("id", screen->ID()); 95 96 monitor_info info; 97 if (screen->GetMonitorInfo(info) == B_OK) { 98 screenSettings.AddString("vendor", info.vendor); 99 screenSettings.AddString("name", info.name); 100 screenSettings.AddInt32("product id", info.product_id); 101 screenSettings.AddString("serial", info.serial_number); 102 screenSettings.AddInt32("produced week", info.produced.week); 103 screenSettings.AddInt32("produced year", info.produced.year); 104 } 105 106 screenSettings.AddRect("frame", item->frame); 107 108 display_mode mode; 109 screen->GetMode(&mode); 110 111 screenSettings.AddInt32("width", mode.virtual_width); 112 screenSettings.AddInt32("height", mode.virtual_height); 113 screenSettings.AddInt32("color space", mode.space); 114 screenSettings.AddData("timing", B_RAW_TYPE, &mode.timing, 115 sizeof(display_timing)); 116 117 settings.AddMessage("screen", &screenSettings); 118 } 119 120 // store the configuration of all monitors currently not attached 121 122 BMessage screenSettings; 123 for (uint32 i = 0; fSettings.FindMessage("screen", i, 124 &screenSettings) == B_OK; i++) { 125 settings.AddMessage("screen", &screenSettings); 126 } 127 128 return B_OK; 129 } 130 131 132 status_t 133 VirtualScreen::AddScreen(Screen* screen) 134 { 135 screen_item* item = new(nothrow) screen_item; 136 if (item == NULL) 137 return B_NO_MEMORY; 138 139 item->screen = screen; 140 141 status_t status = B_ERROR; 142 BMessage settings; 143 if (_GetConfiguration(screen, settings) == B_OK) { 144 // we found settings for this screen, and try to apply them now 145 int32 width, height, colorSpace; 146 const display_timing* timing; 147 ssize_t size; 148 if (settings.FindInt32("width", &width) == B_OK 149 && settings.FindInt32("height", &height) == B_OK 150 && settings.FindInt32("color space", &colorSpace) == B_OK 151 && settings.FindData("timing", B_RAW_TYPE, (const void**)&timing, 152 &size) == B_OK 153 && size == sizeof(display_timing)) 154 status = screen->SetMode(width, height, colorSpace, *timing, true); 155 // TODO: named settings will get lost if setting the mode failed! 156 } 157 if (status < B_OK) { 158 // TODO: more intelligent standard mode (monitor preference, desktop default, ...) 159 status_t status = screen->SetPreferredMode(); 160 if (status != B_OK) 161 status = screen->SetBestMode(1024, 768, B_RGB32, 60.f); 162 if (status != B_OK) 163 screen->SetBestMode(800, 600, B_RGB32, 60.f); 164 } 165 166 // TODO: this works only for single screen configurations 167 fDrawingEngine = screen->GetDrawingEngine(); 168 fHWInterface = screen->HWInterface(); 169 fFrame = screen->Frame(); 170 171 fScreenList.AddItem(item); 172 173 return B_OK; 174 } 175 176 177 status_t 178 VirtualScreen::RemoveScreen(Screen* screen) 179 { 180 // not implemented yet (config changes when running) 181 return B_ERROR; 182 } 183 184 185 void 186 VirtualScreen::UpdateFrame() 187 { 188 int32 virtualWidth = 0, virtualHeight = 0; 189 190 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 191 Screen* screen = fScreenList.ItemAt(i)->screen; 192 193 uint16 width, height; 194 uint32 colorSpace; 195 float frequency; 196 screen->GetMode(width, height, colorSpace, frequency); 197 198 // TODO: compute virtual size depending on the actual screen position! 199 virtualWidth += width; 200 virtualHeight += height; 201 } 202 203 fFrame.Set(0, 0, virtualWidth - 1, virtualHeight - 1); 204 } 205 206 207 /*! 208 Returns the smallest frame that spans over all screens 209 */ 210 BRect 211 VirtualScreen::Frame() const 212 { 213 return fFrame; 214 } 215 216 217 Screen* 218 VirtualScreen::ScreenAt(int32 index) const 219 { 220 screen_item* item = fScreenList.ItemAt(index); 221 if (item != NULL) 222 return item->screen; 223 224 return NULL; 225 } 226 227 228 BRect 229 VirtualScreen::ScreenFrameAt(int32 index) const 230 { 231 screen_item* item = fScreenList.ItemAt(index); 232 if (item != NULL) 233 return item->frame; 234 235 return BRect(0, 0, 0, 0); 236 } 237 238 239 int32 240 VirtualScreen::CountScreens() const 241 { 242 return fScreenList.CountItems(); 243 } 244 245 246 status_t 247 VirtualScreen::_GetConfiguration(Screen* screen, BMessage& settings) 248 { 249 monitor_info info; 250 bool hasInfo = screen->GetMonitorInfo(info) == B_OK; 251 if (!hasInfo) { 252 // only look for a matching ID - this is all we have 253 for (uint32 k = 0; k < 2; k++) { 254 for (uint32 i = 0; fSettings.FindMessage("screen", i, 255 &settings) == B_OK; i++) { 256 int32 id; 257 if (k == 0 && settings.HasString("name") 258 || settings.FindInt32("id", &id) != B_OK 259 || screen->ID() != id) 260 continue; 261 262 // we found our match, only remove unnamed settings 263 if (k == 0) 264 fSettings.RemoveData("screen", i); 265 return B_OK; 266 } 267 } 268 return B_NAME_NOT_FOUND; 269 } 270 271 // look for a monitor configuration that matches ours 272 273 bool exactMatch = false; 274 int32 bestScore = 0; 275 int32 bestIndex = -1; 276 BMessage stored; 277 for (uint32 i = 0; fSettings.FindMessage("screen", i, &stored) == B_OK; 278 i++) { 279 // TODO: should we ignore unnamed settings here completely? 280 int32 score = 0; 281 int32 id; 282 if (stored.FindInt32("id", &id) == B_OK && screen->ID() == id) 283 score++; 284 285 const char* vendor; 286 const char* name; 287 uint32 productID; 288 const char* serial; 289 int32 week, year; 290 if (stored.FindString("vendor", &vendor) == B_OK 291 && stored.FindString("name", &name) == B_OK 292 && stored.FindInt32("product id", (int32*)&productID) == B_OK 293 && stored.FindString("serial", &serial) == B_OK 294 && stored.FindInt32("produced week", &week) == B_OK 295 && stored.FindInt32("produced year", &year) == B_OK) { 296 if (!strcasecmp(vendor, info.vendor) 297 && !strcasecmp(name, info.name) 298 && productID == info.product_id) { 299 score += 2; 300 if (!strcmp(serial, info.serial_number)) { 301 exactMatch = true; 302 score += 2; 303 } 304 if (info.produced.year == year && info.produced.week == week) 305 score++; 306 } else 307 score -= 2; 308 } 309 310 if (score > bestScore) { 311 settings = stored; 312 bestScore = score; 313 bestIndex = i; 314 } 315 } 316 317 if (bestIndex >= 0) { 318 if (exactMatch) 319 fSettings.RemoveData("screen", bestIndex); 320 return B_OK; 321 } 322 323 return B_NAME_NOT_FOUND; 324 } 325 326