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, false); 164 } 165 166 // TODO: this works only for single screen configurations 167 fDrawingEngine = screen->GetDrawingEngine(); 168 fHWInterface = screen->HWInterface(); 169 fFrame = screen->Frame(); 170 item->frame = fFrame; 171 172 fScreenList.AddItem(item); 173 174 return B_OK; 175 } 176 177 178 status_t 179 VirtualScreen::RemoveScreen(Screen* screen) 180 { 181 // not implemented yet (config changes when running) 182 return B_ERROR; 183 } 184 185 186 void 187 VirtualScreen::UpdateFrame() 188 { 189 int32 virtualWidth = 0, virtualHeight = 0; 190 191 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 192 Screen* screen = fScreenList.ItemAt(i)->screen; 193 194 uint16 width, height; 195 uint32 colorSpace; 196 float frequency; 197 screen->GetMode(width, height, colorSpace, frequency); 198 199 // TODO: compute virtual size depending on the actual screen position! 200 virtualWidth += width; 201 virtualHeight += height; 202 } 203 204 fFrame.Set(0, 0, virtualWidth - 1, virtualHeight - 1); 205 } 206 207 208 /*! 209 Returns the smallest frame that spans over all screens 210 */ 211 BRect 212 VirtualScreen::Frame() const 213 { 214 return fFrame; 215 } 216 217 218 Screen* 219 VirtualScreen::ScreenAt(int32 index) const 220 { 221 screen_item* item = fScreenList.ItemAt(index); 222 if (item != NULL) 223 return item->screen; 224 225 return NULL; 226 } 227 228 229 BRect 230 VirtualScreen::ScreenFrameAt(int32 index) const 231 { 232 screen_item* item = fScreenList.ItemAt(index); 233 if (item != NULL) 234 return item->frame; 235 236 return BRect(0, 0, 0, 0); 237 } 238 239 240 int32 241 VirtualScreen::CountScreens() const 242 { 243 return fScreenList.CountItems(); 244 } 245 246 247 status_t 248 VirtualScreen::_GetConfiguration(Screen* screen, BMessage& settings) 249 { 250 monitor_info info; 251 bool hasInfo = screen->GetMonitorInfo(info) == B_OK; 252 if (!hasInfo) { 253 // only look for a matching ID - this is all we have 254 for (uint32 k = 0; k < 2; k++) { 255 for (uint32 i = 0; fSettings.FindMessage("screen", i, 256 &settings) == B_OK; i++) { 257 int32 id; 258 if (k == 0 && settings.HasString("name") 259 || settings.FindInt32("id", &id) != B_OK 260 || screen->ID() != id) 261 continue; 262 263 // we found our match, only remove unnamed settings 264 if (k == 0) 265 fSettings.RemoveData("screen", i); 266 return B_OK; 267 } 268 } 269 return B_NAME_NOT_FOUND; 270 } 271 272 // look for a monitor configuration that matches ours 273 274 bool exactMatch = false; 275 int32 bestScore = 0; 276 int32 bestIndex = -1; 277 BMessage stored; 278 for (uint32 i = 0; fSettings.FindMessage("screen", i, &stored) == B_OK; 279 i++) { 280 // TODO: should we ignore unnamed settings here completely? 281 int32 score = 0; 282 int32 id; 283 if (stored.FindInt32("id", &id) == B_OK && screen->ID() == id) 284 score++; 285 286 const char* vendor; 287 const char* name; 288 uint32 productID; 289 const char* serial; 290 int32 week, year; 291 if (stored.FindString("vendor", &vendor) == B_OK 292 && stored.FindString("name", &name) == B_OK 293 && stored.FindInt32("product id", (int32*)&productID) == B_OK 294 && stored.FindString("serial", &serial) == B_OK 295 && stored.FindInt32("produced week", &week) == B_OK 296 && stored.FindInt32("produced year", &year) == B_OK) { 297 if (!strcasecmp(vendor, info.vendor) 298 && !strcasecmp(name, info.name) 299 && productID == info.product_id) { 300 score += 2; 301 if (!strcmp(serial, info.serial_number)) { 302 exactMatch = true; 303 score += 2; 304 } 305 if (info.produced.year == year && info.produced.week == week) 306 score++; 307 } else 308 score -= 2; 309 } 310 311 if (score > bestScore) { 312 settings = stored; 313 bestScore = score; 314 bestIndex = i; 315 } 316 } 317 318 if (bestIndex >= 0) { 319 if (exactMatch) 320 fSettings.RemoveData("screen", bestIndex); 321 return B_OK; 322 } 323 324 return B_NAME_NOT_FOUND; 325 } 326 327