xref: /haiku/src/servers/app/ScreenManager.cpp (revision ae0a10cad3999b13cbfa47a3d947a5219d2d90f4)
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 	_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 }
86 
87 
88 Screen*
89 ScreenManager::ScreenAt(int32 index) const
90 {
91 	if (!IsLocked())
92 		debugger("Called ScreenManager::ScreenAt() without lock!");
93 
94 	screen_item* item = fScreenList.ItemAt(index);
95 	if (item != NULL)
96 		return item->screen.Get();
97 
98 	return NULL;
99 }
100 
101 
102 int32
103 ScreenManager::CountScreens() const
104 {
105 	if (!IsLocked())
106 		debugger("Called ScreenManager::CountScreens() without lock!");
107 
108 	return fScreenList.CountItems();
109 }
110 
111 
112 status_t
113 ScreenManager::AcquireScreens(ScreenOwner* owner, int32* wishList,
114 	int32 wishCount, const char* target, bool force, ScreenList& list)
115 {
116 	BAutolock locker(this);
117 	int32 added = 0;
118 
119 	// TODO: don't ignore the wish list
120 
121 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
122 		screen_item* item = fScreenList.ItemAt(i);
123 
124 		if (item->owner == NULL && list.AddItem(item->screen.Get())) {
125 			item->owner = owner;
126 			added++;
127 		}
128 	}
129 
130 	if (added == 0 && target != NULL) {
131 		// there's a specific target screen we want to initialize
132 		// TODO: right now we only support remote screens, but we could
133 		// also target specific accelerants to support other graphics cards
134 		HWInterface* interface;
135 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
136 		interface = new(nothrow) ViewHWInterface();
137 #else
138 		interface = new(nothrow) RemoteHWInterface(target);
139 #endif
140 		if (interface != NULL) {
141 			screen_item* item = _AddHWInterface(interface);
142 			if (item != NULL && list.AddItem(item->screen.Get())) {
143 				item->owner = owner;
144 				added++;
145 			}
146 		}
147 	}
148 
149 	return added > 0 ? B_OK : B_ENTRY_NOT_FOUND;
150 }
151 
152 
153 void
154 ScreenManager::ReleaseScreens(ScreenList& list)
155 {
156 	BAutolock locker(this);
157 
158 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
159 		screen_item* item = fScreenList.ItemAt(i);
160 
161 		for (int32 j = 0; j < list.CountItems(); j++) {
162 			Screen* screen = list.ItemAt(j);
163 
164 			if (item->screen.Get() == screen)
165 				item->owner = NULL;
166 		}
167 	}
168 }
169 
170 
171 void
172 ScreenManager::ScreenChanged(Screen* screen)
173 {
174 	BAutolock locker(this);
175 
176 	for (int32 i = 0; i < fScreenList.CountItems(); i++) {
177 		screen_item* item = fScreenList.ItemAt(i);
178 		if (item->screen.Get() == screen)
179 			item->owner->ScreenChanged(screen);
180 	}
181 }
182 
183 
184 void
185 ScreenManager::_ScanDrivers()
186 {
187 	HWInterface* interface = NULL;
188 
189 	// Eventually we will loop through drivers until
190 	// one can't initialize in order to support multiple monitors.
191 	// For now, we'll just load one and be done with it.
192 
193 	// ToDo: to make monitoring the driver directory useful, we need more
194 	//	power and data here, and should do the scanning on our own
195 
196 	bool initDrivers = true;
197 	while (initDrivers) {
198 
199 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
200 		  interface = new AccelerantHWInterface();
201 #elif defined(USE_DIRECT_WINDOW_TEST_MODE)
202 		  interface = new DWindowHWInterface();
203 #else
204 		  interface = new ViewHWInterface();
205 #endif
206 
207 		_AddHWInterface(interface);
208 		initDrivers = false;
209 	}
210 }
211 
212 
213 ScreenManager::screen_item*
214 ScreenManager::_AddHWInterface(HWInterface* interface)
215 {
216 	ObjectDeleter<Screen> screen(
217 		new(nothrow) Screen(interface, fScreenList.CountItems()));
218 	if (!screen.IsSet()) {
219 		delete interface;
220 		return NULL;
221 	}
222 
223 	// The interface is now owned by the screen
224 
225 	if (screen->Initialize() >= B_OK) {
226 		screen_item* item = new(nothrow) screen_item;
227 
228 		if (item != NULL) {
229 			item->screen.SetTo(screen.Detach());
230 			item->owner = NULL;
231 			item->listener.SetTo(
232 				new(nothrow) ScreenChangeListener(*this, item->screen.Get()));
233 			if (item->listener.IsSet()
234 				&& interface->AddListener(item->listener.Get())) {
235 				if (fScreenList.AddItem(item))
236 					return item;
237 
238 				interface->RemoveListener(item->listener.Get());
239 			}
240 
241 			delete item;
242 		}
243 	}
244 
245 	return NULL;
246 }
247 
248 
249 void
250 ScreenManager::MessageReceived(BMessage* message)
251 {
252 	switch (message->what) {
253 		case B_NODE_MONITOR:
254 			// TODO: handle notification
255 			break;
256 
257 		default:
258 			BHandler::MessageReceived(message);
259 	}
260 }
261