/* * Copyright 2000-2008, François Revol, . All rights reserved. * Distributed under the terms of the MIT License. */ /* * WinampSkin ThemesAddon class */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ThemesAddon.h" #include "UITheme.h" #ifdef SINGLE_BINARY #define instantiate_themes_addon instantiate_themes_addon_winamp_skin #endif #define A_NAME "Winamp Skin" #define A_MSGNAME Z_THEME_WINAMP_SKIN_SETTINGS #define A_DESCRIPTION "Handle CL-Amp and SoundPlay (not yet) Skins - requires SkinSelector plugin to be activated in CL-Amp and SoundPlay." #define CL_SETTINGS_NAME "CL-Amp/CL-Amp.preferences" #define CL_APP_SIG "application/x-vnd.ClaesL-CLAmp" #define SP_SETTINGS_NAME "PrefServer/pref0:$USER:application:x-vnd.marcone-soundplay" //BMessage('save') { //skinpath = string("/wincrash/Program Files/Winamp/Skins", 37 bytes) //skinname = string("/wincrash/Program Files/Winamp/Skins/XP_Amp_2.wsz", 50 bytes) } #define SP_APP_SIG "application/x-vnd.marcone-soundplay" #define USE_CL 1 #define USE_SP 2 class WinampSkinThemesAddon : public ThemesAddon { public: WinampSkinThemesAddon(); ~WinampSkinThemesAddon(); const char *Description(); status_t RunPreferencesPanel(); status_t AddNames(BMessage &names); status_t ApplyTheme(BMessage &theme, uint32 flags=0L); status_t MakeTheme(BMessage &theme, uint32 flags=0L); status_t ApplyDefaultTheme(uint32 flags=0L); int32 WhichApp(); /* which app should I use to repport current skin? */ status_t CLSkin(BString *to, bool preffile = false); status_t SPSkin(BString *to, bool preffile = false); status_t CLSkinPath(BPath *to); status_t SPSkinPath(BPath *to); status_t SetCLSkin(BString *from); status_t SetSPSkin(BString *from); status_t StripPath(BString *path); }; WinampSkinThemesAddon::WinampSkinThemesAddon() : ThemesAddon(A_NAME, A_MSGNAME) { } WinampSkinThemesAddon::~WinampSkinThemesAddon() { } const char * WinampSkinThemesAddon::Description() { return A_DESCRIPTION; } status_t WinampSkinThemesAddon::RunPreferencesPanel() { return B_OK; } status_t WinampSkinThemesAddon::AddNames(BMessage &names) { names.AddString(Z_THEME_WINAMP_SKIN_SETTINGS, "CLAmp/SoundPlay Skin Settings"); return B_OK; } status_t WinampSkinThemesAddon::ApplyTheme(BMessage &theme, uint32 flags) { BMessage skin; BString name; status_t err; if (!(flags & UI_THEME_SETTINGS_SET_ALL) || !(AddonFlags() & Z_THEME_ADDON_DO_SET_ALL)) return B_OK; err = MyMessage(theme, skin); if (err) return err; err = skin.FindString("winamp:skin", &name); if (err) return err; SetCLSkin(&name); SetSPSkin(&name); return B_OK; } status_t WinampSkinThemesAddon::MakeTheme(BMessage &theme, uint32 flags) { BMessage skin; BString name; status_t err = B_ERROR; (void)flags; err = MyMessage(theme, skin); if (err) skin.MakeEmpty(); if (WhichApp() == USE_CL) err = CLSkin(&name); else err = SPSkin(&name); /* try the other way round */ if (err) if (WhichApp() == USE_CL) err = CLSkin(&name, true); else err = SPSkin(&name, true); if (!err) skin.AddString("winamp:skin", name); err = SetMyMessage(theme, skin); return err; } status_t WinampSkinThemesAddon::ApplyDefaultTheme(uint32 flags) { BMessage theme; BMessage skin; skin.AddString("skin", "none"); theme.AddMessage(Z_THEME_WINAMP_SKIN_SETTINGS, &skin); return ApplyTheme(theme, flags); } int32 WinampSkinThemesAddon::WhichApp() { // XXX /* BMessenger spmsgr(SP_APP_SIG); if (spmsgr.IsValid()) { PRINT(("WinampSkinThemesAddon: SoundPlay BMessenger valid\n")); return USE_SP; }*/ BMessenger clmsgr(CL_APP_SIG); if (clmsgr.IsValid()) { PRINT(("WinampSkinThemesAddon: CL-Amp BMessenger valid\n")); return USE_CL; } return USE_SP; } status_t WinampSkinThemesAddon::CLSkin(BString *to, bool preffile) { if (preffile) { BPath CLSPath; char buffer[B_FILE_NAME_LENGTH+1]; if (!to) return EINVAL; buffer[B_FILE_NAME_LENGTH] = '\0'; if (find_directory(B_USER_SETTINGS_DIRECTORY, &CLSPath) < B_OK) return B_ERROR; CLSPath.Append(CL_SETTINGS_NAME); BFile CLSettings(CLSPath.Path(), B_READ_ONLY); if (CLSettings.InitCheck() < B_OK) return CLSettings.InitCheck(); ssize_t got = CLSettings.ReadAt(0x8LL, buffer, B_FILE_NAME_LENGTH); if (got < B_FILE_NAME_LENGTH) return EIO; *to = buffer; StripPath(to); return B_ERROR; } BMessenger msgr(CL_APP_SIG); BMessage msg('skin'); BMessage reply; msgr.SendMessage(&msg, &reply, 500000, 500000); if (reply.FindString("result", to) >= B_OK) { StripPath(to); return B_OK; } return B_ERROR; } status_t WinampSkinThemesAddon::SPSkin(BString *to, bool preffile) { if (preffile) { status_t err; BMessage settings; BPath SPSPath; if (find_directory(B_USER_SETTINGS_DIRECTORY, &SPSPath) < B_OK) return B_ERROR; BString leaf(SP_SETTINGS_NAME); BString user(getenv("USER")); user.RemoveFirst("USER="); leaf.IReplaceFirst("$USER", user.String()); SPSPath.Append(leaf.String()); PRINT(("SPP %s\n", SPSPath.Path())); BFile SPSettings(SPSPath.Path(), B_READ_ONLY); if (SPSettings.InitCheck() < B_OK) return SPSettings.InitCheck(); if (settings.Unflatten(&SPSettings) < B_OK) return EIO; err = settings.FindString("skinname", to); StripPath(to); return err; } BMessenger msgr(SP_APP_SIG); BMessage msg('skin'); BMessage reply; msgr.SendMessage(&msg, (BHandler *)NULL, 500000); if (reply.FindString("result", to) >= B_OK) { StripPath(to); return B_OK; } return B_ERROR; } status_t WinampSkinThemesAddon::CLSkinPath(BPath *to) { char buffer[B_FILE_NAME_LENGTH+1]; BPath CLSPath; buffer[B_FILE_NAME_LENGTH] = '\0'; if (find_directory(B_USER_SETTINGS_DIRECTORY, &CLSPath) < B_OK) return B_ERROR; CLSPath.Append(CL_SETTINGS_NAME); BFile CLSettings(CLSPath.Path(), B_READ_ONLY); if (CLSettings.InitCheck() < B_OK) return CLSettings.InitCheck(); ssize_t got = CLSettings.ReadAt(0x150LL, buffer, B_FILE_NAME_LENGTH); if (got < B_FILE_NAME_LENGTH) return EIO; to->SetTo(buffer); return B_OK; } status_t WinampSkinThemesAddon::SPSkinPath(BPath *to) { status_t err; BMessage settings; BPath SPSPath; BString str; if (find_directory(B_USER_SETTINGS_DIRECTORY, &SPSPath) < B_OK) return B_ERROR; BString leaf(SP_SETTINGS_NAME); BString user(getenv("USER")); user.RemoveFirst("USER="); leaf.IReplaceFirst("$USER", user.String()); SPSPath.Append(leaf.String()); BFile SPSettings(SPSPath.Path(), B_READ_ONLY); if (SPSettings.InitCheck() < B_OK) return SPSettings.InitCheck(); if (settings.Unflatten(&SPSettings) < B_OK) return EIO; err = settings.FindString("skinpath", &str); PRINT(("SPSP %s\n", str.String())); to->SetTo(str.String()); return err; } status_t WinampSkinThemesAddon::SetCLSkin(BString *from) { status_t err; BPath p; err = CLSkinPath(&p); if (err < B_OK) return err; p.Append(from->String()); /* update the prefs file */ BPath CLSPath; if (!from) return EINVAL; /* CL-Amp doesn't grok long names */ if (strlen(p.Path()) >= B_FILE_NAME_LENGTH) return B_NAME_TOO_LONG; if (find_directory(B_USER_SETTINGS_DIRECTORY, &CLSPath) < B_OK) return B_ERROR; CLSPath.Append(CL_SETTINGS_NAME); BFile CLSettings(CLSPath.Path(), B_WRITE_ONLY); if (CLSettings.InitCheck() < B_OK) return CLSettings.InitCheck(); CLSettings.WriteAt(0x8LL, p.Path(), strlen(p.Path())+1); /* then tell the app */ BMessenger msgr(CL_APP_SIG); BMessage msg('skin'); msg.AddString("name", p.Path()); msg.PrintToStream(); msgr.SendMessage(&msg, (BHandler *)NULL, 500000); return B_OK; } status_t WinampSkinThemesAddon::SetSPSkin(BString *from) { status_t err; BPath p; err = SPSkinPath(&p); if (err < B_OK) return err; p.Append(from->String()); err = p.InitCheck(); if (err < B_OK) return err; /* update the prefs file */ BPath SPSPath; BMessage settings; if (!from) return EINVAL; if (from->Length() >= B_PATH_NAME_LENGTH) return B_NAME_TOO_LONG; if (find_directory(B_USER_SETTINGS_DIRECTORY, &SPSPath) < B_OK) return B_ERROR; BString leaf(SP_SETTINGS_NAME); BString user(getenv("USER")); user.RemoveFirst("USER="); leaf.IReplaceFirst("$USER", user.String()); SPSPath.Append(leaf.String()); PRINT(("SPP %s\n", SPSPath.Path())); BFile SPSettings(SPSPath.Path(), B_READ_WRITE); PRINT(("SP:BFile\n")); if (SPSettings.InitCheck() < B_OK) return SPSettings.InitCheck(); PRINT(("SP:BFile::InitCheck\n")); //SPSettings.WriteAt(0x8LL, from->String(), from->Length()+1); if (settings.Unflatten(&SPSettings) < B_OK) return EIO; PRINT(("SP:Unflatten\n")); settings.ReplaceString("skinname", p.Path()); PRINT(("SP:Replace\n")); SPSettings.Seek(0LL, SEEK_SET); if (settings.Flatten(&SPSettings) < B_OK) return EIO; PRINT(("SP:Flatten\n")); /* then tell the app */ /* first make sure the native BeOS is shown (the 'sk!n' message toggles, wonder Why TF...) */ bool beosIfaceHidden; BMessenger msgr(SP_APP_SIG); BMessage command(B_GET_PROPERTY); BMessage answer; command.AddSpecifier("Hidden"); command.AddSpecifier("Window", 0L); // TitleSpectrumAnalyzer does change the title from "SoundPlay"! err = msgr.SendMessage(&command, &answer,(bigtime_t)2E6,(bigtime_t)2E6); if(B_OK == err) { if (answer.FindBool("result", &beosIfaceHidden) != B_OK) beosIfaceHidden = false; } else { PRINT(("WinampSkinThemesAddon: couldn't talk to SoundPlay: error 0x%08lx\n", err)); return EIO; } BMessage msg('sk!n'); msg.AddString("path", p.Path()); msg.PrintToStream(); if (!beosIfaceHidden) { // native GUI is active // -> sending the message to the App will make ituse the skin for all tracks PRINT(("SP:Sending to app\n")); msgr.SendMessage(&msg, (BHandler *)NULL, 500000); } else { // native GUI is hidden (= winamp GUI used) int32 wincnt; command.MakeEmpty(); command.what = B_COUNT_PROPERTIES; answer.MakeEmpty(); command.AddSpecifier("Window"); err = msgr.SendMessage(&command, &answer,(bigtime_t)2E6,(bigtime_t)2E6); if(B_OK == err) { if (answer.FindInt32("result", &wincnt) != B_OK) wincnt = 1; } else { PRINT(("WinampSkinThemesAddon: couldn't talk to SoundPlay: (2) error 0x%08lx\n", err)); return EIO; } // send to all windows but first one. for (int32 i = 1; i < wincnt; i++) { BMessage wmsg(msg); PRINT(("SP:Sending to window %ld\n", i)); wmsg.AddSpecifier("Window", i); wmsg.PrintToStream(); msgr.SendMessage(&wmsg, (BHandler *)NULL, 500000); } } return B_OK; } status_t WinampSkinThemesAddon::StripPath(BString *path) { if (!path) return EINVAL; BPath p(path->String()); *path = p.Leaf(); return B_OK; } ThemesAddon * instantiate_themes_addon() { return (ThemesAddon *) new WinampSkinThemesAddon; }