xref: /haiku/src/preferences/media/MediaWindow.cpp (revision 6b0cdfbc24e965bcf4f4d934a719c7a429fe0955)
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 <Roster.h>
27 #include <Screen.h>
28 #include <ScrollView.h>
29 #include <SeparatorView.h>
30 #include <SpaceLayoutItem.h>
31 #include <StorageKit.h>
32 #include <String.h>
33 #include <TextView.h>
34 
35 // Images
36 #include "iconfile.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 // MediaWindow - Constructor
47 MediaWindow::MediaWindow(BRect frame)
48 	:
49 	BWindow (frame, B_TRANSLATE("Media"), B_TITLED_WINDOW,
50 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
51 	fCurrentNode(NULL),
52 	fParamWeb(NULL),
53 	fAudioInputs(5, true),
54 	fAudioOutputs(5, true),
55 	fVideoInputs(5, true),
56 	fVideoOutputs(5, true),
57 	fAlert(NULL),
58 	fInitCheck(B_OK)
59 {
60 	InitWindow();
61 }
62 
63 
64 status_t
65 MediaWindow::InitCheck()
66 {
67 	return fInitCheck;
68 }
69 
70 
71 MediaWindow::~MediaWindow()
72 {
73 	_EmptyNodeLists();
74 
75 	BMediaRoster* roster = BMediaRoster::Roster();
76 	if (roster && fCurrentNode)
77 		roster->ReleaseNode(*fCurrentNode);
78 
79 	char buffer[512];
80 	BRect rect = Frame();
81 	PRINT_OBJECT(rect);
82 	sprintf(buffer, "# MediaPrefs Settings\n rect = %i,%i,%i,%i\n",
83 		int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
84 
85 	BPath path;
86 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
87 		path.Append(SETTINGS_FILE);
88 		BFile file(path.Path(), B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE);
89 		if (file.InitCheck()==B_OK) {
90 			file.Write(buffer, strlen(buffer));
91 		}
92 	}
93 }
94 
95 
96 void
97 MediaWindow::_FindNodes()
98 {
99 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
100 	_FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
101 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs);
102 	_FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_INPUT, fAudioInputs);
103 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
104 	_FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
105 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs);
106 	_FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_INPUT, fVideoInputs);
107 }
108 
109 
110 void
111 MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into)
112 {
113 	dormant_node_info node_info[64];
114 	int32 node_info_count = 64;
115 	media_format format;
116 	media_format* format1 = NULL, *format2 = NULL;
117 	BMediaRoster* roster = BMediaRoster::Roster();
118 	format.type = type;
119 
120 	if (kind & B_PHYSICAL_OUTPUT)
121 		format1 = &format;
122 	else if (kind & B_PHYSICAL_INPUT)
123 		format2 = &format;
124 	else
125 		return;
126 
127 	if (roster->GetDormantNodes(node_info, &node_info_count, format1, format2,
128 			NULL, kind)!=B_OK) {
129 		// TODO: better error reporting!
130 		fprintf(stderr, "error\n");
131 		return;
132 	}
133 
134 	for (int32 i = 0; i < node_info_count; i++) {
135 		PRINT(("node : %s, media_addon %i, flavor_id %i\n",
136 			node_info[i].name, node_info[i].addon, node_info[i].flavor_id));
137 
138 		dormant_node_info* info = new dormant_node_info();
139 		strncpy(info->name, node_info[i].name, B_MEDIA_NAME_LENGTH);
140 		info->flavor_id = node_info[i].flavor_id;
141 		info->addon = node_info[i].addon;
142 		into.AddItem(info);
143 	}
144 }
145 
146 
147 MediaListItem *
148 MediaWindow::FindMediaListItem(dormant_node_info* info)
149 {
150 	for (int32 j = 0; j<fListView->CountItems(); j++) {
151 		MediaListItem* item
152 			= static_cast<MediaListItem *>(fListView->ItemAt(j));
153 		if (item->fInfo && item->fInfo->addon == info->addon
154 				&& item->fInfo->flavor_id == info->flavor_id) {
155 			return item;
156 			break;
157 		}
158 	}
159 	return NULL;
160 }
161 
162 
163 void
164 MediaWindow::_AddNodeItems(NodeList &list, bool isVideo)
165 {
166 	int32 count = list.CountItems();
167 	for (int32 i = 0; i < count; i++) {
168 		dormant_node_info* info = list.ItemAt(i);
169 		if (!FindMediaListItem(info))
170 			fListView->AddItem(new MediaListItem(info, 1, isVideo, &fIcons));
171 	}
172 }
173 
174 
175 void
176 MediaWindow::_EmptyNodeLists()
177 {
178 	fAudioOutputs.MakeEmpty();
179 	fAudioInputs.MakeEmpty();
180 	fVideoOutputs.MakeEmpty();
181 	fVideoInputs.MakeEmpty();
182 }
183 
184 
185 void
186 MediaWindow::InitWindow(void)
187 {
188 	// Bitmaps
189 	BRect iconRect(0, 0, 15, 15);
190 	BBitmap* icon = new BBitmap(iconRect, B_CMAP8);
191 	icon->SetBits(kDevicesBits, kDevicesWidth * kDevicesHeight, 0,
192 			kDevicesColorSpace);
193 	fIcons.AddItem(icon);
194 	icon = new BBitmap(iconRect, B_CMAP8);
195 	icon->SetBits(kMixerBits, kMixerWidth * kMixerHeight, 0,
196 			kMixerColorSpace);
197 	fIcons.AddItem(icon);
198 	icon = new BBitmap(iconRect, B_CMAP8);
199 	icon->SetBits(kMicBits, kMicWidth * kMicHeight, 0, kMicColorSpace);
200 	fIcons.AddItem(icon);
201 	icon = new BBitmap(iconRect, B_CMAP8);
202 	icon->SetBits(kSpeakerBits, kSpeakerWidth * kSpeakerHeight, 0,
203 			kSpeakerColorSpace);
204 	fIcons.AddItem(icon);
205 	icon = new BBitmap(iconRect, B_CMAP8);
206 	icon->SetBits(kCamBits, kCamWidth * kCamHeight, 0, kCamColorSpace);
207 	fIcons.AddItem(icon);
208 	icon = new BBitmap(iconRect, B_CMAP8);
209 	icon->SetBits(kTVBits, kTVWidth * kTVHeight, 0, kTVColorSpace);
210 	fIcons.AddItem(icon);
211 
212 	const float scrollWidth = 9 * be_plain_font->Size() + 30;
213 
214 	fListView = new BListView("media_list_view");
215 	fListView->SetSelectionMessage(new BMessage(ML_SELECTED_NODE));
216 
217 	// Add ScrollView to Media Menu
218 	BScrollView* scrollView = new BScrollView("listscroller",
219 		fListView, 0, false, false, B_FANCY_BORDER);
220 	scrollView->SetExplicitMinSize(BSize(scrollWidth, B_SIZE_UNSET));
221 	scrollView->SetExplicitMaxSize(BSize(scrollWidth, B_SIZE_UNSET));
222 
223 	// Create the Views
224 	fBox = new BBox("background", B_WILL_DRAW | B_FRAME_EVENTS,
225 		B_PLAIN_BORDER);
226 	SetLayout(new BGroupLayout(B_HORIZONTAL));
227 	GetLayout()->AddView(fBox);
228 
229 	// StringViews
230 	fTitleView = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER);
231 	fTitleView->SetLabel(B_TRANSLATE("Audio settings"));
232 	fTitleView->SetFont(be_bold_font);
233 
234 	fContentView = new BBox("contentView", B_WILL_DRAW | B_FRAME_EVENTS,
235 		B_NO_BORDER);
236 
237 	fAudioView = new SettingsView(false);
238 	fVideoView = new SettingsView(true);
239 
240 
241 	// Layout all views
242 	BGroupView* rightView = new BGroupView(B_VERTICAL, 5);
243 	rightView->GroupLayout()->SetInsets(14, 0, 0, 0);
244 	rightView->GroupLayout()->AddView(fTitleView);
245 	rightView->GroupLayout()->AddView(fContentView);
246 
247 	BGroupLayout* rootLayout = new BGroupLayout(B_HORIZONTAL);
248 	rootLayout->SetInsets(14, 14, 14, 14);
249 	fBox->SetLayout(rootLayout);
250 
251 	rootLayout->AddView(scrollView);
252 
253 	rootLayout->AddView(rightView);
254 
255 	// Start the window
256 	fInitCheck = InitMedia(true);
257 	if (fInitCheck != B_OK) {
258 		PostMessage(B_QUIT_REQUESTED);
259 	} else {
260 		if (IsHidden())
261 			Show();
262 	}
263 }
264 
265 
266 // #pragma mark -
267 
268 
269 status_t
270 MediaWindow::InitMedia(bool first)
271 {
272 	status_t err = B_OK;
273 	BMediaRoster* roster = BMediaRoster::Roster(&err);
274 
275 	if (first && err != B_OK) {
276 		BAlert* alert = new BAlert("start_media_server",
277 			B_TRANSLATE("Could not connect to the media server.\n"
278 			"Would you like to start it ?"),
279 			B_TRANSLATE("Quit"),
280 			B_TRANSLATE("Start media server"), NULL,
281 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
282 		if (alert->Go()==0)
283 			return B_ERROR;
284 
285 		fAlert = new MediaAlert(BRect(0, 0, 300, 60),
286 			"restart_alert", B_TRANSLATE(
287 				"Restarting media services\nStarting media server"
288 				B_UTF8_ELLIPSIS "\n"));
289 		fAlert->Show();
290 
291 		Show();
292 
293 		launch_media_server();
294 	}
295 
296 	Lock();
297 
298 	bool isVideoSelected = true;
299 	if (!first && fListView->ItemAt(0) && fListView->ItemAt(0)->IsSelected())
300 		isVideoSelected = false;
301 
302 	if ((!first || (first && err) ) && fAlert) {
303 		BAutolock locker(fAlert);
304 		if (locker.IsLocked())
305 			fAlert->TextView()->SetText(
306 				B_TRANSLATE("Ready for use" B_UTF8_ELLIPSIS));
307 	}
308 
309 	_EmptyNodeLists();
310 
311 	// Grab Media Info
312 	_FindNodes();
313 
314 	// Add video nodes first. They might have an additional audio
315 	// output or input, but still should be listed as video node.
316 	_AddNodeItems(fVideoOutputs, true);
317 	_AddNodeItems(fVideoInputs, true);
318 	_AddNodeItems(fAudioOutputs, false);
319 	_AddNodeItems(fAudioInputs, false);
320 
321 	fAudioView->AddNodes(fAudioOutputs, false);
322 	fAudioView->AddNodes(fAudioInputs, true);
323 	fVideoView->AddNodes(fVideoOutputs, false);
324 	fVideoView->AddNodes(fVideoInputs, true);
325 
326 	// build our list view
327 	MediaListItem* audio = new MediaListItem(B_TRANSLATE("Audio settings"), 0,
328 		false, &fIcons);
329 	fListView->AddItem(audio);
330 
331 	MediaListItem* video = new MediaListItem(B_TRANSLATE("Video settings"), 0,
332 		true, &fIcons);
333 	fListView->AddItem(video);
334 
335 	MediaListItem* mixer = new MediaListItem(B_TRANSLATE("Audio mixer"),
336 		1, false, &fIcons);
337 	fListView->AddItem(mixer);
338 	mixer->SetAudioMixer(true);
339 
340 	fListView->SortItems(&MediaListItem::Compare);
341 
342 	// Set default nodes for our setting views
343 	media_node default_node;
344 	dormant_node_info node_info;
345 	int32 outputID;
346 	BString outputName;
347 
348 	if (roster->GetAudioInput(&default_node) == B_OK) {
349 		roster->GetDormantNodeFor(default_node, &node_info);
350 		MediaListItem* item = FindMediaListItem(&node_info);
351 		if (item)
352 			item->SetDefault(true, true);
353 		fAudioView->SetDefault(node_info, true);
354 	}
355 
356 	if (roster->GetAudioOutput(&default_node, &outputID, &outputName)==B_OK) {
357 		roster->GetDormantNodeFor(default_node, &node_info);
358 		MediaListItem* item = FindMediaListItem(&node_info);
359 		if (item)
360 			item->SetDefault(true, false);
361 		fAudioView->SetDefault(node_info, false, outputID);
362 	}
363 
364 	if (roster->GetVideoInput(&default_node)==B_OK) {
365 		roster->GetDormantNodeFor(default_node, &node_info);
366 		MediaListItem* item = FindMediaListItem(&node_info);
367 		if (item)
368 			item->SetDefault(true, true);
369 		fVideoView->SetDefault(node_info, true);
370 	}
371 
372 	if (roster->GetVideoOutput(&default_node)==B_OK) {
373 		roster->GetDormantNodeFor(default_node, &node_info);
374 		MediaListItem* item = FindMediaListItem(&node_info);
375 		if (item)
376 			item->SetDefault(true, false);
377 		fVideoView->SetDefault(node_info, false);
378 	}
379 
380 	if (first) {
381 		fListView->Select(fListView->IndexOf(mixer));
382 	} else {
383 		if (!fAudioView->fRestartView->IsHidden())
384 			fAudioView->fRestartView->Hide();
385 		if (!fVideoView->fRestartView->IsHidden())
386 			fVideoView->fRestartView->Hide();
387 
388 		if (isVideoSelected)
389 			fListView->Select(fListView->IndexOf(video));
390 		else
391 			fListView->Select(fListView->IndexOf(audio));
392 	}
393 
394 	if (fAlert) {
395 		snooze(800000);
396 		fAlert->PostMessage(B_QUIT_REQUESTED);
397 	}
398 	fAlert = NULL;
399 
400 	Unlock();
401 
402 	return B_OK;
403 }
404 
405 
406 bool
407 MediaWindow::QuitRequested()
408 {
409 	// stop watching the MediaRoster
410 	BMediaRoster* roster = BMediaRoster::CurrentRoster();
411 	if (roster && fCurrentNode)	{
412 		roster->StopWatching(this, *fCurrentNode, B_MEDIA_WILDCARD);
413 	}
414 	be_app->PostMessage(B_QUIT_REQUESTED);
415 	return true;
416 }
417 
418 
419 void
420 MediaWindow::FrameResized (float width, float height)
421 {
422 	// This makes sure our SideBar colours down to the bottom when resized
423 	BRect r;
424 	r = Bounds();
425 }
426 
427 
428 // ErrorAlert -- Displays a BAlert Box with a Custom Error or Debug Message
429 void
430 ErrorAlert(char* errorMessage) {
431 	printf("%s\n", errorMessage);
432 	BAlert* alert = new BAlert("BAlert", errorMessage, B_TRANSLATE("OK"),
433 		NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
434 	alert->Go();
435 	exit(1);
436 }
437 
438 
439 void
440 MediaWindow::MessageReceived(BMessage* message)
441 {
442 	switch(message->what)
443 	{
444 		case ML_INIT_MEDIA:
445 			InitMedia(false);
446 			break;
447 		case ML_DEFAULTOUTPUT_CHANGE:
448 			{
449 				int32 index;
450 				if (message->FindInt32("index", &index)!=B_OK)
451 					break;
452 				Settings2Item* item = static_cast<Settings2Item*>(
453 					fAudioView->fMenu3->ItemAt(index));
454 
455 				if (item) {
456 					BMediaRoster* roster = BMediaRoster::Roster();
457 					roster->SetAudioOutput(*item->fInput);
458 
459 					if (fAudioView->fRestartView->IsHidden())
460 						fAudioView->fRestartView->Show();
461 				} else
462 					fprintf(stderr, "Settings2Item not found\n");
463 			}
464 			break;
465 		case ML_DEFAULT_CHANGE:
466 			{
467 				bool isVideo = true;
468 				bool isInput = true;
469 				if (message->FindBool("isVideo", &isVideo)!=B_OK)
470 					break;
471 				if (message->FindBool("isInput", &isInput)!=B_OK)
472 					break;
473 				int32 index;
474 				if (message->FindInt32("index", &index)!=B_OK)
475 					break;
476 				SettingsView* settingsView = isVideo ? fVideoView : fAudioView;
477 				BMenu* menu = isInput ? settingsView->fMenu1
478 					: settingsView->fMenu2;
479 				SettingsItem* item = static_cast<SettingsItem*>(
480 					menu->ItemAt(index));
481 
482 				if (item) {
483 					PRINT(("isVideo %i isInput %i\n", isVideo, isInput));
484 					BMediaRoster* roster = BMediaRoster::Roster();
485 					if (isVideo) {
486 						if (isInput)
487 							roster->SetVideoInput(*item->fInfo);
488 						else
489 							roster->SetVideoOutput(*item->fInfo);
490 					} else {
491 						if (isInput)
492 							roster->SetAudioInput(*item->fInfo);
493 						else {
494 							roster->SetAudioOutput(*item->fInfo);
495 							fAudioView->SetDefault(*item->fInfo, false, 0);
496 						}
497 					}
498 
499 					MediaListItem* oldListItem = NULL;
500 					for (int32 j = 0; j < fListView->CountItems(); j++) {
501 						oldListItem = static_cast<MediaListItem*>(
502 							fListView->ItemAt(j));
503 						if (oldListItem->fInfo
504 							&& oldListItem->IsVideo() == isVideo
505 							&& oldListItem->IsDefault(isInput))
506 							break;
507 					}
508 					if (oldListItem)
509 						oldListItem->SetDefault(false, isInput);
510 					else
511 						fprintf(stderr, "oldListItem not found\n");
512 
513 					MediaListItem* listItem = FindMediaListItem(item->fInfo);
514 					if (listItem) {
515 						listItem->SetDefault(true, isInput);
516 					} else
517 						fprintf(stderr, "MediaListItem not found\n");
518 					fListView->Invalidate();
519 
520 					if (settingsView->fRestartView->IsHidden())
521 						settingsView->fRestartView->Show();
522 				} else
523 					fprintf(stderr, "SettingsItem not found\n");
524 			}
525 			break;
526 		case ML_RESTART_MEDIA_SERVER:
527 		{
528 			thread_id thread = spawn_thread(&MediaWindow::RestartMediaServices,
529 				"restart_thread", B_NORMAL_PRIORITY, this);
530 			if (thread < B_OK)
531 				fprintf(stderr, "couldn't create restart thread\n");
532 			else
533 				resume_thread(thread);
534 			break;
535 		}
536 		case ML_SHOW_VOLUME_CONTROL:
537 		{
538 			BDeskbar deskbar;
539 			if (fAudioView->fVolumeCheckBox->Value() == B_CONTROL_ON) {
540 				BEntry entry("/bin/desklink", true);
541 				int32 id;
542 				entry_ref ref;
543 				status_t status = entry.GetRef(&ref);
544 				if (status == B_OK)
545 					status = deskbar.AddItem(&ref, &id);
546 
547 				if (status != B_OK) {
548 					fprintf(stderr, B_TRANSLATE(
549 						"Couldn't add volume control in Deskbar: %s\n"),
550 						strerror(status));
551 				}
552 			} else {
553 				status_t status = deskbar.RemoveItem("MediaReplicant");
554 				if (status != B_OK) {
555 					fprintf(stderr, B_TRANSLATE(
556 						"Couldn't remove volume control in Deskbar: %s\n"),
557 						strerror(status));
558 				}
559 			}
560 			break;
561 		}
562 		case ML_ENABLE_REAL_TIME:
563 			{
564 				bool isVideo = true;
565 				if (message->FindBool("isVideo", &isVideo)!=B_OK)
566 					break;
567 				SettingsView* settingsView = isVideo ? fVideoView : fAudioView;
568 				uint32 flags;
569 				uint32 realtimeFlag = isVideo
570 					? B_MEDIA_REALTIME_VIDEO : B_MEDIA_REALTIME_AUDIO;
571 				BMediaRoster* roster = BMediaRoster::Roster();
572 				roster->GetRealtimeFlags(&flags);
573 				if (settingsView->fRealtimeCheckBox->Value() == B_CONTROL_ON)
574 					flags |= realtimeFlag;
575 				else
576 					flags &= ~realtimeFlag;
577 				roster->SetRealtimeFlags(flags);
578 			}
579 			break;
580 		case B_MEDIA_WEB_CHANGED:
581 		case ML_SELECTED_NODE:
582 			{
583 				PRINT_OBJECT(*message);
584 
585 				MediaListItem* item = static_cast<MediaListItem*>(
586 						fListView->ItemAt(fListView->CurrentSelection()));
587 				if (!item)
588 					break;
589 				BMediaRoster* roster = BMediaRoster::Roster();
590 				if (fCurrentNode) {
591 					// stop watching the MediaRoster
592 					roster->StopWatching(this, *fCurrentNode, B_MEDIA_WILDCARD);
593 					roster->ReleaseNode(*fCurrentNode);
594 				}
595 				fCurrentNode = NULL;
596 				BView* paramView = fContentView->ChildAt(0);
597 				if (paramView!=NULL) {
598 					fContentView->RemoveChild(paramView);
599 				}
600 				paramView = NULL;
601 				if (fParamWeb)
602 					delete fParamWeb;
603 				fParamWeb = NULL;
604 
605 				fTitleView->SetLabel(item->GetLabel());
606 
607 				if (item->OutlineLevel() == 0) {
608 					if (item->IsVideo())
609 						fContentView->AddChild(fVideoView);
610 					else
611 						fContentView->AddChild(fAudioView);
612 				} else {
613 
614 					if (!fCurrentNode)
615 						fCurrentNode = new media_node();
616 					media_node_id node_id;
617 					if (item->IsAudioMixer())
618 						roster->GetAudioMixer(fCurrentNode);
619 					else if (roster->GetInstancesFor(item->fInfo->addon, item->fInfo->flavor_id, &node_id)!=B_OK)
620 						roster->InstantiateDormantNode(*(item->fInfo), fCurrentNode, B_FLAVOR_IS_GLOBAL);
621 					else
622 						roster->GetNodeFor(node_id, fCurrentNode);
623 
624 					if (roster->GetParameterWebFor(*fCurrentNode, &fParamWeb)==B_OK
625 						&& (paramView = BMediaTheme::PreferredTheme()->ViewFor(fParamWeb)) != NULL) {
626 						fContentView->AddChild(paramView);
627 						paramView->ResizeTo(fContentView->Bounds().Width(), fContentView->Bounds().Height() - 10);
628 
629 						roster->StartWatching(this, *fCurrentNode, B_MEDIA_WILDCARD);
630 					} else {
631 						delete fParamWeb;
632 						fParamWeb = NULL;
633 
634 						BRect bounds = fContentView->Bounds();
635 						BStringView* stringView = new BStringView(bounds,
636 							"noControls", B_TRANSLATE("This hardware has no controls."),
637 							B_FOLLOW_V_CENTER | B_FOLLOW_H_CENTER);
638 						stringView->ResizeToPreferred();
639 						fContentView->AddChild(stringView);
640 						stringView->MoveBy((bounds.Width()-stringView->Bounds().Width())/2,
641 							(bounds.Height()-stringView->Bounds().Height())/2);
642 					}
643 				}
644 			}
645 			break;
646 		case B_SOME_APP_LAUNCHED:
647 			{
648 				PRINT_OBJECT(*message);
649 				if (!fAlert)
650 					break;
651 
652 				BString mimeSig;
653 				if (message->FindString("be:signature", &mimeSig) == B_OK
654 					&& (mimeSig == "application/x-vnd.Be.addon-host"
655 						|| mimeSig == "application/x-vnd.Be.media-server")) {
656 					fAlert->Lock();
657 					fAlert->TextView()->SetText(
658 						B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
659 					fAlert->Unlock();
660 				}
661 			}
662 			break;
663 		case B_SOME_APP_QUIT:
664 			{
665 				PRINT_OBJECT(*message);
666 				BString mimeSig;
667 				if (message->FindString("be:signature", &mimeSig) == B_OK) {
668 					if (mimeSig == "application/x-vnd.Be.addon-host"
669 						|| mimeSig == "application/x-vnd.Be.media-server") {
670 						BMediaRoster* roster = BMediaRoster::CurrentRoster();
671 						if (roster && roster->Lock())
672 							roster->Quit();
673 					}
674 				}
675 
676 			}
677 			break;
678 		default:
679 			BWindow::MessageReceived(message);
680 			break;
681 	}
682 }
683 
684 status_t
685 MediaWindow::RestartMediaServices(void* data)
686 {
687 	MediaWindow* window = (MediaWindow*)data;
688 	window->fAlert = new MediaAlert(BRect(0, 0, 300, 60),
689 		"restart_alert", B_TRANSLATE(
690 		"Restarting media services\nShutting down media server\n"));
691 
692 	window->fAlert->Show();
693 
694 	shutdown_media_server(B_INFINITE_TIMEOUT, MediaWindow::UpdateProgress,
695 		window->fAlert);
696 
697 	{
698 		BAutolock locker(window->fAlert);
699 		if (locker.IsLocked())
700 			window->fAlert->TextView()->SetText(
701 				B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS));
702 	}
703 	launch_media_server();
704 
705 	return window->PostMessage(ML_INIT_MEDIA);
706 }
707 
708 
709 bool
710 MediaWindow::UpdateProgress(int stage, const char * message, void * cookie)
711 {
712 	MediaAlert* alert = static_cast<MediaAlert*>(cookie);
713 	PRINT(("stage : %i\n", stage));
714 	const char* string = "Unknown stage";
715 	switch (stage) {
716 		case 10:
717 			string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS);
718 			break;
719 		case 20:
720 			string = B_TRANSLATE("Telling media_addon_server to quit.");
721 			break;
722 		case 40:
723 			string = B_TRANSLATE("Waiting for media_server to quit.");
724 			break;
725 		case 70:
726 			string = B_TRANSLATE("Cleaning up.");
727 			break;
728 		case 100:
729 			string = B_TRANSLATE("Done shutting down.");
730 			break;
731 	}
732 
733 	BAutolock locker(alert);
734 	if (locker.IsLocked())
735 		alert->TextView()->SetText(string);
736 	return true;
737 }
738 
739