2 * Copyright 2003-2013, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
10 * Axel Dörfler, axeld@pinc-software.de.
11 * Stephan Aßmus <superstippi@gmx.de>
12 * Puck Meerburg, puck@puckipedia.nl
16 //! Volume control, and media shortcuts in Deskbar
27 #include <FindDirectory.h>
28 #include <IconUtils.h>
31 #include <PopUpMenu.h>
34 #include <StringView.h>
36 #include <ToolTipManager.h>
40 #include "MixerControl.h"
41 #include "VolumeWindow.h"
44 #undef B_TRANSLATION_CONTEXT
45 #define B_TRANSLATION_CONTEXT "MediaReplicant"
48 static const uint32 kMsgOpenMediaSettings
= 'mese';
49 static const uint32 kMsgOpenSoundSettings
= 'sose';
50 static const uint32 kMsgOpenMediaPlayer
= 'omep';
51 static const uint32 kMsgToggleBeep
= 'tdbp';
52 static const uint32 kMsgVolumeWhich
= 'svwh';
54 static const char* kReplicantName
= "MediaReplicant";
55 // R5 name needed, Media prefs manel removes by name
57 static const char* kSettingsFile
= "x-vnd.Haiku-desklink";
60 class VolumeToolTip
: public BToolTip
{
62 VolumeToolTip(int32 which
= VOLUME_USE_MIXER
)
66 fView
= new BStringView("", "");
69 virtual ~VolumeToolTip()
74 virtual BView
* View() const
79 virtual void AttachedToWindow()
84 void SetWhich(int32 which
)
94 if (fMuteMessage
.Length() != 0)
95 fView
->SetText(fMuteMessage
.String());
98 control
.Connect(fWhich
);
101 text
.SetToFormat(B_TRANSLATE("%g dB"), control
.Volume());
102 fView
->SetText(text
.String());
108 void SetMuteMessage(const char* message
)
110 fMuteMessage
= message
== NULL
? "" : message
;
116 BString fMuteMessage
;
120 class MediaReplicant
: public BView
{
122 MediaReplicant(BRect frame
, const char* name
,
123 uint32 resizeMask
= B_FOLLOW_ALL
,
124 uint32 flags
= B_WILL_DRAW
| B_NAVIGABLE
126 MediaReplicant(BMessage
* archive
);
128 virtual ~MediaReplicant();
130 // archiving overrides
131 static MediaReplicant
* Instantiate(BMessage
* data
);
132 virtual status_t
Archive(BMessage
* data
, bool deep
= true) const;
135 virtual void AttachedToWindow();
136 virtual void MouseDown(BPoint point
);
137 virtual void Draw(BRect updateRect
);
138 virtual void MessageReceived(BMessage
* message
);
139 virtual void Pulse();
142 status_t
_LaunchByPath(const char* path
);
143 status_t
_LaunchBySignature(const char* signature
);
144 void _Launch(const char* prettyName
,
145 const char* signature
, directory_which base
,
146 const char* fileName
);
147 void _LoadSettings();
148 void _SaveSettings();
153 VolumeWindow
* fVolumeSlider
;
155 // don't beep on volume change
157 // which volume parameter to act on (Mixer/Phys.Output)
162 MediaReplicant::MediaReplicant(BRect frame
, const char* name
,
163 uint32 resizeMask
, uint32 flags
)
165 BView(frame
, name
, resizeMask
, flags
),
173 MediaReplicant::MediaReplicant(BMessage
* message
)
183 MediaReplicant::~MediaReplicant()
191 MediaReplicant::Instantiate(BMessage
* data
)
193 if (!validate_instantiation(data
, kReplicantName
))
196 return new(std::nothrow
) MediaReplicant(data
);
201 MediaReplicant::Archive(BMessage
* data
, bool deep
) const
203 status_t status
= BView::Archive(data
, deep
);
207 return data
->AddString("add_on", kAppSignature
);
212 MediaReplicant::AttachedToWindow()
214 BView
* parent
= Parent();
216 SetViewColor(parent
->ViewColor());
218 BView::AttachedToWindow();
223 MediaReplicant::Draw(BRect rect
)
225 SetDrawingMode(B_OP_OVER
);
226 DrawBitmap(fMuted
? fMutedIcon
: fIcon
);
231 MediaReplicant::MouseDown(BPoint point
)
233 int32 buttons
= B_PRIMARY_MOUSE_BUTTON
;
234 if (Looper() != NULL
&& Looper()->CurrentMessage() != NULL
)
235 Looper()->CurrentMessage()->FindInt32("buttons", &buttons
);
237 BPoint where
= ConvertToScreen(point
);
239 if ((buttons
& B_SECONDARY_MOUSE_BUTTON
) != 0) {
240 BPopUpMenu
* menu
= new BPopUpMenu("", false, false);
241 menu
->SetFont(be_plain_font
);
243 menu
->AddItem(new BMenuItem(
244 B_TRANSLATE("Media preferences" B_UTF8_ELLIPSIS
),
245 new BMessage(kMsgOpenMediaSettings
)));
246 menu
->AddItem(new BMenuItem(
247 B_TRANSLATE("Sound preferences" B_UTF8_ELLIPSIS
),
248 new BMessage(kMsgOpenSoundSettings
)));
250 menu
->AddSeparatorItem();
252 menu
->AddItem(new BMenuItem(B_TRANSLATE("Open MediaPlayer"),
253 new BMessage(kMsgOpenMediaPlayer
)));
255 menu
->AddSeparatorItem();
257 BMenu
* subMenu
= new BMenu(B_TRANSLATE("Options"));
258 menu
->AddItem(subMenu
);
260 BMenuItem
* item
= new BMenuItem(B_TRANSLATE("Control physical output"),
261 new BMessage(kMsgVolumeWhich
));
262 item
->SetMarked(fVolumeWhich
== VOLUME_USE_PHYS_OUTPUT
);
263 subMenu
->AddItem(item
);
265 item
= new BMenuItem(B_TRANSLATE("Beep"),
266 new BMessage(kMsgToggleBeep
));
267 item
->SetMarked(!fDontBeep
);
268 subMenu
->AddItem(item
);
270 menu
->SetTargetForItems(this);
271 subMenu
->SetTargetForItems(this);
273 menu
->Go(where
, true, true, BRect(where
- BPoint(4, 4),
274 where
+ BPoint(4, 4)));
276 } else if ((buttons
& B_TERTIARY_MOUSE_BUTTON
) != 0) {
277 MixerControl mixerControl
;
278 if (mixerControl
.Connect(fVolumeWhich
)) {
279 mixerControl
.SetMute(!fMuted
);
280 fMuted
= mixerControl
.Mute();
281 VolumeToolTip
* tip
= dynamic_cast<VolumeToolTip
*>(ToolTip());
283 tip
->SetMuteMessage(fMuted
? B_TRANSLATE("Muted"): NULL
);
291 fVolumeSlider
= new VolumeWindow(BRect(where
.x
, where
.y
,
292 where
.x
+ 207, where
.y
+ 19), fDontBeep
, fVolumeWhich
);
293 fVolumeSlider
->Show();
299 MediaReplicant::Pulse()
301 bool setMuted
= false;
302 MixerControl mixerControl
;
303 const char* errorString
= NULL
;
304 if (!mixerControl
.Connect(fVolumeWhich
, NULL
, &errorString
)) {
308 setMuted
= mixerControl
.Mute();
310 if (setMuted
!= fMuted
) {
312 VolumeToolTip
* tip
= dynamic_cast<VolumeToolTip
*>(ToolTip());
314 tip
->SetMuteMessage(errorString
);
321 MediaReplicant::MessageReceived(BMessage
* message
)
323 switch (message
->what
) {
324 case kMsgOpenMediaPlayer
:
325 _Launch("MediaPlayer", "application/x-vnd.Haiku-MediaPlayer",
326 B_SYSTEM_APPS_DIRECTORY
, "MediaPlayer");
329 case kMsgOpenMediaSettings
:
330 _Launch("Media Preferences", "application/x-vnd.Haiku-Media",
331 B_SYSTEM_PREFERENCES_DIRECTORY
, "Media");
334 case kMsgOpenSoundSettings
:
335 _Launch("Sounds Preferences", "application/x-vnd.Haiku-Sounds",
336 B_SYSTEM_PREFERENCES_DIRECTORY
, "Sounds");
342 if (message
->FindPointer("source", (void**)&item
) != B_OK
)
345 item
->SetMarked(!item
->IsMarked());
346 fDontBeep
= !item
->IsMarked();
350 case kMsgVolumeWhich
:
353 if (message
->FindPointer("source", (void**)&item
) != B_OK
)
356 item
->SetMarked(!item
->IsMarked());
357 fVolumeWhich
= item
->IsMarked()
358 ? VOLUME_USE_PHYS_OUTPUT
: VOLUME_USE_MIXER
;
360 if (VolumeToolTip
* tip
= dynamic_cast<VolumeToolTip
*>(ToolTip()))
361 tip
->SetWhich(fVolumeWhich
);
365 case B_MOUSE_WHEEL_CHANGED
:
368 if (message
->FindFloat("be:wheel_delta_y", &deltaY
) == B_OK
370 MixerControl mixerControl
;
371 mixerControl
.Connect(fVolumeWhich
);
372 mixerControl
.ChangeVolumeBy(deltaY
< 0 ? 6 : -6);
374 VolumeToolTip
* tip
= dynamic_cast<VolumeToolTip
*>(ToolTip());
384 BView::MessageReceived(message
);
391 MediaReplicant::_LaunchByPath(const char* path
)
394 status_t status
= get_ref_for_path(path
, &ref
);
398 status
= be_roster
->Launch(&ref
);
399 if (status
!= B_ALREADY_RUNNING
)
402 // The application runs already, bring it to front
405 status
= be_roster
->GetAppInfo(&ref
, &appInfo
);
409 return be_roster
->ActivateApp(appInfo
.team
);
414 MediaReplicant::_LaunchBySignature(const char* signature
)
416 status_t status
= be_roster
->Launch(signature
);
417 if (status
!= B_ALREADY_RUNNING
)
420 // The application runs already, bring it to front
423 status
= be_roster
->GetAppInfo(signature
, &appInfo
);
427 return be_roster
->ActivateApp(appInfo
.team
);
432 MediaReplicant::_Launch(const char* prettyName
, const char* signature
,
433 directory_which base
, const char* fileName
)
436 status_t status
= find_directory(base
, &path
);
438 path
.Append(fileName
);
440 // launch the application
441 if (_LaunchBySignature(signature
) != B_OK
442 && _LaunchByPath(path
.Path()) != B_OK
) {
443 BString message
= B_TRANSLATE("Couldn't launch ");
444 message
<< prettyName
;
446 BAlert
* alert
= new BAlert(B_TRANSLATE("desklink"), message
.String(),
448 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
455 MediaReplicant::_LoadSettings()
458 fVolumeWhich
= VOLUME_USE_MIXER
;
461 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
, false) < B_OK
)
464 path
.Append(kSettingsFile
);
466 BFile
settings(path
.Path(), B_READ_ONLY
);
467 if (settings
.InitCheck() < B_OK
)
471 if (msg
.Unflatten(&settings
) < B_OK
)
474 msg
.FindInt32("volwhich", &fVolumeWhich
);
475 msg
.FindBool("dontbeep", &fDontBeep
);
480 MediaReplicant::_SaveSettings()
483 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
, false) < B_OK
)
486 path
.Append(kSettingsFile
);
488 BFile
settings(path
.Path(), B_WRITE_ONLY
| B_CREATE_FILE
| B_ERASE_FILE
);
489 if (settings
.InitCheck() < B_OK
)
492 BMessage
msg('CNFG');
493 msg
.AddInt32("volwhich", fVolumeWhich
);
494 msg
.AddBool("dontbeep", fDontBeep
);
497 msg
.Flatten(&settings
, &size
);
502 MediaReplicant::_Init()
504 fIcon
= new BBitmap(BRect(0, 0, kSpeakerWidth
- 1, kSpeakerHeight
- 1),
506 BIconUtils::GetVectorIcon(kSpeakerIcon
, sizeof(kSpeakerIcon
), fIcon
);
508 fMutedIcon
= new BBitmap(BRect(0, 0, kSpeakerWidth
- 1, kSpeakerHeight
- 1),
510 BIconUtils::GetVectorIcon(kMutedSpeakerIcon
, sizeof(kMutedSpeakerIcon
),
515 SetToolTip(new VolumeToolTip(fVolumeWhich
));
523 instantiate_deskbar_item(void)
525 return new MediaReplicant(BRect(0, 0, 16, 16), kReplicantName
);