1 /* 2 * Copyright 2003-2012, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Sikosis, Jérôme Duval 7 * yourpalal, Alex Wilson 8 */ 9 10 11 #include "MediaWindow.h" 12 13 #include <stdio.h> 14 15 #include <Alert.h> 16 #include <Application.h> 17 #include <Autolock.h> 18 #include <Bitmap.h> 19 #include <Button.h> 20 #include <CardLayout.h> 21 #include <Catalog.h> 22 #include <Debug.h> 23 #include <Deskbar.h> 24 #include <LayoutBuilder.h> 25 #include <Locale.h> 26 #include <MediaRoster.h> 27 #include <MediaTheme.h> 28 #include <Notification.h> 29 #include <Resources.h> 30 #include <Roster.h> 31 #include <Screen.h> 32 #include <ScrollView.h> 33 #include <SeparatorView.h> 34 #include <SpaceLayoutItem.h> 35 #include <StorageKit.h> 36 #include <String.h> 37 #include <TextView.h> 38 39 #include "MediaIcons.h" 40 #include "MidiSettingsView.h" 41 42 #undef B_TRANSLATION_CONTEXT 43 #define B_TRANSLATION_CONTEXT "Media Window" 44 45 46 const uint32 ML_SELECTED_NODE = 'MlSN'; 47 const uint32 ML_INIT_MEDIA = 'MlIM'; 48 49 50 class NodeListItemUpdater : public MediaListItem::Visitor { 51 public: 52 typedef void (NodeListItem::*UpdateMethod)(bool); 53 54 NodeListItemUpdater(NodeListItem* target, UpdateMethod action) 55 : 56 fComparator(target), 57 fAction(action) 58 { 59 } 60 61 62 virtual void Visit(AudioMixerListItem*){} 63 virtual void Visit(DeviceListItem*){} 64 virtual void Visit(MidiListItem*){} 65 virtual void Visit(NodeListItem* item) 66 { 67 item->Accept(fComparator); 68 (item->*(fAction))(fComparator.result == 0); 69 } 70 71 private: 72 73 NodeListItem::Comparator fComparator; 74 UpdateMethod fAction; 75 }; 76 77 78 MediaWindow::SmartNode::SmartNode(const BMessenger& notifyHandler) 79 : 80 fNode(NULL), 81 fMessenger(notifyHandler) 82 { 83 } 84 85 86 MediaWindow::SmartNode::~SmartNode() 87 { 88 _FreeNode(); 89 } 90 91 92 void 93 MediaWindow::SmartNode::SetTo(const dormant_node_info* info) 94 { 95 _FreeNode(); 96 if (!info) 97 return; 98 99 fNode = new media_node(); 100 BMediaRoster* roster = BMediaRoster::Roster(); 101 102 // TODO: error codes 103 media_node_id node_id; 104 if (roster->GetInstancesFor(info->addon, info->flavor_id, &node_id) == B_OK) 105 roster->GetNodeFor(node_id, fNode); 106 else 107 roster->InstantiateDormantNode(*info, fNode, B_FLAVOR_IS_GLOBAL); 108 roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD); 109 } 110 111 112 void 113 MediaWindow::SmartNode::SetTo(const media_node& node) 114 { 115 _FreeNode(); 116 fNode = new media_node(node); 117 BMediaRoster* roster = BMediaRoster::Roster(); 118 roster->StartWatching(fMessenger, *fNode, B_MEDIA_WILDCARD); 119 } 120 121 122 bool 123 MediaWindow::SmartNode::IsSet() 124 { 125 return fNode != NULL; 126 } 127 128 129 MediaWindow::SmartNode::operator media_node() 130 { 131 if (fNode) 132 return *fNode; 133 media_node node; 134 return node; 135 } 136 137 138 void 139 MediaWindow::SmartNode::_FreeNode() 140 { 141 if (!IsSet()) 142 return; 143 // TODO: check error codes 144 BMediaRoster* roster = BMediaRoster::Roster(); 145 roster->StopWatching(fMessenger, *fNode, B_MEDIA_WILDCARD); 146 roster->ReleaseNode(*fNode); 147 delete fNode; 148 fNode = NULL; 149 } 150 151 152 // #pragma mark - 153 154 155 MediaWindow::MediaWindow(BRect frame) 156 : 157 BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Media"), B_TITLED_WINDOW, 158 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 159 fCurrentNode(BMessenger(this)), 160 fParamWeb(NULL), 161 fAudioInputs(5, true), 162 fAudioOutputs(5, true), 163 fVideoInputs(5, true), 164 fVideoOutputs(5, true), 165 fInitCheck(B_OK) 166 { 167 _InitWindow(); 168 } 169 170 171 MediaWindow::~MediaWindow() 172 { 173 _EmptyNodeLists(); 174 _ClearParamView(); 175 176 char buffer[512]; 177 BRect rect = Frame(); 178 PRINT_OBJECT(rect); 179 snprintf(buffer, 512, "# MediaPrefs Settings\n rect = %i,%i,%i,%i\n", 180 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); 181 182 BPath path; 183 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 184 path.Append(SETTINGS_FILE); 185 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 186 if (file.InitCheck() == B_OK) 187 file.Write(buffer, strlen(buffer)); 188 } 189 } 190 191 192 status_t 193 MediaWindow::InitCheck() 194 { 195 return fInitCheck; 196 } 197 198 199 void 200 MediaWindow::SelectNode(const dormant_node_info* node) 201 { 202 fCurrentNode.SetTo(node); 203 _MakeParamView(); 204 fTitleView->SetLabel(node->name); 205 } 206 207 208 void 209 MediaWindow::SelectAudioSettings(const char* title) 210 { 211 fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fAudioView)); 212 fTitleView->SetLabel(title); 213 } 214 215 216 void 217 MediaWindow::SelectVideoSettings(const char* title) 218 { 219 fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fVideoView)); 220 fTitleView->SetLabel(title); 221 } 222 223 224 void 225 MediaWindow::SelectAudioMixer(const char* title) 226 { 227 media_node mixerNode; 228 BMediaRoster* roster = BMediaRoster::Roster(); 229 roster->GetAudioMixer(&mixerNode); 230 fCurrentNode.SetTo(mixerNode); 231 _MakeParamView(); 232 fTitleView->SetLabel(title); 233 } 234 235 236 void 237 MediaWindow::SelectMidiSettings(const char* title) 238 { 239 fContentLayout->SetVisibleItem(fContentLayout->IndexOfView(fMidiView)); 240 fTitleView->SetLabel(title); 241 } 242 243 244 void 245 MediaWindow::UpdateInputListItem(MediaListItem::media_type type, 246 const dormant_node_info* node) 247 { 248 NodeListItem compareTo(node, type); 249 NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultInput); 250 for (int32 i = 0; i < fListView->CountItems(); i++) { 251 MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i)); 252 item->Accept(updater); 253 } 254 fListView->Invalidate(); 255 } 256 257 258 void 259 MediaWindow::UpdateOutputListItem(MediaListItem::media_type type, 260 const dormant_node_info* node) 261 { 262 NodeListItem compareTo(node, type); 263 NodeListItemUpdater updater(&compareTo, &NodeListItem::SetDefaultOutput); 264 for (int32 i = 0; i < fListView->CountItems(); i++) { 265 MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i)); 266 item->Accept(updater); 267 } 268 fListView->Invalidate(); 269 } 270 271 272 bool 273 MediaWindow::QuitRequested() 274 { 275 // stop watching the MediaRoster 276 fCurrentNode.SetTo(NULL); 277 be_app->PostMessage(B_QUIT_REQUESTED); 278 return true; 279 } 280 281 282 void 283 MediaWindow::MessageReceived(BMessage* message) 284 { 285 switch (message->what) { 286 case ML_INIT_MEDIA: 287 _InitMedia(false); 288 break; 289 case ML_RESTART_MEDIA_SERVER: 290 { 291 thread_id thread = spawn_thread(&MediaWindow::_RestartMediaServices, 292 "restart_thread", B_NORMAL_PRIORITY, this); 293 if (thread < 0) 294 fprintf(stderr, "couldn't create restart thread\n"); 295 else 296 resume_thread(thread); 297 break; 298 } 299 case B_MEDIA_WEB_CHANGED: 300 case ML_SELECTED_NODE: 301 { 302 PRINT_OBJECT(*message); 303 304 MediaListItem* item = static_cast<MediaListItem*>( 305 fListView->ItemAt(fListView->CurrentSelection())); 306 if (item == NULL) 307 break; 308 309 fCurrentNode.SetTo(NULL); 310 _ClearParamView(); 311 item->AlterWindow(this); 312 break; 313 } 314 case B_SOME_APP_LAUNCHED: 315 { 316 PRINT_OBJECT(*message); 317 318 BString mimeSig; 319 if (message->FindString("be:signature", &mimeSig) == B_OK 320 && (mimeSig == "application/x-vnd.Be.addon-host" 321 || mimeSig == "application/x-vnd.Be.media-server")) { 322 BNotification notificationPopup(B_PROGRESS_NOTIFICATION); 323 notificationPopup.SetMessageID(MEDIA_SERVICE_NOTIFICATION_ID); 324 notificationPopup.SetTitle(B_TRANSLATE("Media Service")); 325 notificationPopup.SetProgress(0.5); 326 notificationPopup.SetContent( 327 B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS)); 328 notificationPopup.Send(); 329 } 330 break; 331 } 332 case B_SOME_APP_QUIT: 333 { 334 PRINT_OBJECT(*message); 335 BString mimeSig; 336 if (message->FindString("be:signature", &mimeSig) == B_OK) { 337 if (mimeSig == "application/x-vnd.Be.addon-host" 338 || mimeSig == "application/x-vnd.Be.media-server") { 339 BMediaRoster* roster = BMediaRoster::CurrentRoster(); 340 if (roster != NULL && roster->Lock()) 341 roster->Quit(); 342 } 343 } 344 break; 345 } 346 default: 347 BWindow::MessageReceived(message); 348 break; 349 } 350 } 351 352 353 // #pragma mark - private 354 355 356 void 357 MediaWindow::_InitWindow() 358 { 359 fListView = new BListView("media_list_view"); 360 fListView->SetSelectionMessage(new BMessage(ML_SELECTED_NODE)); 361 fListView->SetExplicitMinSize(BSize(140, B_SIZE_UNSET)); 362 363 // Add ScrollView to Media Menu for pretty border 364 BScrollView* scrollView = new BScrollView("listscroller", 365 fListView, 0, false, false, B_FANCY_BORDER); 366 367 // Create the Views 368 fTitleView = new BSeparatorView(B_HORIZONTAL, B_FANCY_BORDER); 369 fTitleView->SetLabel(B_TRANSLATE("Audio settings")); 370 fTitleView->SetFont(be_bold_font); 371 372 fContentLayout = new BCardLayout(); 373 new BView("content view", 0, fContentLayout); 374 fContentLayout->Owner()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 375 fContentLayout->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 376 377 fAudioView = new AudioSettingsView(); 378 fContentLayout->AddView(fAudioView); 379 380 fVideoView = new VideoSettingsView(); 381 fContentLayout->AddView(fVideoView); 382 383 fMidiView = new MidiSettingsView(); 384 fContentLayout->AddView(fMidiView); 385 386 // Layout all views 387 BLayoutBuilder::Group<>(this, B_HORIZONTAL) 388 .SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 389 B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) 390 .Add(scrollView, 0.0f) 391 .AddGroup(B_VERTICAL) 392 .SetInsets(0, 0, 0, 0) 393 .Add(fTitleView) 394 .Add(fContentLayout); 395 396 // Start the window 397 fInitCheck = _InitMedia(true); 398 if (fInitCheck != B_OK) 399 PostMessage(B_QUIT_REQUESTED); 400 else if (IsHidden()) 401 Show(); 402 } 403 404 405 status_t 406 MediaWindow::_InitMedia(bool first) 407 { 408 status_t err = B_OK; 409 BMediaRoster* roster = BMediaRoster::Roster(&err); 410 411 if (first && err != B_OK) { 412 BAlert* alert = new BAlert("start_media_server", 413 B_TRANSLATE("Could not connect to the media server.\n" 414 "Would you like to start it ?"), 415 B_TRANSLATE("Quit"), 416 B_TRANSLATE("Start media server"), NULL, 417 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 418 alert->SetShortcut(0, B_ESCAPE); 419 if (alert->Go() == 0) 420 return B_ERROR; 421 422 BNotification notificationPopup(B_PROGRESS_NOTIFICATION); 423 notificationPopup.SetMessageID(MEDIA_SERVICE_NOTIFICATION_ID); 424 notificationPopup.SetTitle(B_TRANSLATE("Media Service")); 425 notificationPopup.SetProgress(0.5); 426 notificationPopup.SetContent( 427 B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS)); 428 notificationPopup.Send(); 429 430 Show(); 431 432 launch_media_server(); 433 } 434 435 Lock(); 436 437 bool isVideoSelected = true; 438 if (!first && fListView->ItemAt(0) != NULL 439 && fListView->ItemAt(0)->IsSelected()) 440 isVideoSelected = false; 441 442 if (!first || (first && err) ) { 443 BNotification notificationPopup(B_PROGRESS_NOTIFICATION); 444 notificationPopup.SetMessageID(MEDIA_SERVICE_NOTIFICATION_ID); 445 notificationPopup.SetTitle(B_TRANSLATE("Media Service")); 446 notificationPopup.SetProgress(1.0); 447 notificationPopup.SetContent( 448 B_TRANSLATE("Ready for use" B_UTF8_ELLIPSIS)); 449 notificationPopup.Send(); 450 } 451 452 while (fListView->CountItems() > 0) 453 delete fListView->RemoveItem((int32)0); 454 _EmptyNodeLists(); 455 456 // Grab Media Info 457 _FindNodes(); 458 459 // Add video nodes first. They might have an additional audio 460 // output or input, but still should be listed as video node. 461 _AddNodeItems(fVideoOutputs, MediaListItem::VIDEO_TYPE); 462 _AddNodeItems(fVideoInputs, MediaListItem::VIDEO_TYPE); 463 _AddNodeItems(fAudioOutputs, MediaListItem::AUDIO_TYPE); 464 _AddNodeItems(fAudioInputs, MediaListItem::AUDIO_TYPE); 465 466 fAudioView->AddOutputNodes(fAudioOutputs); 467 fAudioView->AddInputNodes(fAudioInputs); 468 fVideoView->AddOutputNodes(fVideoOutputs); 469 fVideoView->AddInputNodes(fVideoInputs); 470 471 // build our list view 472 DeviceListItem* audio = new DeviceListItem(B_TRANSLATE("Audio settings"), 473 MediaListItem::AUDIO_TYPE); 474 fListView->AddItem(audio); 475 476 MidiListItem* midi = new MidiListItem(B_TRANSLATE("MIDI Settings")); 477 fListView->AddItem(midi); 478 479 MediaListItem* video = new DeviceListItem(B_TRANSLATE("Video settings"), 480 MediaListItem::VIDEO_TYPE); 481 fListView->AddItem(video); 482 483 MediaListItem* mixer = new AudioMixerListItem(B_TRANSLATE("Audio mixer")); 484 fListView->AddItem(mixer); 485 486 fListView->SortItems(&MediaListItem::Compare); 487 _UpdateListViewMinWidth(); 488 489 // Set default nodes for our setting views 490 media_node defaultNode; 491 dormant_node_info nodeInfo; 492 int32 outputID; 493 BString outputName; 494 495 if (roster->GetAudioInput(&defaultNode) == B_OK) { 496 roster->GetDormantNodeFor(defaultNode, &nodeInfo); 497 fAudioView->SetDefaultInput(&nodeInfo); 498 // this causes our listview to be updated as well 499 } 500 501 if (roster->GetAudioOutput(&defaultNode, &outputID, &outputName) == B_OK) { 502 roster->GetDormantNodeFor(defaultNode, &nodeInfo); 503 fAudioView->SetDefaultOutput(&nodeInfo); 504 fAudioView->SetDefaultChannel(outputID); 505 // this causes our listview to be updated as well 506 } 507 508 if (roster->GetVideoInput(&defaultNode) == B_OK) { 509 roster->GetDormantNodeFor(defaultNode, &nodeInfo); 510 fVideoView->SetDefaultInput(&nodeInfo); 511 // this causes our listview to be updated as well 512 } 513 514 if (roster->GetVideoOutput(&defaultNode) == B_OK) { 515 roster->GetDormantNodeFor(defaultNode, &nodeInfo); 516 fVideoView->SetDefaultOutput(&nodeInfo); 517 // this causes our listview to be updated as well 518 } 519 520 if (first) 521 fListView->Select(fListView->IndexOf(mixer)); 522 else if (isVideoSelected) 523 fListView->Select(fListView->IndexOf(video)); 524 else 525 fListView->Select(fListView->IndexOf(audio)); 526 527 Unlock(); 528 529 return B_OK; 530 } 531 532 533 void 534 MediaWindow::_FindNodes() 535 { 536 _FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs); 537 _FindNodes(B_MEDIA_RAW_AUDIO, B_PHYSICAL_INPUT, fAudioInputs); 538 _FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_OUTPUT, fAudioOutputs); 539 _FindNodes(B_MEDIA_ENCODED_AUDIO, B_PHYSICAL_INPUT, fAudioInputs); 540 _FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs); 541 _FindNodes(B_MEDIA_RAW_VIDEO, B_PHYSICAL_INPUT, fVideoInputs); 542 _FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_OUTPUT, fVideoOutputs); 543 _FindNodes(B_MEDIA_ENCODED_VIDEO, B_PHYSICAL_INPUT, fVideoInputs); 544 } 545 546 547 void 548 MediaWindow::_FindNodes(media_type type, uint64 kind, NodeList& into) 549 { 550 dormant_node_info nodeInfo[64]; 551 int32 nodeInfoCount = 64; 552 553 media_format format; 554 media_format* nodeInputFormat = NULL; 555 media_format* nodeOutputFormat = NULL; 556 format.type = type; 557 558 // output nodes must be BBufferConsumers => they have an input format 559 // input nodes must be BBufferProducers => they have an output format 560 if ((kind & B_PHYSICAL_OUTPUT) != 0) 561 nodeInputFormat = &format; 562 else if ((kind & B_PHYSICAL_INPUT) != 0) 563 nodeOutputFormat = &format; 564 else 565 return; 566 567 BMediaRoster* roster = BMediaRoster::Roster(); 568 569 if (roster->GetDormantNodes(nodeInfo, &nodeInfoCount, nodeInputFormat, 570 nodeOutputFormat, NULL, kind) != B_OK) { 571 // TODO: better error reporting! 572 fprintf(stderr, "error\n"); 573 return; 574 } 575 576 for (int32 i = 0; i < nodeInfoCount; i++) { 577 PRINT(("node : %s, media_addon %i, flavor_id %i\n", 578 nodeInfo[i].name, (int)nodeInfo[i].addon, 579 (int)nodeInfo[i].flavor_id)); 580 581 dormant_node_info* info = new dormant_node_info(); 582 strncpy(info->name, nodeInfo[i].name, B_MEDIA_NAME_LENGTH); 583 info->flavor_id = nodeInfo[i].flavor_id; 584 info->addon = nodeInfo[i].addon; 585 into.AddItem(info); 586 } 587 } 588 589 590 void 591 MediaWindow::_AddNodeItems(NodeList& list, MediaListItem::media_type type) 592 { 593 int32 count = list.CountItems(); 594 for (int32 i = 0; i < count; i++) { 595 dormant_node_info* info = list.ItemAt(i); 596 if (_FindNodeListItem(info) == NULL) 597 fListView->AddItem(new NodeListItem(info, type)); 598 } 599 } 600 601 602 void 603 MediaWindow::_EmptyNodeLists() 604 { 605 fAudioOutputs.MakeEmpty(); 606 fAudioInputs.MakeEmpty(); 607 fVideoOutputs.MakeEmpty(); 608 fVideoInputs.MakeEmpty(); 609 } 610 611 612 NodeListItem* 613 MediaWindow::_FindNodeListItem(dormant_node_info* info) 614 { 615 NodeListItem audioItem(info, MediaListItem::AUDIO_TYPE); 616 NodeListItem videoItem(info, MediaListItem::VIDEO_TYPE); 617 618 NodeListItem::Comparator audioComparator(&audioItem); 619 NodeListItem::Comparator videoComparator(&videoItem); 620 621 for (int32 i = 0; i < fListView->CountItems(); i++) { 622 MediaListItem* item = static_cast<MediaListItem*>(fListView->ItemAt(i)); 623 item->Accept(audioComparator); 624 if (audioComparator.result == 0) 625 return static_cast<NodeListItem*>(item); 626 627 item->Accept(videoComparator); 628 if (videoComparator.result == 0) 629 return static_cast<NodeListItem*>(item); 630 } 631 return NULL; 632 } 633 634 635 void 636 MediaWindow::_UpdateListViewMinWidth() 637 { 638 float width = 0; 639 for (int32 i = 0; i < fListView->CountItems(); i++) { 640 BListItem* item = fListView->ItemAt(i); 641 width = max_c(width, item->Width()); 642 } 643 fListView->SetExplicitMinSize(BSize(width, B_SIZE_UNSET)); 644 fListView->InvalidateLayout(); 645 } 646 647 648 status_t 649 MediaWindow::_RestartMediaServices(void* data) 650 { 651 MediaWindow* window = (MediaWindow*)data; 652 653 BNotification notificationPopup(B_PROGRESS_NOTIFICATION); 654 notificationPopup.SetMessageID(MEDIA_SERVICE_NOTIFICATION_ID); 655 notificationPopup.SetTitle(B_TRANSLATE("Media Service")); 656 notificationPopup.SetContent( B_TRANSLATE("Shutting down media server")); 657 658 shutdown_media_server(B_INFINITE_TIMEOUT, MediaWindow::_UpdateProgress, 659 NULL); 660 661 notificationPopup.SetContent( 662 B_TRANSLATE("Starting media server" B_UTF8_ELLIPSIS)); 663 notificationPopup.SetProgress(0.5); 664 notificationPopup.Send(); 665 666 launch_media_server(); 667 668 notificationPopup.SetProgress(1); 669 notificationPopup.Send(); 670 671 return window->PostMessage(ML_INIT_MEDIA); 672 } 673 674 675 bool 676 MediaWindow::_UpdateProgress(int stage, const char* message, void* cookie) 677 { 678 // parameters "message" and "cookie" are no longer used. 679 // They remain here because they're declared within BeOS API and 680 // thus could not be removed. 681 682 PRINT(("stage : %i\n", stage)); 683 const char* string = "Unknown stage"; 684 switch (stage) { 685 case 10: 686 string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS); 687 break; 688 case 20: 689 string = B_TRANSLATE("Telling media_addon_server to quit."); 690 break; 691 case 40: 692 string = B_TRANSLATE("Waiting for media_server to quit."); 693 break; 694 case 70: 695 string = B_TRANSLATE("Cleaning up."); 696 break; 697 case 100: 698 string = B_TRANSLATE("Done shutting down."); 699 break; 700 } 701 702 BNotification info(B_PROGRESS_NOTIFICATION); 703 info.SetMessageID(MEDIA_SERVICE_NOTIFICATION_ID); 704 info.SetProgress(stage/100.0); 705 info.SetTitle(B_TRANSLATE("Media Service")); 706 info.SetContent(string); 707 info.Send(); 708 709 return true; 710 } 711 712 713 void 714 MediaWindow::_ClearParamView() 715 { 716 BLayoutItem* item = fContentLayout->VisibleItem(); 717 if (!item) 718 return; 719 720 BView* view = item->View(); 721 if (view != fVideoView && view != fAudioView && view != fMidiView) { 722 fContentLayout->RemoveItem(item); 723 delete item; 724 delete view; 725 delete fParamWeb; 726 fParamWeb = NULL; 727 } 728 } 729 730 731 void 732 MediaWindow::_MakeParamView() 733 { 734 if (!fCurrentNode.IsSet()) 735 return; 736 737 fParamWeb = NULL; 738 BMediaRoster* roster = BMediaRoster::Roster(); 739 if (roster->GetParameterWebFor(fCurrentNode, &fParamWeb) == B_OK) { 740 BRect hint(fContentLayout->Frame()); 741 BView* paramView = BMediaTheme::ViewFor(fParamWeb, &hint); 742 if (paramView) { 743 fContentLayout->AddView(paramView); 744 fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1); 745 return; 746 } 747 } 748 749 _MakeEmptyParamView(); 750 } 751 752 753 void 754 MediaWindow::_MakeEmptyParamView() 755 { 756 fParamWeb = NULL; 757 758 BStringView* stringView = new BStringView("noControls", 759 B_TRANSLATE("This hardware has no controls.")); 760 761 BSize unlimited(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); 762 stringView->SetExplicitMaxSize(unlimited); 763 764 BAlignment centered(B_ALIGN_HORIZONTAL_CENTER, 765 B_ALIGN_VERTICAL_CENTER); 766 stringView->SetExplicitAlignment(centered); 767 stringView->SetAlignment(B_ALIGN_CENTER); 768 769 fContentLayout->AddView(stringView); 770 fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1); 771 772 rgb_color panel = stringView->LowColor(); 773 stringView->SetHighColor(tint_color(panel, 774 B_DISABLED_LABEL_TINT)); 775 } 776 777