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