xref: /haiku/src/servers/app/ScreenManager.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 (added == 0 && target != NULL) {
138 		// there's a specific target screen we want to initialize
139 		// TODO: right now we only support remote screens, but we could
140 		// also target specific accelerants to support other graphics cards
141 		HWInterface* interface;
142 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
143 		interface = new(nothrow) ViewHWInterface();
144 #else
145 		interface = new(nothrow) RemoteHWInterface(target);
146 #endif
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 
156 	return added > 0 ? B_OK : B_ENTRY_NOT_FOUND;
157 }
158 
159 
160 void
161 ScreenManager::ReleaseScreens(ScreenList& list)
162 {
163 	BAutolock locker(this);
164 
165 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
166 		screen_item* item = fScreenList.ItemAt(i);
167 
168 		for (int32 j = 0; j < list.CountItems(); j++) {
169 			Screen* screen = list.ItemAt(j);
170 
171 			if (item->screen == screen)
172 				item->owner = NULL;
173 		}
174 	}
175 }
176 
177 
178 void
179 ScreenManager::ScreenChanged(Screen* screen)
180 {
181 	BAutolock locker(this);
182 
183 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
184 		screen_item* item = fScreenList.ItemAt(i);
185 		if (item->screen == screen)
186 			item->owner->ScreenChanged(screen);
187 	}
188 }
189 
190 
191 void
192 ScreenManager::_ScanDrivers()
193 {
194 	HWInterface* interface = NULL;
195 
196 	// Eventually we will loop through drivers until
197 	// one can't initialize in order to support multiple monitors.
198 	// For now, we'll just load one and be done with it.
199 
200 	// ToDo: to make monitoring the driver directory useful, we need more
201 	//	power and data here, and should do the scanning on our own
202 
203 	bool initDrivers = true;
204 	while (initDrivers) {
205 
206 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
207 		  interface = new AccelerantHWInterface();
208 #elif defined(USE_DIRECT_WINDOW_TEST_MODE)
209 		  interface = new DWindowHWInterface();
210 #else
211 		  interface = new ViewHWInterface();
212 #endif
213 
214 		_AddHWInterface(interface);
215 		initDrivers = false;
216 	}
217 }
218 
219 
220 ScreenManager::screen_item*
221 ScreenManager::_AddHWInterface(HWInterface* interface)
222 {
223 	Screen* screen = new(nothrow) Screen(interface, fScreenList.CountItems());
224 	if (screen == NULL) {
225 		delete interface;
226 		return NULL;
227 	}
228 
229 	// The interface is now owned by the screen
230 
231 	if (screen->Initialize() >= B_OK) {
232 		screen_item* item = new(nothrow) screen_item;
233 
234 		if (item != NULL) {
235 			item->screen = screen;
236 			item->owner = NULL;
237 			item->listener = new(nothrow) ScreenChangeListener(*this, screen);
238 			if (item->listener != NULL
239 				&& interface->AddListener(item->listener)) {
240 				if (fScreenList.AddItem(item))
241 					return item;
242 
243 				interface->RemoveListener(item->listener);
244 			}
245 
246 			delete item->listener;
247 			delete item;
248 		}
249 	}
250 
251 	delete screen;
252 	return NULL;
253 }
254 
255 
256 void
257 ScreenManager::MessageReceived(BMessage* message)
258 {
259 	switch (message->what) {
260 		case B_NODE_MONITOR:
261 			// TODO: handle notification
262 			break;
263 
264 		default:
265 			BHandler::MessageReceived(message);
266 	}
267 }
268 
269