Skip to content

Commit

Permalink
macOS: Add M1/arm64 support
Browse files Browse the repository at this point in the history
Closes #1884
  • Loading branch information
hluk committed Mar 3, 2024
1 parent 0438f39 commit 54a648d
Show file tree
Hide file tree
Showing 29 changed files with 367 additions and 307 deletions.
16 changes: 10 additions & 6 deletions .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ jobs:
include:
- os: macos-12
buildname: macOS 10.15
create_bundle: true
bundle_suffix: '-macos-10'
cmake_preset: macOS-10

- os: macos-14
buildname: macOS 12 M1
bundle_suffix: '-macos-12-m1'
cmake_preset: macOS-12-m1

steps:
- name: Checkout source code
Expand Down Expand Up @@ -42,20 +48,18 @@ jobs:
- name: Build with CMake
uses: lukka/run-cmake@v10
with:
configurePreset: macOS
buildPreset: macOS
configurePreset: '${{ matrix.cmake_preset }}'
buildPreset: '${{ matrix.cmake_preset }}'

- name: Create gnupg directory for tests
run: mkdir -p ~/.gnupg && chmod go-rwx ~/.gnupg

- name: Create macOS bundle
if: matrix.create_bundle
working-directory: '${{runner.workspace}}/build'
run: '${{github.workspace}}/utils/github/bundle-macos.sh'

