]> git.sur5r.net Git - minitube/blobdiff - src/mainwindow.cpp
New upstream version 3.1
[minitube] / src / mainwindow.cpp
index 3fcf2fe8684ef4ec2f056d4144a9a14a63a46343..4a3a480ef200d8594bcd428c9e254f5360d20c24 100644 (file)
@@ -60,6 +60,7 @@ $END_LICENSE */
 #endif
 #include <iostream>
 #ifdef APP_EXTRA
+#include "compositefader.h"
 #include "extra.h"
 #include "updatedialog.h"
 #endif
@@ -74,12 +75,19 @@ $END_LICENSE */
 #include "seekslider.h"
 #include "sidebarwidget.h"
 #include "toolbarmenu.h"
-#include "videoareawidget.h"
+#include "videoarea.h"
 #include "yt3.h"
 #include "ytregions.h"
 
+#ifdef MEDIA_QTAV
+#include "mediaqtav.h"
+#endif
+#ifdef MEDIA_MPV
+#include "mediampv.h"
+#endif
+
 namespace {
-static MainWindow *mainWindowInstance;
+MainWindow *mainWindowInstance;
 }
 
 MainWindow *MainWindow::instance() {
@@ -87,26 +95,23 @@ MainWindow *MainWindow::instance() {
 }
 
 MainWindow::MainWindow()
-    : updateChecker(0), aboutView(0), downloadView(0), regionsView(0), mainToolBar(0),
-#ifdef APP_PHONON
-      mediaObject(0), audioOutput(0),
-#endif
-      fullScreenActive(false), compactModeActive(false), initialized(false), toolbarMenu(0) {
-
+    : aboutView(nullptr), downloadView(nullptr), regionsView(nullptr), mainToolBar(nullptr),
+      fullScreenActive(false), compactModeActive(false), initialized(false), toolbarMenu(nullptr),
+      media(nullptr) {
     mainWindowInstance = this;
 
     // views mechanism
     views = new QStackedWidget();
-    views->hide();
     setCentralWidget(views);
 
 #ifdef APP_EXTRA
     Extra::windowSetup(this);
 #endif
 
-    messageLabel = new QLabel();
-    messageLabel->setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint);
-    messageLabel->setStyleSheet("padding:5px;border:1px solid #808080;background:palette(window)");
+    messageLabel = new QLabel(this);
+    messageLabel->setWordWrap(false);
+    messageLabel->setStyleSheet("padding:5px;border:0;background:palette(window)");
+    messageLabel->setAlignment(Qt::AlignCenter);
     messageLabel->hide();
     adjustMessageLabelPosition();
     messageTimer = new QTimer(this);
@@ -126,7 +131,7 @@ MainWindow::MainWindow()
     // build ui
     createActions();
     createMenus();
-    createToolBars();
+    createToolBar();
     hideToolbar();
     createStatusBar();
 
@@ -146,25 +151,18 @@ MainWindow::MainWindow()
         views->widget(i)->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
     setMinimumWidth(0);
 
-    views->show();
-
 #ifdef APP_ACTIVATION
     Activation::instance().initialCheck();
 #else
     showHome();
 #endif
 
-    QTimer::singleShot(100, this, &MainWindow::lazyInit);
+    QTimer::singleShot(1000, this, &MainWindow::lazyInit);
 }
 
 void MainWindow::lazyInit() {
-#ifdef APP_PHONON
-    initPhonon();
-#endif
     mediaView->initialize();
-#ifdef APP_PHONON
-    mediaView->setMediaObject(mediaObject);
-#endif
+    initMedia();
     qApp->processEvents();
 
     // CLI
@@ -229,6 +227,12 @@ void MainWindow::changeEvent(QEvent *e) {
         getAction("minimize")->setEnabled(!isMinimized());
     }
 #endif
+    if (messageLabel->isVisible()) {
+        if (e->type() == QEvent::ActivationChange || e->type() == QEvent::WindowStateChange ||
+            e->type() == QEvent::WindowDeactivate || e->type() == QEvent::ApplicationStateChange) {
+            hideMessage();
+        }
+    }
     QMainWindow::changeEvent(e);
 }
 
@@ -303,27 +307,35 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *e) {
         toolbarMenu->move(mapToGlobal(p));
     }
 
+    if (obj == this && t == QEvent::StyleChange) {
+        qDebug() << "Style change detected";
+        qApp->paletteChanged(qApp->palette());
+        return false;
+    }
+
     // standard event processing
     return QMainWindow::eventFilter(obj, e);
 }
 
 void MainWindow::createActions() {
-    stopAct = new QAction(IconUtils::icon("media-playback-stop"), tr("&Stop"), this);
+    stopAct = new QAction(tr("&Stop"), this);
+    IconUtils::setIcon(stopAct, "media-playback-stop");
     stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
-    stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape)
-                                                << QKeySequence(Qt::Key_MediaStop));
+    stopAct->setShortcuts(QList<QKeySequence>()
+                          << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
     stopAct->setEnabled(false);
     actionMap.insert("stop", stopAct);
     connect(stopAct, SIGNAL(triggered()), SLOT(stop()));
 
-    skipBackwardAct = new QAction(IconUtils::icon("media-skip-backward"), tr("P&revious"), this);
+    skipBackwardAct = new QAction(tr("P&revious"), this);
     skipBackwardAct->setStatusTip(tr("Go back to the previous track"));
     skipBackwardAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Left));
     skipBackwardAct->setEnabled(false);
     actionMap.insert("previous", skipBackwardAct);
     connect(skipBackwardAct, SIGNAL(triggered()), mediaView, SLOT(skipBackward()));
 
-    skipAct = new QAction(IconUtils::icon("media-skip-forward"), tr("S&kip"), this);
+    skipAct = new QAction(tr("S&kip"), this);
+    IconUtils::setIcon(skipAct, "media-skip-forward");
     skipAct->setStatusTip(tr("Skip to the next video"));
     skipAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right)
                                                 << QKeySequence(Qt::Key_MediaNext));
@@ -331,15 +343,17 @@ void MainWindow::createActions() {
     actionMap.insert("skip", skipAct);
     connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
 
-    pauseAct = new QAction(IconUtils::icon("media-playback-start"), tr("&Play"), this);
+    pauseAct = new QAction(tr("&Play"), this);
+    IconUtils::setIcon(pauseAct, "media-playback-start");
     pauseAct->setStatusTip(tr("Resume playback"));
-    pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space)
-                                                 << QKeySequence(Qt::Key_MediaPlay));
+    pauseAct->setShortcuts(QList<QKeySequence>()
+                           << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
     pauseAct->setEnabled(false);
     actionMap.insert("pause", pauseAct);
     connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
 
-    fullscreenAct = new QAction(IconUtils::icon("view-fullscreen"), tr("&Full Screen"), this);
+    fullscreenAct = new QAction(tr("&Full Screen"), this);
+    IconUtils::setIcon(fullscreenAct, "view-fullscreen");
     fullscreenAct->setStatusTip(tr("Go full screen"));
     QList<QKeySequence> fsShortcuts;
 #ifdef APP_MAC
@@ -355,11 +369,7 @@ void MainWindow::createActions() {
 
     compactViewAct = new QAction(tr("&Compact Mode"), this);
     compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
-#ifdef APP_MAC
-    compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::META + Qt::Key_C));
-#else
     compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C));
