1/*
2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
4 */
5
6
7#include "ScreenConfigurations.h"
8
9#include <new>
10#include <string.h>
11#include <strings.h>
12
13#include <Message.h>
14
15
16ScreenConfigurations::ScreenConfigurations()
17	:
18	fConfigurations(10, true)
19{
20}
21
22
23ScreenConfigurations::~ScreenConfigurations()
24{
25}
26
27
28screen_configuration*
29ScreenConfigurations::CurrentByID(int32 id) const
30{
31	for (int32 i = fConfigurations.CountItems(); i-- > 0;) {
32		screen_configuration* configuration = fConfigurations.ItemAt(i);
33
34		if (configuration->id == id && configuration->is_current)
35			return configuration;
36	}
37
38	return NULL;
39}
40
41
42screen_configuration*
43ScreenConfigurations::BestFit(int32 id, const monitor_info* info,
44	bool* _exactMatch) const
45{
46	if (info == NULL) {
47		// Only look for a matching ID - this is all we have
48		for (uint32 pass = 0; pass < 2; pass++) {
49			for (int32 i = fConfigurations.CountItems(); i-- > 0;) {
50				screen_configuration* configuration = fConfigurations.ItemAt(i);
51
52				if ((pass != 0 || !configuration->has_info)
53					&& id == configuration->id)
54					return configuration;
55			}
56		}
57
58		return NULL;
59	}
60
61	// Look for a configuration that matches the monitor
62
63	bool exactMatch = false;
64	int32 bestScore = 0;
65	int32 bestIndex = -1;
66	BMessage stored;
67
68	for (int32 i = fConfigurations.CountItems(); i-- > 0;) {
69		screen_configuration* configuration = fConfigurations.ItemAt(i);
70		if (!configuration->has_info)
71			continue;
72
73		int32 score = 0;
74
75		if (!strcasecmp(configuration->info.vendor, info->vendor)
76			&& !strcasecmp(configuration->info.name, info->name)
77			&& configuration->info.product_id == info->product_id) {
78			score += 2;
79			if (info->serial_number[0] != '\0'
80				&& !strcmp(configuration->info.serial_number,
81						info->serial_number)) {
82				exactMatch = true;
83				score += 2;
84			}
85			if (configuration->info.produced.year == info->produced.year
86				&& configuration->info.produced.week == info->produced.week)
87				score++;
88		}
89
90		if (score > bestScore) {
91			bestScore = score;
92			bestIndex = i;
93		}
94	}
95
96	if (bestIndex < 0)
97		return NULL;
98
99	if (_exactMatch != NULL)
100		*_exactMatch = exactMatch;
101
102	return fConfigurations.ItemAt(bestIndex);
103}
104
105
106status_t
107ScreenConfigurations::Set(int32 id, const monitor_info* info,
108	const BRect& frame, const display_mode& mode)
109{
110	// Find configuration that we can overwrite
111
112	bool exactMatch;
113	screen_configuration* configuration = BestFit(id, info, &exactMatch);
114
115	if (configuration != NULL && configuration->has_info && !exactMatch) {
116		// only overwrite exact or unspecified configurations
117		configuration->is_current = false;
118			// TODO: provide a more obvious current mechanism...
119		configuration = NULL;
120	}
121
122	if (configuration == NULL) {
123		// we need a new configuration to store
124		configuration = new (std::nothrow) screen_configuration;
125		if (configuration == NULL)
126			return B_NO_MEMORY;
127
128		fConfigurations.AddItem(configuration);
129	}
130
131	configuration->id = id;
132	configuration->frame = frame;
133	configuration->is_current = true;
134
135	if (info != NULL) {
136		memcpy(&configuration->info, info, sizeof(monitor_info));
137		configuration->has_info = true;
138	} else
139		configuration->has_info = false;
140
141	memcpy(&configuration->mode, &mode, sizeof(display_mode));
142
143	return B_OK;
144}
145
146
147void
148ScreenConfigurations::Remove(screen_configuration* configuration)
149{
150	if (configuration == NULL)
151		return;
152
153	fConfigurations.RemoveItem(configuration);
154		// this also deletes the configuration
155}
156
157
158/*!	Stores all configurations as separate BMessages into the provided
159	\a settings container.
160*/
161status_t
162ScreenConfigurations::Store(BMessage& settings) const
163{
164	// Store the configuration of all current screens
165
166	for (int32 i = 0; i < fConfigurations.CountItems(); i++) {
167		screen_configuration* configuration = fConfigurations.ItemAt(i);
168
169		BMessage screenSettings;
170		screenSettings.AddInt32("id", configuration->id);
171
172		if (configuration->has_info) {
173			screenSettings.AddString("vendor", configuration->info.vendor);
174			screenSettings.AddString("name", configuration->info.name);
175			screenSettings.AddInt32("product id",
176				configuration->info.product_id);
177			screenSettings.AddString("serial",
178				configuration->info.serial_number);
179			screenSettings.AddInt32("produced week",
180				configuration->info.produced.week);
181			screenSettings.AddInt32("produced year",
182				configuration->info.produced.year);
183		}
184
185		screenSettings.AddRect("frame", configuration->frame);
186		screenSettings.AddData("mode", B_RAW_TYPE, &configuration->mode,
187			sizeof(display_mode));
188
189		settings.AddMessage("screen", &screenSettings);
190	}
191
192	return B_OK;
193}
194
195
196status_t
197ScreenConfigurations::Restore(const BMessage& settings)
198{
199	fConfigurations.MakeEmpty();
200
201	BMessage stored;
202	for (int32 i = 0; settings.FindMessage("screen", i, &stored) == B_OK; i++) {
203		const display_mode* mode;
204		ssize_t size;
205		int32 id;
206		if (stored.FindInt32("id", &id) != B_OK
207			|| stored.FindData("mode", B_RAW_TYPE, (const void**)&mode,
208					&size) != B_OK
209			|| size != sizeof(display_mode))
210			continue;
211
212		screen_configuration* configuration
213			= new(std::nothrow) screen_configuration;
214		if (configuration == NULL)
215			return B_NO_MEMORY;
216
217		configuration->id = id;
218		configuration->is_current = false;
219
220		const char* vendor;
221		const char* name;
222		uint32 productID;
223		const char* serial;
224		int32 week, year;
225		if (stored.FindString("vendor", &vendor) == B_OK
226			&& stored.FindString("name", &name) == B_OK
227			&& stored.FindInt32("product id", (int32*)&productID) == B_OK
228			&& stored.FindString("serial", &serial) == B_OK
229			&& stored.FindInt32("produced week", &week) == B_OK
230			&& stored.FindInt32("produced year", &year) == B_OK) {
231			// create monitor info
232			strlcpy(configuration->info.vendor, vendor,
233				sizeof(configuration->info.vendor));
234			strlcpy(configuration->info.name, name, sizeof(configuration->info.name));
235			strlcpy(configuration->info.serial_number, serial,
236				sizeof(configuration->info.serial_number));
237			configuration->info.product_id = productID;
238			configuration->info.produced.week = week;
239			configuration->info.produced.year = year;
240			configuration->has_info = true;
241		} else
242			configuration->has_info = false;
243
244		stored.FindRect("frame", &configuration->frame);
245		memcpy(&configuration->mode, mode, sizeof(display_mode));
246
247		fConfigurations.AddItem(configuration);
248	}
249
250	return B_OK;
251}
252