xref: /haiku/src/servers/app/VirtualScreen.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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 			status = screen->SetBestMode(1024, 768, B_RGB32, 60.f);
134 		if (status != B_OK)
135 			status = screen->SetBestMode(800, 600, B_RGB32, 60.f, false);
136 		if (status != B_OK) {
137 			debug_printf("app_server: Failed to set mode: %s\n",
138 				strerror(status));
139 
140 			delete item;
141 			return status;
142 		}
143 	}
144 
145 	// TODO: this works only for single screen configurations
146 	fDrawingEngine = screen->GetDrawingEngine();
147 	fHWInterface = screen->HWInterface();
148 	fFrame = screen->Frame();
149 	item->frame = fFrame;
150 
151 	fScreenList.AddItem(item);
152 
153 	return B_OK;
154 }
155 
156 
157 status_t
158 VirtualScreen::RemoveScreen(Screen* screen)
159 {
160 	// not implemented yet (config changes when running)
161 	return B_ERROR;
162 }
163 
164 
165 void
166 VirtualScreen::UpdateFrame()
167 {
168 	int32 virtualWidth = 0, virtualHeight = 0;
169 
170 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
171 		Screen* screen = fScreenList.ItemAt(i)->screen;
172 
173 		uint16 width, height;
174 		uint32 colorSpace;
175 		float frequency;
176 		screen->GetMode(width, height, colorSpace, frequency);
177 
178 		// TODO: compute virtual size depending on the actual screen position!
179 		virtualWidth += width;
180 		virtualHeight = max_c(virtualHeight, height);
181 	}
182 
183 	fFrame.Set(0, 0, virtualWidth - 1, virtualHeight - 1);
184 }
185 
186 
187 /*!	Returns the smallest frame that spans over all screens
188 */
189 BRect
190 VirtualScreen::Frame() const
191 {
192 	return fFrame;
193 }
194 
195 
196 Screen*
197 VirtualScreen::ScreenAt(int32 index) const
198 {
199 	screen_item* item = fScreenList.ItemAt(index);
200 	if (item != NULL)
201 		return item->screen;
202 
203 	return NULL;
204 }
205 
206 
207 Screen*
208 VirtualScreen::ScreenByID(int32 id) const
209 {
210 	for (int32 i = fScreenList.CountItems(); i-- > 0;) {
211 		screen_item* item = fScreenList.ItemAt(i);
212 
213 		if (item->screen->ID() == id || id == B_MAIN_SCREEN_ID.id)
214 			return item->screen;
215 	}
216 
217 	return NULL;
218 }
219 
220 
221 BRect
222 VirtualScreen::ScreenFrameAt(int32 index) const
223 {
224 	screen_item* item = fScreenList.ItemAt(index);
225 	if (item != NULL)
226 		return item->frame;
227 
228 	return BRect(0, 0, 0, 0);
229 }
230 
231 
232 int32
233 VirtualScreen::CountScreens() const
234 {
235 	return fScreenList.CountItems();
236 }
237 
238 
239 status_t
240 VirtualScreen::_GetMode(Screen* screen, ScreenConfigurations& configurations,
241 	display_mode& mode) const
242 {
243 	monitor_info info;
244 	bool hasInfo = screen->GetMonitorInfo(info) == B_OK;
245 
246 	screen_configuration* configuration = configurations.BestFit(screen->ID(),
247 		hasInfo ? &info : NULL);
248 	if (configuration == NULL)
249 		return B_NAME_NOT_FOUND;
250 
251 	mode = configuration->mode;
252 	configuration->is_current = true;
253 
254 	return B_OK;
255 }
256 
257