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