xref: /haiku/src/preferences/media/MediaWindow.cpp (revision a906d0a031e721e2f2ec9d95274103e74a3a774f)
1 /*
2  * Copyright (c) 2003-2005, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Sikosis, Jérôme Duval
7  */
8 
9 
10 #include "MediaWindow.h"
11 
12 #include <stdio.h>
13 
14 #include <Alert.h>
15 #include <Application.h>
16 #include <Autolock.h>
17 #include <Bitmap.h>
18 #include <Button.h>
19 #include <Catalog.h>
20 #include <Debug.h>
21 #include <Deskbar.h>
22 #include <GroupView.h>
23 #include <Locale.h>
24 #include <MediaRoster.h>
25 #include <MediaTheme.h>
26 #include <Resources.h>
27 #include <Roster.h>
28 #include <Screen.h>
29 #include <ScrollView.h>
30 #include <SeparatorView.h>
31 #include <SpaceLayoutItem.h>
32 #include <StorageKit.h>
33 #include <String.h>
34 #include <TextView.h>
35 
36 #include "MediaIcons.h"
37 
38 
39 #undef B_TRANSLATE_CONTEXT
40 #define B_TRANSLATE_CONTEXT "Media Window"
41 
42 
43 const uint32 ML_SELECTED_NODE = 'MlSN';
44 const uint32 ML_INIT_MEDIA = 'MlIM';
45 
46 
47 MediaWindow::SmartNode::SmartNode(const BMessenger& notifyHandler)
48 	:
49 	fNode(NULL),
50 	fMessenger(notifyHandler)
51 {
52 }
53 
54 
55 MediaWindow::SmartNode::~SmartNode()
56 {
57 	_FreeNode();
58 }
59 
60 
61 void
62 MediaWindow::SmartNode::SetTo(dormant_node_info* info)
63 {
64 	_FreeNode();
65 	if (!info)
66 		return;
67 
68 	fNode = new media_node();
69 
70 	// TODO: check error codes
71 	BMediaRoster* roster = BMediaRoster::Roster();
72 
73 	media_node_id node_id;
74 	if (roster->GetInstancesFor(info->addon, info->flavor_id, &node_id) == B_OK)
75 		roster->GetNodeFor(node_id, fNode);
76 	else
77 		roster->InstantiateDormantNode(*info, fNode, B_FLAVOR_IS_GLOBAL);
78 	roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
79 }
80 
81 
82 void
83 MediaWindow::SmartNode::SetTo(const media_node& node)
84 {
85 	_FreeNode();
86 	fNode = new media_node(node);
87 	BMediaRoster* roster = BMediaRoster::Roster();
88 	roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
89 }
90 
91 
92 bool
93 MediaWindow::SmartNode::IsSet()
94 {
95 	return fNode != NULL;
96 }
97 
98 
99 MediaWindow::SmartNode::operator media_node()
100 {
101 	if (fNode)
102 		return *fNode;
103 	media_node node;
104 	return node;
105 }
106 
107 
108 void
109 MediaWindow::SmartNode::_FreeNode()
110 {
111 	if (!IsSet())
112 		return;
113 	// TODO: check error codes
114 	BMediaRoster* roster = BMediaRoster::Roster();
115 	roster->StopWatching(fMessenger, *fNode, B_MEDIA_WILDCARD);
116 	roster->ReleaseNode(*fNode);
117 	delete fNode;
118 	fNode = NULL;
119 }
120 
121 
122 // MediaWindow - Constructor
123 MediaWindow::MediaWindow(BRect frame)
124 	:
125 	BWindow (frame, B_TRANSLATE("Media"), B_TITLED_WINDOW,
126 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
127 	fCurrentNode(BMessenger(this)),
128 	fParamWeb(NULL),
129 	fAudioInputs(5, true),
130 	fAudioOutputs(5, true),
131 	fVideoInputs(5, true),
132 	fVideoOutputs(5, true),
133 	fAlert(NULL),
134 	fInitCheck(B_OK)
135 {
136 	InitWindow();
137 }
138 
139 
140 status_t
141 MediaWindow::InitCheck()
142 {
143 	return fInitCheck;
144 }
145 
146 
147 MediaWindow::~MediaWindow()
148 {
149 	_EmptyNodeLists();
150 	_ClearParamView();
151 	delete fVideoView;
152 	delete fAudioView;
153 
154 	char buffer[512];
155 	BRect rect = Frame();
156 	PRINT_OBJECT(rect);
157 	sprintf(buffer, "# MediaPrefs Settings\n rect = %i,%i,%i,%i\n",
158 		int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
159 
160 	BPath path;
161 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
162 		path.Append(SETTINGS_FILE);
163 		BFile file(path.Path(), B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE);
164 		if (file.InitCheck()==B_OK) {
165 			file.Write(buffer, strlen(buffer));
166 		}
167 	}
168 }
169 
170 
171 void
172 MediaWindow::SelectNode(dormant_node_info* node)
173 {
174 	fCurrentNode.SetTo(node);
175 	_MakeParamView();
176 	fTitleView->SetLabel(node->name);
177 }
178 
179 
180 void
181 MediaWindow::SelectAudioSettings(const char* title)
182 {
183 	fContentView->AddChild(fAudioView);
184 	fTitleView->SetLabel(title);
185 }
186 
187 
188 void
189 MediaWindow::SelectVideoSettings(const char* title)
190 {
191 	fContentView->AddChild(fVideoView);
192 	fTitleView->SetLabel(title);
193 }
194 
195 
196 void
197 MediaWindow::SelectAudioMixer(const char* title)
198 {
199 	media_node mixerNode;
200 	BMediaRoster* roster = BMediaRoster::Roster();
201 	roster->GetAudioMixer(&mixerNode);
202 	fCurrentNode.SetTo(mixerNode);
203 	_MakeParamView();
204 	fTitleView->SetLabel(title);
205 }
206 
207 
208 void
209 MediaWindow::_FindNodes()
210 {
211 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
212 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
213 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
214 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
215 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
216 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
217 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
218 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
219 }
220 
221 
222 void
223 MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into)
224 {
225 	dormant_node_info node_info[64];
226 	int32 node_info_count = 64;
227 
228 	media_format format;
229 	media_format* nodeInputFormat = NULL, *nodeOutputFormat = NULL;
230 	format.type = type;
231 
232 	// output nodes must be BBufferConsumers => they have an input format
233 	// input nodes must be BBufferProducers => they have an output format
234 	if (kind & B_PHYSICAL_OUTPUT)
235 		nodeInputFormat = &format;
236 	else if (kind & B_PHYSICAL_INPUT)
237 		nodeOutputFormat = &format;
238 	else
239 		return;
240 
241 	BMediaRoster* roster = BMediaRoster::Roster();
242 
243 	if (roster->GetDormantNodes(node_info, &node_info_count, nodeInputFormat,
244 		nodeOutputFormat, NULL, kind) != B_OK) {
245 		// TODO: better error reporting!
246 		fprintf(stderr, "error\n");
247 		return;
248 	}
249 
250 	for (int32 i = 0; i < node_info_count; i++) {
251 		PRINT(("node : %s, media_addon %i, flavor_id %i\n",
252 			node_info[i].name, node_info[i].addon, node_info[i].flavor_id));
253 
254 		dormant_node_info* info = new dormant_node_info();
255 		strncpy(info->name, node_info[i].name, B_MEDIA_NAME_LENGTH);
256 		info->flavor_id = node_info[i].flavor_id;
257 		info->addon = node_info[i].addon;
258 		into.AddItem(info);
259 	}
260 }
261 
262 
263 NodeListItem*
264 MediaWindow::_FindNodeListItem(dormant_node_info* info)
265 {
266 	for (int32 i = 0; i < fListView->CountItems(); i++) {
267 		MediaListItem* item
268 			= static_cast<MediaListItem*>(fListView->ItemAt(i));
269 		dormant_node_info* itemInfo = item->NodeInfo();
270 		if (itemInfo && itemInfo->addon == info->addon
271 				&& itemInfo->flavor_id == info->flavor_id) {
272 			return dynamic_cast<NodeListItem*>(item);
273 		}
274 	}
275 	return NULL;
276 }
277 
278 
279 void
280 MediaWindow::_AddNodeItems(NodeList &list, MediaListItem::media_type type)
281 {
282 	int32 count = list.CountItems();
283 	for (int32 i = 0; i < count; i++) {
284 		dormant_node_info* info = list.ItemAt(i);
285 		if (!_FindNodeListItem(info))
286 			fListView->AddItem(new NodeListItem(info, type));
287 	}
288 }
289 
290 
291 void
292 MediaWindow::_EmptyNodeLists()
293 {
294 	fAudioOutputs.MakeEmpty();
295 	fAudioInputs.MakeEmpty();
296 	fVideoOutputs.MakeEmpty();
297 	fVideoInputs.MakeEmpty();
298 }
299 
300 
301 void
302 MediaWindow::InitWindow()
303 {
304 	const float scrollWidth = 9 * be_plain_font->Size() + 30;
305 
306 	fListView = new BListView("media_list_view");
307 	fListView->SetSelectionMessage(new BMessage(ML_SELECTED_NODE));
308 
309 	// Add ScrollView to Media Menu
310 	BScrollView* scrollView = new BScrollView("listscroller",
311 		fListView, 0, false, false, B_FANCY_BORDER);
312 	scrollView->SetExplicitMinSize(BSize(scrollWidth, B_SIZE_UNSET));
313 	scrollView->SetExplicitMaxSize(BSize(scrollWidth, B_SIZE_UNSET));
314 
315 	// Create the Views
316 	fBox = new BBox("background", B_WILL_DRAW | B_FRAME_EVENTS,
317 		B_PLAIN_BORDER);
318 	SetLayout(new BGroupLayout(B_HORIZONTAL));
319 	GetLayout()->AddView(fBox);
320 
321 	// StringViews
322 	fTitleView = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER);
323 	fTitleView->SetLabel(B_TRANSLATE("Audio settings"));
324 	fTitleView->SetFont(be_bold_font);
325 
326 	fContentView = new BBox("contentView", B_WILL_DRAW | B_FRAME_EVENTS,
327 		B_NO_BORDER);
328 
329 	fAudioView = new SettingsView(false);
330 	fVideoView = new SettingsView(true);
331 
332 
333 	// Layout all views
334 	BGroupView* rightView = new BGroupView(B_VERTICAL, 5);
335 	rightView->GroupLayout()->SetInsets(14, 0, 0, 0);
336 	rightView->GroupLayout()->AddView(fTitleView);
337 	rightView->GroupLayout()->AddView(fContentView);
338 
339 	BGroupLayout* rootLayout = new BGroupLayout(B_HORIZONTAL);
340 	rootLayout->SetInsets(14, 14, 14, 14);
341 	fBox->SetLayout(rootLayout);
342 
343 	rootLayout->AddView(scrollView);
344 
345 	rootLayout->AddView(rightView);
346 
347 	// Start the window
348 	fInitCheck = InitMedia(true);
349 	if (fInitCheck != B_OK) {
350 		PostMessage(B_QUIT_REQUESTED);
351 	} else {
352 		if (IsHidden())
353 			Show();
354 	}
355 }
356 
357 
358 // #pragma mark -
359 
360 
361 status_t
362 MediaWindow::InitMedia(bool first)
363 {
364 	status_t err = B_OK;
365 	BMediaRoster* roster = BMediaRoster::Roster(&err);
366 
367 	if (first && err != B_OK) {
368 		BAlert* alert = new BAlert("start_media_server",
369 			B_TRANSLATE("Could not connect to the media server.\n"
370 			"Would you like to start it ?"),
371 			B_TRANSLATE("Quit"),
372 			B_TRANSLATE("Start media server"), NULL,
373 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
374 		if (alert->Go()==0)
375 			return B_ERROR;
376 
377 		fAlert = new MediaAlert(BRect(0, 0, 300, 60),
378 			"restart_alert", B_TRANSLATE(
379 				"Restarting media services\nStarting media server"
380 				B_UTF8_ELLIPSIS "\n"));
381 		fAlert->Show();
382 
383 		Show();
384 
385 		launch_media_server();
386 	}
387 
388 	Lock();
389 
390 	bool isVideoSelected = true;
391 	if (!first && fListView->ItemAt(0) && fListView->ItemAt(0)->IsSelected())
392 		isVideoSelected = false;
393 
394 	if ((!first || (first && err) ) && fAlert) {
395 		BAutolock locker(fAlert);
396 		if (locker.IsLocked())
397 			fAlert->TextView()->SetText(
398 				B_TRANSLATE("Ready for use" B_UTF8_ELLIPSIS));
399 	}
400 
401 	while (fListView->CountItems() > 0)
402 		delete static_cast<MediaListItem*>(fListView->RemoveItem((int32)0));
403 	_EmptyNodeLists();
404 
405 	// Grab Media Info
406 	_FindNodes();
407 
408 	// Add video nodes first. They might have an additional audio
409 	// output or input, but still should be listed as video node.
410 	_AddNodeItems(fVideoOutputs, MediaListItem::VIDEO_TYPE);
411 	_AddNodeItems(fVideoInputs, MediaListItem::VIDEO_TYPE);
412 	_AddNodeItems(fAudioOutputs, MediaListItem::AUDIO_TYPE);
413 	_AddNodeItems(fAudioInputs, MediaListItem::AUDIO_TYPE);
414 
415 	fAudioView->AddNodes(fAudioOutputs, false);
416 	fAudioView->AddNodes(fAudioInputs, true);
417 	fVideoView->AddNodes(fVideoOutputs, false);
418 	fVideoView->AddNodes(fVideoInputs, true);
419 
420 	// build our list view
421 	DeviceListItem* audio = new DeviceListItem(B_TRANSLATE("Audio settings"),
422 		MediaListItem::AUDIO_TYPE);
423 	fListView->AddItem(audio);
424 
425 	MediaListItem* video = new DeviceListItem(B_TRANSLATE("Video settings"),
426 		MediaListItem::VIDEO_TYPE);
427 	fListView->AddItem(video);
428 
429 	MediaListItem* mixer = new AudioMixerListItem(B_TRANSLATE("Audio mixer"));
430 	fListView->AddItem(mixer);
431 
432 	fListView->SortItems(&MediaListItem::Compare);
433 
434 	// Set default nodes for our setting views
435 	media_node default_node;
436 	dormant_node_info node_info;
437 	int32 outputID;
438 	BString outputName;
439 
440 	if (roster->GetAudioInput(&default_node) == B_OK) {
441 		roster->GetDormantNodeFor(default_node, &node_info);
442 		NodeListItem* item = _FindNodeListItem(&node_info);
443 		if (item)
444 			item->SetDefaultInput(true);
445 		fAudioView->SetDefault(node_info, true);
446 	}
447 
448 	if (roster->GetAudioOutput(&default_node, &outputID, &outputName)==B_OK) {
449 		roster->GetDormantNodeFor(default_node, &node_info);
450 		NodeListItem* item = _FindNodeListItem(&node_info);
451 		if (item)
452 			item->SetDefaultOutput(true);
453 		fAudioView->SetDefault(node_info, false, outputID);
454 	}
455 
456 	if (roster->GetVideoInput(&default_node)==B_OK) {
457 		roster->GetDormantNodeFor(default_node, &node_info);
458 		NodeListItem* item = _FindNodeListItem(&node_info);
459 		if (item)
460 			item->SetDefaultInput(true);
461 		fVideoView->SetDefault(node_info, true);
462 	}
463 
464 	if (roster->GetVideoOutput(&default_node)==B_OK) {
465 		roster->GetDormantNodeFor(default_node, &node_info);
466 		NodeListItem* item = _FindNodeListItem(&node_info);
467 		if (item)
468 			item->SetDefaultOutput(true);
469 		fVideoView->SetDefault(node_info, false);
470 	}
471 
472 	if (first) {
473 		fListView->Select(fListView->IndexOf(mixer));
474 	} else {
475 		if (!fAudioView->fRestartView->IsHidden())
476 			fAudioView->fRestartView->Hide();
477 		if (!fVideoView->fRestartView->IsHidden())
478 			fVideoView->fRestartView->Hide();
479 
480 		if (isVideoSelected)
481 			fListView->Select(fListView->IndexOf(video));
482 		else
483 			fListView->Select(fListView->IndexOf(audio));
484 	}
485 
486 	if (fAlert) {
487 		snooze(800000);
488 		fAlert->PostMessage(B_QUIT_REQUESTED);
489 	}
490 	fAlert = NULL;
491 
492 	Unlock();
493 
494 	return B_OK;
495 }
496 
497 
498 bool
499 MediaWindow::QuitRequested()
500 {
501 	// stop watching the MediaRoster
502 	fCurrentNode.SetTo(NULL);
503 	be_app->PostMessage(B_QUIT_REQUESTED);
504 	return true;
505 }
506 
507 
508 void
509 MediaWindow::FrameResized (float width, float height)
510 {
511 	// This makes sure our SideBar colours down to the bottom when resized
512 	BRect r;
513 	r = Bounds();
514 }
515 
516 
517 // ErrorAlert -- Displays a BAlert Box with a Custom Error or Debug Message
518 void
519 ErrorAlert(char* errorMessage) {
520 	printf("%s\n", errorMessage);
521 	BAlert* alert = new BAlert("BAlert", errorMessage, B_TRANSLATE("OK"),
522 		NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
523 	alert->Go();
524 	exit(1);
525 }
526 
527 
528 void
529 MediaWindow::MessageReceived(BMessage* message)
530 {
531 	switch(message->what)
532 	{
533 		case ML_INIT_MEDIA:
534 			InitMedia(false);
535 			break;
536 		case ML_DEFAULTOUTPUT_CHANGE:
537 			{
538 				int32 index;
539 				if (message->FindInt32("index", &index)!=B_OK)
540 					break;
541 				Settings2Item* item = static_cast<Settings2Item*>(
542 					fAudioView->fChannelMenu->ItemAt(index));
543 
544 				if (item) {
545 					BMediaRoster* roster = BMediaRoster::Roster();
546 					roster->SetAudioOutput(*item->fInput);
547 
548 					if (fAudioView->fRestartView->IsHidden())
549 						fAudioView->fRestartView->Show();
550 				} else
551 					fprintf(stderr, "Settings2Item not found\n");
552 			}
553 			break;
554 		case ML_DEFAULT_CHANGE:
555 			{
556 				bool isVideo = true;
557 				bool isInput = true;
558 				if (message->FindBool("isVideo", &isVideo)!=B_OK)
559 					break;
560 				if (message->FindBool("isInput", &isInput)!=B_OK)
561 					break;
562 				int32 index;
563 				if (message->FindInt32("index", &index)!=B_OK)
564 					break;
565 				SettingsView* settingsView = isVideo ? fVideoView : fAudioView;
566 				BMenu* menu = isInput ? settingsView->fInputMenu
567 					: settingsView->fOutputMenu;
568 				SettingsItem* item = static_cast<SettingsItem*>(
569 					menu->ItemAt(index));
570 
571 				if (item) {
572 					PRINT(("isVideo %i isInput %i\n", isVideo, isInput));
573 					BMediaRoster* roster = BMediaRoster::Roster();
574 					if (isVideo) {
575 						if (isInput)
576 							roster->SetVideoInput(*item->fInfo);
577 						else
578 							roster->SetVideoOutput(*item->fInfo);
579 					} else {
580 						if (isInput)
581 							roster->SetAudioInput(*item->fInfo);
582 						else {
583 							roster->SetAudioOutput(*item->fInfo);
584 							fAudioView->SetDefault(*item->fInfo, false, 0);
585 						}
586 					}
587 
588 					NodeListItem* oldListItem = NULL;
589 					MediaListItem::media_type mediaType = isVideo ?
590 						MediaListItem::VIDEO_TYPE : MediaListItem::AUDIO_TYPE;
591 					for (int32 j = 0; j < fListView->CountItems(); j++) {
592 						NodeListItem* item = dynamic_cast<NodeListItem*>(
593 							fListView->ItemAt(j));
594 						if (!oldListItem)
595 							continue;
596 						if (oldListItem->Type() != mediaType)
597 							continue;
598 						if (isInput && !oldListItem->IsDefaultInput()) {
599 							oldListItem = item;
600 							break;
601 						} else if (!isInput && oldListItem->IsDefaultOutput()) {
602 							oldListItem = item;
603 							break;
604 						}
605 					}
606 					if (oldListItem && isInput)
607 						oldListItem->SetDefaultInput(false);
608 					else if (oldListItem && !isInput)
609 						oldListItem->SetDefaultOutput(false);
610 					else
611 						fprintf(stderr, "oldListItem not found\n");
612 
613 					NodeListItem* listItem = _FindNodeListItem(item->fInfo);
614 					if (listItem && isInput)
615 						listItem->SetDefaultInput(true);
616 					else if (listItem && !isInput)
617 						listItem->SetDefaultOutput(true);
618 					else
619 						fprintf(stderr, "MediaListItem not found\n");
620 					fListView->Invalidate();
621 
622 					if (settingsView->fRestartView->IsHidden())
623 						settingsView->fRestartView->Show();
624 				} else
625 					fprintf(stderr, "SettingsItem not found\n");
626 			}
627 			break;
628 		case ML_RESTART_MEDIA_SERVER:
629 		{
630 			thread_id thread = spawn_thread(&MediaWindow::RestartMediaServices,
631 				"restart_thread", B_NORMAL_PRIORITY, this);
632 			if (thread < B_OK)
633 				fprintf(stderr, "couldn't create restart thread\n");
634 			else
635 				resume_thread(thread);
636 			break;
637 		}
638 		case ML_SHOW_VOLUME_CONTROL:
639 		{
640 			BDeskbar deskbar;
641 			if (fAudioView->fVolumeCheckBox->Value() == B_CONTROL_ON) {
642 				BEntry entry("/bin/desklink", true);
643 				int32 id;
644 				entry_ref ref;
645 				status_t status = entry.GetRef(&ref);
646 				if (status == B_OK)
647 					status = deskbar.AddItem(&ref, &id);
648 
649 				if (status != B_OK) {
650 					fprintf(stderr, B_TRANSLATE(
651 						"Couldn't add volume control in Deskbar: %s\n"),
652 						strerror(status));
653 				}
654 			} else {
655 				status_t status = deskbar.RemoveItem("MediaReplicant");
656 				if (status != B_OK) {
657 					fprintf(stderr, B_TRANSLATE(
658 						"Couldn't remove volume control in Deskbar: %s\n"),
659 						strerror(status));
660 				}
661 			}
662 			break;
663 		}
664 		case ML_ENABLE_REAL_TIME:
665 			{
666 				bool isVideo = true;
667 				if (message->FindBool("isVideo", &isVideo) != B_OK)
668 					break;
669 				SettingsView* settingsView = isVideo ? fVideoView : fAudioView;
670 				uint32 flags;
671 				uint32 realtimeFlag = isVideo
672 					? B_MEDIA_REALTIME_VIDEO : B_MEDIA_REALTIME_AUDIO;
673 				BMediaRoster* roster = BMediaRoster::Roster();
674 				roster->GetRealtimeFlags(&flags);
675 				if (settingsView->fRealtimeCheckBox->Value() == B_CONTROL_ON)
676 					flags |= realtimeFlag;
677 				else
678 					flags &= ~realtimeFlag;
679 				roster->SetRealtimeFlags(flags);
680 			}
681 			break;
682 		case B_MEDIA_WEB_CHANGED:
683 		case ML_SELECTED_NODE:
684 			{
685 				PRINT_OBJECT(*message);
686 
687 				MediaListItem* item = static_cast<MediaListItem*>(
688 						fListView->ItemAt(fListView->CurrentSelection()));
689 				if (!item)
690 					break;
691 
692 				fCurrentNode.SetTo(NULL);
693 				_ClearParamView();
694 				item->AlterWindow(this);
695 			}
696 			break;
697 		case B_SOME_APP_LAUNCHED:
698 			{
699 				PRINT_OBJECT(*message);
700 				if (!fAlert)
701 					break;
702 
703 				BString mimeSig;
704 				if (message->FindString("be:signature", &mimeSig) == B_OK
705 					&& (mimeSig == "application/x-vnd.Be.addon-host"
706 						|| mimeSig == "application/x-vnd.Be.media-server")) {
707 					fAlert->Lock();
708 					fAlert->TextView()->SetText(
709 						B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
710 					fAlert->Unlock();
711 				}
712 			}
713 			break;
714 		case B_SOME_APP_QUIT:
715 			{
716 				PRINT_OBJECT(*message);
717 				BString mimeSig;
718 				if (message->FindString("be:signature", &mimeSig) == B_OK) {
719 					if (mimeSig == "application/x-vnd.Be.addon-host"
720 						|| mimeSig == "application/x-vnd.Be.media-server") {
721 						BMediaRoster* roster = BMediaRoster::CurrentRoster();
722 						if (roster && roster->Lock())
723 							roster->Quit();
724 					}
725 				}
726 
727 			}
728 			break;
729 		default:
730 			BWindow::MessageReceived(message);
731 			break;
732 	}
733 }
734 
735 status_t
736 MediaWindow::RestartMediaServices(void* data)
737 {
738 	MediaWindow* window = (MediaWindow*)data;
739 	window->fAlert = new MediaAlert(BRect(0, 0, 300, 60),
740 		"restart_alert", B_TRANSLATE(
741 		"Restarting media services\nShutting down media server\n"));
742 
743 	window->fAlert->Show();
744 
745 	shutdown_media_server(B_INFINITE_TIMEOUT, MediaWindow::UpdateProgress,
746 		window->fAlert);
747 
748 	{
749 		BAutolock locker(window->fAlert);
750 		if (locker.IsLocked())
751 			window->fAlert->TextView()->SetText(
752 				B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
753 	}
754 	launch_media_server();
755 
756 	return window->PostMessage(ML_INIT_MEDIA);
757 }
758 
759 
760 bool
761 MediaWindow::UpdateProgress(int stage, const char * message, void * cookie)
762 {
763 	MediaAlert* alert = static_cast<MediaAlert*>(cookie);
764 	PRINT(("stage : %i\n", stage));
765 	const char* string = "Unknown stage";
766 	switch (stage) {
767 		case 10:
768 			string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS);
769 			break;
770 		case 20:
771 			string = B_TRANSLATE("Telling media_addon_server to quit.");
772 			break;
773 		case 40:
774 			string = B_TRANSLATE("Waiting for media_server to quit.");
775 			break;
776 		case 70:
777 			string = B_TRANSLATE("Cleaning up.");
778 			break;
779 		case 100:
780 			string = B_TRANSLATE("Done shutting down.");
781 			break;
782 	}
783 
784 	BAutolock locker(alert);
785 	if (locker.IsLocked())
786 		alert->TextView()->SetText(string);
787 	return true;
788 }
789 
790 
791 void
792 MediaWindow::_ClearParamView()
793 {
794 	BView* child = fContentView->ChildAt(0);
795 	if (child)
796 		child->RemoveSelf();
797 	if (child != fVideoView && child != fAudioView)
798 		delete child;
799 	delete fParamWeb;
800 	fParamWeb = NULL;
801 }
802 
803 
804 void
805 MediaWindow::_MakeParamView()
806 {
807 	if (!fCurrentNode.IsSet())
808 		return;
809 
810 	fParamWeb = NULL;
811 	BMediaRoster* roster = BMediaRoster::Roster();
812 	if (roster->GetParameterWebFor(fCurrentNode, &fParamWeb) == B_OK) {
813 		BView* paramView = BMediaTheme::ViewFor(fParamWeb);
814 		if (paramView) {
815 			fContentView->AddChild(paramView);
816 			paramView->ResizeTo(1, 1);
817 				// make sure we don't get stuck with a very large
818 				// paramView
819 			return;
820 		}
821 	}
822 	_MakeEmptyParamView();
823 
824 }
825 
826 
827 void
828 MediaWindow::_MakeEmptyParamView()
829 {
830 	fParamWeb = NULL;
831 
832 	BStringView* stringView = new BStringView("noControls",
833 		B_TRANSLATE("This hardware has no controls."));
834 
835 	BSize unlimited(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
836 	stringView->SetExplicitMaxSize(unlimited);
837 
838 	BAlignment centered(B_ALIGN_HORIZONTAL_CENTER,
839 		B_ALIGN_VERTICAL_CENTER);
840 	stringView->SetExplicitAlignment(centered);
841 	stringView->SetAlignment(B_ALIGN_CENTER);
842 
843 	fContentView->AddChild(stringView);
844 
845 	rgb_color panel = stringView->LowColor();
846 	stringView->SetHighColor(tint_color(panel,
847 		B_DISABLED_LABEL_TINT));
848 }
849 
850