⛏️ index : haiku.git

/*
 * Copyright (c) 1999-2000, Eric Moon.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions, and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


// InfoWindowManager.cpp

#include "InfoWindowManager.h"
// InfoWindow
#include "AppNodeInfoView.h"
#include "ConnectionInfoView.h"
#include "DormantNodeInfoView.h"
#include "EndPointInfoView.h"
#include "FileNodeInfoView.h"
#include "LiveNodeInfoView.h"
#include "InfoWindow.h"
// NodeManager
#include "AddOnHostProtocol.h"
#include "Connection.h"
#include "NodeRef.h"

// Application Kit
#include <Application.h>
#include <AppDefs.h>
#include <Roster.h>
// Media Kit
#include <MediaAddOn.h>
#include <MediaRoster.h>
// Support Kit
#include <List.h>

__USE_CORTEX_NAMESPACE

#include <Debug.h>
#define D_ACCESS(x) //PRINT (x)
#define D_ALLOC(x) //PRINT (x)
#define D_INTERNAL(x) //PRINT (x)
#define D_MESSAGE(x) //PRINT (x)
#define D_WINDOW(x) //PRINT (x)

// -------------------------------------------------------- //
// internal types
// -------------------------------------------------------- //

// used to remember window for live nodes
struct live_node_window {

public:						// *** ctor/dtor

							live_node_window(
								const NodeRef *ref,
								BWindow *window)
								: ref(ref),
								  window(window)
							{ }

public:						// *** data members

	const NodeRef		   *ref;

	BWindow				   *window;
};

// used to remember windows for dormant nodes
struct dormant_node_window {

public:						// *** ctor/dtor

							dormant_node_window(
								const dormant_node_info &info,
								BWindow *window)
								: info(info),
								  window(window)
							{ }

public:						// *** data members

	const dormant_node_info	info;

	BWindow				   *window;
};

// used to remember windows for connections
struct connection_window {

public:						// *** ctor/dtor

							connection_window(
								const media_source &source,
								const media_destination &destination,
								BWindow *window)
								: source(source),
								  destination(destination),
								  window(window)
							{ }

public:						// *** data members

	media_source			source;

	media_destination		destination;

	BWindow				   *window;
};

// used to remember windows for media_inputs
struct input_window {

public:						// *** ctor/dtor

							input_window(
								const media_destination &destination,
								BWindow *window)
								: destination(destination),
								  window(window)
							{ }

public:						// *** data members

	media_destination		destination;

	BWindow				   *window;
};

// used to remember windows for media_outputs
struct output_window {

public:						// *** ctor/dtor

							output_window(
								const media_source &source,
								BWindow *window)
								: source(source),
								  window(window)
							{ }

public:						// *** data members

	media_source			source;

	BWindow				   *window;
};

// -------------------------------------------------------- //
// static member init
// -------------------------------------------------------- //

const BPoint InfoWindowManager::M_DEFAULT_OFFSET	= BPoint(20.0, 20.0);
const BPoint InfoWindowManager::M_INIT_POSITION	= BPoint(90.0, 90.0);

InfoWindowManager *InfoWindowManager::s_instance = 0;

// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //

/* hidden */
InfoWindowManager::InfoWindowManager()
	: BLooper("InfoWindowManager",
			  B_NORMAL_PRIORITY),
	  m_liveNodeWindows(0),
	  m_dormantNodeWindows(0),
	  m_connectionWindows(0),
	  m_inputWindows(0),
	  m_outputWindows(0),
	  m_nextWindowPosition(M_INIT_POSITION) {
	D_ALLOC(("InfoWindowManager::InfoWindowManager()\n"));

	Run();

	BMediaRoster *roster = BMediaRoster::CurrentRoster();
	if (roster) {
		roster->StartWatching(BMessenger(0, this),
							  B_MEDIA_CONNECTION_BROKEN);
	}
}

