diff --git a/NEXTCLOUD.cmake b/NEXTCLOUD.cmake index a4ff94da5ae29..cc6287dca8a31 100644 --- a/NEXTCLOUD.cmake +++ b/NEXTCLOUD.cmake @@ -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 diff --git a/NextcloudCPack.cmake b/NextcloudCPack.cmake index d0e0f2da99791..d2f7ce4cd28ef 100644 --- a/NextcloudCPack.cmake +++ b/NextcloudCPack.cmake @@ -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" ) diff --git a/REUSE.toml b/REUSE.toml index 997d22e58fda8..b03c78d05c3a3 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -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" diff --git a/cmake/modules/CompileAppleIconComposer.cmake b/cmake/modules/CompileAppleIconComposer.cmake new file mode 100644 index 0000000000000..613c9268fff57 --- /dev/null +++ b/cmake/modules/CompileAppleIconComposer.cmake @@ -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 `.icns` fallback. +# +# compile_apple_icon_composer( ) +# +# Arguments: +# icon_source Absolute path to the source `.icon` directory. +# out_dir Directory where actool writes its output (Assets.car, +# .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/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() diff --git a/cmake/modules/MacOSXBundleInfo.plist.in b/cmake/modules/MacOSXBundleInfo.plist.in index a94e577d5d8fd..36f2ea735e6a5 100644 --- a/cmake/modules/MacOSXBundleInfo.plist.in +++ b/cmake/modules/MacOSXBundleInfo.plist.in @@ -19,7 +19,9 @@ CFBundleExecutable @APPLICATION_NAME@ CFBundleIconFile - @APPLICATION_ICON_NAME@.icns + AppIcon + CFBundleIconName + AppIcon CFBundleIdentifier @APPLICATION_REV_DOMAIN@ CFBundleInfoDictionaryVersion diff --git a/shell_integration/MacOSX/CMakeLists.txt b/shell_integration/MacOSX/CMakeLists.txt index 1e02a6faf1459..27b35bf69af9d 100644 --- a/shell_integration/MacOSX/CMakeLists.txt +++ b/shell_integration/MacOSX/CMakeLists.txt @@ -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") diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b0f89b0247bdf..21041f63d1806 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "8f26ef5980fd6743c42a9528e8af0e6bb1160646507b45d0ef74f6cd19da5953", + "originHash" : "ad2fabef3f8c4e5fae5744c0f0ebc476847ccf47a09730d368fe211fdfb0aade", "pins" : [ { "identity" : "alamofire", @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/nextcloud/NextcloudKit", "state" : { - "revision" : "6f25e101f5833d4d01961c5012acb37d526fffd2", - "version" : "7.2.8" + "revision" : "ef7b20a5dab6061d4139f943e824981369ef949e", + "version" : "7.3.3" } }, { diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 93ec2da180511..c1b2982ed730f 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -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) @@ -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) @@ -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}) diff --git a/src/gui/wizard/qml/AccountWizardWindow.qml b/src/gui/wizard/qml/AccountWizardWindow.qml index 209b558a3f14f..ad09f48904bd5 100644 --- a/src/gui/wizard/qml/AccountWizardWindow.qml +++ b/src/gui/wizard/qml/AccountWizardWindow.qml @@ -10,6 +10,8 @@ import QtQuick.Window import com.nextcloud.desktopclient import Style +import "../../tray" + ApplicationWindow { id: root diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt index 87ee8c3ed1122..be060e8ce275e 100644 --- a/src/libsync/CMakeLists.txt +++ b/src/libsync/CMakeLists.txt @@ -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} diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index 78dedac439fd2..830554b98ee4c 100644 --- a/src/libsync/theme.cpp +++ b/src/libsync/theme.cpp @@ -29,6 +29,10 @@ #include #endif +#ifdef Q_OS_MACOS +#include "theme_mac.h" +#endif + #include "nextcloudtheme.h" #ifdef THEME_INCLUDE @@ -256,6 +260,11 @@ QString Theme::configFileName() const QIcon Theme::applicationIcon() const { +#ifdef Q_OS_MACOS + if (auto bundleIcon = loadAppIconFromBundle(); !bundleIcon.isNull()) { + return bundleIcon; + } +#endif return themeIcon(QStringLiteral(APPLICATION_ICON_NAME "-icon")); } diff --git a/src/libsync/theme_mac.h b/src/libsync/theme_mac.h new file mode 100644 index 0000000000000..68debbda68871 --- /dev/null +++ b/src/libsync/theme_mac.h @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include + +namespace OCC { + +/** + * 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(); + +} diff --git a/src/libsync/theme_mac.mm b/src/libsync/theme_mac.mm new file mode 100644 index 0000000000000..29599415b105e --- /dev/null +++ b/src/libsync/theme_mac.mm @@ -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 +#include +#include + +#import + +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(png.bytes), static_cast(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; + } +} + +} diff --git a/theme/colored/AppIcon.icon/Assets/Nextcloud-logo-white.svg b/theme/colored/AppIcon.icon/Assets/Nextcloud-logo-white.svg new file mode 100644 index 0000000000000..73902557f5fd2 --- /dev/null +++ b/theme/colored/AppIcon.icon/Assets/Nextcloud-logo-white.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/theme/colored/AppIcon.icon/icon.json b/theme/colored/AppIcon.icon/icon.json new file mode 100644 index 0000000000000..84a97631d8866 --- /dev/null +++ b/theme/colored/AppIcon.icon/icon.json @@ -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" + } +} \ No newline at end of file diff --git a/theme/colored/Nextcloud-macOS-icon.svg b/theme/colored/Nextcloud-macOS-icon.svg deleted file mode 100644 index 571fcdf5b2623..0000000000000 --- a/theme/colored/Nextcloud-macOS-icon.svg +++ /dev/null @@ -1,287 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/theme/colored/Nextcloud-macOS-sidebar.svg b/theme/colored/Nextcloud-macOS-sidebar.svg deleted file mode 100644 index 620f219a4e965..0000000000000 --- a/theme/colored/Nextcloud-macOS-sidebar.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file