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