-#endif
     compactViewAct->setCheckable(true);
     compactViewAct->setChecked(false);
     compactViewAct->setEnabled(false);
@@ -373,7 +383,8 @@ void MainWindow::createActions() {
     actionMap.insert("webpage", webPageAct);
     connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
 
-    copyPageAct = new QAction(IconUtils::icon("link"), tr("Copy the YouTube &Link"), this);
+    copyPageAct = new QAction(tr("Copy the YouTube &Link"), this);
+    IconUtils::setIcon(copyPageAct, "link");
     copyPageAct->setStatusTip(tr("Copy the current video YouTube link to the clipboard"));
     copyPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
     copyPageAct->setEnabled(false);
@@ -396,8 +407,8 @@ void MainWindow::createActions() {
 
     removeAct = new QAction(tr("&Remove"), this);
     removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
-    removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del")
-                                                  << QKeySequence("Backspace"));
+    removeAct->setShortcuts(QList<QKeySequence>()
+                            << QKeySequence("Del") << QKeySequence("Backspace"));
     removeAct->setEnabled(false);
     actionMap.insert("remove", removeAct);
     connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
@@ -475,24 +486,47 @@ void MainWindow::createActions() {
     addAction(volumeDownAct);
 
     volumeMuteAct = new QAction(this);
-    volumeMuteAct->setIcon(IconUtils::icon("audio-volume-high"));
+    IconUtils::setIcon(volumeMuteAct, "audio-volume-high");
     volumeMuteAct->setStatusTip(tr("Mute volume"));
-    volumeMuteAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_K));
+    volumeMuteAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_M));
     actionMap.insert("volumeMute", volumeMuteAct);
-    connect(volumeMuteAct, SIGNAL(triggered()), SLOT(volumeMute()));
+    connect(volumeMuteAct, SIGNAL(triggered()), SLOT(toggleVolumeMute()));
     addAction(volumeMuteAct);
 
-    QAction *definitionAct = new QAction(this);
-    definitionAct->setIcon(IconUtils::icon("video-display"));
+    QToolButton *definitionButton = new QToolButton(this);
+    definitionButton->setText(YT3::instance().maxVideoDefinition().getName());
+    IconUtils::setIcon(definitionButton, "video-display");
+    definitionButton->setIconSize(QSize(16, 16));
+    definitionButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+    definitionButton->setPopupMode(QToolButton::InstantPopup);
+    QMenu *definitionMenu = new QMenu(this);
+    QActionGroup *group = new QActionGroup(this);
+    for (auto &defName : VideoDefinition::getDefinitionNames()) {
+        QAction *a = new QAction(defName);
+        a->setCheckable(true);
+        a->setActionGroup(group);
+        a->setChecked(defName == YT3::instance().maxVideoDefinition().getName());
+        connect(a, &QAction::triggered, this, [this, defName, definitionButton] {
+            setDefinitionMode(defName);
+            definitionButton->setText(defName);
+        });
+        connect(&YT3::instance(), &YT3::maxVideoDefinitionChanged, this,
+                [defName, definitionButton](const QString &name) {
+                    if (defName == name) definitionButton->setChecked(true);
+                });
+        definitionMenu->addAction(a);
+    }
+    definitionButton->setMenu(definitionMenu);
+    QWidgetAction *definitionAct = new QWidgetAction(this);
+    definitionAct->setDefaultWidget(definitionButton);
     definitionAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
     actionMap.insert("definition", definitionAct);
-    connect(definitionAct, SIGNAL(triggered()), SLOT(toggleDefinitionMode()));
     addAction(definitionAct);
 
     QAction *action;
 
-    action = new QAction(IconUtils::icon("media-playback-start"), tr("&Manually Start Playing"),
-                         this);
+    action = new QAction(tr("&Manually Start Playing"), this);
+    IconUtils::setIcon(action, "media-playback-start");
     action->setStatusTip(tr("Manually start playing videos"));
     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_T));
     action->setCheckable(true);
@@ -500,17 +534,17 @@ void MainWindow::createActions() {
     actionMap.insert("manualplay", action);
 
     action = new QAction(tr("&Downloads"), this);
+    IconUtils::setIcon(action, "document-save");
     action->setStatusTip(tr("Show details about video downloads"));
     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_J));
     action->setCheckable(true);
-    action->setIcon(IconUtils::icon("document-save"));
     connect(action, SIGNAL(toggled(bool)), SLOT(toggleDownloads(bool)));
     actionMap.insert("downloads", action);
 
     action = new QAction(tr("&Download"), this);
+    IconUtils::setIcon(action, "document-save");
     action->setStatusTip(tr("Download the current video"));
     action->setShortcut(QKeySequence::Save);
-    action->setIcon(IconUtils::icon("document-save"));
     action->setEnabled(false);
     action->setVisible(false);
     action->setPriority(QAction::LowPriority);
@@ -531,23 +565,26 @@ void MainWindow::createActions() {
     action->setEnabled(false);
     connect(action, SIGNAL(triggered()), mediaView, SLOT(toggleSubscription()));
     actionMap.insert("subscribeChannel", action);
-    mediaView->updateSubscriptionAction(0, false);
+    mediaView->updateSubscriptionActionForVideo(0, false);
 
     QString shareTip = tr("Share the current video using %1");
 
-    action = new QAction(IconUtils::icon("twitter"), "&Twitter", this);
+    action = new QAction("&Twitter", this);
+    IconUtils::setIcon(action, "twitter");
     action->setStatusTip(shareTip.arg("Twitter"));
     action->setEnabled(false);
     actionMap.insert("twitter", action);
     connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaTwitter()));
 
-    action = new QAction(IconUtils::icon("facebook"), "&Facebook", this);
+    action = new QAction("&Facebook", this);
+    IconUtils::setIcon(action, "facebook");
     action->setStatusTip(shareTip.arg("Facebook"));
     action->setEnabled(false);
     actionMap.insert("facebook", action);
     connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaFacebook()));
 
-    action = new QAction(IconUtils::icon("email"), tr("&Email"), this);
+    action = new QAction(tr("&Email"), this);
+    IconUtils::setIcon(action, "email");
     action->setStatusTip(shareTip.arg(tr("Email")));
     action->setEnabled(false);
     actionMap.insert("email", action);
