diff --git a/juk.cpp b/juk.cpp index 65972560..a153d312 100644 --- a/juk.cpp +++ b/juk.cpp @@ -1,603 +1,606 @@ /** * Copyright (C) 2002-2004 Scott Wheeler * Copyright (C) 2008, 2009, 2017 Michael Pyne * * 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. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ #include "juk.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "slideraction.h" #include "statuslabel.h" #include "systemtray.h" #include "keydialog.h" #include "tagguesserconfigdlg.h" #include "filerenamerconfigdlg.h" #include "scrobbler.h" #include "scrobbleconfigdlg.h" #include "actioncollection.h" #include "cache.h" #include "playlistsplitter.h" #include "collectionlist.h" #include "covermanager.h" #include "tagtransactionmanager.h" #include "juk_debug.h" using namespace ActionCollection; JuK* JuK::m_instance; template void deleteAndClear(T *&ptr) { delete ptr; ptr = 0; } //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// JuK::JuK(const QStringList &filesToOpen, QWidget *parent) : KXmlGuiWindow(parent, Qt::WindowFlags(Qt::WA_DeleteOnClose)), m_splitter(nullptr), m_statusLabel(nullptr), m_systemTray(nullptr), m_player(new PlayerManager), m_scrobbler(nullptr), m_filesToOpen(filesToOpen), m_shuttingDown(false) { // Expect segfaults if you change this order. m_instance = this; readSettings(); Cache::ensureAppDataStorageExists(); setupActions(); setupLayout(); bool firstRun = !KSharedConfig::openConfig()->hasGroup("MainWindow"); if(firstRun) { KConfigGroup mainWindowConfig(KSharedConfig::openConfig(), "MainWindow"); KConfigGroup playToolBarConfig(&mainWindowConfig, "Toolbar playToolBar"); playToolBarConfig.writeEntry("ToolButtonStyle", "IconOnly"); } QSize defaultSize(800, 480); if(QApplication::isRightToLeft()) setupGUI(defaultSize, ToolBar | Save | Create, "jukui-rtl.rc"); else setupGUI(defaultSize, ToolBar | Save | Create); // Center the GUI if this is our first run ever. if(firstRun) { QRect r = rect(); r.moveCenter(QApplication::desktop()->screenGeometry().center()); move(r.topLeft()); } connect(m_splitter, SIGNAL(guiReady()), SLOT(slotSetupSystemTray())); readConfig(); setupGlobalAccels(); activateScrobblerIfEnabled(); - connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), SLOT(slotAboutToQuit())); - // slotCheckCache loads the cached entries first to populate the collection list QTimer::singleShot(0, this, SLOT(slotClearOldCovers())); QTimer::singleShot(0, CollectionList::instance(), SLOT(startLoadingCachedItems())); QTimer::singleShot(0, this, SLOT(slotProcessArgs())); } JuK::~JuK() { + if(!m_shuttingDown) { + // Sometimes KMainWindow doesn't actually call QCoreApplication::quit + // after queryClose, even if not in a session shutdown, so make sure to + // do so ourselves when closing the main window. + slotQuit(); + } + + // Some items need to be deleted before others, though I haven't looked + // at this in some time so refinement is probably possible. + delete m_systemTray; + delete m_splitter; + delete m_player; + delete m_statusLabel; } JuK* JuK::JuKInstance() { return m_instance; } PlayerManager *JuK::playerManager() const { return m_player; } void JuK::coverDownloaded(const QPixmap &cover) { QString event(cover.isNull() ? "coverFailed" : "coverDownloaded"); KNotification *notification = new KNotification(event, this); notification->setPixmap(cover); notification->setFlags(KNotification::CloseOnTimeout); if(cover.isNull()) notification->setText(i18n("Your album art failed to download.")); else notification->setText(i18n("Your album art has finished downloading.")); notification->sendEvent(); } //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// void JuK::setupLayout() { m_splitter = new PlaylistSplitter(m_player, this); setCentralWidget(m_splitter); m_statusLabel = new StatusLabel(*m_splitter->playlist(), statusBar()); statusBar()->addWidget(m_statusLabel, 1); connect(m_player, &PlayerManager::tick, m_statusLabel, &StatusLabel::setItemCurrentTime); connect(m_player, &PlayerManager::totalTimeChanged, m_statusLabel, &StatusLabel::setItemTotalTime); connect(m_splitter, &PlaylistSplitter::currentPlaylistChanged, m_statusLabel, &StatusLabel::slotCurrentPlaylistHasChanged); m_splitter->setFocus(); } void JuK::setupActions() { KActionCollection *collection = ActionCollection::actions(); // Setup KDE standard actions that JuK uses. KStandardAction::quit(this, SLOT(slotQuit()), collection); KStandardAction::undo(this, SLOT(slotUndo()), collection); KStandardAction::cut(collection); KStandardAction::copy(collection); KStandardAction::paste(collection); QAction *clear = KStandardAction::clear(collection); KStandardAction::selectAll(collection); KStandardAction::keyBindings(this, SLOT(slotEditKeys()), collection); KStandardAction::showMenubar(menuBar(), SLOT(setVisible(bool)), collection); // Setup the menu which handles the random play options. KActionMenu *actionMenu = collection->add("actionMenu"); actionMenu->setText(i18n("&Random Play")); actionMenu->setIcon(QIcon::fromTheme( QLatin1String( "media-playlist-shuffle" ))); actionMenu->setDelayed(false); QActionGroup* randomPlayGroup = new QActionGroup(this); QAction *act = collection->add("disableRandomPlay"); act->setText(i18n("&Disable Random Play")); act->setIcon(QIcon::fromTheme( QLatin1String( "go-down" ))); act->setActionGroup(randomPlayGroup); actionMenu->addAction(act); m_randomPlayAction = collection->add("randomPlay"); m_randomPlayAction->setText(i18n("Use &Random Play")); m_randomPlayAction->setIcon(QIcon::fromTheme( QLatin1String( "media-playlist-shuffle" ))); m_randomPlayAction->setActionGroup(randomPlayGroup); actionMenu->addAction(m_randomPlayAction); act = collection->add("albumRandomPlay"); act->setText(i18n("Use &Album Random Play")); act->setIcon(QIcon::fromTheme( QLatin1String( "media-playlist-shuffle" ))); act->setActionGroup(randomPlayGroup); connect(act, SIGNAL(triggered(bool)), SLOT(slotCheckAlbumNextAction(bool))); actionMenu->addAction(act); act = collection->addAction("removeFromPlaylist", clear, SLOT(clear())); act->setText(i18n("Remove From Playlist")); act->setIcon(QIcon::fromTheme( QLatin1String( "list-remove" ))); act = collection->addAction("play", m_player, SLOT(play())); act->setText(i18n("&Play")); act->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-start" ))); act = collection->addAction("pause", m_player, SLOT(pause())); act->setText(i18n("P&ause")); act->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-pause" ))); act = collection->addAction("stop", m_player, SLOT(stop())); act->setText(i18n("&Stop")); act->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-stop" ))); act = new KToolBarPopupAction(QIcon::fromTheme( QLatin1String( "media-skip-backward") ), i18nc("previous track", "Previous" ), collection); collection->addAction("back", act); connect(act, SIGNAL(triggered(bool)), m_player, SLOT(back())); act = collection->addAction("forward", m_player, SLOT(forward())); act->setText(i18nc("next track", "&Next")); act->setIcon(QIcon::fromTheme( QLatin1String( "media-skip-forward" ))); act = collection->addAction("loopPlaylist"); act->setText(i18n("&Loop Playlist")); act->setCheckable(true); act = collection->add("resizeColumnsManually"); act->setText(i18n("&Resize Playlist Columns Manually")); // the following are not visible by default act = collection->addAction("mute", m_player, SLOT(mute())); act->setText(i18nc("silence playback", "Mute")); act->setIcon(QIcon::fromTheme( QLatin1String( "audio-volume-muted" ))); act = collection->addAction("volumeUp", m_player, SLOT(volumeUp())); act->setText(i18n("Volume Up")); act->setIcon(QIcon::fromTheme( QLatin1String( "audio-volume-high" ))); act = collection->addAction("volumeDown", m_player, SLOT(volumeDown())); act->setText(i18n("Volume Down")); act->setIcon(QIcon::fromTheme( QLatin1String( "audio-volume-low" ))); act = collection->addAction("playPause", m_player, SLOT(playPause())); act->setText(i18n("Play / Pause")); act->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-start" ))); act = collection->addAction("seekForward", m_player, SLOT(seekForward())); act->setText(i18n("Seek Forward")); act->setIcon(QIcon::fromTheme( QLatin1String( "media-seek-forward" ))); act = collection->addAction("seekBack", m_player, SLOT(seekBack())); act->setText(i18n("Seek Back")); act->setIcon(QIcon::fromTheme( QLatin1String( "media-seek-backward" ))); act = collection->addAction("showHide", this, SLOT(slotShowHide())); act->setText(i18n("Show / Hide")); ////////////////////////////////////////////////// // settings menu ////////////////////////////////////////////////// m_toggleSystemTrayAction = collection->add("toggleSystemTray"); m_toggleSystemTrayAction->setText(i18n("&Dock in System Tray")); connect(m_toggleSystemTrayAction, SIGNAL(triggered(bool)), SLOT(slotToggleSystemTray(bool))); m_toggleDockOnCloseAction = collection->add("dockOnClose"); m_toggleDockOnCloseAction->setText(i18n("&Stay in System Tray on Close")); m_togglePopupsAction = collection->add("togglePopups"); m_togglePopupsAction->setText(i18n("Popup &Track Announcement")); act = collection->add("saveUpcomingTracks"); act->setText(i18n("Save &Play Queue on Exit")); act = collection->addAction("tagGuesserConfig", this, SLOT(slotConfigureTagGuesser())); act->setText(i18n("&Tag Guesser...")); act = collection->addAction("fileRenamerConfig", this, SLOT(slotConfigureFileRenamer())); act->setText(i18n("&File Renamer...")); act = collection->addAction("scrobblerConfig", this, SLOT(slotConfigureScrobbling())); act->setText(i18n("&Configure scrobbling...")); ////////////////////////////////////////////////// // just in the toolbar ////////////////////////////////////////////////// collection->addAction("trackPositionAction", new TrackPositionAction(i18n("Track Position"), this)); collection->addAction("volumeAction", new VolumeAction(i18n("Volume"), this)); ActionCollection::actions()->addAssociatedWidget(this); foreach (QAction* action, ActionCollection::actions()->actions()) action->setShortcutContext(Qt::WidgetWithChildrenShortcut); } void JuK::slotSetupSystemTray() { if(m_toggleSystemTrayAction && m_toggleSystemTrayAction->isChecked()) { - qCDebug(JUK_LOG) << "Setting up systray"; - QTime stopwatch; stopwatch.start(); m_systemTray = new SystemTray(m_player, this); - m_systemTray->setObjectName( QLatin1String("systemTray" )); + m_systemTray->setObjectName(QStringLiteral("systemTray")); m_toggleDockOnCloseAction->setEnabled(true); m_togglePopupsAction->setEnabled(true); - qCDebug(JUK_LOG) << "Finished setting up systray, took" << stopwatch.elapsed() << "ms"; + + // If this flag gets set then JuK will quit if you click the cover on + // the track announcement popup when JuK is only in the system tray + // (the systray has no widget). + + qGuiApp->setQuitOnLastWindowClosed(false); } else { - m_systemTray = 0; + m_systemTray = nullptr; m_toggleDockOnCloseAction->setEnabled(false); m_togglePopupsAction->setEnabled(false); } } void JuK::setupGlobalAccels() { KeyDialog::setupActionShortcut("play"); KeyDialog::setupActionShortcut("playPause"); KeyDialog::setupActionShortcut("stop"); KeyDialog::setupActionShortcut("back"); KeyDialog::setupActionShortcut("forward"); KeyDialog::setupActionShortcut("seekBack"); KeyDialog::setupActionShortcut("seekForward"); KeyDialog::setupActionShortcut("volumeUp"); KeyDialog::setupActionShortcut("volumeDown"); KeyDialog::setupActionShortcut("mute"); KeyDialog::setupActionShortcut("showHide"); KeyDialog::setupActionShortcut("forwardAlbum"); } void JuK::slotProcessArgs() { CollectionList::instance()->addFiles(m_filesToOpen); } void JuK::slotClearOldCovers() { // Find all saved covers from the previous run of JuK and clear them out, in case // we find our tracks in a different order this run, which would cause old saved // covers to be wrong. // See mpris2/mediaplayer2player.cpp QString tmpDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation); QStringList nameFilters; nameFilters << QStringLiteral("juk-cover-*.png"); QDirIterator jukCoverIter(tmpDir, nameFilters); while (jukCoverIter.hasNext()) { QFile::remove(jukCoverIter.next()); } } void JuK::keyPressEvent(QKeyEvent *e) { if (e->key() >= Qt::Key_Back && e->key() <= Qt::Key_MediaLast) e->accept(); KXmlGuiWindow::keyPressEvent(e); } /** * These are settings that need to be know before setting up the GUI. */ void JuK::readSettings() { KConfigGroup config(KSharedConfig::openConfig(), "Settings"); m_startDocked = config.readEntry("StartDocked", false); } void JuK::readConfig() { // player settings KConfigGroup playerConfig(KSharedConfig::openConfig(), "Player"); if(m_player) { const int maxVolume = 100; const int volume = playerConfig.readEntry("Volume", maxVolume); m_player->setVolume(volume * 0.01); //bool enableCrossfade = playerConfig.readEntry("CrossfadeTracks", true); //m_player->setCrossfadeEnabled(enableCrossfade); //ActionCollection::action("crossfadeTracks")->setChecked(enableCrossfade); } // Default to no random play ActionCollection::action("disableRandomPlay")->setChecked(true); QString randomPlayMode = playerConfig.readEntry("RandomPlay", "Disabled"); if(randomPlayMode == "true" || randomPlayMode == "Normal") m_randomPlayAction->setChecked(true); else if(randomPlayMode == "AlbumRandomPlay") ActionCollection::action("albumRandomPlay")->setChecked(true); bool loopPlaylist = playerConfig.readEntry("LoopPlaylist", false); ActionCollection::action("loopPlaylist")->setChecked(loopPlaylist); // general settings KConfigGroup settingsConfig(KSharedConfig::openConfig(), "Settings"); bool dockInSystemTray = settingsConfig.readEntry("DockInSystemTray", true); m_toggleSystemTrayAction->setChecked(dockInSystemTray); bool dockOnClose = settingsConfig.readEntry("DockOnClose", true); m_toggleDockOnCloseAction->setChecked(dockOnClose); bool showPopups = settingsConfig.readEntry("TrackPopup", false); m_togglePopupsAction->setChecked(showPopups); } void JuK::saveConfig() { // player settings KConfigGroup playerConfig(KSharedConfig::openConfig(), "Player"); if (m_player) { playerConfig.writeEntry("Volume", static_cast(100.0 * m_player->volume())); } playerConfig.writeEntry("RandomPlay", m_randomPlayAction->isChecked()); QAction *a = ActionCollection::action("loopPlaylist"); playerConfig.writeEntry("LoopPlaylist", a->isChecked()); playerConfig.writeEntry("CrossfadeTracks", false); // TODO bring back a = ActionCollection::action("albumRandomPlay"); if(a->isChecked()) playerConfig.writeEntry("RandomPlay", "AlbumRandomPlay"); else if(m_randomPlayAction->isChecked()) playerConfig.writeEntry("RandomPlay", "Normal"); else playerConfig.writeEntry("RandomPlay", "Disabled"); // general settings KConfigGroup settingsConfig(KSharedConfig::openConfig(), "Settings"); settingsConfig.writeEntry("StartDocked", m_startDocked); settingsConfig.writeEntry("DockInSystemTray", m_toggleSystemTrayAction->isChecked()); settingsConfig.writeEntry("DockOnClose", m_toggleDockOnCloseAction->isChecked()); settingsConfig.writeEntry("TrackPopup", m_togglePopupsAction->isChecked()); KSharedConfig::openConfig()->sync(); } bool JuK::queryClose() { if(!m_shuttingDown && !qApp->isSavingSession() && m_systemTray && m_toggleDockOnCloseAction->isChecked()) { KMessageBox::information(this, i18n("Closing the main window will keep JuK running in the system tray. " "Use Quit from the File menu to quit the application."), i18n("Docking in System Tray"), "hideOnCloseInfo"); hide(); return false; } - else - { - // Some phonon backends will crash on shutdown unless we've stopped - // playback. - if(m_player->playing()) - m_player->stop(); - - // Save configuration data. - m_startDocked = !isVisible(); - saveConfig(); - return true; - } + + return true; } //////////////////////////////////////////////////////////////////////////////// // private slot definitions //////////////////////////////////////////////////////////////////////////////// void JuK::slotShowHide() { setHidden(!isHidden()); } -void JuK::slotAboutToQuit() -{ - m_shuttingDown = true; - m_player->stop(); - - deleteAndClear(m_systemTray); - deleteAndClear(m_splitter); - deleteAndClear(m_player); - deleteAndClear(m_statusLabel); -} - void JuK::slotQuit() { m_shuttingDown = true; + // Some phonon backends will crash on shutdown unless we've stopped + // playback. + if(m_player->playing()) { + m_player->stop(); + } + + m_startDocked = !isVisible(); saveConfig(); - qApp->quit(); + + QTimer::singleShot(0, qApp, &QCoreApplication::quit); } //////////////////////////////////////////////////////////////////////////////// // settings menu //////////////////////////////////////////////////////////////////////////////// void JuK::slotToggleSystemTray(bool enabled) { if(enabled && !m_systemTray) slotSetupSystemTray(); else if(!enabled && m_systemTray) { delete m_systemTray; - m_systemTray = 0; + m_systemTray = nullptr; m_toggleDockOnCloseAction->setEnabled(false); m_togglePopupsAction->setEnabled(false); + + qGuiApp->setQuitOnLastWindowClosed(true); } } void JuK::slotEditKeys() { KeyDialog(ActionCollection::actions(), this).configure(); } void JuK::slotConfigureTagGuesser() { TagGuesserConfigDlg(this).exec(); } void JuK::slotConfigureFileRenamer() { FileRenamerConfigDlg(this).exec(); } void JuK::slotConfigureScrobbling() { ScrobbleConfigDlg(this).exec(); activateScrobblerIfEnabled(); } void JuK::activateScrobblerIfEnabled() { bool isScrobbling = Scrobbler::isScrobblingEnabled(); if (!m_scrobbler && isScrobbling) { m_scrobbler = new Scrobbler(this); connect (m_player, SIGNAL(signalItemChanged(FileHandle)), m_scrobbler, SLOT(nowPlaying(FileHandle))); } else if (m_scrobbler && !isScrobbling) { delete m_scrobbler; m_scrobbler = 0; } } void JuK::slotUndo() { TagTransactionManager::instance()->undo(); } void JuK::slotCheckAlbumNextAction(bool albumRandomEnabled) { // If album random play is enabled, then enable the Play Next Album action // unless we're not playing right now. if(albumRandomEnabled && !m_player->playing()) albumRandomEnabled = false; action("forwardAlbum")->setEnabled(albumRandomEnabled); } // vim: set et sw=4 tw=0 sta: diff --git a/juk.h b/juk.h index 4022684e..20889612 100644 --- a/juk.h +++ b/juk.h @@ -1,106 +1,105 @@ /** * Copyright (C) 2002-2004 Scott Wheeler * * 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. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ #ifndef JUK_H #define JUK_H #include #include "playermanager.h" #include class KToggleAction; class KGlobalAccel; class SliderAction; class StatusLabel; class SystemTray; class PlayerManager; class PlaylistSplitter; class Scrobbler; class JuK : public KXmlGuiWindow { Q_OBJECT public: JuK(const QStringList &filesToOpen, QWidget* parent = 0); virtual ~JuK(); static JuK* JuKInstance(); PlayerManager *playerManager() const; // Use a null cover for failure void coverDownloaded(const QPixmap &cover); private: void setupLayout(); void setupActions(); void setupGlobalAccels(); void keyPressEvent(QKeyEvent *); void activateScrobblerIfEnabled(); /** * readSettings() is separate from readConfig() in that it contains settings * that need to be read before the GUI is setup. */ void readSettings(); void readConfig(); void saveConfig(); virtual bool queryClose(); private slots: void slotSetupSystemTray(); void slotShowHide(); - void slotAboutToQuit(); void slotQuit(); void slotToggleSystemTray(bool enabled); void slotEditKeys(); void slotConfigureTagGuesser(); void slotConfigureFileRenamer(); void slotConfigureScrobbling(); void slotUndo(); void slotCheckAlbumNextAction(bool albumRandomEnabled); void slotProcessArgs(); void slotClearOldCovers(); private: PlaylistSplitter *m_splitter; StatusLabel *m_statusLabel; SystemTray *m_systemTray; KToggleAction *m_randomPlayAction; KToggleAction *m_toggleSystemTrayAction; KToggleAction *m_toggleDockOnCloseAction; KToggleAction *m_togglePopupsAction; PlayerManager *m_player; Scrobbler *m_scrobbler; QStringList m_filesToOpen; bool m_startDocked; bool m_shuttingDown; static JuK* m_instance; }; #endif // vim: set et sw=4 tw=0 sta: diff --git a/main.cpp b/main.cpp index e42e8715..db1f742c 100644 --- a/main.cpp +++ b/main.cpp @@ -1,125 +1,119 @@ /** * Copyright (C) 2002-2007 Scott Wheeler * Copyright (C) 2004-2017 Michael Pyne * * 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. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include "juk.h" #include "config-juk.h" static const char description[] = I18N_NOOP("Jukebox and music manager by the KDE community"); static const char scott[] = I18N_NOOP("Author, chief dork and keeper of the funk"); static const char michael[] = I18N_NOOP("Assistant super-hero, fixer of many things"); static const char georg[] = I18N_NOOP("More KDE Platform 4 porting efforts"); static const char daniel[] = I18N_NOOP("System tray docking, \"inline\" tag editing,\nbug fixes, evangelism, moral support"); static const char tim[] = I18N_NOOP("GStreamer port"); static const char stefan[] = I18N_NOOP("Global keybindings support"); static const char stephen[] = I18N_NOOP("Track announcement popups"); static const char frerich[] = I18N_NOOP("Automagic track data guessing, bugfixes"); static const char zack[] = I18N_NOOP("More automagical things, now using MusicBrainz"); static const char adam[] = I18N_NOOP("Co-conspirator in MusicBrainz wizardry"); static const char matthias[] = I18N_NOOP("Friendly, neighborhood aRts guru"); static const char maks[] = I18N_NOOP("Making JuK friendlier to people with terabytes of music"); static const char antonio[] = I18N_NOOP("DCOP interface"); static const char allan[] = I18N_NOOP("FLAC and MPC support"); static const char nathan[] = I18N_NOOP("Album cover manager"); static const char pascal[] = I18N_NOOP("Gimper of splash screen"); static const char laurent[] = I18N_NOOP("Porting to KDE 4 when no one else was around"); static const char giorgos[] = I18N_NOOP("Badly-needed tag editor bugfixes."); static const char sandsmark[] = I18N_NOOP("Last.fm scrobbling support, lyrics, prepping for KDE Frameworks."); static const char sho[] = I18N_NOOP("MPRIS2 Interface implementation."); static const char kacper[] = I18N_NOOP("Porting to KF5 when no one else was around"); int main(int argc, char *argv[]) { QApplication a(argc, argv); KLocalizedString::setApplicationDomain("juk"); KAboutData aboutData(QStringLiteral("juk"), i18n("JuK"), QStringLiteral(JUK_VERSION), i18n(description), KAboutLicense::GPL, i18n("© 2002–2017, Scott Wheeler, Michael Pyne, and others"), QStringLiteral(""), QStringLiteral("https://www.kde.org/applications/multimedia/juk/")); aboutData.addAuthor(i18n("Scott Wheeler"), i18n(scott), "wheeler@kde.org"); aboutData.addAuthor(i18n("Michael Pyne"), i18n(michael), "mpyne@kde.org"); aboutData.addCredit(i18n("Kacper Kasper"), i18n(kacper), "kacperkasper@gmail.com", "http://kacperkasper.pl/"); aboutData.addCredit(i18n("Eike Hein"), i18n(sho), "hein@kde.org"); aboutData.addCredit(i18n("Martin Sandsmark"), i18n(sandsmark), "martin.sandsmark@kde.org"); aboutData.addCredit(i18n("Γιώργος Κυλάφας (Giorgos Kylafas)"), i18n(giorgos), "gekylafas@gmail.com"); aboutData.addCredit(i18n("Georg Grabler"), i18n(georg), "georg@grabler.net"); aboutData.addCredit(i18n("Laurent Montel"), i18n(laurent), "montel@kde.org"); aboutData.addCredit(i18n("Nathan Toone"), i18n(nathan), "nathan@toonetown.com"); aboutData.addCredit(i18n("Matthias Kretz"), i18n(matthias), "kretz@kde.org"); aboutData.addCredit(i18n("Daniel Molkentin"), i18n(daniel), "molkentin@kde.org"); aboutData.addCredit(i18n("Tim Jansen"), i18n(tim), "tim@tjansen.de"); aboutData.addCredit(i18n("Stefan Asserhäll"), i18n(stefan), "stefan.asserhall@telia.com"); aboutData.addCredit(i18n("Stephen Douglas"), i18n(stephen), "stephen_douglas@yahoo.com"); aboutData.addCredit(i18n("Frerich Raabe"), i18n(frerich), "raabe@kde.org"); aboutData.addCredit(i18n("Zack Rusin"), i18n(zack), "zack@kde.org"); aboutData.addCredit(i18n("Adam Treat"), i18n(adam), "manyoso@yahoo.com"); aboutData.addCredit(i18n("Maks Orlovich"), i18n(maks), "maksim@kde.org"); aboutData.addCredit(i18n("Antonio Larrosa Jimenez"), i18n(antonio), "larrosa@kde.org"); aboutData.addCredit(i18n("Allan Sandfeld Jensen"), i18n(allan), "kde@carewolf.com"); aboutData.addCredit(i18n("Pascal Klein"), i18n(pascal), "4pascal@tpg.com.au"); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addVersionOption(); parser.addHelpOption(); parser.addPositionalArgument(QLatin1String("[file(s)]"), i18n("File(s) to open")); parser.process(a); aboutData.processCommandLine(&parser); KCrash::initialize(); - // If this flag gets set then JuK will quit if you click the cover on the track - // announcement popup when JuK is only in the system tray (the systray has no widget). - - a.setQuitOnLastWindowClosed(false); - // Create the main window and such - JuK *juk = new JuK(parser.positionalArguments()); if(a.isSessionRestored() && KMainWindow::canBeRestored(1)) juk->restore(1, false /* don't show */); KConfigGroup config(KSharedConfig::openConfig(), "Settings"); if(!config.readEntry("StartDocked", false) || !config.readEntry("DockInSystemTray", false)) { juk->show(); } else if(!a.isSessionRestored()) { QString message = i18n("JuK running in docked mode\nUse context menu in system tray to restore."); KNotification::event("dock_mode",i18n("JuK Docked"), message); } return a.exec(); } // vim: set et sw=4 tw=0 sta fileencoding=utf8: