# SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
#
# SPDX-License-Identifier: CC0-1.0

cmake_minimum_required(VERSION 3.10)

project(dde-simple-launcher VERSION 0.7.0)

option(BUILD_TEST "Whether or not to build the tests" OFF)
option(CMAKE_EXPORT_COMPILE_COMMANDS "clangd support" ON)

set(CMAKE_CXX_STANDARD 17) # blurhash requires 17, otherwish we can still use 14
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON) # ensure adapter class can include launchercontroller.h
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

include(FeatureSummary)
include(GNUInstallDirs)

# deepin/Debian multiarch 修正：库必须装到 /usr/lib/<arch-triplet>（如 x86_64-linux-gnu），
# 否则 simplelaunchercommon.so 会装到 /usr/lib 而运行时从 multiarch 路径加载旧库，
# 导致 QML 改动完全不生效（曾因此出现"10列/ESC/分页全部无效"）。
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" AND NOT CMAKE_INSTALL_LIBDIR MATCHES "x86_64-linux-gnu")
    set(CMAKE_INSTALL_LIBDIR "lib/x86_64-linux-gnu" CACHE PATH "Library install directory (multiarch)" FORCE)
endif()

set(QT_NS Qt6)
set(DTK_NS Dtk6)
set(ASQT_NS AppStreamQt)

find_package(QT NAMES ${QT_NS} REQUIRED COMPONENTS Core)
find_package(${QT_NS} REQUIRED COMPONENTS Core Gui Concurrent DBus Qml Svg Quick QuickControls2 LinguistTools)
find_package(${DTK_NS} REQUIRED COMPONENTS Core Gui)
find_package(${ASQT_NS} 1.0 REQUIRED)
find_package(DDEShell REQUIRED)
find_package(ECM NO_MODULE)
if(Qt6_VERSION VERSION_GREATER_EQUAL 6.10)
  find_package(Qt6 COMPONENTS GuiPrivate REQUIRED)
endif()

# Check if dde-api provides EventLogger (header-only)
find_package(DDEAPI QUIET)
if(DDEAPI_FOUND)
    set(HAVE_DDE_API_EVENTLOGGER ON)
    message(STATUS "Found DDEAPI: EventLogger available")
else()
    message(STATUS "DDEAPI not found, event logging will be disabled")
endif()

set_package_properties(${ASQT_NS} PROPERTIES
    DESCRIPTION "Library that lists Appstream resources"
    URL "https://www.freedesktop.org"
    TYPE RECOMMENDED)

feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)

set(QML_IMPORT_PATH ${QML_IMPORT_PATH} ${CMAKE_CURRENT_BINARY_DIR}/ CACHE STRING "" FORCE)

if (ECM_FOUND)
    set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH};${ECM_MODULE_PATH};${PROJECT_SOURCE_DIR}/cmake")

    include(KDEClangFormat)
    include(KDEGitCommitHooks)
endif()

