xref: /haiku/src/preferences/media/MediaWindow.cpp (revision 644fa5a93845dc4a1bc155f1fd0f94ebdf0b47bc)
1 /*
2  * Copyright 2003-2012, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Sikosis, Jérôme Duval
7  *		yourpalal, Alex Wilson
8  */
9 
10 
11 #include "MediaWindow.h"
12 
13 #include <stdio.h>
14 
15 #include <Alert.h>
16 #include <Application.h>
17 #include <Autolock.h>
18 #include <Bitmap.h>
19 #include <Button.h>
20 #include <CardLayout.h>
21 #include <Catalog.h>
22 #include <Debug.h>
23 #include <Deskbar.h>
24 #include <IconUtils.h>
25 #include <LayoutBuilder.h>
26 #include <Locale.h>
27 #include <MediaRoster.h>
28 #include <MediaTheme.h>
29 #include <Notification.h>
30 #include <Resources.h>
31 #include <Roster.h>
32 #include <Screen.h>
33 #include <ScrollView.h>
34 #include <SeparatorView.h>
35 #include <SpaceLayoutItem.h>
36 #include <StorageKit.h>
37 #include <String.h>
38 #include <TextView.h>
39 
40 #include "Media.h"
41 #include "MediaIcons.h"
42 #include "MidiSettingsView.h"
43 
44 #undef B_TRANSLATION_CONTEXT
45 #define B_TRANSLATION_CONTEXT "Media Window"
46 
47 
48 const uint32 ML_SELECTED_NODE = 'MlSN';
49 const uint32 ML_INIT_MEDIA = 'MlIM';
50 
51 
52 class NodeListItemUpdater : public MediaListItem::Visitor {
53 public:
54 	typedef void (NodeListItem::*UpdateMethod)(bool);
55 
56 	NodeListItemUpdater(NodeListItem* target, UpdateMethod action)
57 		:
58 		fComparator(target),
59 		fAction(action)
60 	{
61 	}
62 
63 
64 	virtual	void	Visit(AudioMixerListItem*){}
65 	virtual	void	Visit(DeviceListItem*){}
66 	virtual	void	Visit(MidiListItem*){}
67 	virtual void	Visit(NodeListItem* item)
68 	{
69 		item->Accept(fComparator);
70 		(item->*(fAction))(fComparator.result == 0);
71 	}
72 
73 private:
74 
75 			NodeListItem::Comparator		fComparator;
76 			UpdateMethod					fAction;
77 };
78 
79 
80 MediaWindow::SmartNode::SmartNode(const BMessenger& notifyHandler)
81 	:
82 	fNode(NULL),
83 	fMessenger(notifyHandler)
84 {
85 }
86 
87 
88 MediaWindow::SmartNode::~SmartNode()
89 {
90 	_FreeNode();
91 }
92 
93 
94 void
95 MediaWindow::SmartNode::SetTo(const dormant_node_info* info)
96 {
97 	_FreeNode();
98 	if (!info)
99 		return;
100 
101 	fNode = new media_node();
102 	BMediaRoster* roster = BMediaRoster::Roster();
103 
104 	// TODO: error codes
105 	media_node_id node_id;
106 	if (roster->GetInstancesFor(info->addon, info->flavor_id, &node_id) == B_OK)
107 		roster->GetNodeFor(node_id, fNode);
108 	else
109 		roster->InstantiateDormantNode(*info, fNode, B_FLAVOR_IS_GLOBAL);
110 	roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
111 }
112 
113 
114 void
115 MediaWindow::SmartNode::SetTo(const media_node& node)
116 {
117 	_FreeNode();
118 	fNode = new media_node(node);
119 	BMediaRoster* roster = BMediaRoster::Roster();
120 	roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
121 }
122 
123 
124 bool
125 MediaWindow::SmartNode::IsSet()
126 {
127 	return fNode != NULL;
128 }
129 
130 
131 MediaWindow::SmartNode::operator media_node()
132 {
133 	if (fNode)
134 		return *fNode;
135 	media_node node;
136 	return node;
137 }
138 
139 
140 void
141 MediaWindow::SmartNode::_FreeNode()
142 {
143 	if (!IsSet())
144 		return;
145 	// TODO: check error codes
146 	BMediaRoster* roster = BMediaRoster::Roster();
147 	roster->StopWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
148 	roster->ReleaseNode(*fNode);
149 	delete fNode;
150 	fNode = NULL;
151 }
152 
153 
154 // #pragma mark -
155 
156 
157 MediaWindow::MediaWindow(BRect frame)
158 	:
159 	BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Media"), B_TITLED_WINDOW,
160 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
161 	fCurrentNode(BMessenger(this)),
162 	fParamWeb(NULL),
163 	fAudioInputs(5, true),
164 	fAudioOutputs(5, true),
165 	fVideoInputs(5, true),
166 	fVideoOutputs(5, true),
167 	fInitCheck(B_OK)
168 {
169 	_InitWindow();
170 }
171 
172 
173 MediaWindow::~MediaWindow()
174 {
175 	_EmptyNodeLists();
176 	_ClearParamView();
177 
178 	char buffer[512];
179 	BRect rect = Frame();
180 	PRINT_OBJECT(rect);
181 	snprintf(buffer, 512, "# MediaPrefs Settings\n rect = %i,%i,%i,%i\n",
182 		int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
183 
184 	BPath path;
185 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
186 		path.Append(SETTINGS_FILE);
187 		BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
188 		if (file.InitCheck() == B_OK)
189 			file.Write(buffer, strlen(buffer));
190 	}
191 }
192 
193 
194 status_t
195 MediaWindow::InitCheck()
196 {
197 	return fInitCheck;
198 }
199 
200 
201 void
202 MediaWindow::SelectNode(const dormant_node_info* node)
203 {
204 	fCurrentNode.SetTo(node);
205 	_MakeParamView();
206 	fTitleView->SetLabel(node->name);
207 }
208 
209 
210 void
211 MediaWindow::SelectAudioSettings(const char* title)
212 {
213 	fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fAudioView));
214 	fTitleView->SetLabel(title);
215 }
216 
217 
218 void
219 MediaWindow::SelectVideoSettings(const char* title)
220 {
221 	fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fVideoView));
222 	fTitleView->SetLabel(title);
223 }
224 
225 
226 void
227 MediaWindow::SelectAudioMixer(const char* title)
228 {
229 	media_node mixerNode;
230 	BMediaRoster* roster = BMediaRoster::Roster();
231 	roster->GetAudioMixer(&mixerNode);
232 	fCurrentNode.SetTo(mixerNode);
233 	_MakeParamView();
234 	fTitleView->SetLabel(title);
235 }
236 
237 
238 void
239 MediaWindow::SelectMidiSettings(const char* title)
240 {
241 	fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fMidiView));
242 	fTitleView->SetLabel(title);
243 }
244 
245 
246 void
247 MediaWindow::UpdateInputListItem(MediaListItem::media_type type,
248 	const dormant_node_info* node)
249 {
250 	NodeListItem compareTo(node, type);
251 	NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultInput);
252 	for (int32 i = 0; i < fListView->CountItems(); i++) {
253 		MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
254 		item->Accept(updater);
255 	}
256 	fListView->Invalidate();
257 }
258 
259 
260 void
261 MediaWindow::UpdateOutputListItem(MediaListItem::media_type type,
262 	const dormant_node_info* node)
263 {
264 	NodeListItem compareTo(node, type);
265 	NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultOutput);
266 	for (int32 i = 0; i < fListView->CountItems(); i++) {
267 		MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
268 		item->Accept(updater);
269 	}
270 	fListView->Invalidate();
271 }
272 
273 
274 bool
275 MediaWindow::QuitRequested()
276 {
277 	// stop watching the MediaRoster
278 	fCurrentNode.SetTo(NULL);
279 	be_app->PostMessage(B_QUIT_REQUESTED);
280 	return true;
281 }
282 
283 
284 void
285 MediaWindow::MessageReceived(BMessage* message)
286 {
287 	switch (message->what) {
288 		case ML_INIT_MEDIA:
289 			_InitMedia(false);
290 			break;
291 		case ML_RESTART_MEDIA_SERVER:
292 		{
293 			thread_id thread = spawn_thread(&MediaWindow::_RestartMediaServices,
294 				"restart_thread", B_NORMAL_PRIORITY, this);
295 			if (thread < 0)
296 				fprintf(stderr, "couldn't create restart thread\n");
297 			else
298 				resume_thread(thread);
299 			break;
300 		}
301 		case B_MEDIA_WEB_CHANGED:
302 		case ML_SELECTED_NODE:
303 		{
304 			PRINT_OBJECT(*message);
305 
306 			MediaListItem* item = static_cast<MediaListItem*>(
307 					fListView->ItemAt(fListView->CurrentSelection()));
308 			if (item == NULL)
309 				break;
310 
311 			fCurrentNode.SetTo(NULL);
312 			_ClearParamView();
313 			item->AlterWindow(this);
314 			break;
315 		}
316 		case B_SOME_APP_LAUNCHED:
317 		{
318 			PRINT_OBJECT(*message);
319 
320 			BString mimeSig;
321 			if (message->FindString("be:signature", &mimeSig) == B_OK
322 				&& (mimeSig == "application/x-vnd.Be.addon-host"
323 					|| mimeSig == "application/x-vnd.Be.media-server")) {
324 				_Notify(0.75, B_TRANSLATE("Starting media server"
325 					B_UTF8_ELLIPSIS));
326 			}
327 			break;
328 		}
329 		case B_SOME_APP_QUIT:
330 		{
331 			PRINT_OBJECT(*message);
332 			BString mimeSig;
333 			if (message->FindString("be:signature", &mimeSig) == B_OK) {
334 				if (mimeSig == "application/x-vnd.Be.addon-host"
335 					|| mimeSig == "application/x-vnd.Be.media-server") {
336 					BMediaRoster* roster = BMediaRoster::CurrentRoster();
337 					if (roster != NULL && roster->Lock())
338 						roster->Quit();
339 				}
340 			}
341 			break;
342 		}
343 		default:
344 			BWindow::MessageReceived(message);
345 			break;
346 	}
347 }
348 
349 
350 // #pragma mark - private
351 
352 
353 void
354 MediaWindow::_InitWindow()
355 {
356 	fListView = new BListView("media_list_view");
357 	fListView->SetSelectionMessage(new BMessage(ML_SELECTED_NODE));
358 	fListView->SetExplicitMinSize(BSize(140, B_SIZE_UNSET));
359 
360 	// Add ScrollView to Media Menu for pretty border
361 	BScrollView* scrollView = new BScrollView("listscroller",
362 		fListView, 0, false, false, B_FANCY_BORDER);
363 
364 	// Create the Views
365 	fTitleView = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER);
366 	fTitleView->SetLabel(B_TRANSLATE("Audio settings"));
367 	fTitleView->SetFont(be_bold_font);
368 
369 	fContentLayout = new BCardLayout();
370 	new BView("content view", 0, fContentLayout);
371 	fContentLayout->Owner()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
372 	fContentLayout->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
373 
374 	fAudioView = new AudioSettingsView();
375 	fContentLayout->AddView(fAudioView);
376 
377 	fVideoView = new VideoSettingsView();
378 	fContentLayout->AddView(fVideoView);
379 
380 	fMidiView = new MidiSettingsView();
381 	fContentLayout->AddView(fMidiView);
382 
383 	// Layout all views
384 	BLayoutBuilder::Group<>(this, B_HORIZONTAL)
385 		.SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
386 			B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
387 		.Add(scrollView, 0.0f)
388 		.AddGroup(B_VERTICAL)
389 			.SetInsets(0, 0, 0, 0)
390 			.Add(fTitleView)
391 			.Add(fContentLayout);
392 
393 	// Start the window
394 	fInitCheck = _InitMedia(true);
395 	if (fInitCheck != B_OK)
396 		PostMessage(B_QUIT_REQUESTED);
397 	else if (IsHidden())
398 		Show();
399 }
400 
401 
402 status_t
403 MediaWindow::_InitMedia(bool first)
404 {
405 	status_t err = B_OK;
406 	BMediaRoster* roster = BMediaRoster::Roster(&err);
407 
408 	if (first && err != B_OK) {
409 		BAlert* alert = new BAlert("start_media_server",
410 			B_TRANSLATE("Could not connect to the media server.\n"
411 				"Would you like to start it ?"),
412 			B_TRANSLATE("Quit"),
413 			B_TRANSLATE("Start media server"), NULL,
414 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
415 		alert->SetShortcut(0, B_ESCAPE);
416 		if (alert->Go() == 0)
417 			return B_ERROR;
418 
419 		_Notify(0, B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
420 
421 		Show();
422 
423 		launch_media_server();
424 	}
425 
426 	Lock();
427 
428 	bool isVideoSelected = true;
429 	if (!first && fListView->ItemAt(0) != NULL
430 		&& fListView->ItemAt(0)->IsSelected())
431 		isVideoSelected = false;
432 
433 	if (!first || (first && err) )
434 		_Notify(1, B_TRANSLATE("Ready for use" B_UTF8_ELLIPSIS));
435 
436 	while (fListView->CountItems() > 0)
437 		delete fListView->RemoveItem((int32)0);
438 	_EmptyNodeLists();
439 
440 	// Grab Media Info
441 	_FindNodes();
442 
443 	// Add video nodes first. They might have an additional audio
444 	// output or input, but still should be listed as video node.
445 	_AddNodeItems(fVideoOutputs, MediaListItem::VIDEO_TYPE);
446 	_AddNodeItems(fVideoInputs, MediaListItem::VIDEO_TYPE);
447 	_AddNodeItems(fAudioOutputs, MediaListItem::AUDIO_TYPE);
448 	_AddNodeItems(fAudioInputs, MediaListItem::AUDIO_TYPE);
449 
450 	fAudioView->AddOutputNodes(fAudioOutputs);
451 	fAudioView->AddInputNodes(fAudioInputs);
452 	fVideoView->AddOutputNodes(fVideoOutputs);
453 	fVideoView->AddInputNodes(fVideoInputs);
454 
455 	// build our list view
456 	DeviceListItem* audio = new DeviceListItem(B_TRANSLATE("Audio settings"),
457 		MediaListItem::AUDIO_TYPE);
458 	fListView->AddItem(audio);
459 
460 	MidiListItem* midi = new MidiListItem(B_TRANSLATE("MIDI Settings"));
461 	fListView->AddItem(midi);
462 
463 	MediaListItem* video = new DeviceListItem(B_TRANSLATE("Video settings"),
464 		MediaListItem::VIDEO_TYPE);
465 	fListView->AddItem(video);
466 
467 	MediaListItem* mixer = new AudioMixerListItem(B_TRANSLATE("Audio mixer"));
468 	fListView->AddItem(mixer);
469 
470 	fListView->SortItems(&MediaListItem::Compare);
471 	_UpdateListViewMinWidth();
472 
473 	// Set default nodes for our setting views
474 	media_node defaultNode;
475 	dormant_node_info nodeInfo;
476 	int32 outputID;
477 	BString outputName;
478 
479 	if (roster->GetAudioInput(&defaultNode) == B_OK) {
480 		roster->GetDormantNodeFor(defaultNode, &nodeInfo);
481 		fAudioView->SetDefaultInput(&nodeInfo);
482 			// this causes our listview to be updated as well
483 	}
484 
485 	if (roster->GetAudioOutput(&defaultNode, &outputID, &outputName) == B_OK) {
486 		roster->GetDormantNodeFor(defaultNode, &nodeInfo);
487 		fAudioView->SetDefaultOutput(&nodeInfo);
488 		fAudioView->SetDefaultChannel(outputID);
489 			// this causes our listview to be updated as well
490 	}
491 
492 	if (roster->GetVideoInput(&defaultNode) == B_OK) {
493 		roster->GetDormantNodeFor(defaultNode, &nodeInfo);
494 		fVideoView->SetDefaultInput(&nodeInfo);
495 			// this causes our listview to be updated as well
496 	}
497 
498 	if (roster->GetVideoOutput(&defaultNode) == B_OK) {
499 		roster->GetDormantNodeFor(defaultNode, &nodeInfo);
500 		fVideoView->SetDefaultOutput(&nodeInfo);
501 			// this causes our listview to be updated as well
502 	}
503 
504 	if (first)
505 		fListView->Select(fListView->IndexOf(mixer));
506 	else if (isVideoSelected)
507 		fListView->Select(fListView->IndexOf(video));
508 	else
509 		fListView->Select(fListView->IndexOf(audio));
510 
511 	Unlock();
512 
513 	return B_OK;
514 }
515 
516 
517 void
518 MediaWindow::_FindNodes()
519 {
520 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
521 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
522 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
523 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
524 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
525 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
526 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
527 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
528 }
529 
530 
531 void
532 MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into)
533 {
534 	dormant_node_info nodeInfo[64];
535 	int32 nodeInfoCount = 64;
536 
537 	media_format format;
538 	media_format* nodeInputFormat = NULL;
539 	media_format* nodeOutputFormat = NULL;
540 	format.type = type;
541 
542 	// output nodes must be BBufferConsumers => they have an input format
543 	// input nodes must be BBufferProducers => they have an output format
544 	if ((kind & B_PHYSICAL_OUTPUT) != 0)
545 		nodeInputFormat = &format;
546 	else if ((kind & B_PHYSICAL_INPUT) != 0)
547 		nodeOutputFormat = &format;
548 	else
549 		return;
550 
551 	BMediaRoster* roster = BMediaRoster::Roster();
552 
553 	if (roster->GetDormantNodes(nodeInfo, &nodeInfoCount, nodeInputFormat,
554 			nodeOutputFormat, NULL, kind) != B_OK) {
555 		// TODO: better error reporting!
556 		fprintf(stderr, "error\n");
557 		return;
558 	}
559 
560 	for (int32 i = 0; i < nodeInfoCount; i++) {
561 		PRINT(("node : %s, media_addon %i, flavor_id %i\n",
562 			nodeInfo[i].name, (int)nodeInfo[i].addon,
563 			(int)nodeInfo[i].flavor_id));
564 
565 		dormant_node_info* info = new dormant_node_info();
566 		strncpy(info->name, nodeInfo[i].name, B_MEDIA_NAME_LENGTH);
567 		info->flavor_id = nodeInfo[i].flavor_id;
568 		info->addon = nodeInfo[i].addon;
569 		into.AddItem(info);
570 	}
571 }
572 
573 
574 void
575 MediaWindow::_AddNodeItems(NodeList& list, MediaListItem::media_type type)
576 {
577 	int32 count = list.CountItems();
578 	for (int32 i = 0; i < count; i++) {
579 		dormant_node_info* info = list.ItemAt(i);
580 		if (_FindNodeListItem(info) == NULL)
581 			fListView->AddItem(new NodeListItem(info, type));
582 	}
583 }
584 
585 
586 void
587 MediaWindow::_EmptyNodeLists()
588 {
589 	fAudioOutputs.MakeEmpty();
590 	fAudioInputs.MakeEmpty();
591 	fVideoOutputs.MakeEmpty();
592 	fVideoInputs.MakeEmpty();
593 }
594 
595 
596 NodeListItem*
597 MediaWindow::_FindNodeListItem(dormant_node_info* info)
598 {
599 	NodeListItem audioItem(info, MediaListItem::AUDIO_TYPE);
600 	NodeListItem videoItem(info, MediaListItem::VIDEO_TYPE);
601 
602 	NodeListItem::Comparator audioComparator(&audioItem);
603 	NodeListItem::Comparator videoComparator(&videoItem);
604 
605 	for (int32 i = 0; i < fListView->CountItems(); i++) {
606 		MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i));
607 		item->Accept(audioComparator);
608 		if (audioComparator.result == 0)
609 			return static_cast<NodeListItem*>(item);
610 
611 		item->Accept(videoComparator);
612 		if (videoComparator.result == 0)
613 			return static_cast<NodeListItem*>(item);
614 	}
615 	return NULL;
616 }
617 
618 
619 void
620 MediaWindow::_UpdateListViewMinWidth()
621 {
622 	float width = 0;
623 	for (int32 i = 0; i < fListView->CountItems(); i++) {
624 		BListItem* item = fListView->ItemAt(i);
625 		width = max_c(width, item->Width());
626 	}
627 	fListView->SetExplicitMinSize(BSize(width, B_SIZE_UNSET));
628 	fListView->InvalidateLayout();
629 }
630 
631 
632 status_t
633 MediaWindow::_RestartMediaServices(void* data)
634 {
635 	MediaWindow* window = (MediaWindow*)data;
636 
637 	shutdown_media_server(B_INFINITE_TIMEOUT, MediaWindow::_UpdateProgress,
638 		data);
639 
640 	launch_media_server();
641 
642 	return window->PostMessage(ML_INIT_MEDIA);
643 }
644 
645 
646 bool
647 MediaWindow::_UpdateProgress(int stage, const char* message, void* cookie)
648 {
649 	// parameter "message" is no longer used. It is kept for compatibility with
650 	// BeOS as this is used as a shutdown_media_server callback.
651 
652 	PRINT(("stage : %i\n", stage));
653 	const char* string = "Unknown stage";
654 	switch (stage) {
655 		case 10:
656 			string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS);
657 			break;
658 		case 20:
659 			string = B_TRANSLATE("Telling media_addon_server to quit.");
660 			break;
661 		case 40:
662 			string = B_TRANSLATE("Waiting for media_server to quit.");
663 			break;
664 		case 70:
665 			string = B_TRANSLATE("Cleaning up.");
666 			break;
667 		case 100:
668 			string = B_TRANSLATE("Done shutting down.");
669 			break;
670 	}
671 
672 	((MediaWindow*)cookie)->_Notify(stage / 150.0, string);
673 
674 	return true;
675 }
676 
677 
678 void
679 MediaWindow::_Notify(float progress, const char* message)
680 {
681 	BNotification notification(B_PROGRESS_NOTIFICATION);
682 	notification.SetMessageID(MEDIA_SERVICE_NOTIFICATION_ID);
683 	notification.SetProgress(progress);
684 	notification.SetGroup(B_TRANSLATE("Media Service"));
685 	notification.SetContent(message);
686 
687 	app_info info;
688 	be_roster->GetAppInfo(kApplicationSignature, &info);
689 	BBitmap icon(BRect(0, 0, 32, 32), B_RGBA32);
690 	BNode node(&info.ref);
691 	BIconUtils::GetVectorIcon(&node, "BEOS:ICON", &icon);
692 	notification.SetIcon(&icon);
693 
694 	notification.Send();
695 }
696 
697 
698 void
699 MediaWindow::_ClearParamView()
700 {
701 	BLayoutItem* item = fContentLayout->VisibleItem();
702 	if (!item)
703 		return;
704 
705 	BView* view = item->View();
706 	if (view != fVideoView && view != fAudioView && view != fMidiView) {
707 		fContentLayout->RemoveItem(item);
708 		delete item;
709 		delete view;
710 		delete fParamWeb;
711 		fParamWeb = NULL;
712 	}
713 }
714 
715 
716 void
717 MediaWindow::_MakeParamView()
718 {
719 	if (!fCurrentNode.IsSet())
720 		return;
721 
722 	fParamWeb = NULL;
723 	BMediaRoster* roster = BMediaRoster::Roster();
724 	if (roster->GetParameterWebFor(fCurrentNode, &fParamWeb) == B_OK) {
725 		BRect hint(fContentLayout->Frame());
726 		BView* paramView = BMediaTheme::ViewFor(fParamWeb, &hint);
727 		if (paramView) {
728 			fContentLayout->AddView(paramView);
729 			fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1);
730 			return;
731 		}
732 	}
733 
734 	_MakeEmptyParamView();
735 }
736 
737 
738 void
739 MediaWindow::_MakeEmptyParamView()
740 {
741 	fParamWeb = NULL;
742 
743 	BStringView* stringView = new BStringView("noControls",
744 		B_TRANSLATE("This hardware has no controls."));
745 
746 	BSize unlimited(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
747 	stringView->SetExplicitMaxSize(unlimited);
748 
749 	BAlignment centered(B_ALIGN_HORIZONTAL_CENTER,
750 		B_ALIGN_VERTICAL_CENTER);
751 	stringView->SetExplicitAlignment(centered);
752 	stringView->SetAlignment(B_ALIGN_CENTER);
753 
754 	fContentLayout->AddView(stringView);
755 	fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1);
756 
757 	rgb_color panel = stringView->LowColor();
758 	stringView->SetHighColor(tint_color(panel,
759 		B_DISABLED_LABEL_TINT));
760 }
761 
762