tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / bin / desklink / MediaReplicant.cpp
blob2b8d18e9ce18801ddeabf46c4ff1285b898254da
1 /*
2 * Copyright 2003-2013, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Jérôme Duval
7 * François Revol
8 * Marcus Overhagen
9 * Jonas Sundström
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
19 #include <new>
20 #include <stdio.h>
22 #include <Alert.h>
23 #include <Bitmap.h>
24 #include <Catalog.h>
25 #include <Entry.h>
26 #include <File.h>
27 #include <FindDirectory.h>
28 #include <IconUtils.h>
29 #include <MenuItem.h>
30 #include <Path.h>
31 #include <PopUpMenu.h>
32 #include <Roster.h>
33 #include <String.h>
34 #include <StringView.h>
35 #include <ToolTip.h>
36 #include <ToolTipManager.h>
38 #include "desklink.h"
39 #include "iconfile.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 {
61 public:
62 VolumeToolTip(int32 which = VOLUME_USE_MIXER)
64 fWhich(which)
66 fView = new BStringView("", "");
69 virtual ~VolumeToolTip()
71 delete fView;
74 virtual BView* View() const
76 return fView;
79 virtual void AttachedToWindow()
81 Update();
84 void SetWhich(int32 which)
86 fWhich = which;
89 void Update()
91 if (!Lock())
92 return;
94 if (fMuteMessage.Length() != 0)
95 fView->SetText(fMuteMessage.String());
96 else {
97 MixerControl control;
98 control.Connect(fWhich);
100 BString text;
101 text.SetToFormat(B_TRANSLATE("%g dB"), control.Volume());
102 fView->SetText(text.String());
105 Unlock();
108 void SetMuteMessage(const char* message)
110 fMuteMessage = message == NULL ? "" : message;
113 private:
114 BStringView* fView;
115 int32 fWhich;
116 BString fMuteMessage;
120 class MediaReplicant : public BView {
121 public:
122 MediaReplicant(BRect frame, const char* name,
123 uint32 resizeMask = B_FOLLOW_ALL,
124 uint32 flags = B_WILL_DRAW | B_NAVIGABLE
125 | B_PULSE_NEEDED);
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;
134 // BView overrides
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();
141 private:
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();
149 void _Init();
151 BBitmap* fIcon;
152 BBitmap* fMutedIcon;
153 VolumeWindow* fVolumeSlider;
154 bool fDontBeep;
155 // don't beep on volume change
156 int32 fVolumeWhich;
157 // which volume parameter to act on (Mixer/Phys.Output)
158 bool fMuted;
162 MediaReplicant::MediaReplicant(BRect frame, const char* name,
163 uint32 resizeMask, uint32 flags)
165 BView(frame, name, resizeMask, flags),
166 fVolumeSlider(NULL),
167 fMuted(false)
169 _Init();
173 MediaReplicant::MediaReplicant(BMessage* message)
175 BView(message),
176 fVolumeSlider(NULL),
177 fMuted(false)
179 _Init();
183 MediaReplicant::~MediaReplicant()
185 delete fIcon;
186 _SaveSettings();
190 MediaReplicant*
191 MediaReplicant::Instantiate(BMessage* data)
193 if (!validate_instantiation(data, kReplicantName))
194 return NULL;
196 return new(std::nothrow) MediaReplicant(data);
200 status_t
201 MediaReplicant::Archive(BMessage* data, bool deep) const
203 status_t status = BView::Archive(data, deep);
204 if (status < B_OK)
205 return status;
207 return data->AddString("add_on", kAppSignature);
211 void
212 MediaReplicant::AttachedToWindow()
214 BView* parent = Parent();
215 if (parent)
216 SetViewColor(parent->ViewColor());
218 BView::AttachedToWindow();
222 void
223 MediaReplicant::Draw(BRect rect)
225 SetDrawingMode(B_OP_OVER);
226 DrawBitmap(fMuted ? fMutedIcon : fIcon);
230 void
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());
282 if (tip != NULL) {
283 tip->SetMuteMessage(fMuted ? B_TRANSLATE("Muted"): NULL);
284 ShowToolTip(tip);
286 Invalidate();
289 } else {
290 // Show VolumeWindow
291 fVolumeSlider = new VolumeWindow(BRect(where.x, where.y,
292 where.x + 207, where.y + 19), fDontBeep, fVolumeWhich);
293 fVolumeSlider->Show();
298 void
299 MediaReplicant::Pulse()
301 bool setMuted = false;
302 MixerControl mixerControl;
303 const char* errorString = NULL;
304 if (!mixerControl.Connect(fVolumeWhich, NULL, &errorString)) {
305 fMuted = true;
306 errorString = NULL;
307 } else
308 setMuted = mixerControl.Mute();
310 if (setMuted != fMuted) {
311 fMuted = setMuted;
312 VolumeToolTip* tip = dynamic_cast<VolumeToolTip*>(ToolTip());
313 if (tip != NULL)
314 tip->SetMuteMessage(errorString);
315 Invalidate();
320 void
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");
327 break;
329 case kMsgOpenMediaSettings:
330 _Launch("Media Preferences", "application/x-vnd.Haiku-Media",
331 B_SYSTEM_PREFERENCES_DIRECTORY, "Media");
332 break;
334 case kMsgOpenSoundSettings:
335 _Launch("Sounds Preferences", "application/x-vnd.Haiku-Sounds",
336 B_SYSTEM_PREFERENCES_DIRECTORY, "Sounds");
337 break;
339 case kMsgToggleBeep:
341 BMenuItem* item;
342 if (message->FindPointer("source", (void**)&item) != B_OK)
343 return;
345 item->SetMarked(!item->IsMarked());
346 fDontBeep = !item->IsMarked();
347 break;
350 case kMsgVolumeWhich:
352 BMenuItem* item;
353 if (message->FindPointer("source", (void**)&item) != B_OK)
354 return;
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);
362 break;
365 case B_MOUSE_WHEEL_CHANGED:
367 float deltaY;
368 if (message->FindFloat("be:wheel_delta_y", &deltaY) == B_OK
369 && deltaY != 0.0) {
370 MixerControl mixerControl;
371 mixerControl.Connect(fVolumeWhich);
372 mixerControl.ChangeVolumeBy(deltaY < 0 ? 6 : -6);
374 VolumeToolTip* tip = dynamic_cast<VolumeToolTip*>(ToolTip());
375 if (tip != NULL) {
376 tip->Update();
377 ShowToolTip(tip);
380 break;
383 default:
384 BView::MessageReceived(message);
385 break;
390 status_t
391 MediaReplicant::_LaunchByPath(const char* path)
393 entry_ref ref;
394 status_t status = get_ref_for_path(path, &ref);
395 if (status != B_OK)
396 return status;
398 status = be_roster->Launch(&ref);
399 if (status != B_ALREADY_RUNNING)
400 return status;
402 // The application runs already, bring it to front
404 app_info appInfo;
405 status = be_roster->GetAppInfo(&ref, &appInfo);
406 if (status != B_OK)
407 return status;
409 return be_roster->ActivateApp(appInfo.team);
413 status_t
414 MediaReplicant::_LaunchBySignature(const char* signature)
416 status_t status = be_roster->Launch(signature);
417 if (status != B_ALREADY_RUNNING)
418 return status;
420 // The application runs already, bring it to front
422 app_info appInfo;
423 status = be_roster->GetAppInfo(signature, &appInfo);
424 if (status != B_OK)
425 return status;
427 return be_roster->ActivateApp(appInfo.team);
431 void
432 MediaReplicant::_Launch(const char* prettyName, const char* signature,
433 directory_which base, const char* fileName)
435 BPath path;
436 status_t status = find_directory(base, &path);
437 if (status == B_OK)
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(),
447 B_TRANSLATE("OK"));
448 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
449 alert->Go();
454 void
455 MediaReplicant::_LoadSettings()
457 fDontBeep = false;
458 fVolumeWhich = VOLUME_USE_MIXER;
460 BPath path;
461 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, false) < B_OK)
462 return;
464 path.Append(kSettingsFile);
466 BFile settings(path.Path(), B_READ_ONLY);
467 if (settings.InitCheck() < B_OK)
468 return;
470 BMessage msg;
471 if (msg.Unflatten(&settings) < B_OK)
472 return;
474 msg.FindInt32("volwhich", &fVolumeWhich);
475 msg.FindBool("dontbeep", &fDontBeep);
479 void
480 MediaReplicant::_SaveSettings()
482 BPath path;
483 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, false) < B_OK)
484 return;
486 path.Append(kSettingsFile);
488 BFile settings(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
489 if (settings.InitCheck() < B_OK)
490 return;
492 BMessage msg('CNFG');
493 msg.AddInt32("volwhich", fVolumeWhich);
494 msg.AddBool("dontbeep", fDontBeep);
496 ssize_t size = 0;
497 msg.Flatten(&settings, &size);
501 void
502 MediaReplicant::_Init()
504 fIcon = new BBitmap(BRect(0, 0, kSpeakerWidth - 1, kSpeakerHeight - 1),
505 B_RGBA32);
506 BIconUtils::GetVectorIcon(kSpeakerIcon, sizeof(kSpeakerIcon), fIcon);
508 fMutedIcon = new BBitmap(BRect(0, 0, kSpeakerWidth - 1, kSpeakerHeight - 1),
509 B_RGBA32);
510 BIconUtils::GetVectorIcon(kMutedSpeakerIcon, sizeof(kMutedSpeakerIcon),
511 fMutedIcon);
513 _LoadSettings();
515 SetToolTip(new VolumeToolTip(fVolumeWhich));
519 // #pragma mark -
522 extern "C" BView*
523 instantiate_deskbar_item(void)
525 return new MediaReplicant(BRect(0, 0, 16, 16), kReplicantName);