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
25using 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
36ScreenManager* gScreenManager;
37
38
39class ScreenChangeListener : public HWInterfaceListener {
40public:
41								ScreenChangeListener(ScreenManager& manager,
42									Screen* screen);
43
44private:
45virtual	void					ScreenChanged(HWInterface* interface);
46
47			ScreenManager&		fManager;
48			Screen*				fScreen;
49};
50
51
52ScreenChangeListener::ScreenChangeListener(ScreenManager& manager,
53	Screen* screen)
54	:
55	fManager(manager),
56	fScreen(screen)
57{
58}
59
60
61void
62ScreenChangeListener::ScreenChanged(HWInterface* interface)
63{
64	fManager.ScreenChanged(fScreen);
65}
66
67
68ScreenManager::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
91ScreenManager::~ScreenManager()
92{
93}
94
95
96Screen*
97ScreenManager::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
110int32
111ScreenManager::CountScreens() const
112{
113	if (!IsLocked())
114		debugger("Called ScreenManager::CountScreens() without lock!");
115
116	return fScreenList.CountItems();
117}
118
119
120status_t
121ScreenManager::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
161void
162ScreenManager::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
179void
180ScreenManager::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
192void
193ScreenManager::_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
216ScreenManager::screen_item*
217ScreenManager::_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
252void
253ScreenManager::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