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