1/*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions, and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions, and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32// ParameterWindowManager.cpp
33
34#include "ParameterWindowManager.h"
35#include "ParameterWindow.h"
36// NodeManager
37#include "NodeRef.h"
38
39// Application Kit
40#include <AppDefs.h>
41// Media Kit
42#include <MediaRoster.h>
43// Support Kit
44#include <List.h>
45
46__USE_CORTEX_NAMESPACE
47
48#include <Debug.h>
49#define D_ACCESS(x) //PRINT (x)
50#define D_ALLOC(x) //PRINT (x)
51#define D_INTERNAL(x) //PRINT (x)
52#define D_MESSAGE(x) //PRINT (x)
53#define D_WINDOW(x) //PRINT (x)
54
55// -------------------------------------------------------- //
56// internal types
57// -------------------------------------------------------- //
58
59// used to remember the list of ParameterWindows
60struct window_map_entry {
61
62public:						// *** ctor/dtor
63
64							window_map_entry(
65								const NodeRef *ref,
66								BWindow *window)
67								: ref(ref),
68								  window(window)
69							{ }
70
71public:						// *** data members
72
73	const NodeRef		   *ref;
74
75	BWindow				   *window;
76};
77
78// used to remember the list of ControlPanels
79struct panel_map_entry {
80
81public:						// *** ctor/dtor
82
83							panel_map_entry(
84								int32 id,
85								const BMessenger &messenger)
86								: id(id),
87								  messenger(messenger)
88							{ }
89
90public:						// *** data members
91
92	int32					id;
93
94	const BMessenger		messenger;
95};
96
97// -------------------------------------------------------- //
98// static member init
99// -------------------------------------------------------- //
100
101const BPoint ParameterWindowManager::M_DEFAULT_OFFSET	= BPoint(20.0, 20.0);
102const BPoint ParameterWindowManager::M_INIT_POSITION	= BPoint(90.0, 90.0);
103
104ParameterWindowManager *ParameterWindowManager::s_instance = 0;
105
106// -------------------------------------------------------- //
107// *** ctor/dtor
108// -------------------------------------------------------- //
109
110/* hidden */
111ParameterWindowManager::ParameterWindowManager()
112	: BLooper("ParameterWindowManager",
113			  B_NORMAL_PRIORITY),
114	  m_windowList(0),
115	  m_panelList(0),
116	  m_lastWindowPosition(M_INIT_POSITION - M_DEFAULT_OFFSET) {
117	D_ALLOC(("ParameterWindowManager::ParameterWindowManager()\n"));
118
119	m_windowList = new BList();
120	m_panelList = new BList();
121	Run();
122}
123
124ParameterWindowManager::~ParameterWindowManager() {
125	D_ALLOC(("ParameterWindowManager::~ParameterWindowManager()\n"));
126
127	while (m_windowList->CountItems() > 0) {
128		window_map_entry *entry = static_cast<window_map_entry *>
129								  (m_windowList->ItemAt(0));
130		if (entry && entry->window) {
131			remove_observer(this, entry->ref);
132			entry->window->Lock();
133			entry->window->Quit();
134		}
135		m_windowList->RemoveItem(reinterpret_cast<void *>(entry));
136		delete entry;
137	}
138	delete m_windowList;
139
140	while (m_panelList->CountItems() > 0) {
141		panel_map_entry *entry = static_cast<panel_map_entry *>
142								 (m_panelList->ItemAt(0));
143		if (entry && entry->messenger.IsValid()) {
144			entry->messenger.SendMessage(B_QUIT_REQUESTED);
145		}
146		m_panelList->RemoveItem(reinterpret_cast<void *>(entry));
147		delete entry;
148	}
149	delete m_panelList;
150
151	s_instance = 0;
152}
153
154// -------------------------------------------------------- //
155// *** singleton access
156// -------------------------------------------------------- //
157
158/*static*/
159ParameterWindowManager *ParameterWindowManager::Instance() {
160	D_ACCESS(("ParameterWindowManager::Instance()\n"));
161
162	if (!s_instance) {
163		D_ACCESS((" -> create instance\n"));
164		s_instance = new ParameterWindowManager();
165	}
166
167	return s_instance;
168}
169
170/* static */
171void ParameterWindowManager::shutDown() {
172	D_WINDOW(("ParameterWindowManager::shutDown()\n"));
173
174	if (s_instance) {
175		s_instance->Lock();
176		s_instance->Quit();
177	}
178}
179
180// -------------------------------------------------------- //
181// *** operations
182// -------------------------------------------------------- //
183
184status_t ParameterWindowManager::openWindowFor(
185	const NodeRef *ref) {
186	D_WINDOW(("ParameterWindowManager::openWindowFor()\n"));
187
188	// make absolutely sure we're locked
189	if (!IsLocked()) {
190		debugger("The looper must be locked !");
191	}
192
193	// make sure the ref is valid
194	if (!ref) {
195		return B_ERROR;
196	}
197
198	BWindow *window = 0;
199	if (_findWindowFor(ref->id(), &window)) {
200		// window for this node already exists, activate it
201		window->SetWorkspaces(B_CURRENT_WORKSPACE);
202		window->Activate();
203		return B_OK;
204	}
205
206	BMessenger messenger(0, this);
207	live_node_info nodeInfo = ref->nodeInfo();
208	m_lastWindowPosition += M_DEFAULT_OFFSET;
209	window = new ParameterWindow(m_lastWindowPosition,
210								 nodeInfo, &messenger);
211	if (_addWindowFor(ref, window)) {
212		window->Show();
213		return B_OK;
214	}
215	delete window;
216
217	return B_ERROR;
218}
219
220status_t ParameterWindowManager::startControlPanelFor(
221	const NodeRef *ref) {
222	D_WINDOW(("ParameterWindowManager::startControlPanelFor()\n"));
223
224	// make absolutely sure we're locked
225	if (!IsLocked()) {
226		debugger("The looper must be locked !");
227	}
228
229	BMediaRoster *roster = BMediaRoster::CurrentRoster();
230	if (!roster) {
231		D_WINDOW((" -> MediaRoster not available\n"));
232		return B_ERROR;
233	}
234
235	BMessenger messenger;
236	if (_findPanelFor(ref->id(), &messenger)) {
237		// find out if the messengers target still exists
238		if (messenger.IsValid()) {
239			return B_OK;
240		}
241		else {
242			_removePanelFor(ref->id());
243		}
244	}
245
246	status_t error = roster->StartControlPanel(ref->node(),
247											   &messenger);
248	if (error) {
249		D_INTERNAL((" -> StartControlPanel() failed (%s)\n",
250					strerror(error)));
251		return error;
252	}
253
254	_addPanelFor(ref->id(), messenger);
255	return B_OK;
256}
257
258// -------------------------------------------------------- //
259// *** BLooper impl
260// -------------------------------------------------------- //
261
262void ParameterWindowManager::MessageReceived(
263	BMessage *message) {
264	D_MESSAGE(("ParameterWindowManager::MessageReceived()\n"));
265
266	switch (message->what) {
267		case ParameterWindow::M_CLOSED: {
268			D_MESSAGE((" -> ParameterWindow::M_CLOSED\n"));
269			int32 nodeID;
270			if (message->FindInt32("nodeID", &nodeID) != B_OK) {
271				return;
272			}
273			_removeWindowFor(nodeID);
274			break;
275		}
276		case ParameterWindow::M_CONTROL_PANEL_STARTED: {
277			D_MESSAGE((" -> ParameterWindow::M_CONTROL_PANEL_STARTED\n"));
278			int32 nodeID;
279			if (message->FindInt32("nodeID", &nodeID) != B_OK) {
280				return;
281			}
282			BMessenger messenger;
283			if (message->FindMessenger("messenger", &messenger) != B_OK) {
284				return;
285			}
286			_addPanelFor(nodeID, messenger);
287			break;
288		}
289		case NodeRef::M_RELEASED: {
290			D_MESSAGE((" -> NodeRef::M_RELEASED\n"));
291			int32 nodeID;
292			if (message->FindInt32("nodeID", &nodeID) != B_OK) {
293				return;
294			}
295			BWindow *window;
296			if (_findWindowFor(nodeID, &window)) {
297				window->Lock();
298				window->Quit();
299				_removeWindowFor(nodeID);
300			}
301			break;
302		}
303		default: {
304			BLooper::MessageReceived(message);
305		}
306	}
307}
308
309// -------------------------------------------------------- //
310// *** internal operations
311// -------------------------------------------------------- //
312
313bool ParameterWindowManager::_addWindowFor(
314	const NodeRef *ref,
315	BWindow *window) {
316	D_INTERNAL(("ParameterWindowManager::_addWindowFor()\n"));
317
318	window_map_entry *entry = new window_map_entry(ref,
319												   window);
320	if (m_windowList->AddItem(reinterpret_cast<void *>(entry))) {
321		add_observer(this, entry->ref);
322		return true;
323	}
324
325	return false;
326}
327
328bool ParameterWindowManager::_findWindowFor(
329	int32 id,
330	BWindow **outWindow) {
331	D_INTERNAL(("ParameterWindowManager::_findWindowFor()\n"));
332
333	for (int32 i = 0; i < m_windowList->CountItems(); i++) {
334		window_map_entry *entry = static_cast<window_map_entry *>
335								  (m_windowList->ItemAt(i));
336		if (entry->ref->id() == id) {
337			*outWindow = entry->window;
338			return true;
339		}
340	}
341
342	return false;
343}
344
345void ParameterWindowManager::_removeWindowFor(
346	int32 id) {
347	D_INTERNAL(("ParameterWindowManager::_removeWindowFor()\n"));
348
349	for (int32 i = 0; i < m_windowList->CountItems(); i++) {
350		window_map_entry *entry = static_cast<window_map_entry *>
351								  (m_windowList->ItemAt(i));
352		if (entry->ref->id() == id) {
353			m_windowList->RemoveItem(reinterpret_cast<void *>(entry));
354			remove_observer(this, entry->ref);
355			delete entry;
356		}
357	}
358
359	// try to shutdown
360	if (m_windowList->CountItems() == 0) {
361		int32 i = 0;
362		while (true) {
363			// take all invalid messengers out of the panel list
364			panel_map_entry *entry = static_cast<panel_map_entry *>
365									 (m_panelList->ItemAt(i));
366			if (!entry) {
367				// end of list
368				break;
369			}
370			if (!entry->messenger.IsValid()) {
371				// this control panel doesn't exist anymore
372				m_panelList->RemoveItem(entry);
373				continue;
374			}
375		}
376		if (m_panelList->CountItems() == 0) {
377			// neither windows nor panels to manage, go to sleep
378			PostMessage(B_QUIT_REQUESTED);
379		}
380	}
381}
382
383bool ParameterWindowManager::_addPanelFor(
384	int32 id,
385	const BMessenger &messenger) {
386	D_INTERNAL(("ParameterWindowManager::_addPanelFor()\n"));
387
388	panel_map_entry *entry = new panel_map_entry(id,
389												 messenger);
390	if (m_panelList->AddItem(reinterpret_cast<void *>(entry))) {
391		return true;
392	}
393
394	return false;
395}
396
397bool ParameterWindowManager::_findPanelFor(
398	int32 id,
399	BMessenger *outMessenger) {
400	D_INTERNAL(("ParameterWindowManager::_findPanelFor()\n"));
401
402	for (int32 i = 0; i < m_panelList->CountItems(); i++) {
403		panel_map_entry *entry = static_cast<panel_map_entry *>
404								 (m_panelList->ItemAt(i));
405		if (entry->id == id) {
406			*outMessenger = entry->messenger;
407			return true;
408		}
409	}
410
411	return false;
412}
413
414void ParameterWindowManager::_removePanelFor(
415	int32 id) {
416	D_INTERNAL(("ParameterWindowManager::_removeWindowFor()\n"));
417
418	for (int32 i = 0; i < m_panelList->CountItems(); i++) {
419		panel_map_entry *entry = static_cast<panel_map_entry *>
420								 (m_panelList->ItemAt(i));
421		if (entry->id == id) {
422			m_panelList->RemoveItem(reinterpret_cast<void *>(entry));
423			delete entry;
424		}
425	}
426}
427
428// END -- ParameterWindowManager.cpp --
429