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