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