InfoWindowManager::~InfoWindowManager() {
	D_ALLOC(("InfoWindowManager::~InfoWindowManager()\n"));

	BMediaRoster *roster = BMediaRoster::CurrentRoster();
	if (roster) {
		roster->StopWatching(BMessenger(0, this),
							  B_MEDIA_CONNECTION_BROKEN);
	}

	if (m_liveNodeWindows) {
		while (m_liveNodeWindows->CountItems() > 0) {
			live_node_window *entry = static_cast<live_node_window *>
									  (m_liveNodeWindows->ItemAt(0));
			if (entry && entry->window) {
				remove_observer(this, entry->ref);
				BMessenger messenger(0, entry->window);
				messenger.SendMessage(B_QUIT_REQUESTED);
			}
			m_liveNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}	
		delete m_liveNodeWindows;
		m_liveNodeWindows = 0;
	}

	if (m_dormantNodeWindows) {
		while (m_dormantNodeWindows->CountItems() > 0) {
			dormant_node_window *entry = static_cast<dormant_node_window *>
										 (m_dormantNodeWindows->ItemAt(0));
			if (entry && entry->window) {
				BMessenger messenger(0, entry->window);
				messenger.SendMessage(B_QUIT_REQUESTED);
			}
			m_dormantNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}	
		delete m_dormantNodeWindows;
		m_dormantNodeWindows = 0;
	}

	if (m_connectionWindows) {
		while (m_connectionWindows->CountItems() > 0) {
			connection_window *entry = static_cast<connection_window *>
									   (m_connectionWindows->ItemAt(0));
			if (entry && entry->window) {
				BMessenger messenger(0, entry->window);
				messenger.SendMessage(B_QUIT_REQUESTED);
			}
			m_connectionWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}	
		delete m_connectionWindows;
		m_connectionWindows = 0;
	}

	if (m_inputWindows) {
		while (m_inputWindows->CountItems() > 0) {
			input_window *entry = static_cast<input_window *>
								  (m_inputWindows->ItemAt(0));
			if (entry && entry->window) {
				BMessenger messenger(0, entry->window);
				messenger.SendMessage(B_QUIT_REQUESTED);
			}
			m_inputWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}	
		delete m_inputWindows;
		m_inputWindows = 0;
	}

	if (m_outputWindows) {
		while (m_outputWindows->CountItems() > 0) {
			output_window *entry = static_cast<output_window *>
								   (m_outputWindows->ItemAt(0));
			if (entry && entry->window) {
				BMessenger messenger(0, entry->window);
				messenger.SendMessage(B_QUIT_REQUESTED);
			}
			m_outputWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}	
		delete m_outputWindows;
		m_outputWindows = 0;
	}
}

// -------------------------------------------------------- //
// *** singleton access
// -------------------------------------------------------- //

/*static*/
InfoWindowManager *InfoWindowManager::Instance() {
	D_ACCESS(("InfoWindowManager::Instance()\n"));

	if (!s_instance) {
		D_ACCESS((" -> create instance\n"));
		s_instance = new InfoWindowManager();
	}		

	return s_instance;
}

/* static */
void InfoWindowManager::shutDown() {
	D_WINDOW(("InfoWindowManager::shutDown()\n"));

	if (s_instance) {
		s_instance->Lock();
		s_instance->Quit();
		s_instance = 0;
	}
}

// -------------------------------------------------------- //
// *** operations
// -------------------------------------------------------- //

status_t InfoWindowManager::openWindowFor(
	const NodeRef *ref) {
	D_WINDOW(("InfoWindowManager::openWindowFor(live_node)\n"));

	// make absolutely sure we're locked
	if (!IsLocked()) {
		debugger("The looper must be locked !");
	}

	// make sure the ref is valid
	if (!ref) {
		return B_ERROR;
	}

	BWindow *window = 0;
	if (_findWindowFor(ref->id(), &window)) {
		// window for this node already exists, activate it
		window->SetWorkspaces(B_CURRENT_WORKSPACE);
		window->Activate();
		return B_OK;
	}

	BRect frame = InfoView::M_DEFAULT_FRAME;
	frame.OffsetTo(m_nextWindowPosition);
	m_nextWindowPosition += M_DEFAULT_OFFSET;
	window = new InfoWindow(frame);

	if (_addWindowFor(ref, window)) {
		// find the correct InfoView sub-class
		BMediaRoster *roster = BMediaRoster::CurrentRoster();
		dormant_node_info dormantNodeInfo;
		if (ref->kind() & B_FILE_INTERFACE)
		{
			window->AddChild(new FileNodeInfoView(ref));
		}
		else if (roster->GetDormantNodeFor(ref->node(), &dormantNodeInfo) != B_OK) {
			port_info portInfo;
			app_info appInfo;
			if ((get_port_info(ref->node().port, &portInfo) == B_OK)
			 && (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK)) {
				app_info thisAppInfo;
				if ((be_app->GetAppInfo(&thisAppInfo) != B_OK)
				 || ((strcmp(appInfo.signature, thisAppInfo.signature) != 0)
				 && (strcmp(appInfo.signature, addon_host::g_appSignature) != 0))) {
					window->AddChild(new AppNodeInfoView(ref));
				}
				else {
					window->AddChild(new LiveNodeInfoView(ref));
				}
			}
			else {
				window->AddChild(new LiveNodeInfoView(ref));
			}
		}
		else {
			window->AddChild(new LiveNodeInfoView(ref));
		}
		// display the window
		window->Show();
		return B_OK;
	}

	// failed
	delete window;
	return B_ERROR;
}

