Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions NEXTCLOUD.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ set( APPLICATION_VENDOR "Nextcloud GmbH" )
set( APPLICATION_UPDATE_URL "https://updates.nextcloud.org/client/" CACHE STRING "URL for updater" )
set( APPLICATION_HELP_URL "" CACHE STRING "URL for the help menu" )

if(APPLE AND (APPLICATION_NAME STREQUAL "Nextcloud" OR NEXTCLOUD_DEV) AND EXISTS "${CMAKE_SOURCE_DIR}/theme/colored/Nextcloud-macOS-icon.svg")
set( APPLICATION_ICON_NAME "Nextcloud-macOS" )
message("Using macOS-specific application icon: ${APPLICATION_ICON_NAME}")
endif()

set( APPLICATION_ICON_SET "SVG" )
set( APPLICATION_SERVER_URL "" CACHE STRING "URL for the server to use. If entered, the UI field will be pre-filled with it" )
set( APPLICATION_SERVER_URL_ENFORCE ON ) # If set and APPLICATION_SERVER_URL is defined, the server can only connect to the pre-defined URL
Expand Down
2 changes: 1 addition & 1 deletion NextcloudCPack.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ if(APPLE)
set( CPACK_GENERATOR "DragNDrop" )
set( CPACK_SOURCE_GENERATOR "")
set( CPACK_PACKAGE_FILE_NAME ${APPLICATION_SHORTNAME}-${CPACK_PACKAGE_VERSION} )
set( CPACK_PACKAGE_ICON ${CMAKE_BINARY_DIR}/src/gui/${APPLICATION_ICON_NAME}.icns)
set( CPACK_PACKAGE_ICON ${CMAKE_BINARY_DIR}/src/gui/AppIconCompiled/AppIcon.icns)

set( CPACK_DMG_DS_STORE "${CMAKE_SOURCE_DIR}/admin/osx/DS_Store.in")
# set( CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/admin/osx/DMGBackground.png" )
Expand Down
2 changes: 1 addition & 1 deletion REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ SPDX-FileCopyrightText = "2018 Nextcloud GmbH and Nextcloud contributors"
SPDX-License-Identifier = "GPL-2.0-or-later"

