xref: /haiku/src/apps/cortex/ParameterView/ParameterWindowManager.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
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
60 struct window_map_entry {
61 
62 public:						// *** ctor/dtor
63 
64 							window_map_entry(
65 								const NodeRef *ref,
66 								BWindow *window)
67 								: ref(ref),
68 								  window(window)
69 							{ }
70 
71 public:						// *** data members
72 
73 	const NodeRef		   *ref;
74 
75 	BWindow				   *window;
76 };
77 
78 // used to remember the list of ControlPanels
79 struct panel_map_entry {
80 
81 public:						// *** ctor/dtor
82 
83 							panel_map_entry(
84 								int32 id,
85 								const BMessenger &messenger)
86 								: id(id),
87 								  messenger(messenger)
88 							{ }
89 
90 public:						// *** data members
91 
92 	int32					id;
93 
94 	const BMessenger		messenger;
95 };
96 
97 // -------------------------------------------------------- //
98 // static member init
99 // -------------------------------------------------------- //
100 
101 const BPoint ParameterWindowManager::M_DEFAULT_OFFSET	= BPoint(20.0, 20.0);
102 const BPoint ParameterWindowManager::M_INIT_POSITION	= BPoint(90.0, 90.0);
103 
104 ParameterWindowManager *ParameterWindowManager::s_instance = 0;
105 
106 // -------------------------------------------------------- //
107 // *** ctor/dtor
108 // -------------------------------------------------------- //
109 
110 /* hidden */
111 ParameterWindowManager::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 
124 ParameterWindowManager::~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*/
159 ParameterWindowManager *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 */
171 void 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 
184 status_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 
220 status_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 
262 void 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 
313 bool 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 
328 bool 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 
345 void 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 
383 bool 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 
397 bool 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 
414 void 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