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