# QML 模块安装位置（org.deepin.simplelauncher / .models / .windowed）
#
# 为什么必须显式安装：官方版由 dde-shell 直接加载 C++ applet，QML 模块随进程可用；
# 简洁启动器去掉 applet 后，dock 上的切换器（运行在 dde-shell 进程内）要 import
# org.deepin.simplelauncher，只能从磁盘的 QML import 路径解析，因此这里必须产出完整 QML 模块。
# QML 文件内容由 simplelaunchercommon.so 的资源提供（qmldir 中的 prefer :/qt/qml/...），
# 磁盘上只需 qmldir + 插件 .so；models/windowed 是 STATIC 模块，类型由主插件静态注册，只需 qmldir。
set(SL_QML_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/qt6/qml")
set(SL_QML_MODULE_DIR "${SL_QML_INSTALL_DIR}/org/deepin/simplelauncher")

add_subdirectory(src/gioutils)
add_subdirectory(src/utils)
add_subdirectory(src/ddeintegration)
add_subdirectory(src/models)
add_subdirectory(qml/windowed)
add_subdirectory(dbus)

if(BUILD_TEST)
    enable_testing()
    add_subdirectory(tests)
endif()

set(SOURCE_FILES
    desktopintegration.cpp desktopintegration.h
    launchercontroller.cpp launchercontroller.h
    debughelper.cpp debughelper.h
    inputeventitem.h inputeventitem.cpp
    pagesliceproxymodel.cpp pagesliceproxymodel.h
)

set(QML_FILES
    ${PROJECT_SOURCE_DIR}/qml/Helper.qml
    ${PROJECT_SOURCE_DIR}/qml/AppItemMenu.qml
    ${PROJECT_SOURCE_DIR}/qml/GridViewContainer.qml
    ${PROJECT_SOURCE_DIR}/qml/IconItemDelegate.qml
    ${PROJECT_SOURCE_DIR}/qml/DebugBounding.qml
    ${PROJECT_SOURCE_DIR}/qml/FolderGridViewPopup.qml
)
foreach(QML_FILE ${QML_FILES})
    get_filename_component(file_name ${QML_FILE} NAME)
    set_source_files_properties(${QML_FILE}
        PROPERTIES QT_RESOURCE_ALIAS ${file_name}
    )
endforeach()

# ---- 翻译（i18n）----
# 源码 .ts 与编译后的 .qm 均已提交到 translations/。构建期**直接安装已提交的 .qm**，
# 不再在构建机调用 lrelease——本机 lrelease 为 qtchooser 包装器，常因缺少 Qt 版本选择
# 链路而报 "could not find a Qt installation of ''"，导致构建失败。
# 维护：若修改 translations/*.ts，请用 Qt6 的 lrelease 重新编译并一并提交 .qm：
#   /usr/lib/qt6/bin/lrelease translations/dde-simple-launcher_zh_CN.ts \
#       -qm translations/dde-simple-launcher_zh_CN.qm
set(SL_TRANSLATIONS_QM "")
foreach(_ts ${PROJECT_SOURCE_DIR}/translations/dde-simple-launcher_zh_CN.ts)
    get_filename_component(_qm_name ${_ts} NAME_WE)
    set(_src_qm ${PROJECT_SOURCE_DIR}/translations/${_qm_name}.qm)
    set(_qm ${CMAKE_CURRENT_BINARY_DIR}/translations/${_qm_name}.qm)
    list(APPEND SL_TRANSLATIONS_QM ${_qm})
    configure_file(${_src_qm} ${_qm} COPYONLY)
endforeach()
if(SL_TRANSLATIONS_QM)
    add_custom_target(simplelauncher_translations ALL DEPENDS ${SL_TRANSLATIONS_QM})
    install(FILES ${SL_TRANSLATIONS_QM}
            DESTINATION ${CMAKE_INSTALL_DATADIR}/dde-simple-launcher/translations)
endif()

set_source_files_properties(${PROJECT_SOURCE_DIR}/qml/Helper.qml
    PROPERTIES
        QT_QML_SINGLETON_TYPE TRUE
)

qt_add_dbus_adaptor(DBUS_ADAPTER_FILES dbus/org.deepin.SimpleLauncher.xml launchercontroller.h SimpleLauncherController)

qt_add_library(simplelaunchercommon SHARED
    ${SOURCE_FILES}
    ${DBUS_ADAPTER_FILES}
    ${RESOURCES}
)

qt_add_qml_module(simplelaunchercommon
    URI org.deepin.simplelauncher
    VERSION 1.0
    RESOURCES qml.qrc
    RESOURCE_PREFIX
        /qt/qml
    QML_FILES
        ${QML_FILES}
)
set_target_properties(simplelaunchercommon PROPERTIES PREFIX "")

target_link_libraries(simplelaunchercommon PUBLIC
    ${DTK_NS}::Core
    ${DTK_NS}::Gui
    Qt::GuiPrivate
    Qt::Qml
    Qt::Quick
    Qt::QuickControls2

    simplelauncher-qml-windowed
    gio-utils
    launcher-utils
    simplelauncher-models
    dde-integration-dbus
    Dde::Shell
)

if (HAVE_DDE_API_EVENTLOGGER)
    target_compile_definitions(simplelaunchercommon PRIVATE HAVE_DDE_API_EVENTLOGGER)
    target_link_libraries(simplelaunchercommon PRIVATE DDEAPI::EventLogger)
endif()

install(TARGETS simplelaunchercommon DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(
    FILES dist/org.deepin.dde.shell.simplelauncher.appdata.xml
    DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo"
)
# debug config file
install(FILES ${CMAKE_SOURCE_DIR}/dist/deepin-debug-config/org.deepin.simplelauncher.json
    DESTINATION ${CMAKE_INSTALL_DATADIR}/deepin-debug-config/deepin-debug-config.d)
install(FILES ${CMAKE_SOURCE_DIR}/dist/deepin-log-config/org.deepin.simplelauncher.json
    DESTINATION ${CMAKE_INSTALL_DATADIR}/deepin-log-viewer/deepin-log.conf.d)

# ---- 简洁启动器独立进程（P1a 骨架） ----
qt_add_executable(simplelauncher
    simplelauncher-main.cpp
    appsourcemodel.cpp appsourcemodel.h
    docktype.cpp docktype.h
)
target_link_libraries(simplelauncher PRIVATE
    simplelaunchercommon
    Dde::Shell
    Qt::Qml
    Qt::Quick
    Qt::Gui
    Qt::Core
    ${DTK_NS}::Core
    ${DTK_NS}::Gui
    xcb
    X11
)
target_include_directories(simplelauncher PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(simplelauncher PROPERTIES
    INSTALL_RPATH "$ORIGIN/../lib/x86_64-linux-gnu"
)
# QML 模块安装位置的绝对路径（用户级 ~/.local/... 或系统级 /usr/...），供引擎 addImportPath 使用
target_compile_definitions(simplelauncher PRIVATE
    SIMPLELAUNCHER_QML_DIR="${CMAKE_INSTALL_FULL_LIBDIR}/qt6/qml"
)

# ---- QML 模块落盘（qmldir + 插件；切换器运行在 dde-shell 内，靠这里解析 import）----
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qmldir
    DESTINATION ${SL_QML_MODULE_DIR})
install(TARGETS simplelaunchercommonplugin DESTINATION ${SL_QML_MODULE_DIR})
# 插件要去 ${CMAKE_INSTALL_LIBDIR} 找 simplelaunchercommon.so：
# <libdir>/qt6/qml/org/deepin/simplelauncher/ → 上溯 5 级回到 <libdir>
set_target_properties(simplelaunchercommonplugin PROPERTIES
    INSTALL_RPATH "$ORIGIN/../../../../.."
    INSTALL_RPATH_USE_LINK_PATH FALSE
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/src/models/qmldir
    DESTINATION ${SL_QML_MODULE_DIR}/models)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qml/windowed/qmldir
    DESTINATION ${SL_QML_MODULE_DIR}/windowed)

# 独立进程主程序（官方版没有这个产物，必须显式安装，否则 cmake --install 后无可执行文件）
#
# 注意：真身装到 libexec，bindir 放**包装器**。
# 原因：启动器由 D-Bus 激活，激活进程的会话环境（LD_LIBRARY_PATH / QML2_IMPORT_PATH /
# XDG_CURRENT_DESKTOP）可能缺失，导致"字体/缩放与定制版不一致""启动慢"（历史 p1c-result 已记录）。
# 包装器补齐环境后 exec 真身；exec 使进程名仍为 simplelauncher，不影响 pkill / tiler 名单。
install(TARGETS simplelauncher RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR})
# 包装器用**相对路径**（相对 bindir 推算），故与 --prefix / 目录整体搬移都无关。
# 注意：这里刻意用「相对安装目录 + 伪根 /」来算，**不要**用 CMAKE_INSTALL_FULL_*：
# 本文件前面把 CMAKE_INSTALL_LIBDIR 强制改成 multiarch 值后，GNUInstallDirs 先前算出的
# FULL_LIBDIR 可能仍是旧值，直接喂给 file(RELATIVE_PATH) 会得到空串（已踩，见 H37）。
# 注意：不要把这套计算封进 function() —— `file(RELATIVE_PATH ${_out} …)` 只会写函数
# 局部变量，不 set(… PARENT_SCOPE) 的话返回后就是空串（已踩一次，见 H37）。
if(IS_ABSOLUTE "${CMAKE_INSTALL_BINDIR}")
    set(SL_BIN_ROOT "${CMAKE_INSTALL_BINDIR}")
