xref: /haiku/src/servers/app/VirtualScreen.cpp (revision 7b3e89c0944ae1efa9a8fc66c7303874b7a344b2)
1 /*
2  * Copyright 2005-2013, 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 
18 VirtualScreen::VirtualScreen()
19 	:
20 	fScreenList(4, true),
21 	fDrawingEngine(NULL),
22 	fHWInterface(NULL)
23 {
24 }
25 
26 
27 VirtualScreen::~VirtualScreen()
28 {
29 	_Reset();
30 }
31 
32 
33 void
34 VirtualScreen::_Reset()
35 {
36 	ScreenList list;
37 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
38 		screen_item* item = fScreenList.ItemAt(i);
39 
40 		list.AddItem(item->screen);
41 	}
42 
43 	gScreenManager->ReleaseScreens(list);
44 	fScreenList.MakeEmpty();
45 
46 	fFrame.Set(0, 0, 0, 0);
47 	fDrawingEngine = NULL;
48 	fHWInterface = NULL;
49 }
50 
51 
52 status_t
53 VirtualScreen::SetConfiguration(Desktop& desktop,
54 	ScreenConfigurations& configurations, uint32* _changedScreens)
55 {
56 	// Remember previous screen modes
57 
58 	typedef std::map<Screen*, display_mode> ScreenModeMap;
59 	ScreenModeMap previousModes;
60 	bool previousModesFailed = false;
61 
62 	if (_changedScreens != NULL) {
63 		*_changedScreens = 0;
64 
65 		try {
66 			for (int32 i = 0; i < fScreenList.CountItems(); i++) {
67 				Screen* screen = fScreenList.ItemAt(i)->screen;
68 
69 				display_mode mode;
70 				screen->GetMode(mode);
71 
72 				previousModes.insert(std::make_pair(screen, mode));
73 			}
74 		} catch (...) {
75 			previousModesFailed = true;
76 			*_changedScreens = ~0L;
77 		}
78 	}
79 
80 	_Reset();
81 
82 	ScreenList list;
83 	status_t status = gScreenManager->AcquireScreens(&desktop, NULL, 0,
84 		desktop.TargetScreen(), false, list);
85 	if (status != B_OK) {
86 		// TODO: we would try again here with force == true
87 		return status;
88 	}
89 
90 	for (int32 i = 0; i < list.CountItems(); i++) {
91 		Screen* screen = list.ItemAt(i);
92 
93 		AddScreen(screen, configurations);
94 
95 		if (!previousModesFailed && _changedScreens != NULL) {
96 			// Figure out which screens have changed their mode
97 			display_mode mode;
98 			screen->GetMode(mode);
99 
100 			ScreenModeMap::const_iterator found = previousModes.find(screen);
101 			if (found != previousModes.end()
102 				&& memcmp(&mode, &found->second, sizeof(display_mode)))
103 				*_changedScreens |= 1 << i;
104 		}
105 	}
106 
107 	UpdateFrame();
108 	return B_OK;
109 }
110 
111 
112 status_t
113 VirtualScreen::AddScreen(Screen* screen, ScreenConfigurations& configurations)
114 {
115 	screen_item* item = new(std::nothrow) screen_item;
116 	if (item == NULL)
117 		return B_NO_MEMORY;
118 
119 	item->screen = screen;
120 
121 	status_t status = B_ERROR;
122 	display_mode mode;
123 	if (_GetMode(screen, configurations, mode) == B_OK) {
124 		// we found settings for this screen, and try to apply them now
125 		status = screen->SetMode(mode);
126 	}
127 
128 	if (status != B_OK) {
129 		// We found no configuration or it wasn't valid, try to fallback to
130 		// sane values
131 		status = screen->SetPreferredMode();
132 		if (status == B_OK) {
133 			monitor_info info;
134 			bool hasInfo = screen->GetMonitorInfo(info) == B_OK;
135 			screen->GetMode(mode);
136 			configurations.Set(screen->ID(), hasInfo ? &info : NULL, screen->Frame(), mode);
137 		}
138 		if (status != B_OK)
139 			status = screen->SetBestMode(1024, 768, B_RGB32, 60.f);
140 		if (status != B_OK)
141 			status = screen->SetBestMode(800, 600, B_RGB32, 60.f, false);
142 		if (status != B_OK) {
143 			debug_printf("app_server: Failed to set mode: %s\n",
144 				strerror(status));
145 
146 			delete item;
147 			return status;
148 		}
149 	}
150 
151 	// TODO: this works only for single screen configurations
152 	fDrawingEngine = screen->GetDrawingEngine();
153 	fHWInterface = screen->HWInterface();
154 	fFrame = screen->Frame();
155 	item->frame = fFrame;
156 
157 	fScreenList.AddItem(item);
158 
159 	return B_OK;
160 }
161 
162 
163 status_t
164 VirtualScreen::RemoveScreen(Screen* screen)
165 {
166 	// not implemented yet (config changes when running)
167 	return B_ERROR;
168 }
169 
170 
171 void
172 VirtualScreen::UpdateFrame()
173 {
174 	int32 virtualWidth = 0, virtualHeight = 0;
175 
176 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
177 		Screen* screen = fScreenList.ItemAt(i)->screen;
178 
179 		uint16 width, height;
180 		uint32 colorSpace;
181 		float frequency;
182 		screen->GetMode(width, height, colorSpace, frequency);
183 
184 		// TODO: compute virtual size depending on the actual screen position!
185 		virtualWidth += width;
186 		virtualHeight = max_c(virtualHeight, height);
187 	}
188 
189 	fFrame.Set(0, 0, virtualWidth - 1, virtualHeight - 1);
190 }
191 
192 
193 /*!	Returns the smallest frame that spans over all screens
194 */
195 BRect
196 VirtualScreen::Frame() const
197 {
198 	return fFrame;
199 }
200 
201 
202 Screen*
203 VirtualScreen::ScreenAt(int32 index) const
204 {
205 	screen_item* item = fScreenList.ItemAt(index);
206 	if (item != NULL)
207 		return item->screen;
208 
209 	return NULL;
210 }
211 
212 
213 Screen*
214 VirtualScreen::ScreenByID(int32 id) const
215 {
216 	for (int32 i = fScreenList.CountItems(); i-- > 0;) {
217 		screen_item* item = fScreenList.ItemAt(i);
218 
219 		if (item->screen->ID() == id || id == B_MAIN_SCREEN_ID.id)
220 			return item->screen;
221 	}
222 
223 	return NULL;
224 }
225 
226 
227 BRect
228 VirtualScreen::ScreenFrameAt(int32 index) const
229 {
230 	screen_item* item = fScreenList.ItemAt(index);
231 	if (item != NULL)
232 		return item->frame;
233 
234 	return BRect(0, 0, 0, 0);
235 }
236 
237 
238 int32
239 VirtualScreen::CountScreens() const
240 {
241 	return fScreenList.CountItems();
242 }
243 
244 
245 status_t
246 VirtualScreen::_GetMode(Screen* screen, ScreenConfigurations& configurations,
247 	display_mode& mode) const
248 {
249 	monitor_info info;
250 	bool hasInfo = screen->GetMonitorInfo(info) == B_OK;
251 
252 	screen_configuration* configuration = configurations.BestFit(screen->ID(),
253 		hasInfo ? &info : NULL);
254 	if (configuration == NULL)
255 		return B_NAME_NOT_FOUND;
256 
257 	mode = configuration->mode;
258 	configuration->is_current = true;
259 
260 	return B_OK;
261 }
262 
263