diff options
author | FearlessTobi <thm.frey@gmail.com> | 2023-10-07 17:26:04 +0200 |
---|---|---|
committer | Liam <byteslice@airmail.cc> | 2023-10-07 21:24:11 -0400 |
commit | 9ef9ca0927be1a5ee697f23ccf9f37b74ed12c7c (patch) | |
tree | 53e7c35b0fc4ad3718019c69d1e82236413cd9e9 /src/yuzu/util/util.cpp | |
parent | 7a0da729b45ae2794e84af6808c50cb714d17fc5 (diff) |
yuzu: Add desktop shortcut support for Windows
Allows creating desktop shortcuts with icons for yuzu games.
Co-Authored-By: Jeroen van Schijndel <13182141+roenyroeny@users.noreply.github.com>
Diffstat (limited to 'src/yuzu/util/util.cpp')
-rw-r--r-- | src/yuzu/util/util.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp index 5c3e4589e..61cf00176 100644 --- a/src/yuzu/util/util.cpp +++ b/src/yuzu/util/util.cpp @@ -5,6 +5,10 @@ #include <cmath> #include <QPainter> #include "yuzu/util/util.h" +#ifdef _WIN32 +#include <windows.h> +#include "common/fs/file.h" +#endif QFont GetMonospaceFont() { QFont font(QStringLiteral("monospace")); @@ -37,3 +41,76 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) { painter.drawEllipse({circle_pixmap.width() / 2.0, circle_pixmap.height() / 2.0}, 7.0, 7.0); return circle_pixmap; } + +bool SaveIconToFile(const std::string_view path, const QImage& image) { +#if defined(WIN32) +#pragma pack(push, 2) + struct IconDir { + WORD id_reserved; + WORD id_type; + WORD id_count; + }; + + struct IconDirEntry { + BYTE width; + BYTE height; + BYTE color_count; + BYTE reserved; + WORD planes; + WORD bit_count; + DWORD bytes_in_res; + DWORD image_offset; + }; +#pragma pack(pop) + + QImage source_image = image.convertToFormat(QImage::Format_RGB32); + constexpr int bytes_per_pixel = 4; + const int image_size = source_image.width() * source_image.height() * bytes_per_pixel; + + BITMAPINFOHEADER info_header{}; + info_header.biSize = sizeof(BITMAPINFOHEADER), info_header.biWidth = source_image.width(), + info_header.biHeight = source_image.height() * 2, info_header.biPlanes = 1, + info_header.biBitCount = bytes_per_pixel * 8, info_header.biCompression = BI_RGB; + + const IconDir icon_dir{.id_reserved = 0, .id_type = 1, .id_count = 1}; + const IconDirEntry icon_entry{.width = static_cast<BYTE>(source_image.width()), + .height = static_cast<BYTE>(source_image.height() * 2), + .color_count = 0, + .reserved = 0, + .planes = 1, + .bit_count = bytes_per_pixel * 8, + .bytes_in_res = + static_cast<DWORD>(sizeof(BITMAPINFOHEADER) + image_size), + .image_offset = sizeof(IconDir) + sizeof(IconDirEntry)}; + + Common::FS::IOFile icon_file(path, Common::FS::FileAccessMode::Write, + Common::FS::FileType::BinaryFile); + if (!icon_file.IsOpen()) { + return false; + } + + if (!icon_file.Write(icon_dir)) { + return false; + } + if (!icon_file.Write(icon_entry)) { + return false; + } + if (!icon_file.Write(info_header)) { + return false; + } + + for (int y = 0; y < image.height(); y++) { + const auto* line = source_image.scanLine(source_image.height() - 1 - y); + std::vector<u8> line_data(source_image.width() * bytes_per_pixel); + std::memcpy(line_data.data(), line, line_data.size()); + if (!icon_file.Write(line_data)) { + return false; + } + } + icon_file.Close(); + + return true; +#else + return false; +#endif +} |