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
VirtualScreen()18 VirtualScreen::VirtualScreen()
19 :
20 fScreenList(4, true),
21 fDrawingEngine(NULL),
22 fHWInterface(NULL)
23 {
24 }
25
26
~VirtualScreen()27 VirtualScreen::~VirtualScreen()
28 {
29 _Reset();
30 }
31
32
33 void
_Reset()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
SetConfiguration(Desktop & desktop,ScreenConfigurations & configurations,uint32 * _changedScreens)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
AddScreen(Screen * screen,ScreenConfigurations & configurations)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
RemoveScreen(Screen * screen)164 VirtualScreen::RemoveScreen(Screen* screen)
165 {
166 // not implemented yet (config changes when running)
167 return B_ERROR;
168 }
169
170
171 void
UpdateFrame()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
Frame() const196 VirtualScreen::Frame() const
197 {
198 return fFrame;
199 }
200
201
202 Screen*
ScreenAt(int32 index) const203 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*
ScreenByID(int32 id) const214 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
ScreenFrameAt(int32 index) const228 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
CountScreens() const239 VirtualScreen::CountScreens() const
240 {
241 return fScreenList.CountItems();
242 }
243
244
245 status_t
_GetMode(Screen * screen,ScreenConfigurations & configurations,display_mode & mode) const246 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