else()
    set(SL_BIN_ROOT "/${CMAKE_INSTALL_BINDIR}")
endif()
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
    set(SL_LIB_TARGET "${CMAKE_INSTALL_LIBDIR}")
else()
    set(SL_LIB_TARGET "/${CMAKE_INSTALL_LIBDIR}")
endif()
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBEXECDIR}")
    set(SL_LIBEXEC_TARGET "${CMAKE_INSTALL_LIBEXECDIR}")
else()
    set(SL_LIBEXEC_TARGET "/${CMAKE_INSTALL_LIBEXECDIR}")
endif()
file(RELATIVE_PATH SL_REL_LIB_FROM_BIN "${SL_BIN_ROOT}" "${SL_LIB_TARGET}")
file(RELATIVE_PATH SL_REL_LIBEXEC_FROM_BIN "${SL_BIN_ROOT}" "${SL_LIBEXEC_TARGET}")
message(STATUS "simplelauncher wrapper: bindir -> lib = [${SL_REL_LIB_FROM_BIN}] , libexec = [${SL_REL_LIBEXEC_FROM_BIN}]")
configure_file(
    ${CMAKE_SOURCE_DIR}/dist/simplelauncher-wrapper.in
    ${CMAKE_CURRENT_BINARY_DIR}/simplelauncher-wrapper
    @ONLY
)
install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/simplelauncher-wrapper
    DESTINATION ${CMAKE_INSTALL_BINDIR}
    RENAME simplelauncher
)

add_subdirectory(shell-launcher-applet)
