/* * Copyright 2003-2011, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Sikosis * Jérôme Duval */ #include "MediaViews.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MediaWindow.h" #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Media views" #define MEDIA_DEFAULT_INPUT_CHANGE 'dich' #define MEDIA_DEFAULT_OUTPUT_CHANGE 'doch' #define MEDIA_SHOW_HIDE_VOLUME_CONTROL 'shvc' SettingsView::SettingsView() : BGroupView(B_VERTICAL, B_USE_DEFAULT_SPACING), fInputMenu(NULL), fOutputMenu(NULL) { // input menu fInputMenu = new BPopUpMenu(B_TRANSLATE_ALL("", "VideoInputMenu", "Used when no video input is available")); fInputMenu->SetLabelFromMarked(true); // output menu fOutputMenu = new BPopUpMenu(B_TRANSLATE_ALL("", "VideoOutputMenu", "Used when no video output is available")); fOutputMenu->SetLabelFromMarked(true); } BButton* SettingsView::MakeRestartButton() { return new BButton("restartButton", B_TRANSLATE("Restart media services"), new BMessage(ML_RESTART_MEDIA_SERVER)); } void SettingsView::AddInputNodes(NodeList& list) { _EmptyMenu(fInputMenu); BMessage message(MEDIA_DEFAULT_INPUT_CHANGE); _PopulateMenu(fInputMenu, list, message); } void SettingsView::AddOutputNodes(NodeList& list) { _EmptyMenu(fOutputMenu); BMessage message(MEDIA_DEFAULT_OUTPUT_CHANGE); _PopulateMenu(fOutputMenu, list, message); } void SettingsView::SetDefaultInput(const dormant_node_info* info) { _ClearMenuSelection(fInputMenu); NodeMenuItem* item = _FindNodeItem(fInputMenu, info); if (item) item->SetMarked(true); } void SettingsView::SetDefaultOutput(const dormant_node_info* info) { _ClearMenuSelection(fOutputMenu); NodeMenuItem* item = _FindNodeItem(fOutputMenu, info); if (item) item->SetMarked(true); } void SettingsView::MessageReceived(BMessage* message) { switch (message->what) { case MEDIA_DEFAULT_INPUT_CHANGE: { int32 index; if (message->FindInt32("index", &index)!=B_OK) break; NodeMenuItem* item = static_cast(fInputMenu->ItemAt(index)); SetDefaultInput(item->NodeInfo()); break; } case MEDIA_DEFAULT_OUTPUT_CHANGE: { int32 index; if (message->FindInt32("index", &index)!=B_OK) break; NodeMenuItem* item = static_cast(fOutputMenu->ItemAt(index)); SetDefaultOutput(item->NodeInfo()); break; } default: BGroupView::MessageReceived(message); } } void SettingsView::AttachedToWindow() { BMessenger thisMessenger(this); fInputMenu->SetTargetForItems(thisMessenger); fOutputMenu->SetTargetForItems(thisMessenger); } MediaWindow* SettingsView::_MediaWindow() const { return static_cast(Window()); } void SettingsView::_EmptyMenu(BMenu* menu) { while (menu->CountItems() > 0) delete menu->RemoveItem((int32)0); } void SettingsView::_PopulateMenu(BMenu* menu, NodeList& nodes, const BMessage& message) { for (int32 i = 0; i < nodes.CountItems(); i++) { dormant_node_info* info = nodes.ItemAt(i); menu->AddItem(new NodeMenuItem(info, new BMessage(message))); } if (Window() != NULL) menu->SetTargetForItems(BMessenger(this)); } NodeMenuItem* SettingsView::_FindNodeItem(BMenu* menu, const dormant_node_info* nodeInfo) { for (int32 i = 0; i < menu->CountItems(); i++) { NodeMenuItem* item = static_cast(menu->ItemAt(i)); const dormant_node_info* itemInfo = item->NodeInfo(); if (itemInfo && itemInfo->addon == nodeInfo->addon && itemInfo->flavor_id == nodeInfo->flavor_id) { return item; } } return NULL; } void SettingsView::_ClearMenuSelection(BMenu* menu) { for (int32 i = 0; i < menu->CountItems(); i++) { BMenuItem* item = menu->ItemAt(i); item->SetMarked(false); } } NodeMenuItem::NodeMenuItem(const dormant_node_info* info, BMessage* message, char shortcut, uint32 modifiers) : BMenuItem(info->name, message, shortcut, modifiers), fInfo(info) { } status_t NodeMenuItem::Invoke(BMessage* message) { if (IsMarked()) return B_OK; return BMenuItem::Invoke(message); } ChannelMenuItem::ChannelMenuItem(media_input* input, BMessage* message, char shortcut, uint32 modifiers) : BMenuItem(input->name, message, shortcut, modifiers), fInput(input) { } ChannelMenuItem::~ChannelMenuItem() { delete fInput; } int32 ChannelMenuItem::DestinationID() { return fInput->destination.id; } media_input* ChannelMenuItem::Input() { return fInput; } status_t ChannelMenuItem::Invoke(BMessage* message) { if (IsMarked()) return B_OK; return BMenuItem::Invoke(message); } AudioSettingsView::AudioSettingsView() { BBox* defaultsBox = new BBox("defaults"); defaultsBox->SetLabel(B_TRANSLATE("Defaults")); BGridView* defaultsGridView = new BGridView(); BMenuField* inputMenuField = new BMenuField("inputMenuField", B_TRANSLATE("Audio input:"), InputMenu()); BMenuField* outputMenuField = new BMenuField("outputMenuField", B_TRANSLATE("Audio output:"), OutputMenu()); BLayoutBuilder::Grid<>(defaultsGridView) .SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) .AddMenuField(inputMenuField, 0, 0, B_ALIGN_HORIZONTAL_UNSET, 1, 3, 1) .AddMenuField(outputMenuField, 0, 1) .AddMenuField(_MakeChannelMenu(), 2, 1); defaultsBox->AddChild(defaultsGridView); BLayoutBuilder::Group<>(this) .SetInsets(0, 0, 0, 0) .Add(defaultsBox) .AddGroup(B_HORIZONTAL) .Add(_MakeVolumeCheckBox()) .AddGlue() .Add(MakeRestartButton()) .End() .AddGlue(); } void AudioSettingsView::SetDefaultChannel(int32 channelID) { for (int32 i = 0; i < fChannelMenu->CountItems(); i++) { ChannelMenuItem* item = _ChannelMenuItemAt(i); item->SetMarked(item->DestinationID() == channelID); } } void AudioSettingsView::AttachedToWindow() { SettingsView::AttachedToWindow(); BMessenger thisMessenger(this); fChannelMenu->SetTargetForItems(thisMessenger); fVolumeCheckBox->SetTarget(thisMessenger); } void AudioSettingsView::MessageReceived(BMessage* message) { switch (message->what) { case ML_DEFAULT_CHANNEL_CHANGED: { int32 index; if (message->FindInt32("index", &index) != B_OK) break; ChannelMenuItem* item = _ChannelMenuItemAt(index); if (item) { BMediaRoster* roster = BMediaRoster::Roster(); roster->SetAudioOutput(*item->Input()); } else fprintf(stderr, "ChannelMenuItem not found\n"); } break; case MEDIA_SHOW_HIDE_VOLUME_CONTROL: { if (fVolumeCheckBox->Value() == B_CONTROL_ON) _ShowDeskbarVolumeControl(); else _HideDeskbarVolumeControl(); break; } default: SettingsView::MessageReceived(message); } } void AudioSettingsView::SetDefaultInput(const dormant_node_info* info) { SettingsView::SetDefaultInput(info); _MediaWindow()->UpdateInputListItem(MediaListItem::AUDIO_TYPE, info); BMediaRoster::Roster()->SetAudioInput(*info); } void AudioSettingsView::SetDefaultOutput(const dormant_node_info* info) { SettingsView::SetDefaultOutput(info); _MediaWindow()->UpdateOutputListItem(MediaListItem::AUDIO_TYPE, info); _FillChannelMenu(info); BMediaRoster::Roster()->SetAudioOutput(*info); } BMenuField* AudioSettingsView::_MakeChannelMenu() { fChannelMenu = new BPopUpMenu(B_TRANSLATE("")); fChannelMenu->SetLabelFromMarked(true); BMenuField* channelMenuField = new BMenuField("channelMenuField", B_TRANSLATE("Channel:"), fChannelMenu); return channelMenuField; } BCheckBox* AudioSettingsView::_MakeVolumeCheckBox() { fVolumeCheckBox = new BCheckBox("volumeCheckBox", B_TRANSLATE("Show volume control on Deskbar"), new BMessage(MEDIA_SHOW_HIDE_VOLUME_CONTROL)); if (BDeskbar().HasItem("MediaReplicant")) fVolumeCheckBox->SetValue(B_CONTROL_ON); return fVolumeCheckBox; } void AudioSettingsView::_FillChannelMenu(const dormant_node_info* nodeInfo) { _EmptyMenu(fChannelMenu); BMediaRoster* roster = BMediaRoster::Roster(); media_node node; media_node_id node_id; status_t err = roster->GetInstancesFor(nodeInfo->addon, nodeInfo->flavor_id, &node_id); if (err != B_OK) { err = roster->InstantiateDormantNode(*nodeInfo, &node, B_FLAVOR_IS_GLOBAL); } else { err = roster->GetNodeFor(node_id, &node); } if (err == B_OK) { int32 inputCount = 4; media_input* inputs = new media_input[inputCount]; BPrivate::ArrayDeleter inputDeleter(inputs); while (true) { int32 realInputCount = 0; err = roster->GetAllInputsFor(node, inputs, inputCount, &realInputCount); if (realInputCount > inputCount) { inputCount *= 2; inputs = new media_input[inputCount]; inputDeleter.SetTo(inputs); } else { inputCount = realInputCount; break; } } if (err == B_OK) { BMessage message(ML_DEFAULT_CHANNEL_CHANGED); for (int32 i = 0; i < inputCount; i++) { media_input* input = new media_input(); *input = inputs[i]; ChannelMenuItem* channelItem = new ChannelMenuItem(input, new BMessage(message)); fChannelMenu->AddItem(channelItem); if (channelItem->DestinationID() == 0) channelItem->SetMarked(true); } } } if (Window()) fChannelMenu->SetTargetForItems(BMessenger(this)); } void AudioSettingsView::_ShowDeskbarVolumeControl() { BDeskbar deskbar; BEntry entry("/bin/desklink", true); int32 id; entry_ref ref; status_t status = entry.GetRef(&ref); if (status == B_OK) status = deskbar.AddItem(&ref, &id); if (status != B_OK) { fprintf(stderr, B_TRANSLATE( "Couldn't add volume control in Deskbar: %s\n"), strerror(status)); } } void AudioSettingsView::_HideDeskbarVolumeControl() { BDeskbar deskbar; status_t status = deskbar.RemoveItem("MediaReplicant"); if (status != B_OK) { fprintf(stderr, B_TRANSLATE( "Couldn't remove volume control in Deskbar: %s\n"), strerror(status)); } } ChannelMenuItem* AudioSettingsView::_ChannelMenuItemAt(int32 index) { return static_cast(fChannelMenu->ItemAt(index)); } VideoSettingsView::VideoSettingsView() { BBox* defaultsBox = new BBox("defaults"); defaultsBox->SetLabel(B_TRANSLATE("Defaults")); BGridView* defaultsGridView = new BGridView(); BMenuField* inputMenuField = new BMenuField("inputMenuField", B_TRANSLATE("Video input:"), InputMenu()); BMenuField* outputMenuField = new BMenuField("outputMenuField", B_TRANSLATE("Video output:"), OutputMenu()); BLayoutBuilder::Grid<>(defaultsGridView) .SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) .AddMenuField(inputMenuField, 0, 0) .AddMenuField(outputMenuField, 0, 1); defaultsBox->AddChild(defaultsGridView); BLayoutBuilder::Group<>(this) .SetInsets(0, 0, 0, 0) .Add(defaultsBox) .AddGroup(B_HORIZONTAL) .AddGlue() .Add(MakeRestartButton()) .End() .AddGlue(); } void VideoSettingsView::SetDefaultInput(const dormant_node_info* info) { SettingsView::SetDefaultInput(info); _MediaWindow()->UpdateInputListItem(MediaListItem::VIDEO_TYPE, info); BMediaRoster::Roster()->SetVideoInput(*info); } void VideoSettingsView::SetDefaultOutput(const dormant_node_info* info) { SettingsView::SetDefaultOutput(info); _MediaWindow()->UpdateOutputListItem(MediaListItem::VIDEO_TYPE, info); BMediaRoster::Roster()->SetVideoOutput(*info); }