[[annotations]]
path = ["admin/osx/installer-background.png","admin/osx/installer-background.svg","admin/osx/installer-background_2x.png", "admin/win/msi/gui/banner.bmp","admin/win/msi/gui/banner.svg","admin/win/msi/gui/dialog.bmp", "admin/win/nsi/installer.ico", "admin/win/nsi/page_header.bmp", "admin/win/nsi/welcome.bmp", "doc/_shared_assets/themes/nextcloud_com/static/img/logo.svg", "doc/_shared_assets/static/logo-blue.pdf","doc/_shared_assets/static/logo-blue.png", "doc/logo-blue.pdf", "theme/talk-app.svg", "theme/*/deck.svg", "theme/*/talk-app.svg","theme/*/wizard-nextcloud.png","theme/*/wizard-nextcloud.svg","theme/*/wizard-nextcloud@2x.png","theme/*/wizard-talk.png","theme/*/wizard-talk.svg","theme/*/wizard-talk@2x.png", "theme/colored/talk-bordered.svg", "theme/colored/icons/Nextcloud-icon-win-folder.svg", "theme/colored/Nextcloud-icon-square.svg", "theme/colored/Nextcloud-icon.svg", "theme/colored/Nextcloud-macOS-icon.svg", "theme/colored/Nextcloud-macOS-sidebar.svg", "theme/colored/Nextcloud-w10startmenu.svg", "theme/colored/Nextcloud-w10starttile.png", "theme/colored/wizard_logo.png", "theme/colored/wizard_logo.svg", "theme/colored/wizard_logo@2x.png"]
path = ["admin/osx/installer-background.png","admin/osx/installer-background.svg","admin/osx/installer-background_2x.png", "admin/win/msi/gui/banner.bmp","admin/win/msi/gui/banner.svg","admin/win/msi/gui/dialog.bmp", "admin/win/nsi/installer.ico", "admin/win/nsi/page_header.bmp", "admin/win/nsi/welcome.bmp", "doc/_shared_assets/themes/nextcloud_com/static/img/logo.svg", "doc/_shared_assets/static/logo-blue.pdf","doc/_shared_assets/static/logo-blue.png", "doc/logo-blue.pdf", "theme/talk-app.svg", "theme/*/deck.svg", "theme/*/talk-app.svg","theme/*/wizard-nextcloud.png","theme/*/wizard-nextcloud.svg","theme/*/wizard-nextcloud@2x.png","theme/*/wizard-talk.png","theme/*/wizard-talk.svg","theme/*/wizard-talk@2x.png", "theme/colored/talk-bordered.svg", "theme/colored/icons/Nextcloud-icon-win-folder.svg", "theme/colored/Nextcloud-icon-square.svg", "theme/colored/Nextcloud-icon.svg", "theme/colored/AppIcon.icon/icon.json", "theme/colored/AppIcon.icon/Assets/*", "theme/colored/Nextcloud-w10startmenu.svg", "theme/colored/Nextcloud-w10starttile.png", "theme/colored/wizard_logo.png", "theme/colored/wizard_logo.svg", "theme/colored/wizard_logo@2x.png"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2016 Nextcloud GmbH"
SPDX-License-Identifier = "LicenseRef-NextcloudTrademarks"
Expand Down
75 changes: 75 additions & 0 deletions cmake/modules/CompileAppleIconComposer.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: GPL-2.0-or-later

# Locate `actool` once. Prefer the version inside the active Xcode toolchain
# (xcrun), falling back to whatever is on PATH.
if(NOT ACTOOL_EXECUTABLE)
execute_process(
COMMAND xcrun --find actool
OUTPUT_VARIABLE _actool_path
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE _actool_lookup
ERROR_QUIET)
if(_actool_lookup EQUAL 0 AND EXISTS "${_actool_path}")
set(ACTOOL_EXECUTABLE "${_actool_path}" CACHE FILEPATH "Apple asset catalog compiler")
else()
find_program(ACTOOL_EXECUTABLE actool)
endif()
if(NOT ACTOOL_EXECUTABLE)
message(FATAL_ERROR "actool not found. Install Xcode (or the Command Line Tools) to compile Icon Composer .icon sources.")
endif()
endif()

# Compile an Icon Composer `.icon` bundle into the modern macOS asset catalog
# format (`Assets.car`) plus a loose `<app-icon-name>.icns` fallback.
#
# compile_apple_icon_composer(<icon_source> <out_dir> <out_var>)
#
# Arguments:
# icon_source Absolute path to the source `.icon` directory.
# out_dir Directory where actool writes its output (Assets.car,
# <app-icon-name>.icns, partial Info.plist). Created on demand.
# out_var Name of a parent-scope variable that receives the list of
# generated source files to attach to the macOS bundle target.
# Outputs are tagged with MACOSX_PACKAGE_LOCATION=Resources so
# they land in `<app>.app/Contents/Resources/` automatically.
#
# actool requires its input argument to be a *parent directory* containing the
# `.icon`, not the `.icon` itself, so we stage the icon into a build-side
# folder first.
function(compile_apple_icon_composer icon_source out_dir out_var)
get_filename_component(_icon_name "${icon_source}" NAME_WE)
set(_staging_dir "${out_dir}/Sources")
set(_staged_icon "${_staging_dir}/${_icon_name}.icon")
set(_assets_car "${out_dir}/Assets.car")
set(_app_icns "${out_dir}/${_icon_name}.icns")
set(_partial_plist "${out_dir}/${_icon_name}.partial.plist")

file(MAKE_DIRECTORY "${out_dir}" "${_staging_dir}")

add_custom_command(
OUTPUT "${_assets_car}" "${_app_icns}" "${_partial_plist}"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${_staged_icon}"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${icon_source}" "${_staged_icon}"
COMMAND "${ACTOOL_EXECUTABLE}"
"${_staged_icon}"
--platform macosx
--minimum-deployment-target "${CMAKE_OSX_DEPLOYMENT_TARGET}"
--target-device mac
--app-icon "${_icon_name}"
--standalone-icon-behavior all
--compile "${out_dir}"
--output-partial-info-plist "${_partial_plist}"
--errors --warnings
--output-format human-readable-text
DEPENDS "${icon_source}/icon.json"
WORKING_DIRECTORY "${out_dir}"
COMMENT "Compiling Icon Composer bundle ${_icon_name}.icon with actool"
VERBATIM)

set_source_files_properties("${_assets_car}" "${_app_icns}" PROPERTIES
MACOSX_PACKAGE_LOCATION Resources
GENERATED TRUE)

set(${out_var} "${_assets_car}" "${_app_icns}" PARENT_SCOPE)
endfunction()
4 changes: 3 additions & 1 deletion cmake/modules/MacOSXBundleInfo.plist.in
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
<key>CFBundleExecutable</key>
<string>@APPLICATION_NAME@</string>
<key>CFBundleIconFile</key>
<string>@APPLICATION_ICON_NAME@.icns</string>
<string>AppIcon</string>
<key>CFBundleIconName</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>@APPLICATION_REV_DOMAIN@</string>
<key>CFBundleInfoDictionaryVersion</key>
Expand Down
2 changes: 1 addition & 1 deletion shell_integration/MacOSX/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-FileCopyrightText: 2014 ownCloud GmbH
# SPDX-License-Identifier: GPL-2.0-or-later
if(APPLE)
set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/${APPLICATION_ICON_NAME}.icns")
set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/AppIconCompiled/AppIcon.icns")

if (NEXTCLOUD_DEV)
set(XCODE_TARGET_CONFIGURATION "Debug")
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 8 additions & 14 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -409,15 +409,6 @@ if ((APPLICATION_ICON_SET MATCHES "PNG")
file(TOUCH "${theme_dir}/colored/${APPLICATION_ICON_NAME}-icon.svg")
endif()

if(APPLE)
set(MACOS_SIDEBAR_ICON_SVG "${theme_dir}/colored/${APPLICATION_ICON_NAME}-sidebar.svg")
generate_sized_png_from_svg(${MACOS_SIDEBAR_ICON_SVG} 16)
generate_sized_png_from_svg(${MACOS_SIDEBAR_ICON_SVG} 32)
generate_sized_png_from_svg(${MACOS_SIDEBAR_ICON_SVG} 64)
generate_sized_png_from_svg(${MACOS_SIDEBAR_ICON_SVG} 128)
generate_sized_png_from_svg(${MACOS_SIDEBAR_ICON_SVG} 256)
endif()

if(WIN32)
set(STARTMENU_ICON_SVG "${theme_dir}/colored/${APPLICATION_ICON_NAME}-w10startmenu.svg")
generate_sized_png_from_svg(${STARTMENU_ICON_SVG} 70)
Expand All @@ -444,12 +435,15 @@ endif()
file(GLOB OWNCLOUD_ICONS "${theme_dir}/colored/*-${APPLICATION_ICON_NAME}-icon*")

if(APPLE)
file(GLOB_RECURSE OWNCLOUD_SIDEBAR_ICONS "${theme_dir}/colored/*-${APPLICATION_ICON_NAME}-sidebar*")
MESSAGE(STATUS "OWNCLOUD_SIDEBAR_ICONS: ${APPLICATION_ICON_NAME}: ${OWNCLOUD_SIDEBAR_ICONS}")
include(CompileAppleIconComposer)
compile_apple_icon_composer(
"${CMAKE_SOURCE_DIR}/theme/colored/AppIcon.icon"
"${CMAKE_CURRENT_BINARY_DIR}/AppIconCompiled"
APP_ICON)
else()
ecm_add_app_icon(APP_ICON ICONS "${OWNCLOUD_ICONS}" OUTFILE_BASENAME "${APPLICATION_ICON_NAME}")
endif()

ecm_add_app_icon(APP_ICON ICONS "${OWNCLOUD_ICONS}" SIDEBAR_ICONS "${OWNCLOUD_SIDEBAR_ICONS}" OUTFILE_BASENAME "${APPLICATION_ICON_NAME}")

if(WIN32 AND EXISTS ${APP_ICON_WIN_FOLDER_SVG})
get_filename_component(output_icon_name_win ${APP_ICON_WIN_FOLDER_SVG} NAME_WLE)
# Product icon (for smallest size)
Expand Down Expand Up @@ -565,7 +559,7 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
)
else()
# set(CMAKE_INSTALL_PREFIX ".") # Examples use /Applications. hurmpf.
set(MACOSX_BUNDLE_ICON_FILE "${APPLICATION_ICON_NAME}.icns")
set(MACOSX_BUNDLE_ICON_FILE "AppIcon")

# we must add MACOSX_BUNDLE only if building a bundle
add_executable(nextcloud WIN32 MACOSX_BUNDLE main.cpp ${APP_ICON})
Expand Down
2 changes: 2 additions & 0 deletions src/gui/wizard/qml/AccountWizardWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import QtQuick.Window
import com.nextcloud.desktopclient
import Style

import "../../tray"

ApplicationWindow {
id: root

Expand Down
7 changes: 7 additions & 0 deletions src/libsync/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@ if (WIN32)
add_definitions(-DUMDF_USING_NTSTATUS)
endif()

if(APPLE)
list(APPEND libsync_SRCS
theme_mac.h
theme_mac.mm
)
endif()

if(TOKEN_AUTH_ONLY)
set (libsync_SRCS
${libsync_SRCS}
Expand Down
9 changes: 9 additions & 0 deletions src/libsync/theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
#include <windows.h>
#endif

#ifdef Q_OS_MACOS
#include "theme_mac.h"
#endif

#include "nextcloudtheme.h"

#ifdef THEME_INCLUDE
Expand Down Expand Up @@ -203,9 +207,9 @@
return imagePathToUrl(themeImagePath("state-offline"));
}

/*
* neutral icons for in-app status
*/

Check warning on line 212 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Edit this comment to use the C++ format, i.e. "//".

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowb7&open=AZ6TT6PximOsbUTvowb7&pullRequest=10113

QUrl Theme::offline() const
{
Expand Down Expand Up @@ -256,6 +260,11 @@

QIcon Theme::applicationIcon() const
{
#ifdef Q_OS_MACOS
if (auto bundleIcon = loadAppIconFromBundle(); !bundleIcon.isNull()) {
return bundleIcon;
}
#endif
return themeIcon(QStringLiteral(APPLICATION_ICON_NAME "-icon"));
}

Expand Down Expand Up @@ -368,7 +377,7 @@
// try to find a 2x version


const int dotIndex = fileName.lastIndexOf(QLatin1Char('.'));

Check warning on line 380 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

implicit conversion loses integer precision: 'qsizetype' (aka 'long long') to 'const int'

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowb9&open=AZ6TT6PximOsbUTvowb9&pullRequest=10113
if (dotIndex != -1) {
QString at2xfileName = fileName;
at2xfileName.insert(dotIndex, QStringLiteral("@2x"));
Expand Down Expand Up @@ -444,10 +453,10 @@
{
// Shorten Qt's OS name: "macOS Mojave (10.14)" -> "macOS"
const auto osStringList = Utility::platformName().split(QLatin1Char(' '));
const auto osName = osStringList.at(0);

Check warning on line 456 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Avoid this unnecessary copy by using a "const" reference.

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowb-&open=AZ6TT6PximOsbUTvowb-&pullRequest=10113

const auto devString = QString(tr("%1 Desktop Client Version %2 (%3 running on %4)", "%1 is application name. %2 is the human version string. %3 is the operating system name. %4 is the platform name (wayland, x11, …)"))
.arg(APPLICATION_NAME, QString::fromLatin1(MIRALL_HUMAN_VERSION_STRING), osName, qGuiApp->platformName());

Check warning on line 459 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace "->" with "::" for access to "QGuiApplication::platformName".

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowb_&open=AZ6TT6PximOsbUTvowb_&pullRequest=10113

return devString;
}
Expand Down Expand Up @@ -727,9 +736,9 @@

// Neutral icons for the classic sync folder list

QIcon Theme::folderStateIcon(SyncResult::Status status) const

Check warning on line 739 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unmodified variable "status" of type "enum OCC::SyncResult::Status" should be const-qualified.

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowcA&open=AZ6TT6PximOsbUTvowcA&pullRequest=10113
{
// FIXME: Mind the size!

Check warning on line 741 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Take the required action to fix the issue indicated by this "FIXME" comment.

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowb8&open=AZ6TT6PximOsbUTvowb8&pullRequest=10113
QString statusIcon;

switch (status) {
Expand All @@ -755,7 +764,7 @@
case SyncResult::SetupError:
statusIcon = QLatin1String("offline");
break;
case SyncResult::Error:

Check warning on line 767 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this redundant "case" clause.

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowcB&open=AZ6TT6PximOsbUTvowcB&pullRequest=10113
default:
statusIcon = QLatin1String("error");
}
Expand Down Expand Up @@ -1029,13 +1038,13 @@
void Theme::connectToPaletteSignal() const
{
if (const auto ptr = qobject_cast<QGuiApplication*>(qApp)) {
connect(ptr->styleHints(), &QStyleHints::colorSchemeChanged, this, &Theme::darkModeChanged, Qt::UniqueConnection);

Check warning on line 1041 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace "->" with "::" for access to "QGuiApplication::styleHints".

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowcC&open=AZ6TT6PximOsbUTvowcC&pullRequest=10113
}
}

QVariantMap Theme::systemPalette() const
{
auto systemPalette = QGuiApplication::palette();

Check warning on line 1047 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unmodified variable "systemPalette" of type "class QPalette" should be const-qualified.

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowcD&open=AZ6TT6PximOsbUTvowcD&pullRequest=10113
#if defined(Q_OS_WIN)
if (darkMode() && !isWindows11OrGreater()) {
systemPalette = reserveDarkPalette;
Expand Down Expand Up @@ -1073,7 +1082,7 @@
{
connectToPaletteSignal();
const auto isDarkFromStyle = [] {
switch (qGuiApp->styleHints()->colorScheme())

Check warning on line 1085 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace "->" with "::" for access to "QGuiApplication::styleHints".

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowcF&open=AZ6TT6PximOsbUTvowcF&pullRequest=10113

Check failure on line 1085 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a "default" case to this switch statement.

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowcE&open=AZ6TT6PximOsbUTvowcE&pullRequest=10113
{
case Qt::ColorScheme::Dark:
return true;
Expand Down Expand Up @@ -1148,7 +1157,7 @@
}
}

void Theme::systemPaletteHasChanged()

Check warning on line 1160 in src/libsync/theme.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This function should be declared "const".

See more on https://sonarcloud.io/project/issues?id=nextcloud_desktop&issues=AZ6TT6PximOsbUTvowcG&open=AZ6TT6PximOsbUTvowcG&pullRequest=10113
{
qCInfo(lcTheme()) << "system palette changed";
#ifdef Q_OS_WIN
Expand Down
19 changes: 19 additions & 0 deletions src/libsync/theme_mac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#pragma once

#include <QIcon>

Check failure on line 8 in src/libsync/theme_mac.h

View workflow job for this annotation

GitHub Actions / build

src/libsync/theme_mac.h:8:10 [clang-diagnostic-error]

'QIcon' file not found

namespace OCC {

Check warning on line 10 in src/libsync/theme_mac.h

View workflow job for this annotation

GitHub Actions / build

src/libsync/theme_mac.h:10:11 [cppcoreguidelines-avoid-non-const-global-variables]

variable 'OCC' is non-const and globally accessible, consider making it const

/**
* Build a QIcon from the AppIcon asset compiled into the app bundle's
* Assets.car by `actool`. Returns an empty QIcon when run outside of an
* assembled bundle (e.g. development binaries).
*/
QIcon loadAppIconFromBundle();

}
74 changes: 74 additions & 0 deletions src/libsync/theme_mac.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "theme_mac.h"

#include <QByteArray>
#include <QImage>
#include <QPixmap>

#import <AppKit/AppKit.h>

namespace OCC {

namespace {

QPixmap pixmapFromNSImage(NSImage *image, int side)
{
if (!image) {
return {};
}

NSImage *resized = [[NSImage alloc] initWithSize:NSMakeSize(side, side)];
[resized lockFocus];
[image drawInRect:NSMakeRect(0, 0, side, side)
fromRect:NSZeroRect
operation:NSCompositingOperationCopy
fraction:1.0
respectFlipped:YES
hints:nil];
[resized unlockFocus];

NSData *tiff = [resized TIFFRepresentation];
if (!tiff) {
return {};
}

NSBitmapImageRep *bitmap = [NSBitmapImageRep imageRepWithData:tiff];
NSData *png = [bitmap representationUsingType:NSBitmapImageFileTypePNG properties:@{}];
if (!png) {
return {};
}

const QByteArray bytes(reinterpret_cast<const char *>(png.bytes), static_cast<int>(png.length));
QImage decoded;
if (!decoded.loadFromData(bytes, "PNG")) {
return {};
}
return QPixmap::fromImage(std::move(decoded));
}

}

QIcon loadAppIconFromBundle()
{
@autoreleasepool {
NSImage *appIcon = [NSImage imageNamed:@"AppIcon"];
if (!appIcon) {
return {};
}

QIcon icon;
for (int side : {16, 32, 64, 128, 256, 512, 1024}) {
const auto pixmap = pixmapFromNSImage(appIcon, side);
if (!pixmap.isNull()) {
icon.addPixmap(pixmap);
}
}
return icon;
}
}

}
12 changes: 12 additions & 0 deletions theme/colored/AppIcon.icon/Assets/Nextcloud-logo-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions theme/colored/AppIcon.icon/icon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"fill" : {
"linear-gradient" : [
"display-p3:0.10980,0.68627,1.00000,1.00000",
"srgb:0.00000,0.50980,0.78824,1.00000"
],
"orientation" : {
"start" : {
"x" : 0.5,
"y" : 0
},
"stop" : {
"x" : 0.5,
"y" : 0.7
}
}
},
"groups" : [
{
"layers" : [
{
"image-name" : "Nextcloud-logo-white.svg",
"name" : "Nextcloud-logo-white",
"position" : {
"scale" : 6.8,
"translation-in-points" : [
0,
0
]
}
}
],
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
}
],
"supported-platforms" : {
"circles" : [
"watchOS"
],
"squares" : "shared"
}
}
Loading
Loading