status_t InfoWindowManager::openWindowFor(
	const dormant_node_info &info) {
	D_WINDOW(("InfoWindowManager::openWindowFor(dormant_node)\n"));

	// make absolutely sure we're locked
	if (!IsLocked()) {
		debugger("The looper must be locked !");
	}

	BWindow *window = 0;
	if (_findWindowFor(info, &window)) {
		// window for this node already exists, activate it
		window->SetWorkspaces(B_CURRENT_WORKSPACE);
		window->Activate();
		return B_OK;
	}

	BRect frame = InfoView::M_DEFAULT_FRAME;
	frame.OffsetTo(m_nextWindowPosition);
	m_nextWindowPosition += M_DEFAULT_OFFSET;
	window = new InfoWindow(frame);

	if (_addWindowFor(info, window)) {
		window->AddChild(new DormantNodeInfoView(info));
		window->Show();
		return B_OK;
	}

	// failed
	delete window;
	return B_ERROR;
}

status_t InfoWindowManager::openWindowFor(
	const Connection &connection) {
	D_WINDOW(("InfoWindowManager::openWindowFor(connection)\n"));

	// make absolutely sure we're locked
	if (!IsLocked()) {
		debugger("The looper must be locked !");
	}

	BWindow *window = 0;
	if (_findWindowFor(connection.source(), connection.destination(), &window)) {
		// window for this node already exists, activate it
		window->SetWorkspaces(B_CURRENT_WORKSPACE);
		window->Activate();
		return B_OK;
	}

	BRect frame = InfoView::M_DEFAULT_FRAME;
	frame.OffsetTo(m_nextWindowPosition);
	m_nextWindowPosition += M_DEFAULT_OFFSET;
	window = new InfoWindow(frame);

	if (_addWindowFor(connection, window)) {
		window->AddChild(new ConnectionInfoView(connection));
		window->Show();
		return B_OK;
	}

	// failed
	delete window;
	return B_ERROR;
}

status_t InfoWindowManager::openWindowFor(
	const media_input &input) {
	D_WINDOW(("InfoWindowManager::openWindowFor(input)\n"));

	// make absolutely sure we're locked
	if (!IsLocked()) {
		debugger("The looper must be locked !");
	}

	BWindow *window = 0;
	if (_findWindowFor(input.destination, &window)) {
		// window for this node already exists, activate it
		window->SetWorkspaces(B_CURRENT_WORKSPACE);
		window->Activate();
		return B_OK;
	}

	BRect frame = InfoView::M_DEFAULT_FRAME;
	frame.OffsetTo(m_nextWindowPosition);
	m_nextWindowPosition += M_DEFAULT_OFFSET;
	window = new InfoWindow(frame);

	if (_addWindowFor(input, window)) {
		window->AddChild(new EndPointInfoView(input));
		window->Show();
		return B_OK;
	}

	// failed
	delete window;
	return B_ERROR;
}

status_t InfoWindowManager::openWindowFor(
	const media_output &output) {
	D_WINDOW(("InfoWindowManager::openWindowFor(output)\n"));

	// make absolutely sure we're locked
	if (!IsLocked()) {
		debugger("The looper must be locked !");
	}

	BWindow *window = 0;
	if (_findWindowFor(output.source, &window)) {
		// window for this node already exists, activate it
		window->SetWorkspaces(B_CURRENT_WORKSPACE);
		window->Activate();
		return B_OK;
	}

	BRect frame = InfoView::M_DEFAULT_FRAME;
	frame.OffsetTo(m_nextWindowPosition);
	m_nextWindowPosition += M_DEFAULT_OFFSET;
	window = new BWindow(frame, "", B_DOCUMENT_WINDOW, 0);

	if (_addWindowFor(output, window)) {
		window->AddChild(new EndPointInfoView(output));
		window->Show();
		return B_OK;
	}

	// failed
	delete window;
	return B_ERROR;
}