- name: Upload macOS bundle
if: matrix.create_bundle
uses: actions/upload-artifact@v4
with:
name: CopyQ.dmg
name: 'CopyQ${{ matrix.bundle_suffix }}.dmg'
path: '${{runner.workspace}}/build/CopyQ.dmg'
33 changes: 28 additions & 5 deletions CMakePresets.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 3,
"version": 6,
"configurePresets": [
{
"name": "Debug",
Expand All @@ -14,18 +14,35 @@
}
},
{
"name": "macOS",
"name": "macOS-10",
"generator": "Ninja",
"binaryDir": "${sourceParentDir}/build",
"installDir": "${sourceParentDir}/build",
"cacheVariables": {
"WITH_QT6": "TRUE",
"WITH_TESTS": "TRUE",
"CMAKE_PREFIX_PATH": "/usr/local/opt/qt@5/lib/cmake",
"CMAKE_PREFIX_PATH": "/usr/local/opt/qt/lib/cmake",
"CMAKE_OSX_DEPLOYMENT_TARGET": "10.15",
"CMAKE_C_COMPILER_LAUNCHER": "ccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
"CMAKE_CXX_FLAGS": "-Wno-deprecated-declarations"
}
},
{
"name": "macOS-12-m1",
"generator": "Ninja",
"binaryDir": "${sourceParentDir}/build",
"installDir": "${sourceParentDir}/build",
"cacheVariables": {
"WITH_QT6": "TRUE",
"WITH_TESTS": "TRUE",
"CMAKE_PREFIX_PATH": "/usr/local/opt/qt/lib/cmake",
"CMAKE_OSX_DEPLOYMENT_TARGET": "12",
"CMAKE_OSX_ARCHITECTURES": "arm64",
"CMAKE_C_COMPILER_LAUNCHER": "ccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
"CMAKE_CXX_FLAGS": "-Wno-deprecated-declarations"
}
}
],
"buildPresets": [
Expand All @@ -36,8 +53,14 @@
"targets": "install"
},
{
"name": "macOS",
"configurePreset": "macOS",
"name": "macOS-10",
"configurePreset": "macOS-10",
"configuration": "Release",
"targets": "install"
},
{
"name": "macOS-12-m1",
"configurePreset": "macOS-12-m1",
"configuration": "Release",
"targets": "install"
}
Expand Down
12 changes: 2 additions & 10 deletions docs/build-source-code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,23 +158,15 @@ On OS X, required Qt 5 libraries and utilities can be easily installed with `Hom
# brew untap --force copyq/kde
# and re-run the above "brew tap" command

brew install qt5 copyq/kde/kf5-knotifications
brew install qt6 copyq/kde/kf6-knotifications copyq/kde/kf6-kstatusnotifieritem

Build with the following commands:

::

cmake -DCMAKE_PREFIX_PATH="$(brew --prefix qt5)" .
cmake --build .
cmake --install .
macdeployqt CopyQ.app -dmg -verbose=2 -always-overwrite \
-executable=CopyQ.app/Contents/PlugIns/copyq/libitemfakevim.so \
-executable=CopyQ.app/Contents/PlugIns/copyq/libitemimage.so \
-executable=CopyQ.app/Contents/PlugIns/copyq/libitemnotes.so \
-executable=CopyQ.app/Contents/PlugIns/copyq/libitempinned.so \
-executable=CopyQ.app/Contents/PlugIns/copyq/libitemsync.so \
-executable=CopyQ.app/Contents/PlugIns/copyq/libitemtags.so \
-executable=CopyQ.app/Contents/PlugIns/copyq/libitemtext.so
cpack

This will produce a self-contained application bundle ``CopyQ.app``
which can then be copied or moved into ``/Applications``.
Expand Down
81 changes: 18 additions & 63 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,9 @@ endif()
if (NOT APPLE)
add_executable(${COPYQ_EXECUTABLE_NAME} ${copyq_COMPILE})
else()
# On Macs we must ensure Carbon and Cocoa are linked
FIND_LIBRARY(CARBON_LIBRARY "Carbon")
FIND_LIBRARY(COCOA_LIBRARY "Cocoa")
MARK_AS_ADVANCED (CARBON_LIBRARY
COCOA_LIBRARY)
FIND_LIBRARY(CARBON_LIBRARY Carbon REQUIRED)
FIND_LIBRARY(COCOA_LIBRARY Cocoa REQUIRED)
MARK_AS_ADVANCED(CARBON_LIBRARY COCOA_LIBRARY)
list(APPEND copyq_LIBRARIES "${CARBON_LIBRARY}" "${COCOA_LIBRARY}")

set(COPYQ_VERSION_REGEX "^([0-9]+)\.([0-9]+)\.(.*)$")
Expand Down Expand Up @@ -158,64 +156,21 @@ if (NOT APPLE)
else()
set_source_files_properties(${copyq_QM} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/translations")

set_target_properties(${COPYQ_EXECUTABLE_NAME} PROPERTIES MACOSX_BUNDLE TRUE)
set_target_properties(${COPYQ_EXECUTABLE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/../shared/Info.plist")

set(plugin_dest_dir "${COPYQ_EXECUTABLE_NAME}.app/Contents/PlugIns")
set(qtconf_dest_dir "${COPYQ_EXECUTABLE_NAME}.app/Contents/Resources")

macro(install_qt_plugin _qt_plugin_name _qt_plugins_var)
get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION)
if(EXISTS "${_qt_plugin_path}")
get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME)
get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH)
get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME)
set(_qt_plugin_dest "${plugin_dest_dir}/${_qt_plugin_type}")
install(FILES "${_qt_plugin_path}" DESTINATION "${_qt_plugin_dest}" COMPONENT Runtime)
set(${_qt_plugins_var}
"${${_qt_plugins_var}};\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}")
else()
message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found")
endif()
endmacro()

# Install needed Qt plugins
foreach(_copyq_qt_module ${copyq_qt_modules} "Gui" "Widgets")
set(_module_plugins "${${copyq_qt}${_copyq_qt_module}_PLUGINS}")
foreach(_plugin ${_module_plugins})
install_qt_plugin("${_plugin}" FIXUP_BUNDLE_QT_PLUGINS)
endforeach()
endforeach()

# install a qt.conf file
# this inserts some cmake code into the install script to write the file
install(CODE "
file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths]\nPlugins = PlugIns\nImports = Resources/qml\nQml2Imports = Resources/qml\n\")
"
COMPONENT Runtime
)

# FIXME: Disable cpack for now due to unresolvable libraries:
# https://github.com/Homebrew/homebrew-core/issues/140930
# set(FIXUP_BUNDLE_APPS "\${CMAKE_INSTALL_PREFIX}/${COPYQ_EXECUTABLE_NAME}.app")
#
# get_property(_copyq_installed_plugins GLOBAL PROPERTY COPYQ_INSTALLED_PLUGINS)
#
# # Directories to look for dependencies
# set(FIXUP_BUNDLE_DEP_DIRS "${CMAKE_BINARY_DIR};${QT_LIBRARY_DIRS};${QT_PLUGINS_DIR}/iconengines;${QT_PLUGINS_DIR}/imageformats;${QT_PLUGINS_DIR}/platforms;${QT_PLUGINS_DIR}/tls;${${copyq_qt}Widgets_DIR}/../..")
#
# message(STATUS "Fixup app: ${FIXUP_BUNDLE_APPS}")
# message(STATUS "Fixup app plugins: ${_copyq_installed_plugins}")
# message(STATUS "Fixup qt plugins: ${FIXUP_BUNDLE_QT_PLUGINS}")
# message(STATUS "Fixup dirs: ${FIXUP_BUNDLE_DEP_DIRS}")
# install(CODE "
# include(BundleUtilities)
# set(BU_CHMOD_BUNDLE_ITEMS ON)
# fixup_bundle(\"${FIXUP_BUNDLE_APPS}\" \"${FIXUP_BUNDLE_QT_PLUGINS};${_copyq_installed_plugins}\" \"${FIXUP_BUNDLE_DEP_DIRS}\")
# verify_app(\"${FIXUP_BUNDLE_APPS}\")
# "
# COMPONENT Runtime
# )
#
# set(CPACK_GENERATOR "DragNDrop")
# include(CPack)
set(BUNDLE "\${CMAKE_INSTALL_PREFIX}/${COPYQ_EXECUTABLE_NAME}.app")

# https://doc.qt.io/qt-6/qt-deploy-runtime-dependencies.html
# Generate a deployment script to be executed at install time
qt_generate_deploy_script(
TARGET ${COPYQ_EXECUTABLE_NAME}
OUTPUT_SCRIPT deploy_script
CONTENT "
qt_deploy_runtime_dependencies(
EXECUTABLE \"${BUNDLE}\"
GENERATE_QT_CONF
VERBOSE
)")
install(SCRIPT ${deploy_script})
endif()
10 changes: 7 additions & 3 deletions src/common/sanitize_text_document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#ifdef Q_OS_MAC
# include <QFontDatabase>
# include <algorithm>
#endif

namespace {
Expand Down Expand Up @@ -52,9 +53,12 @@ void sanitizeTextDocument(QTextDocument *document)

#ifdef Q_OS_MAC
// Prevent showing font download dialog on macOS.
const QString fontFamily = charFormat.fontFamily();
if ( !fontDatabase.hasFamily(fontFamily) ) {
charFormat.setFontFamily(QString());
const QStringList fontFamilies = charFormat.fontFamilies().toStringList();
if ( !fontFamilies.isEmpty() &&
!std::any_of(fontFamilies.constBegin(), fontFamilies.constEnd(),
[&](const QString &fontFamily){ return fontDatabase.hasFamily(fontFamily); }) )
{
charFormat.setFontFamilies({});
sanitized = true;
}
#endif
Expand Down
1 change: 1 addition & 0 deletions src/copyq.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
<file alias="images/tab_remove">images/tab_remove.svg</file>
<file alias="images/logo.png">images/icon_512x512.png</file>
<file>images/fontawesome.ttf</file>
<file alias="knotifications6/copyq.notifyrc">knotifications5/copyq.notifyrc</file>
</qresource>
</RCC>
3 changes: 3 additions & 0 deletions src/gui/actiondialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ ActionDialog::ActionDialog(QWidget *parent)
{
ui->setupUi(this);

// WORKAROUND for broken initial focus in Qt 6.6 (QTBUG-121514)
ui->comboBoxCommands->setFocus();

auto shortcut = new QShortcut(QKeySequence(Qt::ControlModifier | Qt::Key_P), this);
connect(shortcut, &QShortcut::activated, this, &ActionDialog::previousCommand);
shortcut = new QShortcut(QKeySequence(Qt::ControlModifier | Qt::Key_N), this);
Expand Down
48 changes: 13 additions & 35 deletions src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,6 @@ bool canExecuteCommand(const Command &command, const QVariantMap &data, const QS
return true;
}

void stealFocus(const QWidget &window)
{
WId wid = window.winId();
PlatformWindowPtr platformWindow = platformNativeInterface()->getWindow(wid);
if (platformWindow)
platformWindow->raise();
}

template <typename WidgetOrAction>
void disableActionWhenTabGroupSelected(WidgetOrAction *action, MainWindow *window)
{
Expand Down Expand Up @@ -274,38 +266,34 @@ QMenu *createSubMenus(QString *name, QMenu *menu)

// WORKAROUND: setWindowFlags() hides the window.
// See: https://doc.qt.io/qt-5/qwidget.html#windowFlags-prop
bool setWindowFlag(QWidget *window, Qt::WindowType flag, bool enable)
void setWindowFlag(QPointer<QWidget> window, Qt::WindowType flag, bool enable)
{
if (!window)
return false;
return;

const Qt::WindowFlags flags = window->windowFlags();
const bool wasEnabled = flags.testFlag(flag);
if (wasEnabled == enable)
return false;
return;

const bool wasVisible = window->isVisible();
const bool wasActive = window->isActiveWindow();

window->setWindowFlags(flags ^ flag);

if (wasVisible) {
if (wasActive) {
window->show();
window->activateWindow();
QApplication::setActiveWindow(window);
raiseWindow(window);
} else {
const bool showWithoutActivating = window->testAttribute(Qt::WA_ShowWithoutActivating);
window->setAttribute(Qt::WA_ShowWithoutActivating);
window->show();
window->setAttribute(Qt::WA_ShowWithoutActivating, showWithoutActivating);
}

if (wasActive) {
window->raise();
window->activateWindow();
QApplication::setActiveWindow(window);
stealFocus(*window);
}
}

return true;
}

void setAlwaysOnTop(QWidget *window, bool alwaysOnTop)
Expand Down Expand Up @@ -598,8 +586,8 @@ MainWindow::MainWindow(const ClipboardBrowserSharedPtr &sharedData, QWidget *par

m_sharedData->menuItems = menuItems();

#ifdef Q_OS_MAC
// Open above fullscreen windows on OS X.
#if defined(Q_OS_MAC) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
// Open above fullscreen windows on macOS and Qt 5.
setWindowModality(Qt::WindowModal);
setWindowFlag(Qt::Sheet);
#endif
Expand Down Expand Up @@ -1954,13 +1942,7 @@ bool MainWindow::toggleMenu(TrayMenu *menu, QPoint pos)
}

menu->popup( toScreen(pos, menu) );

menu->raise();
menu->activateWindow();
QApplication::setActiveWindow(menu);
QApplication::processEvents();
stealFocus(*menu);

raiseWindow(menu);
return true;
}

Expand Down Expand Up @@ -2899,8 +2881,6 @@ void MainWindow::showWindow()
showMaximized();
else
showNormal();
raise();
activateWindow();

auto c = browser();
if (c) {
Expand All @@ -2909,9 +2889,7 @@ void MainWindow::showWindow()
c->setFocus();
}

QApplication::setActiveWindow(this);

stealFocus(*this);
raiseWindow(this);
}

void MainWindow::hideWindow()
Expand Down Expand Up @@ -3707,7 +3685,7 @@ ActionDialog *MainWindow::openActionDialog(const QVariantMap &data)
connect( actionDialog, &ActionDialog::commandAccepted,
this, &MainWindow::onActionDialogAccepted );

stealFocus(*actionDialog);
raiseWindow(actionDialog);

return actionDialog;
}
Expand Down

0 comments on commit 54a648d

Please sign in to comment.