app.cpp
来自「Amarok是一款在LINUX或其他类UNIX操作系统中运行的音频播放器软件。 」· C++ 代码 · 共 1,488 行 · 第 1/4 页
CPP
1,488 行
/*************************************************************************** app.cpp - description -------------------begin : Mit Okt 23 14:35:18 CEST 2002copyright : (C) 2002 by Mark Kretschmannemail : markey@web.de***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "amarok.h"#include "amarokconfig.h"#include "amarokdcophandler.h"#include "app.h"#include "atomicstring.h"#include "config.h"#include "configdialog.h"#include "contextbrowser.h"#include "collectionbrowser.h"#include "dbsetup.h" //firstRunWizard()#include "debug.h"#include "devicemanager.h"#include "mediadevicemanager.h"#include "enginebase.h"#include "enginecontroller.h"#include "equalizersetup.h"#include "firstrunwizard.h"#include "mediabrowser.h"#include "metabundle.h"#include "mountpointmanager.h"#include "osd.h"#include "playerwindow.h"#include "playlist.h"#include "playlistbrowser.h"#include "playlistwindow.h"#include "pluginmanager.h"#include "refreshimages.h"#include "scriptmanager.h"#include "scrobbler.h"#include "statusbar.h"#include "systray.h"#include "threadmanager.h"#include "tracktooltip.h" //engineNewMetaData()#include <iostream>#include <kconfigdialogmanager.h>#include <kcombobox.h> //firstRunWizard()#include <kcmdlineargs.h> //initCliArgs()#include <kcursor.h> //Amarok::OverrideCursor#include <kedittoolbar.h> //slotConfigToolbars()#include <kglobalaccel.h> //initGlobalShortcuts()#include <kglobalsettings.h> //applyColorScheme()#include <kiconloader.h> //amarok Icon#include <kkeydialog.h> //slotConfigShortcuts()#include <klocale.h>#include <kmessagebox.h> //applySettings(), genericEventHandler()#include <krun.h> //Amarok::invokeBrowser()#include <kstandarddirs.h>#include <kurldrag.h> //genericEventHandler()#include <kaboutdata.h>#include <kio/job.h>#include <qevent.h> //genericEventHandler()#include <qeventloop.h> //applySettings()#include <qfile.h>#include <qobjectlist.h> //applyColorScheme()#include <qpalette.h> //applyColorScheme()#include <qpixmap.h> //QPixmap::setDefaultOptimization()#include <qpopupmenu.h> //genericEventHandler#include <qtimer.h> //showHyperThreadingWarning()#include <qtooltip.h> //default tooltip for trayicon// For the HyperThreading fix#ifdef __linux__ #ifdef SCHEDAFFINITY_SUPPORT #include <errno.h> #include <sched.h> #endif //SCHEDAFFINITY_SUPPORT#endif //__linux__QMutex Debug::mutex;QMutex Amarok::globalDirsMutex;int App::mainThreadId = 0;#ifdef Q_WS_MAC#include <qt_mac.h>static AEEventHandlerUPP appleEventProcessorUPP = 0;OSStatusappleEventProcessor(const AppleEvent *ae, AppleEvent *, long /*handlerRefCon*/){ OSType aeID = typeWildCard; OSType aeClass = typeWildCard; AEGetAttributePtr(ae, keyEventClassAttr, typeType, 0, &aeClass, sizeof(aeClass), 0); AEGetAttributePtr(ae, keyEventIDAttr, typeType, 0, &aeID, sizeof(aeID), 0); if(aeClass == kCoreEventClass) { if(aeID == kAEReopenApplication) { if( PlaylistWindow::self() ) PlaylistWindow::self()->show(); } return noErr; } return eventNotHandledErr;}#endifLIBAMAROK_EXPORT KAboutData aboutData( "amarok", I18N_NOOP( "Amarok" ), APP_VERSION, I18N_NOOP( "The audio player for KDE" ), KAboutData::License_GPL, I18N_NOOP( "(C) 2002-2003, Mark Kretschmann\n(C) 2003-2007, The Amarok Development Squad" ), I18N_NOOP( "IRC:\nirc.freenode.net - #amarok, #amarok.de, #amarok.es\n\nFeedback:\namarok@kde.org\n\n(Build Date: " __DATE__ ")" ), ( "http://amarok.kde.org" ) );App::App() : KApplication() , m_pPlayerWindow( 0 ) //will be created in applySettings(){ DEBUG_BLOCK#ifdef Q_WS_MAC // this is inspired by OpenSceneGraph: osgDB/FilePath.cpp // Start with the the Bundle PlugIns directory. // Get the main bundle first. No need to retain or release it since // we are not keeping a reference CFBundleRef myBundle = CFBundleGetMainBundle(); if( myBundle ) { // CFBundleGetMainBundle will return a bundle ref even if // the application isn't part of a bundle, so we need to // check // if the path to the bundle ends in ".app" to see if it is // a // proper application bundle. If it is, the plugins path is // added CFURLRef urlRef = CFBundleCopyBundleURL(myBundle); if(urlRef) { char bundlePath[1024]; if( CFURLGetFileSystemRepresentation( urlRef, true, (UInt8 *)bundlePath, sizeof(bundlePath) ) ) { QCString bp( bundlePath ); size_t len = bp.length(); if( len > 4 && bp.right( 4 ) == ".app" ) { bp.append( "/Contents/MacOS" ); QCString path = getenv( "PATH" ); if( path.length() > 0 ) { path.prepend( ":" ); } path.prepend( bp ); debug() << "setting PATH=" << path << endl; setenv("PATH", path, 1); } } // docs say we are responsible for releasing CFURLRef CFRelease(urlRef); } }#endif QPixmap::setDefaultOptimization( QPixmap::MemoryOptim ); //needs to be created before the wizard new Amarok::DcopPlayerHandler(); // Must be created first new Amarok::DcopPlaylistHandler(); new Amarok::DcopPlaylistBrowserHandler(); new Amarok::DcopContextBrowserHandler(); new Amarok::DcopCollectionHandler(); new Amarok::DcopMediaBrowserHandler(); new Amarok::DcopScriptHandler(); new Amarok::DcopDevicesHandler(); fixHyperThreading(); // tell AtomicString that this is the GUI thread if ( !AtomicString::isMainThread() ) qWarning("AtomicString was initialized from a thread other than the GUI " "thread. This could lead to memory leaks.");#ifdef Q_WS_MAC appleEventProcessorUPP = AEEventHandlerUPP(appleEventProcessor); AEInstallEventHandler(kCoreEventClass, kAEReopenApplication, appleEventProcessorUPP, (long)this, true);#endif QTimer::singleShot( 0, this, SLOT( continueInit() ) );}App::~App(){ DEBUG_BLOCK // Hiding the OSD before exit prevents crash Amarok::OSD::instance()->hide(); EngineBase* const engine = EngineController::engine(); if ( AmarokConfig::resumePlayback() ) { if ( engine->state() != Engine::Empty ) { AmarokConfig::setResumeTrack( EngineController::instance()->playingURL().prettyURL() ); AmarokConfig::setResumeTime( engine->position() ); } else AmarokConfig::setResumeTrack( QString::null ); //otherwise it'll play previous resume next time! } EngineController::instance()->endSession(); //records final statistics EngineController::instance()->detach( this ); // do even if trayicon is not shown, it is safe Amarok::config()->writeEntry( "HiddenOnExit", mainWindow()->isHidden() ); CollectionDB::instance()->stopScan(); delete m_pPlayerWindow; //sets some XT keys delete m_pPlaylistWindow; //sets some XT keys ThreadManager::deleteInstance(); //waits for jobs to finish // this must be deleted before the connection to the Xserver is // severed, or we risk a crash when the QApplication is exited, // I asked Trolltech! *smug* delete Amarok::OSD::instance(); AmarokConfig::setVersion( APP_VERSION ); AmarokConfig::writeConfig(); //need to unload the engine before the kapplication is destroyed PluginManager::unload( engine );}#include <dcopref.h>#include <qstringlist.h>namespace{ // grabbed from KsCD source, kompatctdisk.cpp QString urlToDevice(const QString& device) { KURL deviceUrl(device); if (deviceUrl.protocol() == "media" || deviceUrl.protocol() == "system") { DCOPRef mediamanager( "kded", "mediamanager" ); DCOPReply reply = mediamanager.call( "properties(QString)", deviceUrl.fileName() ); QStringList properties = reply; if (!reply.isValid() || properties.count() < 6) { debug() << "Invalid reply from mediamanager" << endl; return QString(); } else { debug() << "Reply from mediamanager " << properties[5] << endl; return properties[5]; } } return device; }}void App::handleCliArgs() //static{ static char cwd[PATH_MAX]; KCmdLineArgs* const args = KCmdLineArgs::parsedArgs(); if ( args->isSet( "cwd" ) ) { strncpy(cwd, args->getOption( "cwd" ), sizeof(cwd) ); cwd[sizeof(cwd)-1] = '\0'; KCmdLineArgs::setCwd( cwd ); } bool haveArgs = false; if ( args->count() > 0 ) { haveArgs = true; KURL::List list; for( int i = 0; i < args->count(); i++ ) { KURL url = args->url( i ); if( url.protocol() == "itpc" || url.protocol() == "pcast" ) PlaylistBrowser::instance()->addPodcast( url ); else list << url; } int options = Playlist::DefaultOptions; if( args->isSet( "queue" ) ) options = Playlist::Queue; else if( args->isSet( "append" ) || args->isSet( "enqueue" ) ) options = Playlist::Append; else if( args->isSet( "load" ) ) options = Playlist::Replace; if( args->isSet( "play" ) ) options |= Playlist::DirectPlay; Playlist::instance()->insertMedia( list, options ); } //we shouldn't let the user specify two of these since it is pointless! //so we prioritise, pause > stop > play > next > prev //thus pause is the least destructive, followed by stop as brakes are the most important bit of a car(!) //then the others seemed sensible. Feel free to modify this order, but please leave justification in the cvs log //I considered doing some sanity checks (eg only stop if paused or playing), but decided it wasn't worth it else if ( args->isSet( "pause" ) ) { haveArgs = true; EngineController::instance()->pause(); } else if ( args->isSet( "stop" ) ) { haveArgs = true; EngineController::instance()->stop(); } else if ( args->isSet( "play-pause" ) ) { haveArgs = true; EngineController::instance()->playPause(); } else if ( args->isSet( "play" ) ) //will restart if we are playing { haveArgs = true; EngineController::instance()->play(); } else if ( args->isSet( "next" ) ) { haveArgs = true; EngineController::instance()->next(); } else if ( args->isSet( "previous" ) ) { haveArgs = true; EngineController::instance()->previous(); } else if (args->isSet("cdplay")) { haveArgs = true; QString device = args->getOption("cdplay"); device = DeviceManager::instance()->convertMediaUrlToDevice( device ); KURL::List urls; if (EngineController::engine()->getAudioCDContents(device, urls)) { Playlist::instance()->insertMedia( urls, Playlist::Replace|Playlist::DirectPlay); } else { // Default behaviour debug() << "Sorry, the engine doesn't support direct play from AudioCD..." << endl; } } if ( args->isSet( "toggle-playlist-window" ) ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?