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// InfoWindowManager.cpp
33
34#include "InfoWindowManager.h"
35// InfoWindow
36#include "AppNodeInfoView.h"
37#include "ConnectionInfoView.h"
38#include "DormantNodeInfoView.h"
39#include "EndPointInfoView.h"
40#include "FileNodeInfoView.h"
41#include "LiveNodeInfoView.h"
42#include "InfoWindow.h"
43// NodeManager
44#include "AddOnHostProtocol.h"
45#include "Connection.h"
46#include "NodeRef.h"
47
48// Application Kit
49#include <Application.h>
50#include <AppDefs.h>
51#include <Roster.h>
52// Media Kit
53#include <MediaAddOn.h>
54#include <MediaRoster.h>
55// Support Kit
56#include <List.h>
57
58__USE_CORTEX_NAMESPACE
59
60#include <Debug.h>
61#define D_ACCESS(x) //PRINT (x)
62#define D_ALLOC(x) //PRINT (x)
63#define D_INTERNAL(x) //PRINT (x)
64#define D_MESSAGE(x) //PRINT (x)
65#define D_WINDOW(x) //PRINT (x)
66
67// -------------------------------------------------------- //
68// internal types
69// -------------------------------------------------------- //
70
71// used to remember window for live nodes
72struct live_node_window {
73
74public:						// *** ctor/dtor
75
76							live_node_window(
77								const NodeRef *ref,
78								BWindow *window)
79								: ref(ref),
80								  window(window)
81							{ }
82
83public:						// *** data members
84
85	const NodeRef		   *ref;
86
87	BWindow				   *window;
88};
89
90// used to remember windows for dormant nodes
91struct dormant_node_window {
92
93public:						// *** ctor/dtor
94
95							dormant_node_window(
96								const dormant_node_info &info,
97								BWindow *window)
98								: info(info),
99								  window(window)
100							{ }
101
102public:						// *** data members
103
104	const dormant_node_info	info;
105
106	BWindow				   *window;
107};
108
109// used to remember windows for connections
110struct connection_window {
111
112public:						// *** ctor/dtor
113
114							connection_window(
115								const media_source &source,
116								const media_destination &destination,
117								BWindow *window)
118								: source(source),
119								  destination(destination),
120								  window(window)
121							{ }
122
123public:						// *** data members
124
125	media_source			source;
126
127	media_destination		destination;
128
129	BWindow				   *window;
130};
131
132// used to remember windows for media_inputs
133struct input_window {
134
135public:						// *** ctor/dtor
136
137							input_window(
138								const media_destination &destination,
139								BWindow *window)
140								: destination(destination),
141								  window(window)
142							{ }
143
144public:						// *** data members
145
146	media_destination		destination;
147
148	BWindow				   *window;
149};
150
151// used to remember windows for media_outputs
152struct output_window {
153
154public:						// *** ctor/dtor
155
156							output_window(
157								const media_source &source,
158								BWindow *window)
159								: source(source),
160								  window(window)
161							{ }
162
163public:						// *** data members
164
165	media_source			source;
166
167	BWindow				   *window;
168};
169
170// -------------------------------------------------------- //
171// static member init
172// -------------------------------------------------------- //
173
174const BPoint InfoWindowManager::M_DEFAULT_OFFSET	= BPoint(20.0, 20.0);
175const BPoint InfoWindowManager::M_INIT_POSITION	= BPoint(90.0, 90.0);
176
177InfoWindowManager *InfoWindowManager::s_instance = 0;
178
179// -------------------------------------------------------- //
180// *** ctor/dtor
181// -------------------------------------------------------- //
182
183/* hidden */
184InfoWindowManager::InfoWindowManager()
185	: BLooper("InfoWindowManager",
186			  B_NORMAL_PRIORITY),
187	  m_liveNodeWindows(0),
188	  m_dormantNodeWindows(0),
189	  m_connectionWindows(0),
190	  m_inputWindows(0),
191	  m_outputWindows(0),
192	  m_nextWindowPosition(M_INIT_POSITION) {
193	D_ALLOC(("InfoWindowManager::InfoWindowManager()\n"));
194
195	Run();
196
197	BMediaRoster *roster = BMediaRoster::CurrentRoster();
198	if (roster) {
199		roster->StartWatching(BMessenger(0, this),
200							  B_MEDIA_CONNECTION_BROKEN);
201	}
202}
203
204InfoWindowManager::~InfoWindowManager() {
205	D_ALLOC(("InfoWindowManager::~InfoWindowManager()\n"));
206
207	BMediaRoster *roster = BMediaRoster::CurrentRoster();
208	if (roster) {
209		roster->StopWatching(BMessenger(0, this),
210							  B_MEDIA_CONNECTION_BROKEN);
211	}
212
213	if (m_liveNodeWindows) {
214		while (m_liveNodeWindows->CountItems() > 0) {
215			live_node_window *entry = static_cast<live_node_window *>
216									  (m_liveNodeWindows->ItemAt(0));
217			if (entry && entry->window) {
218				remove_observer(this, entry->ref);
219				BMessenger messenger(0, entry->window);
220				messenger.SendMessage(B_QUIT_REQUESTED);
221			}
222			m_liveNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
223			delete entry;
224		}
225		delete m_liveNodeWindows;
226		m_liveNodeWindows = 0;
227	}
228
229	if (m_dormantNodeWindows) {
230		while (m_dormantNodeWindows->CountItems() > 0) {
231			dormant_node_window *entry = static_cast<dormant_node_window *>
232										 (m_dormantNodeWindows->ItemAt(0));
233			if (entry && entry->window) {
234				BMessenger messenger(0, entry->window);
235				messenger.SendMessage(B_QUIT_REQUESTED);
236			}
237			m_dormantNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
238			delete entry;
239		}
240		delete m_dormantNodeWindows;
241		m_dormantNodeWindows = 0;
242	}
243
244	if (m_connectionWindows) {
245		while (m_connectionWindows->CountItems() > 0) {
246			connection_window *entry = static_cast<connection_window *>
247									   (m_connectionWindows->ItemAt(0));
248			if (entry && entry->window) {
249				BMessenger messenger(0, entry->window);
250				messenger.SendMessage(B_QUIT_REQUESTED);
251			}
252			m_connectionWindows->RemoveItem(reinterpret_cast<void *>(entry));
253			delete entry;
254		}
255		delete m_connectionWindows;
256		m_connectionWindows = 0;
257	}
258
259	if (m_inputWindows) {
260		while (m_inputWindows->CountItems() > 0) {
261			input_window *entry = static_cast<input_window *>
262								  (m_inputWindows->ItemAt(0));
263			if (entry && entry->window) {
264				BMessenger messenger(0, entry->window);
265				messenger.SendMessage(B_QUIT_REQUESTED);
266			}
267			m_inputWindows->RemoveItem(reinterpret_cast<void *>(entry));
268			delete entry;
269		}
270		delete m_inputWindows;
271		m_inputWindows = 0;
272	}
273
274	if (m_outputWindows) {
275		while (m_outputWindows->CountItems() > 0) {
276			output_window *entry = static_cast<output_window *>
277								   (m_outputWindows->ItemAt(0));
278			if (entry && entry->window) {
279				BMessenger messenger(0, entry->window);
280				messenger.SendMessage(B_QUIT_REQUESTED);
281			}
282			m_outputWindows->RemoveItem(reinterpret_cast<void *>(entry));
283			delete entry;
284		}
285		delete m_outputWindows;
286		m_outputWindows = 0;
287	}
288}
289
290// -------------------------------------------------------- //
291// *** singleton access
292// -------------------------------------------------------- //
293
294/*static*/
295InfoWindowManager *InfoWindowManager::Instance() {
296	D_ACCESS(("InfoWindowManager::Instance()\n"));
297
298	if (!s_instance) {
299		D_ACCESS((" -> create instance\n"));
300		s_instance = new InfoWindowManager();
301	}
302
303	return s_instance;
304}
305
306/* static */
307void InfoWindowManager::shutDown() {
308	D_WINDOW(("InfoWindowManager::shutDown()\n"));
309
310	if (s_instance) {
311		s_instance->Lock();
312		s_instance->Quit();
313		s_instance = 0;
314	}
315}
316
317// -------------------------------------------------------- //
318// *** operations
319// -------------------------------------------------------- //
320
321status_t InfoWindowManager::openWindowFor(
322	const NodeRef *ref) {
323	D_WINDOW(("InfoWindowManager::openWindowFor(live_node)\n"));
324
325	// make absolutely sure we're locked
326	if (!IsLocked()) {
327		debugger("The looper must be locked !");
328	}
329
330	// make sure the ref is valid
331	if (!ref) {
332		return B_ERROR;
333	}
334
335	BWindow *window = 0;
336	if (_findWindowFor(ref->id(), &window)) {
337		// window for this node already exists, activate it
338		window->SetWorkspaces(B_CURRENT_WORKSPACE);
339		window->Activate();
340		return B_OK;
341	}
342
343	BRect frame = InfoView::M_DEFAULT_FRAME;
344	frame.OffsetTo(m_nextWindowPosition);
345	m_nextWindowPosition += M_DEFAULT_OFFSET;
346	window = new InfoWindow(frame);
347
348	if (_addWindowFor(ref, window)) {
349		// find the correct InfoView sub-class
350		BMediaRoster *roster = BMediaRoster::CurrentRoster();
351		dormant_node_info dormantNodeInfo;
352		if (ref->kind() & B_FILE_INTERFACE)
353		{
354			window->AddChild(new FileNodeInfoView(ref));
355		}
356		else if (roster->GetDormantNodeFor(ref->node(), &dormantNodeInfo) != B_OK) {
357			port_info portInfo;
358			app_info appInfo;
359			if ((get_port_info(ref->node().port, &portInfo) == B_OK)
360			 && (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK)) {
361				app_info thisAppInfo;
362				if ((be_app->GetAppInfo(&thisAppInfo) != B_OK)
363				 || ((strcmp(appInfo.signature, thisAppInfo.signature) != 0)
364				 && (strcmp(appInfo.signature, addon_host::g_appSignature) != 0))) {
365					window->AddChild(new AppNodeInfoView(ref));
366				}
367				else {
368					window->AddChild(new LiveNodeInfoView(ref));
369				}
370			}
371			else {
372				window->AddChild(new LiveNodeInfoView(ref));
373			}
374		}
375		else {
376			window->AddChild(new LiveNodeInfoView(ref));
377		}
378		// display the window
379		window->Show();
380		return B_OK;
381	}
382
383	// failed
384	delete window;
385	return B_ERROR;
386}
387
388status_t InfoWindowManager::openWindowFor(
389	const dormant_node_info &info) {
390	D_WINDOW(("InfoWindowManager::openWindowFor(dormant_node)\n"));
391
392	// make absolutely sure we're locked
393	if (!IsLocked()) {
394		debugger("The looper must be locked !");
395	}
396
397	BWindow *window = 0;
398	if (_findWindowFor(info, &window)) {
399		// window for this node already exists, activate it
400		window->SetWorkspaces(B_CURRENT_WORKSPACE);
401		window->Activate();
402		return B_OK;
403	}
404
405	BRect frame = InfoView::M_DEFAULT_FRAME;
406	frame.OffsetTo(m_nextWindowPosition);
407	m_nextWindowPosition += M_DEFAULT_OFFSET;
408	window = new InfoWindow(frame);
409
410	if (_addWindowFor(info, window)) {
411		window->AddChild(new DormantNodeInfoView(info));
412		window->Show();
413		return B_OK;
414	}
415
416	// failed
417	delete window;
418	return B_ERROR;
419}
420
421status_t InfoWindowManager::openWindowFor(
422	const Connection &connection) {
423	D_WINDOW(("InfoWindowManager::openWindowFor(connection)\n"));
424
425	// make absolutely sure we're locked
426	if (!IsLocked()) {
427		debugger("The looper must be locked !");
428	}
429
430	BWindow *window = 0;
431	if (_findWindowFor(connection.source(), connection.destination(), &window)) {
432		// window for this node already exists, activate it
433		window->SetWorkspaces(B_CURRENT_WORKSPACE);
434		window->Activate();
435		return B_OK;
436	}
437
438	BRect frame = InfoView::M_DEFAULT_FRAME;
439	frame.OffsetTo(m_nextWindowPosition);
440	m_nextWindowPosition += M_DEFAULT_OFFSET;
441	window = new InfoWindow(frame);
442
443	if (_addWindowFor(connection, window)) {
444		window->AddChild(new ConnectionInfoView(connection));
445		window->Show();
446		return B_OK;
447	}
448
449	// failed
450	delete window;
451	return B_ERROR;
452}
453
454status_t InfoWindowManager::openWindowFor(
455	const media_input &input) {
456	D_WINDOW(("InfoWindowManager::openWindowFor(input)\n"));
457
458	// make absolutely sure we're locked
459	if (!IsLocked()) {
460		debugger("The looper must be locked !");
461	}
462
463	BWindow *window = 0;
464	if (_findWindowFor(input.destination, &window)) {
465		// window for this node already exists, activate it
466		window->SetWorkspaces(B_CURRENT_WORKSPACE);
467		window->Activate();
468		return B_OK;
469	}
470
471	BRect frame = InfoView::M_DEFAULT_FRAME;
472	frame.OffsetTo(m_nextWindowPosition);
473	m_nextWindowPosition += M_DEFAULT_OFFSET;
474	window = new InfoWindow(frame);
475
476	if (_addWindowFor(input, window)) {
477		window->AddChild(new EndPointInfoView(input));
478		window->Show();
479		return B_OK;
480	}
481
482	// failed
483	delete window;
484	return B_ERROR;
485}
486
487status_t InfoWindowManager::openWindowFor(
488	const media_output &output) {
489	D_WINDOW(("InfoWindowManager::openWindowFor(output)\n"));
490
491	// make absolutely sure we're locked
492	if (!IsLocked()) {
493		debugger("The looper must be locked !");
494	}
495
496	BWindow *window = 0;
497	if (_findWindowFor(output.source, &window)) {
498		// window for this node already exists, activate it
499		window->SetWorkspaces(B_CURRENT_WORKSPACE);
500		window->Activate();
501		return B_OK;
502	}
503
504	BRect frame = InfoView::M_DEFAULT_FRAME;
505	frame.OffsetTo(m_nextWindowPosition);
506	m_nextWindowPosition += M_DEFAULT_OFFSET;
507	window = new BWindow(frame, "", B_DOCUMENT_WINDOW, 0);
508
509	if (_addWindowFor(output, window)) {
510		window->AddChild(new EndPointInfoView(output));
511		window->Show();
512		return B_OK;
513	}
514
515	// failed
516	delete window;
517	return B_ERROR;
518}
519
520// -------------------------------------------------------- //
521// *** BLooper impl
522// -------------------------------------------------------- //
523
524void InfoWindowManager::MessageReceived(
525	BMessage *message) {
526	D_MESSAGE(("InfoWindowManager::MessageReceived()\n"));
527
528	switch (message->what) {
529		case M_LIVE_NODE_WINDOW_CLOSED: {
530			D_MESSAGE((" -> M_LIVE_NODE_WINDOW_CLOSED\n"));
531			int32 nodeID;
532			if (message->FindInt32("nodeID", &nodeID) != B_OK) {
533				return;
534			}
535			_removeWindowFor(nodeID);
536			break;
537		}
538		case M_DORMANT_NODE_WINDOW_CLOSED: {
539			D_MESSAGE((" -> M_DORMANT_NODE_WINDOW_CLOSED\n"));
540			dormant_node_info info;
541			if (message->FindInt32("addOnID", &info.addon) != B_OK) {
542				return;
543			}
544			if (message->FindInt32("flavorID", &info.flavor_id) != B_OK) {
545				return;
546			}
547			_removeWindowFor(info);
548			break;
549		}
550		case M_CONNECTION_WINDOW_CLOSED: {
551			D_MESSAGE((" -> M_CONNECTION_WINDOW_CLOSED\n"));
552			media_source source;
553			if (message->FindInt32("source_port", &source.port) != B_OK) {
554				return;
555			}
556			if (message->FindInt32("source_id", &source.id) != B_OK) {
557				return;
558			}
559			media_destination destination;
560			if (message->FindInt32("destination_port", &destination.port) != B_OK) {
561				return;
562			}
563			if (message->FindInt32("destination_id", &destination.id) != B_OK) {
564				return;
565			}
566			_removeWindowFor(source, destination);
567			break;
568		}
569		case M_INPUT_WINDOW_CLOSED: {
570			D_MESSAGE((" -> M_INPUT_WINDOW_CLOSED\n"));
571			media_destination destination;
572			if (message->FindInt32("destination_port", &destination.port) != B_OK) {
573				return;
574			}
575			if (message->FindInt32("destination_id", &destination.id) != B_OK) {
576				return;
577			}
578			_removeWindowFor(destination);
579			break;
580		}
581		case M_OUTPUT_WINDOW_CLOSED: {
582			D_MESSAGE((" -> M_OUTPUT_WINDOW_CLOSED\n"));
583			media_source source;
584			if (message->FindInt32("source_port", &source.port) != B_OK) {
585				return;
586			}
587			if (message->FindInt32("source_id", &source.id) != B_OK) {
588				return;
589			}
590			_removeWindowFor(source);
591			break;
592		}
593		case NodeRef::M_RELEASED: {
594			D_MESSAGE((" -> NodeRef::M_RELEASED\n"));
595			int32 nodeID;
596			if (message->FindInt32("nodeID", &nodeID) != B_OK) {
597				return;
598			}
599			BWindow *window;
600			if (_findWindowFor(nodeID, &window)) {
601				window->Lock();
602				window->Quit();
603				_removeWindowFor(nodeID);
604			}
605			break;
606		}
607		case B_MEDIA_CONNECTION_BROKEN: {
608			D_MESSAGE((" -> B_MEDIA_CONNECTION_BROKEN\n"));
609			const void *data;
610			ssize_t dataSize;
611			if (message->FindData("source", B_RAW_TYPE, &data, &dataSize) != B_OK) {
612				return;
613			}
614			const media_source source = *reinterpret_cast<const media_source *>(data);
615			if (message->FindData("destination", B_RAW_TYPE, &data, &dataSize) != B_OK) {
616				return;
617			}
618			const media_destination destination = *reinterpret_cast<const media_destination *>(data);
619			BWindow *window;
620			if (_findWindowFor(source, destination, &window)) {
621				window->Lock();
622				window->Quit();
623				_removeWindowFor(source, destination);
624			}
625			break;
626		}
627		default: {
628			BLooper::MessageReceived(message);
629		}
630	}
631}
632
633// -------------------------------------------------------- //
634// *** internal operations
635// -------------------------------------------------------- //
636
637bool InfoWindowManager::_addWindowFor(
638	const NodeRef *ref,
639	BWindow *window) {
640	D_INTERNAL(("InfoWindowManager::_addWindowFor(live_node)\n"));
641
642	if (!m_liveNodeWindows) {
643		m_liveNodeWindows = new BList();
644	}
645
646	live_node_window *entry = new live_node_window(ref, window);
647	if (m_liveNodeWindows->AddItem(reinterpret_cast<void *>(entry))) {
648		add_observer(this, entry->ref);
649		return true;
650	}
651
652	return false;
653}
654
655bool InfoWindowManager::_findWindowFor(
656	int32 nodeID,
657	BWindow **outWindow) {
658	D_INTERNAL(("InfoWindowManager::_findWindowFor(live_node)\n"));
659
660	if (!m_liveNodeWindows) {
661		return false;
662	}
663
664	for (int32 i = 0; i < m_liveNodeWindows->CountItems(); i++) {
665		live_node_window *entry = static_cast<live_node_window *>
666								  (m_liveNodeWindows->ItemAt(i));
667		if (entry->ref->id() == nodeID) {
668			*outWindow = entry->window;
669			return true;
670		}
671	}
672
673	return false;
674}
675
676void InfoWindowManager::_removeWindowFor(
677	int32 nodeID) {
678	D_INTERNAL(("InfoWindowManager::_removeWindowFor(live_node)\n"));
679
680	if (!m_liveNodeWindows) {
681		return;
682	}
683
684	for (int32 i = 0; i < m_liveNodeWindows->CountItems(); i++) {
685		live_node_window *entry = static_cast<live_node_window *>
686								  (m_liveNodeWindows->ItemAt(i));
687		if (entry->ref->id() == nodeID) {
688			m_liveNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
689			remove_observer(this, entry->ref);
690			delete entry;
691		}
692	}
693
694	if (m_liveNodeWindows->CountItems() <= 0) {
695		delete m_liveNodeWindows;
696		m_liveNodeWindows = 0;
697	}
698}
699
700bool InfoWindowManager::_addWindowFor(
701	const dormant_node_info &info,
702	BWindow *window) {
703	D_INTERNAL(("InfoWindowManager::_addWindowFor(dormant_node)\n"));
704
705	if (!m_dormantNodeWindows) {
706		m_dormantNodeWindows = new BList();
707	}
708
709	dormant_node_window *entry = new dormant_node_window(info, window);
710	return m_dormantNodeWindows->AddItem(reinterpret_cast<void *>(entry));
711}
712
713bool InfoWindowManager::_findWindowFor(
714	const dormant_node_info &info,
715	BWindow **outWindow) {
716	D_INTERNAL(("InfoWindowManager::_findWindowFor(dormant_node)\n"));
717
718	if (!m_dormantNodeWindows) {
719		return false;
720	}
721
722	for (int32 i = 0; i < m_dormantNodeWindows->CountItems(); i++) {
723		dormant_node_window *entry = static_cast<dormant_node_window *>
724									 (m_dormantNodeWindows->ItemAt(i));
725		if ((entry->info.addon == info.addon)
726		 && (entry->info.flavor_id == info.flavor_id)) {
727			*outWindow = entry->window;
728			return true;
729		}
730	}
731
732	return false;
733}
734
735void InfoWindowManager::_removeWindowFor(
736	const dormant_node_info &info) {
737	D_INTERNAL(("InfoWindowManager::_removeWindowFor(dormant_node)\n"));
738
739	if (!m_dormantNodeWindows) {
740		return;
741	}
742
743	for (int32 i = 0; i < m_dormantNodeWindows->CountItems(); i++) {
744		dormant_node_window *entry = static_cast<dormant_node_window *>
745									 (m_dormantNodeWindows->ItemAt(i));
746		if ((entry->info.addon == info.addon)
747		 && (entry->info.flavor_id == info.flavor_id)) {
748			m_dormantNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
749			delete entry;
750		}
751	}
752
753	if (m_dormantNodeWindows->CountItems() >= 0) {
754		delete m_dormantNodeWindows;
755		m_dormantNodeWindows = 0;
756	}
757}
758
759bool InfoWindowManager::_addWindowFor(
760	const Connection &connection,
761	BWindow *window) {
762	D_INTERNAL(("InfoWindowManager::_addWindowFor(connection)\n"));
763
764	if (!m_connectionWindows) {
765		m_connectionWindows = new BList();
766	}
767
768	connection_window *entry = new connection_window(connection.source(),
769													 connection.destination(),
770													 window);
771	return m_connectionWindows->AddItem(reinterpret_cast<void *>(entry));
772}
773
774bool InfoWindowManager::_findWindowFor(
775	const media_source &source,
776	const media_destination &destination,
777	BWindow **outWindow) {
778	D_INTERNAL(("InfoWindowManager::_findWindowFor(connection)\n"));
779
780	if (!m_connectionWindows) {
781		return false;
782	}
783
784	for (int32 i = 0; i < m_connectionWindows->CountItems(); i++) {
785		connection_window *entry = static_cast<connection_window *>
786								   (m_connectionWindows->ItemAt(i));
787		if ((entry->source == source)
788		 && (entry->destination == destination)) {
789			*outWindow = entry->window;
790			return true;
791		}
792	}
793
794	return false;
795}
796
797void InfoWindowManager::_removeWindowFor(
798	const media_source &source,
799	const media_destination &destination) {
800	D_INTERNAL(("InfoWindowManager::_removeWindowFor(connection)\n"));
801
802	if (!m_connectionWindows) {
803		return;
804	}
805
806	for (int32 i = 0; i < m_connectionWindows->CountItems(); i++) {
807		connection_window *entry = static_cast<connection_window *>
808								   (m_connectionWindows->ItemAt(i));
809		if ((entry->source == source)
810		 && (entry->destination == destination)) {
811			m_connectionWindows->RemoveItem(reinterpret_cast<void *>(entry));
812			delete entry;
813		}
814	}
815
816	if (m_connectionWindows->CountItems() >= 0) {
817		delete m_connectionWindows;
818		m_connectionWindows = 0;
819	}
820}
821
822bool InfoWindowManager::_addWindowFor(
823	const media_input &input,
824	BWindow *window) {
825	D_INTERNAL(("InfoWindowManager::_addWindowFor(input)\n"));
826
827	if (!m_inputWindows) {
828		m_inputWindows = new BList();
829	}
830
831	input_window *entry = new input_window(input.destination, window);
832	return m_inputWindows->AddItem(reinterpret_cast<void *>(entry));
833}
834
835bool InfoWindowManager::_findWindowFor(
836	const media_destination &destination,
837	BWindow **outWindow) {
838	D_INTERNAL(("InfoWindowManager::_findWindowFor(input)\n"));
839
840	if (!m_inputWindows) {
841		return false;
842	}
843
844	for (int32 i = 0; i < m_inputWindows->CountItems(); i++) {
845		input_window *entry = static_cast<input_window *>
846							  (m_inputWindows->ItemAt(i));
847		if (entry->destination == destination) {
848			*outWindow = entry->window;
849			return true;
850		}
851	}
852
853	return false;
854}
855
856void InfoWindowManager::_removeWindowFor(
857	const media_destination &destination) {
858	D_INTERNAL(("InfoWindowManager::_removeWindowFor(input)\n"));
859
860	if (!m_inputWindows) {
861		return;
862	}
863
864	for (int32 i = 0; i < m_inputWindows->CountItems(); i++) {
865		input_window *entry = static_cast<input_window *>
866							  (m_inputWindows->ItemAt(i));
867		if (entry->destination == destination) {
868			m_inputWindows->RemoveItem(reinterpret_cast<void *>(entry));
869			delete entry;
870		}
871	}
872
873	if (m_inputWindows->CountItems() >= 0) {
874		delete m_inputWindows;
875		m_inputWindows = 0;
876	}
877}
878
879bool InfoWindowManager::_addWindowFor(
880	const media_output &output,
881	BWindow *window) {
882	D_INTERNAL(("InfoWindowManager::_addWindowFor(output)\n"));
883
884	if (!m_outputWindows) {
885		m_outputWindows = new BList();
886	}
887
888	output_window *entry = new output_window(output.source, window);
889	return m_outputWindows->AddItem(reinterpret_cast<void *>(entry));
890}
891
892bool InfoWindowManager::_findWindowFor(
893	const media_source &source,
894	BWindow **outWindow) {
895	D_INTERNAL(("InfoWindowManager::_findWindowFor(output)\n"));
896
897	if (!m_outputWindows) {
898		return false;
899	}
900
901	for (int32 i = 0; i < m_outputWindows->CountItems(); i++) {
902		output_window *entry = static_cast<output_window *>
903							  (m_outputWindows->ItemAt(i));
904		if (entry->source == source) {
905			*outWindow = entry->window;
906			return true;
907		}
908	}
909
910	return false;
911}
912
913void InfoWindowManager::_removeWindowFor(
914	const media_source &source) {
915	D_INTERNAL(("InfoWindowManager::_removeWindowFor(output)\n"));
916
917	if (!m_outputWindows) {
918		return;
919	}
920
921	for (int32 i = 0; i < m_outputWindows->CountItems(); i++) {
922		output_window *entry = static_cast<output_window *>
923							  (m_outputWindows->ItemAt(i));
924		if (entry->source == source) {
925			m_outputWindows->RemoveItem(reinterpret_cast<void *>(entry));
926			delete entry;
927		}
928	}
929
930	if (m_outputWindows->CountItems() >= 0) {
931		delete m_outputWindows;
932		m_outputWindows = 0;
933	}
934}
935
936// END -- InfoWindowManager.cpp --
937