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
12#include <Message.h>
13
14
15ScreenConfigurations::ScreenConfigurations()
16	:
17	fConfigurations(10, true)
18{
19}
20
21
22ScreenConfigurations::~ScreenConfigurations()
23{
24}
25
26
27screen_configuration*
28ScreenConfigurations::CurrentByID(int32 id) const
29{
30	for (int32 i = fConfigurations.CountItems(); i-- > 0;) {
31		screen_configuration* configuration = fConfigurations.ItemAt(i);
32
33		if (configuration->id == id && configuration->is_current)
34			return configuration;
35	}
36
37	return NULL;
38}
39
40
41screen_configuration*
42ScreenConfigurations::BestFit(int32 id, const monitor_info* info,
43	bool* _exactMatch) const
44{
45	if (info == NULL) {
46		// Only look for a matching ID - this is all we have
47		for (uint32 pass = 0; pass < 2; pass++) {
48			for (int32 i = fConfigurations.CountItems(); i-- > 0;) {
49				screen_configuration* configuration = fConfigurations.ItemAt(i);
50
51				if ((pass != 0 || !configuration->has_info)
52					&& id == configuration->id)
53					return configuration;
54			}
55		}
56
57		return NULL;
58	}
59
60	// Look for a configuration that matches the monitor
61
62	bool exactMatch = false;
63	int32 bestScore = 0;
64	int32 bestIndex = -1;
65	BMessage stored;
66
67	for (int32 i = fConfigurations.CountItems(); i-- > 0;) {
68		screen_configuration* configuration = fConfigurations.ItemAt(i);
69		if (!configuration->has_info)
70			continue;
71
72		int32 score = 0;
73
74		if (!strcasecmp(configuration->info.vendor, info->vendor)
75			&& !strcasecmp(configuration->info.name, info->name)
76			&& configuration->info.product_id == info->product_id) {
77			score += 2;
78			if (info->serial_number[0] != '\0'
79				&& !strcmp(configuration->info.serial_number,
80						info->serial_number)) {
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::Remove(screen_configuration* configuration)
148{
149	if (configuration == NULL)
150		return;
151
152	fConfigurations.RemoveItem(configuration);
153		// this also deletes the configuration
154}
155
156
157/*!	Stores all configurations as separate BMessages into the provided
158	\a settings container.
159*/
160status_t
161ScreenConfigurations::Store(BMessage& settings) const
162{
163	// Store the configuration of all current screens
164
165	for (int32 i = 0; i < fConfigurations.CountItems(); i++) {
166		screen_configuration* configuration = fConfigurations.ItemAt(i);
167
168		BMessage screenSettings;
169		screenSettings.AddInt32("id", configuration->id);
170
171		if (configuration->has_info) {
172			screenSettings.AddString("vendor", configuration->info.vendor);
173			screenSettings.AddString("name", configuration->info.name);
174			screenSettings.AddInt32("product id",
175				configuration->info.product_id);
176			screenSettings.AddString("serial",
177				configuration->info.serial_number);
178			screenSettings.AddInt32("produced week",
179				configuration->info.produced.week);
180			screenSettings.AddInt32("produced year",
181				configuration->info.produced.year);
182		}
183
184		screenSettings.AddRect("frame", configuration->frame);
185		screenSettings.AddData("mode", B_RAW_TYPE, &configuration->mode,
186			sizeof(display_mode));
187
188		settings.AddMessage("screen", &screenSettings);
189	}
190
191	return B_OK;
192}
193
194
195status_t
196ScreenConfigurations::Restore(const BMessage& settings)
197{
198	fConfigurations.MakeEmpty();
199
200	BMessage stored;
201	for (int32 i = 0; settings.FindMessage("screen", i, &stored) == B_OK; i++) {
202		const display_mode* mode;
203		ssize_t size;
204		int32 id;
205		if (stored.FindInt32("id", &id) != B_OK
206			|| stored.FindData("mode", B_RAW_TYPE, (const void**)&mode,
207					&size) != B_OK
208			|| size != sizeof(display_mode))
209			continue;
210
211		screen_configuration* configuration
212			= new(std::nothrow) screen_configuration;
213		if (configuration == NULL)
214			return B_NO_MEMORY;
215
216		configuration->id = id;
217		configuration->is_current = false;
218
219		const char* vendor;
220		const char* name;
221		uint32 productID;
222		const char* serial;
223		int32 week, year;
224		if (stored.FindString("vendor", &vendor) == B_OK
225			&& stored.FindString("name", &name) == B_OK
226			&& stored.FindInt32("product id", (int32*)&productID) == B_OK
227			&& stored.FindString("serial", &serial) == B_OK
228			&& stored.FindInt32("produced week", &week) == B_OK
229			&& stored.FindInt32("produced year", &year) == B_OK) {
230			// create monitor info
231			strlcpy(configuration->info.vendor, vendor,
232				sizeof(configuration->info.vendor));
233			strlcpy(configuration->info.name, name, sizeof(configuration->info.name));
234			strlcpy(configuration->info.serial_number, serial,
235				sizeof(configuration->info.serial_number));
236			configuration->info.product_id = productID;
237			configuration->info.produced.week = week;
238			configuration->info.produced.year = year;
239			configuration->has_info = true;
240		} else
241			configuration->has_info = false;
242
243		stored.FindRect("frame", &configuration->frame);
244		memcpy(&configuration->mode, mode, sizeof(display_mode));
245
246		fConfigurations.AddItem(configuration);
247	}
248
249	return B_OK;
250}
251