cmake_minimum_required(VERSION 3.21)

project(OrbitHub VERSION 2026.9.8.3 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

include(GNUInstallDirs)

find_package(Qt6 6.2 REQUIRED COMPONENTS Widgets Sql)

qt_standard_project_setup()

add_subdirectory(third_party/KodoTerm)

if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/FreeRDP/CMakeLists.txt")
    message(FATAL_ERROR "Vendored FreeRDP source is missing at third_party/FreeRDP")
endif()

# Pin FreeRDP build to the vendored source tree so headers/libs are always from the same revision.
set(FREERDP_UNIFIED_BUILD ON CACHE BOOL "" FORCE)
set(WITH_MANPAGES OFF CACHE BOOL "" FORCE)
set(WITH_SAMPLE OFF CACHE BOOL "" FORCE)
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
set(BUILD_TESTING_INTERNAL OFF CACHE BOOL "" FORCE)
set(WITH_CLIENT_COMMON ON CACHE BOOL "" FORCE)
set(WITH_CLIENT OFF CACHE BOOL "" FORCE)
set(WITH_CLIENT_SDL OFF CACHE BOOL "" FORCE)
set(WITH_CLIENT_INTERFACE OFF CACHE BOOL "" FORCE)
set(WITH_SERVER OFF CACHE BOOL "" FORCE)
set(WITH_CHANNELS ON CACHE BOOL "" FORCE)
set(WITH_CLIENT_CHANNELS ON CACHE BOOL "" FORCE)
set(WITH_FUSE OFF CACHE BOOL "" FORCE)
set(CHANNEL_DRDYNVC ON CACHE BOOL "" FORCE)
set(CHANNEL_DRDYNVC_CLIENT ON CACHE BOOL "" FORCE)
set(CHANNEL_DISP ON CACHE BOOL "" FORCE)
set(CHANNEL_DISP_CLIENT ON CACHE BOOL "" FORCE)
set(CHANNEL_AINPUT OFF CACHE BOOL "" FORCE)
set(CHANNEL_AUDIN OFF CACHE BOOL "" FORCE)
set(CHANNEL_CLIPRDR ON CACHE BOOL "" FORCE)
set(CHANNEL_CLIPRDR_CLIENT ON CACHE BOOL "" FORCE)
set(CHANNEL_DRIVE OFF CACHE BOOL "" FORCE)
set(CHANNEL_ECHO OFF CACHE BOOL "" FORCE)
set(CHANNEL_ENCOMSP OFF CACHE BOOL "" FORCE)
set(CHANNEL_GEOMETRY OFF CACHE BOOL "" FORCE)
set(CHANNEL_LOCATION OFF CACHE BOOL "" FORCE)
set(CHANNEL_PARALLEL OFF CACHE BOOL "" FORCE)
set(CHANNEL_PRINTER OFF CACHE BOOL "" FORCE)
set(CHANNEL_RAIL OFF CACHE BOOL "" FORCE)
set(CHANNEL_RDPDR OFF CACHE BOOL "" FORCE)
set(CHANNEL_RDPEAR OFF CACHE BOOL "" FORCE)
set(CHANNEL_RDPECAM OFF CACHE BOOL "" FORCE)
set(CHANNEL_RDPEI OFF CACHE BOOL "" FORCE)
set(CHANNEL_RDPEMSC OFF CACHE BOOL "" FORCE)
set(CHANNEL_RDPGFX OFF CACHE BOOL "" FORCE)
set(CHANNEL_RDPSND OFF CACHE BOOL "" FORCE)
set(CHANNEL_REMDESK OFF CACHE BOOL "" FORCE)
set(CHANNEL_SERIAL OFF CACHE BOOL "" FORCE)
set(CHANNEL_SMARTCARD OFF CACHE BOOL "" FORCE)
set(CHANNEL_SSHAGENT OFF CACHE BOOL "" FORCE)
set(CHANNEL_TELEMETRY OFF CACHE BOOL "" FORCE)
set(CHANNEL_URBDRC OFF CACHE BOOL "" FORCE)
set(CHANNEL_VIDEO OFF CACHE BOOL "" FORCE)
set(WITH_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_DSP_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_VIDEO_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CAIRO OFF CACHE BOOL "" FORCE)
set(WITH_SWSCALE OFF CACHE BOOL "" FORCE)
set(WITH_JPEG OFF CACHE BOOL "" FORCE)
set(WITH_KRB5 OFF CACHE BOOL "" FORCE)
set(WITH_UNICODE_BUILTIN ON CACHE BOOL "" FORCE)
set(WITH_WINPR_TOOLS OFF CACHE BOOL "" FORCE)

add_subdirectory(third_party/FreeRDP EXCLUDE_FROM_ALL)

set(ORBITHUB_SOURCES
    src/about_dialog.cpp
    src/about_dialog.h
    src/user_guide_dialog.cpp
    src/user_guide_dialog.h
    docs/user_guide.qrc
    src/app_icon.cpp
    src/app_icon.h
    src/main.cpp
    src/profile_dialog.cpp
    src/profile_dialog.h
    src/profile_repository.cpp
    src/profile_repository.h
    src/profiles_tree_widget.cpp
    src/profiles_tree_widget.h
    src/profiles_window.cpp
    src/profiles_window.h
    src/session_backend.h
    src/session_backend_factory.cpp
    src/session_backend_factory.h
    src/session_tab.cpp
    src/session_tab.h
    src/rdp_display_widget.cpp
    src/rdp_display_widget.h
    src/terminal_view.cpp
    src/terminal_view.h
    src/session_window.cpp
    src/session_window.h
    src/rdp_session_backend.cpp
    src/rdp_session_backend.h
    src/ssh_session_backend.cpp
    src/ssh_session_backend.h
    src/unsupported_session_backend.cpp
    src/unsupported_session_backend.h
)

if(WIN32)
    list(APPEND ORBITHUB_SOURCES packaging/windows/orbithub.rc)
endif()

if(APPLE)
    list(APPEND ORBITHUB_SOURCES packaging/macos/orbithub.icns)
    set_source_files_properties(packaging/macos/orbithub.icns PROPERTIES
        MACOSX_PACKAGE_LOCATION "Resources"
    )
    set(MACOSX_BUNDLE_ICON_FILE orbithub.icns)
    set(MACOSX_BUNDLE_BUNDLE_NAME "OrbitHub")
    set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.darksingularity.OrbitHub")
    set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}")
    set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}")
