/* * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. */ #include "ScreenConfigurations.h" #include #include #include #include ScreenConfigurations::ScreenConfigurations() : fConfigurations(10, true) { } ScreenConfigurations::~ScreenConfigurations() { } screen_configuration* ScreenConfigurations::CurrentByID(int32 id) const { for (int32 i = fConfigurations.CountItems(); i-- > 0;) { screen_configuration* configuration = fConfigurations.ItemAt(i); if (configuration->id == id && configuration->is_current) return configuration; } return NULL; } screen_configuration* ScreenConfigurations::BestFit(int32 id, const monitor_info* info, bool* _exactMatch) const { if (info == NULL) { // Only look for a matching ID - this is all we have for (uint32 pass = 0; pass < 2; pass++) { for (int32 i = fConfigurations.CountItems(); i-- > 0;) { screen_configuration* configuration = fConfigurations.ItemAt(i); if ((pass != 0 || !configuration->has_info) && id == configuration->id) return configuration; } } return NULL; } // Look for a configuration that matches the monitor bool exactMatch = false; int32 bestScore = 0; int32 bestIndex = -1; BMessage stored; for (int32 i = fConfigurations.CountItems(); i-- > 0;) { screen_configuration* configuration = fConfigurations.ItemAt(i); if (!configuration->has_info) continue; int32 score = 0; if (!strcasecmp(configuration->info.vendor, info->vendor) && !strcasecmp(configuration->info.name, info->name) && configuration->info.product_id == info->product_id) { score += 2; if (info->serial_number[0] != '\0' && !strcmp(configuration->info.serial_number, info->serial_number)) { exactMatch = true; score += 2; } if (configuration->info.produced.year == info->produced.year && configuration->info.produced.week == info->produced.week) score++; } if (score > bestScore) { bestScore = score; bestIndex = i; } } if (bestIndex < 0) return NULL; if (_exactMatch != NULL) *_exactMatch = exactMatch; return fConfigurations.ItemAt(bestIndex); } status_t ScreenConfigurations::Set(int32 id, const monitor_info* info, const BRect& frame, const display_mode& mode) { // Find configuration that we can overwrite bool exactMatch; screen_configuration* configuration = BestFit(id, info, &exactMatch); if (configuration != NULL && configuration->has_info && !exactMatch) { // only overwrite exact or unspecified configurations configuration->is_current = false; // TODO: provide a more obvious current mechanism... configuration = NULL; } if (configuration == NULL) { // we need a new configuration to store configuration = new (std::nothrow) screen_configuration; if (configuration == NULL) return B_NO_MEMORY; fConfigurations.AddItem(configuration); } configuration->id = id; configuration->frame = frame; configuration->is_current = true; if (info != NULL) { memcpy(&configuration->info, info, sizeof(monitor_info)); configuration->has_info = true; } else configuration->has_info = false; memcpy(&configuration->mode, &mode, sizeof(display_mode)); return B_OK; } void ScreenConfigurations::Remove(screen_configuration* configuration) { if (configuration == NULL) return; fConfigurations.RemoveItem(configuration); // this also deletes the configuration } /*! Stores all configurations as separate BMessages into the provided \a settings container. */ status_t ScreenConfigurations::Store(BMessage& settings) const { // Store the configuration of all current screens for (int32 i = 0; i < fConfigurations.CountItems(); i++) { screen_configuration* configuration = fConfigurations.ItemAt(i); BMessage screenSettings; screenSettings.AddInt32("id", configuration->id); if (configuration->has_info) { screenSettings.AddString("vendor", configuration->info.vendor); screenSettings.AddString("name", configuration->info.name); screenSettings.AddInt32("product id", configuration->info.product_id); screenSettings.AddString("serial", configuration->info.serial_number); screenSettings.AddInt32("produced week", configuration->info.produced.week); screenSettings.AddInt32("produced year", configuration->info.produced.year); } screenSettings.AddRect("frame", configuration->frame); screenSettings.AddData("mode", B_RAW_TYPE, &configuration->mode, sizeof(display_mode)); settings.AddMessage("screen", &screenSettings); } return B_OK; } status_t ScreenConfigurations::Restore(const BMessage& settings) { fConfigurations.MakeEmpty(); BMessage stored; for (int32 i = 0; settings.FindMessage("screen", i, &stored) == B_OK; i++) { const display_mode* mode; ssize_t size; int32 id; if (stored.FindInt32("id", &id) != B_OK || stored.FindData("mode", B_RAW_TYPE, (const void**)&mode, &size) != B_OK || size != sizeof(display_mode)) continue; screen_configuration* configuration = new(std::nothrow) screen_configuration; if (configuration == NULL) return B_NO_MEMORY; configuration->id = id; configuration->is_current = false; const char* vendor; const char* name; uint32 productID; const char* serial; int32 week, year; if (stored.FindString("vendor", &vendor) == B_OK && stored.FindString("name", &name) == B_OK && stored.FindInt32("product id", (int32*)&productID) == B_OK && stored.FindString("serial", &serial) == B_OK && stored.FindInt32("produced week", &week) == B_OK && stored.FindInt32("produced year", &year) == B_OK) { // create monitor info strlcpy(configuration->info.vendor, vendor, sizeof(configuration->info.vendor)); strlcpy(configuration->info.name, name, sizeof(configuration->info.name)); strlcpy(configuration->info.serial_number, serial, sizeof(configuration->info.serial_number)); configuration->info.product_id = productID; configuration->info.produced.week = week; configuration->info.produced.year = year; configuration->has_info = true; } else configuration->has_info = false; stored.FindRect("frame", &configuration->frame); memcpy(&configuration->mode, mode, sizeof(display_mode)); fConfigurations.AddItem(configuration); } return B_OK; }