xref: /haiku/src/servers/app/ScreenManager.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 /**	Manages all available physical screens */
10 
11 
12 #include "ScreenManager.h"
13 
14 #include "Screen.h"
15 #include "ServerConfig.h"
16 
17 #include "RemoteHWInterface.h"
18 
19 #include <Autolock.h>
20 #include <Entry.h>
21 #include <NodeMonitor.h>
22 
23 #include <new>
24 
25 using std::nothrow;
26 
27 
28 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
29 #	include "AccelerantHWInterface.h"
30 #else
31 #	include "ViewHWInterface.h"
32 #	include "DWindowHWInterface.h"
33 #endif
34 
35 
36 ScreenManager* gScreenManager;
37 
38 
39 class ScreenChangeListener : public HWInterfaceListener {
40 public:
41 								ScreenChangeListener(ScreenManager& manager,
42 									Screen* screen);
43 
44 private:
45 virtual	void					ScreenChanged(HWInterface* interface);
46 
47 			ScreenManager&		fManager;
48 			Screen*				fScreen;
49 };
50 
51 
52 ScreenChangeListener::ScreenChangeListener(ScreenManager& manager,
53 	Screen* screen)
54 	:
55 	fManager(manager),
56 	fScreen(screen)
57 {
58 }
59 
60 
61 void
62 ScreenChangeListener::ScreenChanged(HWInterface* interface)
63 {
64 	fManager.ScreenChanged(fScreen);
65 }
66 
67 
68 ScreenManager::ScreenManager()
69 	:
70 	BLooper("screen manager"),
71 	fScreenList(4)
72 {
73 	_ScanDrivers();
74 
75 	// turn on node monitoring the graphics driver directory
76 	BEntry entry("/dev/graphics");
77 	node_ref nodeRef;
78 	if (entry.InitCheck() == B_OK && entry.GetNodeRef(&nodeRef) == B_OK)
79 		watch_node(&nodeRef, B_WATCH_DIRECTORY, this);
80 }
81 
82 
83 ScreenManager::~ScreenManager()
84 {
85 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
86 		screen_item* item = fScreenList.ItemAt(i);
87 
88 		delete item->screen;
89 		delete item->listener;
90 		delete item;
91 	}
92 }
93 
94 
95 Screen*
96 ScreenManager::ScreenAt(int32 index) const
97 {
98 	if (!IsLocked())
99 		debugger("Called ScreenManager::ScreenAt() without lock!");
100 
101 	screen_item* item = fScreenList.ItemAt(index);
102 	if (item != NULL)
103 		return item->screen;
104 
105 	return NULL;
106 }
107 
108 
109 int32
110 ScreenManager::CountScreens() const
111 {
112 	if (!IsLocked())
113 		debugger("Called ScreenManager::CountScreens() without lock!");
114 
115 	return fScreenList.CountItems();
116 }
117 
118 
119 status_t
120 ScreenManager::AcquireScreens(ScreenOwner* owner, int32* wishList,
121 	int32 wishCount, const char* target, bool force, ScreenList& list)
122 {
123 	BAutolock locker(this);
124 	int32 added = 0;
125 
126 	// TODO: don't ignore the wish list
127 
128 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
129 		screen_item* item = fScreenList.ItemAt(i);
130 
131 		if (item->owner == NULL && list.AddItem(item->screen)) {
132 			item->owner = owner;
133 			added++;
134 		}
135 	}
136 
137 #if TEST_MODE == 0
138 	if (added == 0 && target != NULL) {
139 		// there's a specific target screen we want to initialize
140 		// TODO: right now we only support remote screens, but we could
141 		// also target specific accelerants to support other graphics cards
142 		HWInterface* interface;
143 		/*if (strncmp(target, "vnc:", 4) == 0)
144 			interface = new(nothrow) VNCHWInterface(target);
145 		else*/
146 			interface = new(nothrow) RemoteHWInterface(target);
147 		if (interface != NULL) {
148 			screen_item* item = _AddHWInterface(interface);
149 			if (item != NULL && list.AddItem(item->screen)) {
150 				item->owner = owner;
151 				added++;
152 			}
153 		}
154 	}
155 #endif // TEST_MODE == 0
156 
157 	return added > 0 ? B_OK : B_ENTRY_NOT_FOUND;
158 }
159 
160 
161 void
162 ScreenManager::ReleaseScreens(ScreenList& list)
163 {
164 	BAutolock locker(this);
165 
166 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
167 		screen_item* item = fScreenList.ItemAt(i);
168 
169 		for (int32 j = 0; j < list.CountItems(); j++) {
170 			Screen* screen = list.ItemAt(j);
171 
172 			if (item->screen == screen)
173 				item->owner = NULL;
174 		}
175 	}
176 }
177 
178 
179 void
180 ScreenManager::ScreenChanged(Screen* screen)
181 {
182 	BAutolock locker(this);
183 
184 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
185 		screen_item* item = fScreenList.ItemAt(i);
186 		if (item->screen == screen)
187 			item->owner->ScreenChanged(screen);
188 	}
189 }
190 
191 
192 void
193 ScreenManager::_ScanDrivers()
194 {
195 	HWInterface* interface = NULL;
196 
197 	// Eventually we will loop through drivers until
198 	// one can't initialize in order to support multiple monitors.
199 	// For now, we'll just load one and be done with it.
200 
201 	// ToDo: to make monitoring the driver directory useful, we need more
202 	//	power and data here, and should do the scanning on our own
203 
204 	bool initDrivers = true;
205 	while (initDrivers) {
206 
207 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
208 		  interface = new AccelerantHWInterface();
209 #elif defined(USE_DIRECT_WINDOW_TEST_MODE)
210 		  interface = new DWindowHWInterface();
211 #else
212 		  interface = new ViewHWInterface();
213 #endif
214 
215 		_AddHWInterface(interface);
216 		initDrivers = false;
217 	}
218 }
219 
220 
221 ScreenManager::screen_item*
222 ScreenManager::_AddHWInterface(HWInterface* interface)
223 {
224 	Screen* screen = new(nothrow) Screen(interface, fScreenList.CountItems());
225 	if (screen == NULL) {
226 		delete interface;
227 		return NULL;
228 	}
229 
230 	// The interface is now owned by the screen
231 
232 	if (screen->Initialize() >= B_OK) {
233 		screen_item* item = new(nothrow) screen_item;
234 
235 		if (item != NULL) {
236 			item->screen = screen;
237 			item->owner = NULL;
238 			item->listener = new(nothrow) ScreenChangeListener(*this, screen);
239 			if (item->listener != NULL
240 				&& interface->AddListener(item->listener)) {
241 				if (fScreenList.AddItem(item))
242 					return item;
243 
244 				interface->RemoveListener(item->listener);
245 			}
246 
247 			delete item->listener;
248 			delete item;
249 		}
250 	}
251 
252 	delete screen;
253 	return NULL;
254 }
255 
256 
257 void
258 ScreenManager::MessageReceived(BMessage* message)
259 {
260 	switch (message->what) {
261 		case B_NODE_MONITOR:
262 			// TODO: handle notification
263 			break;
264 
265 		default:
266 			BHandler::MessageReceived(message);
267 	}
268 }
269 
270