// -------------------------------------------------------- //
// *** BLooper impl
// -------------------------------------------------------- //

void InfoWindowManager::MessageReceived(
	BMessage *message) {
	D_MESSAGE(("InfoWindowManager::MessageReceived()\n"));

	switch (message->what) {
		case M_LIVE_NODE_WINDOW_CLOSED: {
			D_MESSAGE((" -> M_LIVE_NODE_WINDOW_CLOSED\n"));
			int32 nodeID;
			if (message->FindInt32("nodeID", &nodeID) != B_OK) {
				return;
			}
			_removeWindowFor(nodeID);
			break;
		}
		case M_DORMANT_NODE_WINDOW_CLOSED: {
			D_MESSAGE((" -> M_DORMANT_NODE_WINDOW_CLOSED\n"));
			dormant_node_info info;
			if (message->FindInt32("addOnID", &info.addon) != B_OK) {
				return;
			}
			if (message->FindInt32("flavorID", &info.flavor_id) != B_OK) {
				return;
			}
			_removeWindowFor(info);
			break;
		}
		case M_CONNECTION_WINDOW_CLOSED: {
			D_MESSAGE((" -> M_CONNECTION_WINDOW_CLOSED\n"));
			media_source source;
			if (message->FindInt32("source_port", &source.port) != B_OK) {
				return;
			}
			if (message->FindInt32("source_id", &source.id) != B_OK) {
				return;
			}
			media_destination destination;
			if (message->FindInt32("destination_port", &destination.port) != B_OK) {
				return;
			}
			if (message->FindInt32("destination_id", &destination.id) != B_OK) {
				return;
			}
			_removeWindowFor(source, destination);
			break;
		}
		case M_INPUT_WINDOW_CLOSED: {
			D_MESSAGE((" -> M_INPUT_WINDOW_CLOSED\n"));
			media_destination destination;
			if (message->FindInt32("destination_port", &destination.port) != B_OK) {
				return;
			}
			if (message->FindInt32("destination_id", &destination.id) != B_OK) {
				return;
			}
			_removeWindowFor(destination);
			break;
		}
		case M_OUTPUT_WINDOW_CLOSED: {
			D_MESSAGE((" -> M_OUTPUT_WINDOW_CLOSED\n"));
			media_source source;
			if (message->FindInt32("source_port", &source.port) != B_OK) {
				return;
			}
			if (message->FindInt32("source_id", &source.id) != B_OK) {
				return;
			}
			_removeWindowFor(source);
			break;
		}
		case NodeRef::M_RELEASED: {
			D_MESSAGE((" -> NodeRef::M_RELEASED\n"));
			int32 nodeID;
			if (message->FindInt32("nodeID", &nodeID) != B_OK) {
				return;
			}
			BWindow *window;
			if (_findWindowFor(nodeID, &window)) {
				window->Lock();
				window->Quit();
				_removeWindowFor(nodeID);
			}
			break;
		}
		case B_MEDIA_CONNECTION_BROKEN: {
			D_MESSAGE((" -> B_MEDIA_CONNECTION_BROKEN\n"));
			const void *data;
			ssize_t dataSize;
			if (message->FindData("source", B_RAW_TYPE, &data, &dataSize) != B_OK) {
				return;
			}
			const media_source source = *reinterpret_cast<const media_source *>(data);
			if (message->FindData("destination", B_RAW_TYPE, &data, &dataSize) != B_OK) {
				return;
			}
			const media_destination destination = *reinterpret_cast<const media_destination *>(data);
			BWindow *window;
			if (_findWindowFor(source, destination, &window)) {
				window->Lock();
				window->Quit();
				_removeWindowFor(source, destination);
			}
			break;
		}
		default: {
			BLooper::MessageReceived(message);
		}
	}
}

// -------------------------------------------------------- //
// *** internal operations
// -------------------------------------------------------- //

