xref: /haiku/src/servers/app/ScreenManager.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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, true)
72 {
73 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
74 #	if defined(USE_DIRECT_WINDOW_TEST_MODE)
75 	_AddHWInterface(new DWindowHWInterface());
76 #	else
77 	_AddHWInterface(new ViewHWInterface());
78 #	endif
79 #else
80 	_ScanDrivers();
81 
82 	// turn on node monitoring the graphics driver directory
83 	BEntry entry("/dev/graphics");
84 	node_ref nodeRef;
85 	if (entry.InitCheck() == B_OK && entry.GetNodeRef(&nodeRef) == B_OK)
86 		watch_node(&nodeRef, B_WATCH_DIRECTORY, this);
87 #endif
88 }
89 
90 
91 ScreenManager::~ScreenManager()
92 {
93 }
94 
95 
96 Screen*
97 ScreenManager::ScreenAt(int32 index) const
98 {
99 	if (!IsLocked())
100 		debugger("Called ScreenManager::ScreenAt() without lock!");
101 
102 	screen_item* item = fScreenList.ItemAt(index);
103 	if (item != NULL)
104 		return item->screen.Get();
105 
106 	return NULL;
107 }
108 
109 
110 int32
111 ScreenManager::CountScreens() const
112 {
113 	if (!IsLocked())
114 		debugger("Called ScreenManager::CountScreens() without lock!");
115 
116 	return fScreenList.CountItems();
117 }
118 
119 
120 status_t
121 ScreenManager::AcquireScreens(ScreenOwner* owner, int32* wishList,
122 	int32 wishCount, const char* target, bool force, ScreenList& list)
123 {
124 	BAutolock locker(this);
125 	int32 added = 0;
126 
127 	// TODO: don't ignore the wish list
128 
129 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
130 		screen_item* item = fScreenList.ItemAt(i);
131 
132 		if (item->owner == NULL && list.AddItem(item->screen.Get())) {
133 			item->owner = owner;
134 			added++;
135 		}
136 	}
137 
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 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
144 		interface = new(nothrow) ViewHWInterface();
145 #else
146 		interface = new(nothrow) RemoteHWInterface(target);
147 #endif
148 		if (interface != NULL) {
149 			screen_item* item = _AddHWInterface(interface);
150 			if (item != NULL && list.AddItem(item->screen.Get())) {
151 				item->owner = owner;
152 				added++;
153 			}
154 		}
155 	}
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.Get() == 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.Get() == 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 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
205 	bool initDrivers = true;
206 	while (initDrivers) {
207 		interface = new AccelerantHWInterface();
208 
209 		_AddHWInterface(interface);
210 		initDrivers = false;
211 	}
212 #endif
213 }
214 
215 
216 ScreenManager::screen_item*
217 ScreenManager::_AddHWInterface(HWInterface* interface)
218 {
219 	ObjectDeleter<Screen> screen(
220 		new(nothrow) Screen(interface, fScreenList.CountItems()));
221 	if (!screen.IsSet()) {
222 		delete interface;
223 		return NULL;
224 	}
225 
226 	// The interface is now owned by the screen
227 
228 	if (screen->Initialize() >= B_OK) {
229 		screen_item* item = new(nothrow) screen_item;
230 
231 		if (item != NULL) {
232 			item->screen.SetTo(screen.Detach());
233 			item->owner = NULL;
234 			item->listener.SetTo(
235 				new(nothrow) ScreenChangeListener(*this, item->screen.Get()));
236 			if (item->listener.IsSet()
237 				&& interface->AddListener(item->listener.Get())) {
238 				if (fScreenList.AddItem(item))
239 					return item;
240 
241 				interface->RemoveListener(item->listener.Get());
242 			}
243 
244 			delete item;
245 		}
246 	}
247 
248 	return NULL;
249 }
250 
251 
252 void
253 ScreenManager::MessageReceived(BMessage* message)
254 {
255 	switch (message->what) {
256 		case B_NODE_MONITOR:
257 			// TODO: handle notification
258 			break;
259 
260 		default:
261 			BHandler::MessageReceived(message);
262 	}
263 }
264