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