bool InfoWindowManager::_addWindowFor(
	const NodeRef *ref,
	BWindow *window) {
	D_INTERNAL(("InfoWindowManager::_addWindowFor(live_node)\n"));

	if (!m_liveNodeWindows) {
		m_liveNodeWindows = new BList();
	}

	live_node_window *entry = new live_node_window(ref, window);
	if (m_liveNodeWindows->AddItem(reinterpret_cast<void *>(entry))) {
		add_observer(this, entry->ref);
		return true;
	}

	return false;
}

bool InfoWindowManager::_findWindowFor(
	int32 nodeID,
	BWindow **outWindow) {
	D_INTERNAL(("InfoWindowManager::_findWindowFor(live_node)\n"));

	if (!m_liveNodeWindows) {
		return false;
	}

	for (int32 i = 0; i < m_liveNodeWindows->CountItems(); i++) {
		live_node_window *entry = static_cast<live_node_window *>
								  (m_liveNodeWindows->ItemAt(i));
		if (entry->ref->id() == nodeID) {
			*outWindow = entry->window;
			return true;
		}
	}

	return false;
}

void InfoWindowManager::_removeWindowFor(
	int32 nodeID) {
	D_INTERNAL(("InfoWindowManager::_removeWindowFor(live_node)\n"));

	if (!m_liveNodeWindows) {
		return;
	}

	for (int32 i = 0; i < m_liveNodeWindows->CountItems(); i++) {
		live_node_window *entry = static_cast<live_node_window *>
								  (m_liveNodeWindows->ItemAt(i));
		if (entry->ref->id() == nodeID) {
			m_liveNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
			remove_observer(this, entry->ref);
			delete entry;
		}
	}

	if (m_liveNodeWindows->CountItems() <= 0) {
		delete m_liveNodeWindows;
		m_liveNodeWindows = 0;
	}
}

bool InfoWindowManager::_addWindowFor(
	const dormant_node_info &info,
	BWindow *window) {
	D_INTERNAL(("InfoWindowManager::_addWindowFor(dormant_node)\n"));

	if (!m_dormantNodeWindows) {
		m_dormantNodeWindows = new BList();
	}

	dormant_node_window *entry = new dormant_node_window(info, window);
	return m_dormantNodeWindows->AddItem(reinterpret_cast<void *>(entry));
}

bool InfoWindowManager::_findWindowFor(
	const dormant_node_info &info,
	BWindow **outWindow) {
	D_INTERNAL(("InfoWindowManager::_findWindowFor(dormant_node)\n"));

	if (!m_dormantNodeWindows) {
		return false;
	}

	for (int32 i = 0; i < m_dormantNodeWindows->CountItems(); i++) {
		dormant_node_window *entry = static_cast<dormant_node_window *>
									 (m_dormantNodeWindows->ItemAt(i));
		if ((entry->info.addon == info.addon) 
		 && (entry->info.flavor_id == info.flavor_id)) {
			*outWindow = entry->window;
			return true;
		}
	}

	return false;
}

void InfoWindowManager::_removeWindowFor(
	const dormant_node_info &info) {
	D_INTERNAL(("InfoWindowManager::_removeWindowFor(dormant_node)\n"));

	if (!m_dormantNodeWindows) {
		return;
	}

	for (int32 i = 0; i < m_dormantNodeWindows->CountItems(); i++) {
		dormant_node_window *entry = static_cast<dormant_node_window *>
									 (m_dormantNodeWindows->ItemAt(i));
		if ((entry->info.addon == info.addon) 
		 && (entry->info.flavor_id == info.flavor_id)) {
			m_dormantNodeWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}
	}

	if (m_dormantNodeWindows->CountItems() >= 0) {
		delete m_dormantNodeWindows;
		m_dormantNodeWindows = 0;
	}
}

bool InfoWindowManager::_addWindowFor(
	const Connection &connection,
	BWindow *window) {
	D_INTERNAL(("InfoWindowManager::_addWindowFor(connection)\n"));

	if (!m_connectionWindows) {
		m_connectionWindows = new BList();
	}

	connection_window *entry = new connection_window(connection.source(),
													 connection.destination(),
													 window);
	return m_connectionWindows->AddItem(reinterpret_cast<void *>(entry));
}