endif()

add_executable(orbithub WIN32 MACOSX_BUNDLE ${ORBITHUB_SOURCES})

target_link_libraries(orbithub PRIVATE Qt6::Widgets Qt6::Sql)
target_link_libraries(orbithub PRIVATE KodoTerm::KodoTerm)
if(TARGET freerdp AND TARGET winpr)
    target_compile_definitions(orbithub PRIVATE ORBITHUB_HAS_FREERDP)
    target_include_directories(orbithub PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/third_party/FreeRDP/include
        ${CMAKE_CURRENT_SOURCE_DIR}/third_party/FreeRDP/winpr/include
        ${CMAKE_CURRENT_BINARY_DIR}/third_party/FreeRDP/include
        ${CMAKE_CURRENT_BINARY_DIR}/third_party/FreeRDP/winpr/include
    )
    target_link_libraries(orbithub PRIVATE freerdp winpr)
    if(TARGET freerdp-client)
        target_link_libraries(orbithub PRIVATE freerdp-client)
    endif()
else()
    message(FATAL_ERROR "Vendored FreeRDP targets were not produced as expected.")
endif()

# Qt loads platform integration and SQL driver plugins dynamically at
# runtime (QFactoryLoader), so they never appear in orbithub.exe's import
# table. vcpkg's automatic DLL deployment only follows the import table, so
# these plugins have to be copied out explicitly or the app fails to start
# with "Could not find the Qt platform plugin" / "can not load requested
# driver 'QSQLITE'".
if(WIN32)
    if(TARGET Qt6::QWindowsIntegrationPlugin)
        add_custom_command(TARGET orbithub POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E make_directory
                "$<TARGET_FILE_DIR:orbithub>/platforms"
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
                "$<TARGET_FILE:Qt6::QWindowsIntegrationPlugin>"
                "$<TARGET_FILE_DIR:orbithub>/platforms/"
            COMMENT "Deploying Qt Windows platform plugin"
        )
        install(FILES "$<TARGET_FILE:Qt6::QWindowsIntegrationPlugin>"
            DESTINATION "${CMAKE_INSTALL_BINDIR}/platforms"
        )
    endif()

    if(TARGET Qt6::QSQLiteDriverPlugin)
        add_custom_command(TARGET orbithub POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E make_directory
                "$<TARGET_FILE_DIR:orbithub>/sqldrivers"
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
                "$<TARGET_FILE:Qt6::QSQLiteDriverPlugin>"
                "$<TARGET_FILE_DIR:orbithub>/sqldrivers/"
            COMMENT "Deploying Qt SQLite driver plugin"
        )
        install(FILES "$<TARGET_FILE:Qt6::QSQLiteDriverPlugin>"
            DESTINATION "${CMAKE_INSTALL_BINDIR}/sqldrivers"
        )

        # vcpkg's qtbase[sql-sqlite] links the plugin against vcpkg's own
        # shared sqlite3 port rather than bundling SQLite into the plugin,
        # so the plugin fails to load ("can not load requested driver
        # 'QSQLITE'") unless sqlite3.dll also ships next to the executable.
        find_file(ORBITHUB_SQLITE3_DLL
            NAMES sqlite3.dll
            PATHS ${CMAKE_PREFIX_PATH}
            PATH_SUFFIXES bin
        )
        if(ORBITHUB_SQLITE3_DLL)
            add_custom_command(TARGET orbithub POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy_if_different
                    "${ORBITHUB_SQLITE3_DLL}"
                    "$<TARGET_FILE_DIR:orbithub>/"
                COMMENT "Deploying sqlite3.dll (Qt SQLite plugin dependency)"
            )
            install(FILES "${ORBITHUB_SQLITE3_DLL}" DESTINATION "${CMAKE_INSTALL_BINDIR}")
        endif()
    endif()