@@ -563,13 +600,14 @@ void MainWindow::createActions() {
     actionMap.insert("restore", action);
     connect(action, SIGNAL(triggered()), SLOT(restore()));
 
-    action = new QAction(IconUtils::icon("go-top"), tr("&Float on Top"), this);
+    action = new QAction(tr("&Float on Top"), this);
+    IconUtils::setIcon(action, "go-top");
     action->setCheckable(true);
     actionMap.insert("ontop", action);
     connect(action, SIGNAL(toggled(bool)), SLOT(floatOnTop(bool)));
 
-    action =
-            new QAction(IconUtils::icon("media-playback-stop"), tr("&Stop After This Video"), this);
+    action = new QAction(tr("&Stop After This Video"), this);
+    IconUtils::setIcon(action, "media-playback-stop");
     action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Escape));
     action->setCheckable(true);
     action->setEnabled(false);
@@ -595,7 +633,8 @@ void MainWindow::createActions() {
     action = new QAction(tr("More..."), this);
     actionMap.insert("moreRegion", action);
 
-    action = new QAction(IconUtils::icon("view-list"), tr("&Related Videos"), this);
+    action = new QAction(tr("&Related Videos"), this);
+    IconUtils::setIcon(action, "view-list");
     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
     action->setStatusTip(tr("Watch videos related to the current one"));
     action->setEnabled(false);
@@ -609,7 +648,8 @@ void MainWindow::createActions() {
     actionMap.insert("openInBrowser", action);
     connect(action, SIGNAL(triggered()), mediaView, SLOT(openInBrowser()));
 
-    action = new QAction(IconUtils::icon("safesearch"), tr("Restricted Mode"), this);
+    action = new QAction(tr("Restricted Mode"), this);
+    IconUtils::setIcon(action, "safesearch");
     action->setStatusTip(tr("Hide videos that may contain inappropriate content"));
     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_K));
     action->setCheckable(true);