bool InfoWindowManager::_findWindowFor(
	const media_source &source,
	const media_destination &destination,
	BWindow **outWindow) {
	D_INTERNAL(("InfoWindowManager::_findWindowFor(connection)\n"));

	if (!m_connectionWindows) {
		return false;
	}

	for (int32 i = 0; i < m_connectionWindows->CountItems(); i++) {
		connection_window *entry = static_cast<connection_window *>
								   (m_connectionWindows->ItemAt(i));
		if ((entry->source == source) 
		 && (entry->destination == destination)) {
			*outWindow = entry->window;
			return true;
		}
	}

	return false;
}

void InfoWindowManager::_removeWindowFor(
	const media_source &source,
	const media_destination &destination) {
	D_INTERNAL(("InfoWindowManager::_removeWindowFor(connection)\n"));

	if (!m_connectionWindows) {
		return;
	}

	for (int32 i = 0; i < m_connectionWindows->CountItems(); i++) {
		connection_window *entry = static_cast<connection_window *>
								   (m_connectionWindows->ItemAt(i));
		if ((entry->source == source) 
		 && (entry->destination == destination)) {
			m_connectionWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}
	}

	if (m_connectionWindows->CountItems() >= 0) {
		delete m_connectionWindows;
		m_connectionWindows = 0;
	}
}

bool InfoWindowManager::_addWindowFor(
	const media_input &input,
	BWindow *window) {
	D_INTERNAL(("InfoWindowManager::_addWindowFor(input)\n"));

	if (!m_inputWindows) {
		m_inputWindows = new BList();
	}

	input_window *entry = new input_window(input.destination, window);
	return m_inputWindows->AddItem(reinterpret_cast<void *>(entry));
}

bool InfoWindowManager::_findWindowFor(
	const media_destination &destination,
	BWindow **outWindow) {
	D_INTERNAL(("InfoWindowManager::_findWindowFor(input)\n"));

	if (!m_inputWindows) {
		return false;
	}

	for (int32 i = 0; i < m_inputWindows->CountItems(); i++) {
		input_window *entry = static_cast<input_window *>
							  (m_inputWindows->ItemAt(i));
		if (entry->destination == destination) {
			*outWindow = entry->window;
			return true;
		}
	}

	return false;
}

void InfoWindowManager::_removeWindowFor(
	const media_destination &destination) {
	D_INTERNAL(("InfoWindowManager::_removeWindowFor(input)\n"));

	if (!m_inputWindows) {
		return;
	}

	for (int32 i = 0; i < m_inputWindows->CountItems(); i++) {
		input_window *entry = static_cast<input_window *>
							  (m_inputWindows->ItemAt(i));
		if (entry->destination == destination) {
			m_inputWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}
	}

	if (m_inputWindows->CountItems() >= 0) {
		delete m_inputWindows;
		m_inputWindows = 0;
	}
}

bool InfoWindowManager::_addWindowFor(
	const media_output &output,
	BWindow *window) {
	D_INTERNAL(("InfoWindowManager::_addWindowFor(output)\n"));

	if (!m_outputWindows) {
		m_outputWindows = new BList();
	}

	output_window *entry = new output_window(output.source, window);
	return m_outputWindows->AddItem(reinterpret_cast<void *>(entry));
}

bool InfoWindowManager::_findWindowFor(
	const media_source &source,
	BWindow **outWindow) {
	D_INTERNAL(("InfoWindowManager::_findWindowFor(output)\n"));

	if (!m_outputWindows) {
		return false;
	}

	for (int32 i = 0; i < m_outputWindows->CountItems(); i++) {
		output_window *entry = static_cast<output_window *>
							  (m_outputWindows->ItemAt(i));
		if (entry->source == source) {
			*outWindow = entry->window;
			return true;
		}
	}

	return false;
}

void InfoWindowManager::_removeWindowFor(
	const media_source &source) {
	D_INTERNAL(("InfoWindowManager::_removeWindowFor(output)\n"));

	if (!m_outputWindows) {
		return;
	}

	for (int32 i = 0; i < m_outputWindows->CountItems(); i++) {
		output_window *entry = static_cast<output_window *>
							  (m_outputWindows->ItemAt(i));
		if (entry->source == source) {
			m_outputWindows->RemoveItem(reinterpret_cast<void *>(entry));
			delete entry;
		}
	}

	if (m_outputWindows->CountItems() >= 0) {
		delete m_outputWindows;
		m_outputWindows = 0;
	}
}

// END -- InfoWindowManager.cpp --