diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index f2800b43a..c4f5a9af3 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -408,6 +408,8 @@ MainWindow::MainWindow(Application *app, setWindowIcon(IconLoader::Load(u"strawberry"_s)); } + systemtrayicon_->SetDevicePixelRatioF(devicePixelRatioF()); + QObject::connect(&*app->database(), &Database::Error, this, &MainWindow::ShowErrorDialog); album_cover_choice_controller_->Init(app->network(), app->tagreader_client(), app->collection()->backend(), app->albumcover_loader(), app->current_albumcover_loader(), app->cover_providers(), app->streaming_services()); diff --git a/src/systemtrayicon/macsystemtrayicon.h b/src/systemtrayicon/macsystemtrayicon.h index 8e420541b..d08626cf0 100644 --- a/src/systemtrayicon/macsystemtrayicon.h +++ b/src/systemtrayicon/macsystemtrayicon.h @@ -2,7 +2,7 @@ *Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,6 +47,7 @@ class SystemTrayIcon : public QObject { bool isVisible() const { return true; } void setVisible(const bool) {} + void SetDevicePixelRatioF(const qreal device_pixel_ratio); void SetTrayiconProgress(const bool enabled); void SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *love, QAction *quit); @@ -93,6 +94,7 @@ class SystemTrayIcon : public QObject { QPixmap playing_icon_; QPixmap paused_icon_; QPixmap current_state_icon_; + qreal device_pixel_ratio_; bool trayicon_progress_; int song_progress_; Q_DISABLE_COPY(SystemTrayIcon); diff --git a/src/systemtrayicon/macsystemtrayicon.mm b/src/systemtrayicon/macsystemtrayicon.mm index a3c365973..9a562d17a 100644 --- a/src/systemtrayicon/macsystemtrayicon.mm +++ b/src/systemtrayicon/macsystemtrayicon.mm @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -159,6 +159,7 @@ SystemTrayIcon::SystemTrayIcon(QObject *parent) grey_icon_(QPixmap(u":/pictures/strawberry-grey.png"_s).scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)), playing_icon_(u":/pictures/tiny-play.png"_s), paused_icon_(u":/pictures/tiny-pause.png"_s), + device_pixel_ratio_(1.0), trayicon_progress_(false), song_progress_(0) { @@ -168,6 +169,12 @@ SystemTrayIcon::SystemTrayIcon(QObject *parent) SystemTrayIcon::~SystemTrayIcon() {} +void SystemTrayIcon::SetDevicePixelRatioF(const qreal device_pixel_ratio) { + + device_pixel_ratio_ = device_pixel_ratio; + +} + void SystemTrayIcon::SetTrayiconProgress(const bool enabled) { trayicon_progress_ = enabled; diff --git a/src/systemtrayicon/qtsystemtrayicon.cpp b/src/systemtrayicon/qtsystemtrayicon.cpp index 3a9592584..2d62f7010 100644 --- a/src/systemtrayicon/qtsystemtrayicon.cpp +++ b/src/systemtrayicon/qtsystemtrayicon.cpp @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,33 +36,30 @@ using namespace Qt::Literals::StringLiterals; +namespace { +constexpr int kSystemTrayIconSize = 48; +} + SystemTrayIcon::SystemTrayIcon(QObject *parent) : QSystemTrayIcon(parent), menu_(new QMenu), - pixmap_playing_(u":/pictures/tiny-play.png"_s), - pixmap_paused_(u":/pictures/tiny-pause.png"_s), + icon_normal_(IconLoader::Load(u"strawberry"_s)), + icon_grey_(IconLoader::Load(u"strawberry-grey"_s)), + icon_playing_(QIcon(u":/pictures/tiny-play.png"_s)), + icon_paused_(QIcon(u":/pictures/tiny-pause.png"_s)), action_play_pause_(nullptr), action_stop_(nullptr), action_stop_after_this_track_(nullptr), action_mute_(nullptr), action_love_(nullptr), available_(false), + device_pixel_ratio_(1.0), trayicon_progress_(false), song_progress_(0) { - const QIcon icon = IconLoader::Load(u"strawberry"_s); - const QIcon icon_grey = IconLoader::Load(u"strawberry-grey"_s); - pixmap_normal_ = icon.pixmap(48, QIcon::Normal); - if (icon_grey.isNull()) { - pixmap_grey_ = icon.pixmap(48, QIcon::Disabled); - } - else { - pixmap_grey_ = icon_grey.pixmap(48, QIcon::Disabled); - } - if (isSystemTrayAvailable()) { available_ = true; - setIcon(icon); + setIcon(icon_normal_); setToolTip(QCoreApplication::applicationName()); } @@ -74,6 +71,41 @@ SystemTrayIcon::~SystemTrayIcon() { delete menu_; } +void SystemTrayIcon::InitPixmaps() { + + if (pixmap_normal_.isNull() || pixmap_normal_.devicePixelRatioF() != device_pixel_ratio_) { + pixmap_normal_ = icon_normal_.pixmap(QSize(kSystemTrayIconSize, kSystemTrayIconSize), device_pixel_ratio_, QIcon::Normal); + } + + if (pixmap_grey_.isNull() || pixmap_grey_.devicePixelRatioF() != device_pixel_ratio_) { + if (icon_grey_.isNull()) { + pixmap_grey_ = icon_normal_.pixmap(QSize(kSystemTrayIconSize, kSystemTrayIconSize), device_pixel_ratio_, QIcon::Disabled); + } + else { + pixmap_grey_ = icon_grey_.pixmap(QSize(kSystemTrayIconSize, kSystemTrayIconSize), device_pixel_ratio_, QIcon::Disabled); + } + } + + if (pixmap_playing_.isNull() || pixmap_playing_.devicePixelRatioF() != device_pixel_ratio_) { + pixmap_playing_ = icon_playing_.pixmap(icon_playing_.availableSizes().at(0)); + pixmap_playing_.setDevicePixelRatio(device_pixel_ratio_); + } + + if (pixmap_paused_.isNull() || pixmap_paused_.devicePixelRatioF() != device_pixel_ratio_) { + pixmap_paused_ = icon_paused_.pixmap(icon_paused_.availableSizes().at(0)); + pixmap_paused_.setDevicePixelRatio(device_pixel_ratio_); + } + +} + +void SystemTrayIcon::SetDevicePixelRatioF(const qreal device_pixel_ratio) { + + device_pixel_ratio_ = device_pixel_ratio; + + InitPixmaps(); + +} + void SystemTrayIcon::SetTrayiconProgress(const bool enabled) { trayicon_progress_ = enabled; @@ -131,13 +163,17 @@ void SystemTrayIcon::ShowPopup(const QString &summary, const QString &message, c void SystemTrayIcon::UpdateIcon() { - if (available_) setIcon(CreateIcon(pixmap_normal_, pixmap_grey_)); + if (available_) { + InitPixmaps(); + setIcon(CreateIcon(pixmap_normal_, pixmap_grey_)); + } } -void SystemTrayIcon::SetPlaying(bool enable_play_pause) { +void SystemTrayIcon::SetPlaying(const bool enable_play_pause) { current_state_icon_ = pixmap_playing_; + UpdateIcon(); action_stop_->setEnabled(true); diff --git a/src/systemtrayicon/qtsystemtrayicon.h b/src/systemtrayicon/qtsystemtrayicon.h index 548d27489..4a78eb053 100644 --- a/src/systemtrayicon/qtsystemtrayicon.h +++ b/src/systemtrayicon/qtsystemtrayicon.h @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,6 +46,9 @@ class SystemTrayIcon : public QSystemTrayIcon { bool IsSystemTrayAvailable() const { return available_; } + void InitPixmaps(); + + void SetDevicePixelRatioF(const qreal device_pixel_ratio); void SetTrayiconProgress(const bool enabled); void SetupMenu(QAction *previous, QAction *play, QAction *stop, QAction *stop_after, QAction *next, QAction *mute, QAction *love, QAction *quit); @@ -82,6 +85,12 @@ class SystemTrayIcon : public QSystemTrayIcon { private: QMenu *menu_; + + QIcon icon_normal_; + QIcon icon_grey_; + QIcon icon_playing_; + QIcon icon_paused_; + QPixmap pixmap_normal_; QPixmap pixmap_grey_; QPixmap pixmap_playing_; @@ -94,6 +103,7 @@ class SystemTrayIcon : public QSystemTrayIcon { QAction *action_love_; bool available_; + qreal device_pixel_ratio_; bool trayicon_progress_; int song_progress_; diff --git a/src/systemtrayicon/systemtrayicon.cpp b/src/systemtrayicon/systemtrayicon.cpp index f145a967b..3d6fc3c79 100644 --- a/src/systemtrayicon/systemtrayicon.cpp +++ b/src/systemtrayicon/systemtrayicon.cpp @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2019-2021, Jonas Kvinge + * Copyright 2019-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,45 +35,54 @@ # include "qtsystemtrayicon.h" #endif -QPixmap SystemTrayIcon::CreateIcon(const QPixmap &icon, const QPixmap &grey_icon) { +QPixmap SystemTrayIcon::CreateIcon(const QPixmap &pixmap_icon_normal, const QPixmap &pixmap_icon_grey) { - QRect rect(icon.rect()); + const qreal dpr = pixmap_icon_normal.devicePixelRatio(); + const QRect pixmap_rect = pixmap_icon_normal.rect(); - QPixmap ret(icon); - QPainter p(&ret); + QPixmap pixmap_drawn(pixmap_icon_normal.size()); + pixmap_drawn.setDevicePixelRatio(dpr); + pixmap_drawn.fill(Qt::transparent); + + QPainter p(&pixmap_drawn); + p.setRenderHint(QPainter::SmoothPixmapTransform, true); + p.drawPixmap(0, 0, pixmap_icon_normal); if (trayicon_progress_) { // The angle of the line that's used to cover the icon. // Centered on rect.topLeft() - double angle = static_cast(100 - song_progress_) / 100.0 * M_PI_2; - double length = sqrt(pow(rect.width(), 2.0) + pow(rect.height(), 2.0)); + const double angle = static_cast(100 - song_progress_) / 100.0 * M_PI_2; + const double length = std::sqrt(std::pow(pixmap_rect.width(), 2.0) + std::pow(pixmap_rect.height(), 2.0)); QPolygon mask; - mask << rect.topLeft(); - mask << rect.topLeft() + QPoint(static_cast(length * sin(angle)), static_cast(length * cos(angle))); + mask << pixmap_rect.topLeft(); + mask << pixmap_rect.topLeft() + QPoint(static_cast(length * std::sin(angle)), static_cast(length * std::cos(angle))); - if (song_progress_ > 50) mask << rect.bottomRight(); + if (song_progress_ > 50) { + mask << pixmap_rect.bottomRight(); + } - mask << rect.topRight(); - mask << rect.topLeft(); + mask << pixmap_rect.topRight(); + mask << pixmap_rect.topLeft(); // Draw the grey bit p.setClipRegion(mask); - p.drawPixmap(0, 0, grey_icon); + p.drawPixmap(0, 0, pixmap_icon_grey); p.setClipping(false); } // Draw the playing or paused icon in the top-right if (!current_state_icon_.isNull()) { - int height = rect.height() / 2; - QPixmap scaled(current_state_icon_.scaledToHeight(height, Qt::SmoothTransformation)); + const int height = pixmap_rect.height() / 2; + QPixmap current_state_scaled = current_state_icon_.scaledToHeight(height, Qt::SmoothTransformation); + current_state_scaled.setDevicePixelRatio(dpr); - QRect state_rect(rect.width() - scaled.width(), 0, scaled.width(), scaled.height()); - p.drawPixmap(state_rect, scaled); + const QRect state_rect(static_cast((pixmap_rect.width() - current_state_scaled.width()) / dpr), 0, static_cast(current_state_scaled.width() / dpr), static_cast(current_state_scaled.height() / dpr)); + p.drawPixmap(state_rect, current_state_scaled); } p.end(); - return ret; + return pixmap_drawn; }