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