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 (strcmp(configuration->info.serial_number,
80					info->serial_number) == 0) {
81				exactMatch = true;
82				score += 2;
83			}
84			if (configuration->info.produced.year == info->produced.year
85				&& configuration->info.produced.week == info->produced.week)
86				score++;
87		}
88
89		if (score > bestScore) {
90			bestScore = score;
91			bestIndex = i;
92		}
93	}
94
95	if (bestIndex < 0)
96		return NULL;
97
98	if (_exactMatch != NULL)
99		*_exactMatch = exactMatch;
100
101	return fConfigurations.ItemAt(bestIndex);
102}
103
104
105status_t
106ScreenConfigurations::Set(int32 id, const monitor_info* info,
107	const BRect& frame, const display_mode& mode)
108{
109	// Find configuration that we can overwrite
110
111	bool exactMatch;
112	screen_configuration* configuration = BestFit(id, info, &exactMatch);
113
114	if (configuration != NULL && configuration->has_info && !exactMatch) {
115		// only overwrite exact or unspecified configurations
116		configuration->is_current = false;
117			// TODO: provide a more obvious current mechanism...
118		configuration = NULL;
119	}
120
121	if (configuration == NULL) {
122		// we need a new configuration to store
123		configuration = new (std::nothrow) screen_configuration;
124		if (configuration == NULL)
125			return B_NO_MEMORY;
126
127		fConfigurations.AddItem(configuration);
128	}
129
130	configuration->id = id;
131	configuration->frame = frame;
132	configuration->is_current = true;
133
134	if (info != NULL) {
135		memcpy(&configuration->info, info, sizeof(monitor_info));
136		configuration->has_info = true;
137	} else
138		configuration->has_info = false;
139
140	memcpy(&configuration->mode, &mode, sizeof(display_mode));
141
142	return B_OK;
143}
144
145
146void
147ScreenConfigurations::SetBrightness(int32 id, float brightness)
148{
149	for (int32 i = fConfigurations.CountItems(); i-- > 0;) {
150		screen_configuration* configuration = fConfigurations.ItemAt(i);
151		configuration->brightness = brightness;
152	}
153}
154
155
156float
157ScreenConfigurations::Brightness(int32 id)
158{
159	screen_configuration* configuration = fConfigurations.ItemAt(0);
160
161	if (configuration == NULL)
162		return -1;
163
164	return configuration->brightness;
165}
166
167
168void
169ScreenConfigurations::Remove(screen_configuration* configuration)
170{
171	if (configuration == NULL)
172		return;
173
174	fConfigurations.RemoveItem(configuration);
175		// this also deletes the configuration
176}
177
178
179/*!	Stores all configurations as separate BMessages into the provided
180	\a settings container.
181*/
182status_t
183ScreenConfigurations::Store(BMessage& settings) const
184{
185	// Store the configuration of all current screens
186
187	for (int32 i = 0; i < fConfigurations.CountItems(); i++) {
188		screen_configuration* configuration = fConfigurations.ItemAt(i);
189
190		BMessage screenSettings;
191		screenSettings.AddInt32("id", configuration->id);
192
193		if (configuration->has_info) {
194			screenSettings.AddString("vendor", configuration->info.vendor);
195			screenSettings.AddString("name", configuration->info.name);
196			screenSettings.AddInt32("product id",
197				configuration->info.product_id);
198			screenSettings.AddString("serial",
199				configuration->info.serial_number);
200			screenSettings.AddInt32("produced week",
201				configuration->info.produced.week);
202			screenSettings.AddInt32("produced year",
203				configuration->info.produced.year);
204		}
205
206		screenSettings.AddRect("frame", configuration->frame);
207		screenSettings.AddData("mode", B_RAW_TYPE, &configuration->mode,
208			sizeof(display_mode));
209		screenSettings.AddFloat("brightness", configuration->brightness);
210
211		settings.AddMessage("screen", &screenSettings);
212	}
213
214	return B_OK;
215}
216
217
218status_t
219ScreenConfigurations::Restore(const BMessage& settings)
220{
221	fConfigurations.MakeEmpty();
222
223	BMessage stored;
224	for (int32 i = 0; settings.FindMessage("screen", i, &stored) == B_OK; i++) {
225		const display_mode* mode;
226		ssize_t size;
227		int32 id;
228		if (stored.FindInt32("id", &id) != B_OK
229			|| stored.FindData("mode", B_RAW_TYPE, (const void**)&mode,
230					&size) != B_OK
231			|| size != sizeof(display_mode))
232			continue;
233
234		screen_configuration* configuration
235			= new(std::nothrow) screen_configuration;
236		if (configuration == NULL)
237			return B_NO_MEMORY;
238
239		configuration->id = id;
240		configuration->is_current = false;
241
242		const char* vendor;
243		const char* name;
244		uint32 productID;
245		const char* serial;
246		int32 week, year;
247		if (stored.FindString("vendor", &vendor) == B_OK
248			&& stored.FindString("name", &name) == B_OK
249			&& stored.FindInt32("product id", (int32*)&productID) == B_OK
250			&& stored.FindString("serial", &serial) == B_OK
251			&& stored.FindInt32("produced week", &week) == B_OK
252			&& stored.FindInt32("produced year", &year) == B_OK) {
253			// create monitor info
254			strlcpy(configuration->info.vendor, vendor,
255				sizeof(configuration->info.vendor));
256			strlcpy(configuration->info.name, name,
257				sizeof(configuration->info.name));
258			strlcpy(configuration->info.serial_number, serial,
259				sizeof(configuration->info.serial_number));
260			configuration->info.product_id = productID;
261			configuration->info.produced.week = week;
262			configuration->info.produced.year = year;
263			configuration->has_info = true;
264		} else
265			configuration->has_info = false;
266
267		stored.FindRect("frame", &configuration->frame);
268		memcpy(&configuration->mode, mode, sizeof(display_mode));
269
270		if (stored.FindFloat("brightness", &configuration->brightness) != B_OK)
271			configuration->brightness = 1.0f;
272
273		fConfigurations.AddItem(configuration);
274	}
275
276	return B_OK;
277}
278