endif()

if(APPLE)
    # Mirrors macdeployqt's own layout for Qt frameworks: dylibs live in
    # Contents/Frameworks inside the bundle, found via @executable_path
    # (the macOS/dyld equivalent of Linux's $ORIGIN token, which dyld
    # does not understand).
    set_target_properties(orbithub PROPERTIES
        INSTALL_RPATH "@executable_path/../Frameworks"
        INSTALL_RPATH_USE_LINK_PATH ON
    )
else()
    set_target_properties(orbithub PROPERTIES
        BUILD_RPATH_USE_ORIGIN ON
        INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}/orbithub"
        INSTALL_RPATH_USE_LINK_PATH ON
    )
endif()

install(TARGETS orbithub
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    BUNDLE DESTINATION .
)

if(APPLE)
    set(ORBITHUB_PRIVATE_LIB_DESTINATION "OrbitHub.app/Contents/Frameworks")
else()
    set(ORBITHUB_PRIVATE_LIB_DESTINATION "${CMAKE_INSTALL_LIBDIR}/orbithub")
endif()
set(ORBITHUB_RUNTIME_TARGETS KodoTerm freerdp winpr)
if(TARGET freerdp-client)
    list(APPEND ORBITHUB_RUNTIME_TARGETS freerdp-client)
endif()
foreach(runtime_target IN LISTS ORBITHUB_RUNTIME_TARGETS)
    if(TARGET ${runtime_target})
        install(TARGETS ${runtime_target}
            RUNTIME DESTINATION ${ORBITHUB_PRIVATE_LIB_DESTINATION}
            LIBRARY DESTINATION ${ORBITHUB_PRIVATE_LIB_DESTINATION}
            ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
        )
    endif()
endforeach()

install(FILES
    packaging/linux/org.darksingularity.OrbitHub.desktop
    DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
)
foreach(icon_size IN ITEMS 16 24 32 48 64 128 256)
    install(FILES
        packaging/linux/icons/${icon_size}x${icon_size}/apps/org.darksingularity.OrbitHub.png
        DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/${icon_size}x${icon_size}/apps
    )
endforeach()
install(FILES
    packaging/linux/org.darksingularity.OrbitHub.metainfo.xml
    DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo
)
install(FILES LICENSE
    DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/org.darksingularity.OrbitHub
)
install(FILES third_party/FreeRDP/LICENSE
    DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/org.darksingularity.OrbitHub
    RENAME LICENSE-FreeRDP
)
install(FILES third_party/KodoTerm/LICENSE
    DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/org.darksingularity.OrbitHub
    RENAME LICENSE-KodoTerm
)