@@ -619,7 +659,8 @@ void MainWindow::createActions() {
     connect(action, SIGNAL(triggered()), SLOT(toggleMenuVisibilityWithMessage()));
     actionMap.insert("toggleMenu", action);
 
-    action = new QAction(IconUtils::icon("view-more"), tr("Menu"), this);
+    action = new QAction(tr("Menu"), this);
+    IconUtils::setIcon(action, "open-menu");
     connect(action, SIGNAL(triggered()), SLOT(toggleToolbarMenu()));
     actionMap.insert("toolbarMenu", action);
 
@@ -634,11 +675,11 @@ void MainWindow::createActions() {
 #endif
 
     // common action properties
-    for (QAction *action : actionMap) {
+    for (QAction *action : qAsConst(actionMap)) {
         // add actions to the MainWindow so that they work
         // when the menu is hidden
         addAction(action);
-        IconUtils::setupAction(action);
+        MainWindow::instance()->setupAction(action);
     }
 }
 
@@ -709,8 +750,10 @@ void MainWindow::createMenus() {
     menuMap.insert("view", viewMenu);
     viewMenu->addAction(getAction("ontop"));
     viewMenu->addAction(compactViewAct);
-#ifndef APP_MAC
+    viewMenu->addSeparator();
     viewMenu->addAction(fullscreenAct);
+#ifndef APP_MAC
+    viewMenu->addSeparator();
     viewMenu->addAction(getAction("toggleMenu"));
 #endif
 
@@ -733,46 +776,16 @@ void MainWindow::createMenus() {
 #endif
 }
 
-void MainWindow::createToolBars() {
+void MainWindow::createToolBar() {
     // Create widgets
+    currentTimeLabel = new QLabel("00:00", this);
 
-    currentTimeLabel = new QLabel("00:00");
-    currentTimeLabel->setFont(FontUtils::small());
-
-#ifdef APP_PHONON_SEEK
-    seekSlider = new Phonon::SeekSlider();
-#if APP_LINUX
+    seekSlider = new SeekSlider(this);
+    seekSlider->setEnabled(false);
     seekSlider->setTracking(false);
-#else
-    seekSlider->setTracking(true);
-#endif
-    // Phonon freezes the application with streaming videos if
-    // tracking is set to true and the seek slider is dragged.
-    seekSlider->setIconVisible(false);
-    seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
-#else
-    slider = new SeekSlider(this);
-    slider->setEnabled(false);
-    slider->setTracking(false);
-    slider->setMaximum(1000);
-    slider->setOrientation(Qt::Horizontal);
-    slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
-#endif
-
-#ifdef APP_PHONON
-    volumeSlider = new Phonon::VolumeSlider();
-    volumeSlider->setMuteVisible(false);
-    // qDebug() << volumeSlider->children();
-    // status tip for the volume slider
-    QSlider *volumeQSlider = volumeSlider->findChild<QSlider *>();
-    if (volumeQSlider)
-        volumeQSlider->setStatusTip(
-                tr("Press %1 to raise the volume, %2 to lower it")
-                        .arg(volumeUpAct->shortcut().toString(QKeySequence::NativeText),
-                             volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
-    // this makes the volume slider smaller
-    volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-#endif
+    seekSlider->setMaximum(1000);
+    volumeSlider = new SeekSlider(this);
+    volumeSlider->setValue(volumeSlider->maximum());
 
 #if defined(APP_MAC_SEARCHFIELD) && !defined(APP_MAC_QMACTOOLBAR)
     SearchWrapper *searchWrapper = new SearchWrapper(this);
@@ -781,13 +794,14 @@ void MainWindow::createToolBars() {
     toolbarSearch = new SearchLineEdit(this);
 #endif
     toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize() * 15);
+    toolbarSearch->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
     toolbarSearch->setSuggester(new YTSuggester(this));
     connect(toolbarSearch, SIGNAL(search(const QString &)), SLOT(search(const QString &)));
     connect(toolbarSearch, SIGNAL(suggestionAccepted(Suggestion *)),
             SLOT(suggestionAccepted(Suggestion *)));
     toolbarSearch->setStatusTip(searchFocusAct->statusTip());
 
-// Add widgets to toolbar
+    // Add widgets to toolbar
 
 #ifdef APP_MAC_QMACTOOLBAR
     currentTimeLabel->hide();
@@ -826,32 +840,45 @@ void MainWindow::createToolBars() {
 
     mainToolBar->addWidget(new Spacer());
 
+    currentTimeLabel->setFont(FontUtils::small());
+    currentTimeLabel->setMinimumWidth(currentTimeLabel->fontInfo().pixelSize() * 4);
+    currentTimeLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
     mainToolBar->addWidget(currentTimeLabel);
-    mainToolBar->addWidget(new Spacer(this, currentTimeLabel->sizeHint().height() / 2));
-#ifdef APP_PHONON_SEEK
-    mainToolBar->addWidget(seekSlider);
-#else
-    mainToolBar->addWidget(slider);
+
+#ifdef APP_WIN
+    mainToolBar->addWidget(new Spacer(nullptr, 10));
 #endif
 
-    /*
-    mainToolBar->addWidget(new Spacer());
-    totalTime = new QLabel(mainToolBar);
-    totalTime->setFont(smallerFont);
-    mainToolBar->addWidget(totalTime);
-    */
+    seekSlider->setOrientation(Qt::Horizontal);
+    seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+    seekSlider->setFocusPolicy(Qt::NoFocus);
+    mainToolBar->addWidget(seekSlider);
 
     mainToolBar->addWidget(new Spacer());
+
     mainToolBar->addAction(volumeMuteAct);
-#ifdef APP_LINUX
+#ifndef APP_MAC_QMACTOOLBAR
     QToolButton *volumeMuteButton =
             qobject_cast<QToolButton *>(mainToolBar->widgetForAction(volumeMuteAct));
-    volumeMuteButton->setIcon(volumeMuteButton->icon().pixmap(16));
+    volumeMuteButton->setIconSize(QSize(16, 16));
+    auto fixVolumeMuteIconSize = [volumeMuteButton] {
+        volumeMuteButton->setIcon(volumeMuteButton->icon().pixmap(16));
+    };
+    fixVolumeMuteIconSize();
+    volumeMuteButton->connect(volumeMuteAct, &QAction::changed, volumeMuteButton,
+                              fixVolumeMuteIconSize);
 #endif
 
-#ifdef APP_PHONON
+    volumeSlider->setStatusTip(
+            tr("Press %1 to raise the volume, %2 to lower it")
+                    .arg(volumeUpAct->shortcut().toString(QKeySequence::NativeText),
+                         volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
+
+    volumeSlider->setOrientation(Qt::Horizontal);
+    // this makes the volume slider smaller
+    volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    volumeSlider->setFocusPolicy(Qt::NoFocus);
     mainToolBar->addWidget(volumeSlider);
-#endif
 
     mainToolBar->addWidget(new Spacer());
 
@@ -888,9 +915,8 @@ void MainWindow::createStatusBar() {
         regionMenu->addAction(moreRegionsAction);
         connect(moreRegionsAction, SIGNAL(triggered()), SLOT(showRegionsView()));
         regionAction->setMenu(regionMenu);
-    } else {
-        connect(regionAction, SIGNAL(triggered()), SLOT(showRegionsView()));
     }
+    connect(regionAction, SIGNAL(triggered()), SLOT(showRegionsView()));
 
     /* Stupid code that generates the QRC items
     foreach(YTRegion r, YTRegions::list())
@@ -903,31 +929,39 @@ void MainWindow::createStatusBar() {
 
 void MainWindow::showStopAfterThisInStatusBar(bool show) {
     QAction *action = getAction("stopafterthis");
-    showActionInStatusBar(action, show);
+    showActionsInStatusBar({action}, show);
 }
 
-void MainWindow::showActionInStatusBar(QAction *action, bool show) {
+void MainWindow::showActionsInStatusBar(const QVector<QAction *> &actions, bool show) {
 #ifdef APP_EXTRA
     Extra::fadeInWidget(statusBar(), statusBar());
 #endif
-    if (show) {
-        if (statusToolBar->actions().contains(action)) return;
-        if (statusToolBar->actions().isEmpty()) {
-            statusToolBar->addAction(action);
+    for (auto action : actions) {
+        if (show) {
+            if (statusToolBar->actions().contains(action)) continue;
+            if (statusToolBar->actions().isEmpty()) {
+                statusToolBar->addAction(action);
+            } else {
+                statusToolBar->insertAction(statusToolBar->actions().at(0), action);
+            }
         } else {
-            statusToolBar->insertAction(statusToolBar->actions().at(0), action);
+            statusToolBar->removeAction(action);
         }
+    }
+
+    if (show) {
         if (statusBar()->isHidden() && !fullScreenActive) setStatusBarVisibility(true);
     } else {
-        statusToolBar->removeAction(action);
         if (statusBar()->isVisible() && !needStatusBar()) setStatusBarVisibility(false);
     }
 }
 
 void MainWindow::setStatusBarVisibility(bool show) {
-    statusBar()->setVisible(show);
-    if (views->currentWidget() == mediaView)
-        QTimer::singleShot(0, mediaView, SLOT(adjustWindowSize()));
+    if (statusBar()->isVisible() != show) {
+        statusBar()->setVisible(show);
+        if (views->currentWidget() == mediaView)
+            QTimer::singleShot(0, mediaView, SLOT(adjustWindowSize()));
+    }
 }
 
 void MainWindow::adjustStatusBarVisibility() {
@@ -952,17 +986,18 @@ void MainWindow::showToolbar() {
 
 void MainWindow::readSettings() {
     QSettings settings;
-    if (settings.contains("geometry")) {
-        restoreGeometry(settings.value("geometry").toByteArray());
+    QByteArray geometrySettings = settings.value("geometry").toByteArray();
+    if (!geometrySettings.isEmpty()) {
+        restoreGeometry(geometrySettings);
     } else {
-        const QRect desktopSize = qApp->desktop()->availableGeometry();
+        const QRect desktopSize = QGuiApplication::primaryScreen()->availableGeometry();
         int w = desktopSize.width() * .9;
         int h = qMin(w / 2, desktopSize.height());
         setGeometry(
                 QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, QSize(w, h), desktopSize));
     }
-    const VideoDefinition &firstDefinition = VideoDefinition::getDefinitions().at(0);
-    setDefinitionMode(settings.value("definition", firstDefinition.getName()).toString());
+    setDefinitionMode(settings.value("definition", YT3::instance().maxVideoDefinition().getName())
+                              .toString());
     getAction("manualplay")->setChecked(settings.value("manualplay", false).toBool());
     getAction("safeSearch")->setChecked(settings.value("safeSearch", false).toBool());
 #ifndef APP_MAC
@@ -975,7 +1010,7 @@ void MainWindow::writeSettings() {
 
     if (!isReallyFullScreen()) {
         settings.setValue("geometry", saveGeometry());
-        mediaView->saveSplitterState();
+        if (mediaView) mediaView->saveSplitterState();
     }
 
     settings.setValue("manualplay", getAction("manualplay")->isChecked());
@@ -988,15 +1023,19 @@ void MainWindow::writeSettings() {
 void MainWindow::goBack() {
     if (history.size() > 1) {
         history.pop();
-        QWidget *widget = history.pop();
-        showWidget(widget);
+        showView(history.pop());
     }
 }
 
-void MainWindow::showWidget(QWidget *widget, bool transition) {
-    Q_UNUSED(transition);
+void MainWindow::showView(View *view, bool transition) {
+    if (!history.isEmpty() && view == history.top()) {
+        qDebug() << "Attempting to show same view" << view;
+        return;
+    }
 
-    setUpdatesEnabled(false);
+#ifdef APP_MAC
+    if (transition && !history.isEmpty()) CompositeFader::go(this, this->grab());
+#endif
 
     if (compactViewAct->isChecked()) compactViewAct->toggle();
 
@@ -1004,70 +1043,38 @@ void MainWindow::showWidget(QWidget *widget, bool transition) {
     View *oldView = qobject_cast<View *>(views->currentWidget());
     if (oldView) {
         oldView->disappear();
-        views->currentWidget()->setEnabled(false);
+        oldView->setEnabled(false);
+        oldView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
     } else
-        qDebug() << "Cannot cast view";
+        qDebug() << "Cannot cast old view";
 
-    const bool isMediaView = widget == mediaView;
+    view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    view->setEnabled(true);
+    views->setCurrentWidget(view);
+    view->appear();
 
+    QString title = view->getTitle();
+    if (title.isEmpty())
+        title = Constants::NAME;
+    else
+        title += QLatin1String(" - ") + Constants::NAME;
+    setWindowTitle(title);
+
+    const bool isMediaView = view == mediaView;
     stopAct->setEnabled(isMediaView);
     compactViewAct->setEnabled(isMediaView);
-    toolbarSearch->setEnabled(widget == homeView || isMediaView || widget == downloadView);
-
-    aboutAct->setEnabled(widget != aboutView);
-    getAction("downloads")->setChecked(widget == downloadView);
-
-    QWidget *oldWidget = views->currentWidget();
-    if (oldWidget) oldWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
-
-    views->setCurrentWidget(widget);
-    widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-
-    // call show method on the new view
-    View *newView = qobject_cast<View *>(widget);
-    if (newView) {
-        widget->setEnabled(true);
-
-        QString title = newView->getTitle();
-        if (title.isEmpty())
-            title = Constants::NAME;
-        else
-            title += QLatin1String(" - ") + Constants::NAME;
-        setWindowTitle(title);
-
-        statusToolBar->setUpdatesEnabled(false);
-
-        // dynamic view actions
-        /* Not currently used by any view
-        foreach (QAction* action, viewActions)
-            showActionInStatusBar(action, false);
-        viewActions = newView->getViewActions();
-        foreach (QAction* action, viewActions)
-            showActionInStatusBar(action, true);
-        */
-
-        adjustStatusBarVisibility();
-        messageLabel->hide();
-
-        newView->appear();
-
-        statusToolBar->setUpdatesEnabled(true);
-
-        /*
-        QString desc = metadata.value("description").toString();
-        if (!desc.isEmpty()) showMessage(desc);
-        */
-    }
-
-    setUpdatesEnabled(true);
-
-#ifdef APP_MAC
-    // Workaround cursor bug on macOS
-    unsetCursor();
-    mac::uncloseWindow(winId());
-#endif
+    toolbarSearch->setEnabled(isMediaView);
+    aboutAct->setEnabled(view != aboutView);
+    getAction("downloads")->setChecked(view == downloadView);
+
+    // dynamic view actions
+    /* Not currently used by any view
+    showActionsInStatusBar(viewActions, false);
+    viewActions = newView->getViewActions();
+    showActionsInStatusBar(viewActions, true);
+    */
 
-    history.push(widget);
+    history.push(view);
     emit viewChanged();
 }
 
@@ -1076,7 +1083,7 @@ void MainWindow::about() {
         aboutView = new AboutView(this);
         views->addWidget(aboutView);
     }
-    showWidget(aboutView);
+    showView(aboutView);
 }
 
 void MainWindow::visitSite() {
@@ -1092,7 +1099,7 @@ void MainWindow::donate() {
 }
 
 void MainWindow::reportIssue() {
-    QUrl url("http://flavio.tordini.org/forums/forum/minitube-forums/minitube-troubleshooting");
+    QUrl url("https://flavio.tordini.org/forums/forum/minitube-forums/minitube-troubleshooting");
     QDesktopServices::openUrl(url);
 }
 
@@ -1104,6 +1111,9 @@ void MainWindow::quit() {
 #endif
     // do not save geometry when in full screen or in compact mode
     if (!fullScreenActive && !compactViewAct->isChecked()) {
+#ifdef APP_MAC
+        hideToolbar();
+#endif
         writeSettings();
     }
     // mediaView->stop();
@@ -1111,6 +1121,7 @@ void MainWindow::quit() {
     ChannelAggregator::instance()->stop();
     ChannelAggregator::instance()->cleanup();
     Database::shutdown();
+    HttpUtils::clearCaches();
     qApp->quit();
 }
 
@@ -1139,7 +1150,7 @@ void MainWindow::showEvent(QShowEvent *e) {
 bool MainWindow::confirmQuit() {
     if (DownloadManager::instance()->activeItems() > 0) {
         QMessageBox msgBox(this);
-        msgBox.setIconPixmap(IconUtils::pixmap(":/images/64x64/app.png"));
+        msgBox.setIconPixmap(IconUtils::pixmap(":/images/64x64/app.png", devicePixelRatioF()));
         msgBox.setText(
                 tr("Do you want to exit %1 with a download in progress?").arg(Constants::NAME));
         msgBox.setInformativeText(
@@ -1162,12 +1173,13 @@ bool MainWindow::confirmQuit() {
 }
 
 void MainWindow::showHome() {
-    showWidget(homeView);
+    showView(homeView);
     currentTimeLabel->clear();
+    seekSlider->setValue(0);
 }
 
 void MainWindow::showMedia(SearchParams *searchParams) {
-    showWidget(mediaView);
+    showView(mediaView);
     if (getAction("safeSearch")->isChecked())
         searchParams->setSafeSearch(SearchParams::Strict);
     else
@@ -1176,71 +1188,59 @@ void MainWindow::showMedia(SearchParams *searchParams) {
 }
 
 void MainWindow::showMedia(VideoSource *videoSource) {
-    showWidget(mediaView);
+    showView(mediaView);
     mediaView->setVideoSource(videoSource);
 }
 
-#ifdef APP_PHONON
-void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
-    // qDebug() << "Phonon state: " << newState;
+void MainWindow::stateChanged(Media::State newState) {
+    qDebug() << newState;
+
+    seekSlider->setEnabled(newState != Media::StoppedState);
 
     switch (newState) {
-    case Phonon::ErrorState:
-        if (mediaObject->errorType() == Phonon::FatalError) {
-            // Do not display because we try to play incomplete video files and sometimes trigger
-            // this
-            // We retry automatically (in MediaView) so no need to show it
-            // showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
-        } else {
-            showMessage(tr("Error: %1").arg(mediaObject->errorString()));
-        }
+    case Media::ErrorState:
+        showMessage(tr("Error: %1").arg(media->errorString()));
         break;
 
-    case Phonon::PlayingState:
+    case Media::PlayingState:
         pauseAct->setEnabled(true);
         pauseAct->setIcon(IconUtils::icon("media-playback-pause"));
         pauseAct->setText(tr("&Pause"));
         pauseAct->setStatusTip(tr("Pause playback") + " (" +
                                pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
-        // stopAct->setEnabled(true);
         break;
 
-    case Phonon::StoppedState:
+    case Media::StoppedState:
         pauseAct->setEnabled(false);
         pauseAct->setIcon(IconUtils::icon("media-playback-start"));
         pauseAct->setText(tr("&Play"));
         pauseAct->setStatusTip(tr("Resume playback") + " (" +
                                pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
-        // stopAct->setEnabled(false);
         break;
 
-    case Phonon::PausedState:
+    case Media::PausedState:
         pauseAct->setEnabled(true);
         pauseAct->setIcon(IconUtils::icon("media-playback-start"));
         pauseAct->setText(tr("&Play"));
         pauseAct->setStatusTip(tr("Resume playback") + " (" +
                                pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
-        // stopAct->setEnabled(true);
         break;
 
-    case Phonon::BufferingState:
+    case Media::BufferingState:
         pauseAct->setEnabled(false);
         pauseAct->setIcon(IconUtils::icon("content-loading"));
         pauseAct->setText(tr("&Loading..."));
         pauseAct->setStatusTip(QString());
         break;
 
-    case Phonon::LoadingState:
+    case Media::LoadingState:
         pauseAct->setEnabled(false);
         currentTimeLabel->clear();
-        // totalTime->clear();
-        // stopAct->setEnabled(true);
         break;
 
     default:;
     }
 }
-#endif
 
 void MainWindow::stop() {
     showHome();
@@ -1264,16 +1264,11 @@ void MainWindow::resizeEvent(QResizeEvent *e) {
 #endif
 #ifdef APP_MAC_QMACTOOLBAR
     int moreButtonWidth = 40;
-    toolbarSearch->move(width() - toolbarSearch->width() - moreButtonWidth - 7, -38);
+    toolbarSearch->move(width() - toolbarSearch->width() - moreButtonWidth - 7, -34);
 #endif
     hideMessage();
 }
 
-void MainWindow::moveEvent(QMoveEvent *e) {
-    Q_UNUSED(e);
-    hideMessage();
-}
-
 void MainWindow::enterEvent(QEvent *e) {
     Q_UNUSED(e);
 #ifdef APP_MAC
@@ -1320,7 +1315,7 @@ void MainWindow::toggleFullscreen() {
 #endif
 
     } else {
-// Exit full screen
+        // Exit full screen
 
 #ifdef APP_MAC
         MacSupport::exitFullScreen(this, views);
@@ -1387,8 +1382,8 @@ void MainWindow::updateUIForFullscreen() {
     if (fullScreenActive) {
         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
     } else {
-        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape)
-                                                    << QKeySequence(Qt::Key_MediaStop));
+        stopAct->setShortcuts(QList<QKeySequence>()
+                              << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
     }
 
 #ifdef Q_OS_MAC
@@ -1418,23 +1413,29 @@ bool MainWindow::isReallyFullScreen() {
 }
 
 void MainWindow::missingKeyWarning() {
+    static bool shown = false;
+    if (shown) return;
+    shown = true;
     QMessageBox msgBox(this);
-    msgBox.setIconPixmap(IconUtils::pixmap(":/images/64x64/app.png"));
+    msgBox.setIconPixmap(IconUtils::pixmap(":/images/64x64/app.png", devicePixelRatioF()));
     msgBox.setText(QString("%1 was built without a Google API key.").arg(Constants::NAME));
     msgBox.setInformativeText(QString("It won't work unless you enter one."
                                       "<p>In alternative you can get %1 from the developer site.")
                                       .arg(Constants::NAME));
     msgBox.setModal(true);
     msgBox.setWindowModality(Qt::WindowModal);
+    msgBox.addButton(QMessageBox::Close);
     QPushButton *enterKeyButton =
             msgBox.addButton(QString("Enter API key..."), QMessageBox::AcceptRole);
     QPushButton *devButton = msgBox.addButton(QString("Get from %1").arg(Constants::WEBSITE),
                                               QMessageBox::AcceptRole);
     QPushButton *helpButton = msgBox.addButton(QMessageBox::Help);
+
     msgBox.exec();
+
     if (msgBox.clickedButton() == helpButton) {
-        QDesktopServices::openUrl(QUrl(
-                "https://github.com/flaviotordini/minitube/blob/master/README.md#google-api-key"));
+        QDesktopServices::openUrl(QUrl("https://github.com/flaviotordini/minitube/blob/master/"
+                                       "README.md#google-api-key"));
     } else if (msgBox.clickedButton() == enterKeyButton) {
         bool ok;
         QString text = QInputDialog::getText(this, QString(), "Google API key:", QLineEdit::Normal,
@@ -1447,9 +1448,12 @@ void MainWindow::missingKeyWarning() {
     } else if (msgBox.clickedButton() == devButton) {
         QDesktopServices::openUrl(QUrl(Constants::WEBSITE));
     }
+    shown = false;
 }
 
 void MainWindow::compactView(bool enable) {
+    setUpdatesEnabled(false);
+
     compactModeActive = enable;
 
     static QList<QKeySequence> compactShortcuts;
@@ -1468,7 +1472,7 @@ void MainWindow::compactView(bool enable) {
         if (settings.contains(key))
             restoreGeometry(settings.value(key).toByteArray());
         else
-            resize(320, 180);
+            resize(480, 270);
 
 #ifdef APP_MAC_QMACTOOLBAR
         mac::showToolBar(winId(), !enable);
@@ -1492,12 +1496,14 @@ void MainWindow::compactView(bool enable) {
         mediaView->setFocus();
 
     } else {
+        settings.setValue(key, saveGeometry());
+
         // unset minimum size
         setMinimumSize(0, 0);
+
 #ifdef Q_OS_MAC
         mac::SetupFullScreenWindow(winId());
 #endif
-        settings.setValue(key, saveGeometry());
 #ifdef APP_MAC_QMACTOOLBAR
         mac::showToolBar(winId(), !enable);
 #else
@@ -1525,6 +1531,8 @@ void MainWindow::compactView(bool enable) {
         menuBar()->setVisible(menuVisibleBeforeCompactMode);
     }
 #endif
+
+    setUpdatesEnabled(true);
 }
 
 void MainWindow::toggleToolbarMenu() {
@@ -1540,72 +1548,79 @@ void MainWindow::searchFocus() {
     toolbarSearch->setFocus();
 }
 
-#ifdef APP_PHONON
-void MainWindow::initPhonon() {
-    // Phonon initialization
-    if (mediaObject) delete mediaObject;
-    if (audioOutput) delete audioOutput;
-    mediaObject = new Phonon::MediaObject(this);
-    mediaObject->setTickInterval(100);
-    connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
-            SLOT(stateChanged(Phonon::State, Phonon::State)));
-    connect(mediaObject, SIGNAL(tick(qint64)), SLOT(tick(qint64)));
-    connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), SLOT(totalTimeChanged(qint64)));
-
-    audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
-    connect(audioOutput, SIGNAL(mutedChanged(bool)), SLOT(volumeMutedChanged(bool)));
-    Phonon::createPath(mediaObject, audioOutput);
-    volumeSlider->setAudioOutput(audioOutput);
-
-#ifdef APP_PHONON_SEEK
-    seekSlider->setMediaObject(mediaObject);
+void MainWindow::initMedia() {
+#ifdef MEDIA_QTAV
+    qFatal("QtAV has a showstopper bug. Audio stops randomly. See bug "
+           "https://github.com/wang-bin/QtAV/issues/1184");
+    media = new MediaQtAV(this);
+#elif defined MEDIA_MPV
+    media = new MediaMPV();
+#else
+    qFatal("No media backend defined");
 #endif
+    media->init();
+    media->setUserAgent(HttpUtils::stealthUserAgent());
 
     QSettings settings;
-    audioOutput->setVolume(settings.value("volume", 1.).toReal());
-    // audioOutput->setMuted(settings.value("volumeMute").toBool());
-
-    mediaObject->stop();
+    qreal volume = settings.value("volume", 1.).toReal();
+    media->setVolume(volume);
+
+    connect(media, &Media::error, this, &MainWindow::handleError);
+    connect(media, &Media::stateChanged, this, &MainWindow::stateChanged);
+    connect(media, &Media::positionChanged, this, &MainWindow::tick);
+
+    connect(seekSlider, &QSlider::sliderMoved, this, [this](int value) {
+        // value : maxValue = posit ion : duration
+        qint64 ms = (value * media->duration()) / seekSlider->maximum();
+        qDebug() << "Seeking to" << ms;
+        media->seek(ms);
+        if (media->state() == Media::PausedState) media->play();
+    });
+    connect(seekSlider, &QSlider::sliderPressed, this, [this]() {
+        // value : maxValue = position : duration
+        qint64 ms = (seekSlider->value() * media->duration()) / seekSlider->maximum();
+        media->seek(ms);
+        if (media->state() == Media::PausedState) media->play();
+    });
+    connect(media, &Media::started, this, [this]() { seekSlider->setValue(0); });
+
+    connect(media, &Media::volumeChanged, this, &MainWindow::volumeChanged);
+    connect(media, &Media::volumeMutedChanged, this, &MainWindow::volumeMutedChanged);
+    connect(volumeSlider, &QSlider::sliderMoved, this, [this](int value) {
+        qreal volume = (qreal)value / volumeSlider->maximum();
+        media->setVolume(volume);
+    });
+    connect(volumeSlider, &QSlider::sliderPressed, this, [this]() {
+        qreal volume = (qreal)volumeSlider->value() / volumeSlider->maximum();
+        media->setVolume(volume);
+    });
+
+    mediaView->setMedia(media);
 }
-#endif
 
 void MainWindow::tick(qint64 time) {
+#ifdef APP_MAC
+    bool isDown = seekSlider->property("down").isValid();
+#else
+    bool isDown = seekSlider->isSliderDown();
+#endif
+    if (!isDown && media->state() == Media::PlayingState) {
+        // value : maxValue = position : duration
+        qint64 duration = media->duration();
+        if (duration <= 0) return;
+        int value = (seekSlider->maximum() * media->position()) / duration;
+        seekSlider->setValue(value);
+    }
+
     const QString s = formatTime(time);
     if (s != currentTimeLabel->text()) {
         currentTimeLabel->setText(s);
         emit currentTimeChanged(s);
-    }
-
-// remaining time
-#ifdef APP_PHONON
-    const qint64 remainingTime = mediaObject->remainingTime();
-    currentTimeLabel->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
-
-#ifndef APP_PHONON_SEEK
-    const qint64 totalTime = mediaObject->totalTime();
-    slider->blockSignals(true);
-    // qWarning() << totalTime << time << time * 100 / totalTime;
-    if (totalTime > 0 && time > 0 && !slider->isSliderDown() &&
-        mediaObject->state() == Phonon::PlayingState)
-        slider->setValue(time * slider->maximum() / totalTime);
-    slider->blockSignals(false);
-#endif
 
-#endif
-}
-
-void MainWindow::totalTimeChanged(qint64 time) {
-    if (time <= 0) {
-        // totalTime->clear();
-        return;
+        // remaining time
+        const qint64 remainingTime = media->remainingTime();
+        currentTimeLabel->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
     }
-    // totalTime->setText(formatTime(time));
-
-    /*
-    slider->blockSignals(true);
-    slider->setMaximum(time/1000);
-    slider->blockSignals(false);
-    */
 }
 
 QString MainWindow::formatTime(qint64 duration) {
@@ -1621,31 +1636,31 @@ QString MainWindow::formatTime(qint64 duration) {
 }
 
 void MainWindow::volumeUp() {
-#ifdef APP_PHONON
-    qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
-    if (newVolume > volumeSlider->maximumVolume()) newVolume = volumeSlider->maximumVolume();
-    volumeSlider->audioOutput()->setVolume(newVolume);
-#endif
+    qreal newVolume = media->volume() + .1;
+    if (newVolume > 1.) newVolume = 1.;
+    media->setVolume(newVolume);
 }
 
 void MainWindow::volumeDown() {
-#ifdef APP_PHONON
-    qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
-    if (newVolume < 0.) newVolume = 0.;
-    volumeSlider->audioOutput()->setVolume(newVolume);
-#endif
+    qreal newVolume = media->volume() - .1;
+    if (newVolume < 0) newVolume = 0;
+    media->setVolume(newVolume);
 }
 
-void MainWindow::volumeMute() {
-#ifdef APP_PHONON
-    bool muted = volumeSlider->audioOutput()->isMuted();
-    volumeSlider->audioOutput()->setMuted(!muted);
-    qApp->processEvents();
-    if (muted && volumeSlider->audioOutput()->volume() == 0.) {
-        volumeSlider->audioOutput()->setVolume(volumeSlider->maximumVolume());
-    }
-    qDebug() << volumeSlider->audioOutput()->isMuted() << volumeSlider->audioOutput()->volume();
-#endif
+void MainWindow::toggleVolumeMute() {
+    bool muted = media->volumeMuted();
+    media->setVolumeMuted(!muted);
+}
+
+void MainWindow::volumeChanged(qreal newVolume) {
+    // automatically unmute when volume changes
+    if (media->volumeMuted()) media->setVolumeMuted(false);
+    showMessage(tr("Volume at %1%").arg((int)(newVolume * 100)));
+    // newVolume : 1.0 = x : 1000
+    int value = newVolume * volumeSlider->maximum();
+    volumeSlider->blockSignals(true);
+    volumeSlider->setValue(value);
+    volumeSlider->blockSignals(false);
 }
 
 void MainWindow::volumeMutedChanged(bool muted) {
@@ -1656,11 +1671,6 @@ void MainWindow::volumeMutedChanged(bool muted) {
         volumeMuteAct->setIcon(IconUtils::icon("audio-volume-high"));
         showMessage(tr("Volume is unmuted"));
     }
-#ifdef APP_LINUX
-    QToolButton *volumeMuteButton =
-            qobject_cast<QToolButton *>(mainToolBar->widgetForAction(volumeMuteAct));
-    volumeMuteButton->setIcon(volumeMuteButton->icon().pixmap(16));
-#endif
 }
 
 void MainWindow::setDefinitionMode(const QString &definitionName) {
@@ -1670,18 +1680,15 @@ void MainWindow::setDefinitionMode(const QString &definitionName) {
             tr("Maximum video definition set to %1").arg(definitionAct->text()) + " (" +
             definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
     showMessage(definitionAct->statusTip());
-    QSettings settings;
-    settings.setValue("definition", definitionName);
+    YT3::instance().setMaxVideoDefinition(definitionName);
+    if (views->currentWidget() == mediaView) {
+        mediaView->reloadCurrentVideo();
+    }
 }
 
 void MainWindow::toggleDefinitionMode() {
-    const QString definitionName = QSettings().value("definition").toString();
     const QVector<VideoDefinition> &definitions = VideoDefinition::getDefinitions();
-    const VideoDefinition &currentDefinition = VideoDefinition::forName(definitionName);
-    if (currentDefinition.isEmpty()) {
-        setDefinitionMode(definitions.at(0).getName());
-        return;
-    }
+    const VideoDefinition &currentDefinition = YT3::instance().maxVideoDefinition();
 
     int index = definitions.indexOf(currentDefinition);
     if (index != definitions.size() - 1) {
@@ -1689,7 +1696,6 @@ void MainWindow::toggleDefinitionMode() {
     } else {
         index = 0;
     }
-    // TODO: pass a VideoDefinition instead of QString.
     setDefinitionMode(definitions.at(index).getName());
 }
 
@@ -1712,7 +1718,7 @@ void MainWindow::setManualPlay(bool enabled) {
     if (views->currentWidget() == homeView &&
         homeView->currentWidget() == homeView->getSearchView())
         return;
-    showActionInStatusBar(getAction("manualplay"), enabled);
+    showActionsInStatusBar({getAction("manualplay")}, enabled);
 }
 
 void MainWindow::updateDownloadMessage(const QString &message) {
@@ -1733,8 +1739,8 @@ void MainWindow::toggleDownloads(bool show) {
     } else {
         getAction("downloads")
                 ->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
-        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape)
-                                                    << QKeySequence(Qt::Key_MediaStop));
+        stopAct->setShortcuts(QList<QKeySequence>()
+                              << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
     }
 
     if (!downloadView) {
@@ -1742,7 +1748,7 @@ void MainWindow::toggleDownloads(bool show) {
         views->addWidget(downloadView);
     }
     if (show)
-        showWidget(downloadView);
+        showView(downloadView);
     else
         goBack();
 }
@@ -1796,36 +1802,27 @@ void MainWindow::checkForUpdate() {
     if (secondsSinceLastCheck < 86400) return;
 
     // check it out
-    if (updateChecker) delete updateChecker;
-    updateChecker = new UpdateChecker();
-    connect(updateChecker, SIGNAL(newVersion(QString)), this, SLOT(gotNewVersion(QString)));
+    UpdateChecker *updateChecker = new UpdateChecker();
+    connect(updateChecker, &UpdateChecker::newVersion, this,
+            [this, updateChecker](const QString &version) {
+                updateChecker->deleteLater();
+                QSettings settings;
+                QString checkedVersion = settings.value("checkedVersion").toString();
+                if (checkedVersion == version) return;
+#ifdef APP_SIMPLEUPDATE
+                simpleUpdateDialog(version);
+#elif defined(APP_EXTRA) && !defined(APP_MAC)
+                UpdateDialog *dialog = new UpdateDialog(version, this);
+                dialog->show();
+#endif
+            });
     updateChecker->checkForUpdate();
     settings.setValue(updateCheckKey, unixTime);
 }
 
-void MainWindow::gotNewVersion(const QString &version) {
-    if (updateChecker) {
-        delete updateChecker;
-        updateChecker = 0;
-    }
-
-    QSettings settings;
-    QString checkedVersion = settings.value("checkedVersion").toString();
-    if (checkedVersion == version) return;
-
-#ifdef APP_EXTRA
-#ifndef APP_MAC
-    UpdateDialog *dialog = new UpdateDialog(version, this);
-    dialog->show();
-#endif
-#else
-    simpleUpdateDialog(version);
-#endif
-}
-
 void MainWindow::simpleUpdateDialog(const QString &version) {
     QMessageBox msgBox(this);
-    msgBox.setIconPixmap(IconUtils::pixmap(":/images/64x64/app.png"));
+    msgBox.setIconPixmap(IconUtils::pixmap(":/images/64x64/app.png", devicePixelRatioF()));
     msgBox.setText(tr("%1 version %2 is now available.").arg(Constants::NAME, version));
     msgBox.setModal(true);
     msgBox.setWindowModality(Qt::WindowModal);
@@ -1852,7 +1849,7 @@ void MainWindow::adjustMessageLabelPosition() {
 }
 
 void MainWindow::floatOnTop(bool onTop, bool showAction) {
-    if (showAction) showActionInStatusBar(getAction("ontop"), onTop);
+    if (showAction) showActionsInStatusBar({getAction("ontop")}, onTop);
 #ifdef APP_MAC
     mac::floatOnTop(winId(), onTop);
 #else
@@ -1946,6 +1943,18 @@ void MainWindow::printHelp() {
     std::cout << msg.toLocal8Bit().data();
 }
 
+void MainWindow::setupAction(QAction *action) {
+    // never autorepeat.
+    // unexperienced users tend to keep keys pressed for a "long" time
+    action->setAutoRepeat(false);
+
+    // show keyboard shortcuts in the status bar
+    if (!action->shortcut().isEmpty())
+        action->setStatusTip(action->statusTip() + QLatin1String(" (") +
+                             action->shortcut().toString(QKeySequence::NativeText) +
+                             QLatin1String(")"));
+}
+
 QAction *MainWindow::getAction(const char *name) {
     return actionMap.value(QByteArray::fromRawData(name, strlen(name)));
 }
@@ -1965,13 +1974,13 @@ void MainWindow::showMessage(const QString &message) {
 #endif
     if (statusBar()->isVisible())
         statusBar()->showMessage(message, 60000);
-    else {
+    else if (isActiveWindow()) {
         messageLabel->setText(message);
         QSize size = messageLabel->sizeHint();
-        // round width to nearest 10 to avoid flicker with fast changing messages (e.g. volume
+        // round width to avoid flicker with fast changing messages (e.g. volume
         // changes)
-        int w = size.width();
-        const int multiple = 10;
+        int w = size.width() + 10;
+        const int multiple = 15;
         w = w + multiple / 2;
         w -= w % multiple;
         size.setWidth(w);
@@ -1991,11 +2000,16 @@ void MainWindow::hideMessage() {
     }
 }
 
+void MainWindow::handleError(const QString &message) {
+    qWarning() << message;
+    showMessage(message);
+}
+
 #ifdef APP_ACTIVATION
 void MainWindow::showActivationView() {
-    QWidget *activationView = ActivationView::instance();
+    View *activationView = ActivationView::instance();
     views->addWidget(activationView);
-    if (views->currentWidget() != activationView) showWidget(activationView);
+    if (views->currentWidget() != activationView) showView(activationView);
 }
 #endif
 
@@ -2006,5 +2020,5 @@ void MainWindow::showRegionsView() {
                 SLOT(load()));
         views->addWidget(regionsView);
     }
-    showWidget(regionsView);
+    showView(regionsView);
 }