cmake_minimum_required(VERSION 3.24)
project(inkline VERSION 0.4.18 LANGUAGES C CXX)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)
FetchContent_Declare(ghostty
    GIT_REPOSITORY https://github.com/ghostty-org/ghostty.git
    GIT_TAG 448062571c5edf010b7490d06869b88b5ebf8f80
    # Fetch only. Our wrapper keeps host and ARM outputs in separate build dirs.
    SOURCE_SUBDIR _rmt_fetch_only
)
FetchContent_MakeAvailable(ghostty)
include(cmake/ApplyGhosttyPatch.cmake)
include(cmake/Ghostty.cmake)
include(cmake/DjVuLibre.cmake)

find_package(PNG REQUIRED)
find_package(Threads REQUIRED)
add_library(rmt_core STATIC src/core.c)
target_include_directories(rmt_core PUBLIC include)
target_link_libraries(rmt_core PUBLIC ghostty-vt-static PRIVATE PNG::PNG Threads::Threads)
target_compile_options(rmt_core PRIVATE -Wall -Wextra -Werror)

add_library(rmt_sixel STATIC src/sixel.cpp)
target_include_directories(rmt_sixel PUBLIC include)
target_compile_options(rmt_sixel PRIVATE -Wall -Wextra -Werror)

add_library(rmt_stream STATIC src/stream.cpp)
target_link_libraries(rmt_stream PUBLIC rmt_core rmt_sixel)
target_compile_options(rmt_stream PRIVATE -Wall -Wextra -Werror)

add_library(rmt_pty STATIC src/pty.cpp)
target_include_directories(rmt_pty PUBLIC include)
target_compile_options(rmt_pty PRIVATE -Wall -Wextra -Werror)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
    target_link_libraries(rmt_pty PRIVATE util)
endif()

add_library(rmt_hotkeys STATIC src/hotkey_config.cpp)
target_include_directories(rmt_hotkeys PUBLIC include)
target_compile_options(rmt_hotkeys PRIVATE -Wall -Wextra -Werror)

option(INKLINE_BUILD_APP "Build the Qt Quick tablet application" ON)
if(INKLINE_BUILD_APP)
    configure_file(assets/goblin.png assets/goblin.png COPYONLY)
    file(COPY assets/fonts assets/input-methods DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/assets")
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(QT REQUIRED IMPORTED_TARGET Qt6Quick)
    if(CMAKE_CROSSCOMPILING)
        # Keep the C system headers after libstdc++ for its include_next calls.
        # The toolchain already supplies this directory in the correct order.
        get_target_property(_qt_includes PkgConfig::QT INTERFACE_INCLUDE_DIRECTORIES)
        list(REMOVE_ITEM _qt_includes "${RMT_SYSROOT}/usr/include")
        set_target_properties(PkgConfig::QT PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_qt_includes}")
    endif()
    include(cmake/LegalNotices.cmake)
    add_library(rmt_battery STATIC src/battery.cpp)
    target_include_directories(rmt_battery PUBLIC include)
    target_link_libraries(rmt_battery PUBLIC PkgConfig::QT)
    target_compile_options(rmt_battery PRIVATE -Wall -Wextra -Werror)
    add_library(rmt_wifi STATIC src/wifi.cpp)
    target_include_directories(rmt_wifi PUBLIC include)
    target_link_libraries(rmt_wifi PUBLIC PkgConfig::QT)
    target_compile_options(rmt_wifi PRIVATE -Wall -Wextra -Werror)
    add_library(rmt_images STATIC src/djvu_image.cpp src/image_arena.cpp)
    target_include_directories(rmt_images PUBLIC include)
    target_link_libraries(rmt_images PUBLIC PkgConfig::QT PRIVATE inkline-djvulibre Threads::Threads)
    target_compile_options(rmt_images PRIVATE -Wall -Wextra -Werror)
    add_library(rmt_ui STATIC src/renderer.cpp src/keyboard.cpp src/mouse.cpp src/input.cpp src/folio.cpp src/usb_devices.cpp src/soft_keyboard.cpp src/documents.cpp src/preferences.cpp src/caps_leds.cpp src/clipboard.cpp src/input_method.cpp src/unicode_keyboard.cpp src/shortcut_settings.cpp src/usb_tools.cpp src/hid_keyboard.cpp src/wifi_settings.cpp src/legal_notices.cpp src/view.cpp)
    target_include_directories(rmt_ui PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/generated")
    target_compile_definitions(rmt_ui PUBLIC QT_NO_KEYWORDS)
    target_link_libraries(rmt_ui PUBLIC rmt_stream rmt_pty rmt_hotkeys rmt_battery rmt_wifi rmt_images PkgConfig::QT)
    target_compile_options(rmt_ui PRIVATE -Wall -Wextra -Werror -Wno-missing-field-initializers)
    add_executable(inkline src/main.cpp)
    target_link_libraries(inkline PRIVATE rmt_ui rmt_pty)
    target_compile_options(inkline PRIVATE -Wall -Wextra -Werror -Wno-missing-field-initializers)
    target_compile_definitions(inkline PRIVATE INKLINE_VERSION="${PROJECT_VERSION}")
    add_executable(inkline-battery src/battery_main.cpp)
    target_link_libraries(inkline-battery PRIVATE rmt_battery)
    target_compile_options(inkline-battery PRIVATE -Wall -Wextra -Werror)
    add_executable(inkline-wifi src/wifi_main.cpp)
    target_link_libraries(inkline-wifi PRIVATE rmt_wifi)
    target_compile_options(inkline-wifi PRIVATE -Wall -Wextra -Werror)
    install(TARGETS inkline inkline-battery inkline-wifi RUNTIME DESTINATION bin)
    install(FILES assets/goblin.png DESTINATION bin/assets)
    install(DIRECTORY assets/fonts assets/input-methods DESTINATION bin/assets)
    install(FILES LICENSE NOTICE THIRD_PARTY.md DESTINATION share/doc/inkline)
    install(DIRECTORY licenses DESTINATION share/doc/inkline)
    if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
        add_executable(inkline-hotkey src/hotkey.cpp)
        target_link_libraries(inkline-hotkey PRIVATE rmt_hotkeys)
        target_include_directories(inkline-hotkey PRIVATE include)
        target_compile_options(inkline-hotkey PRIVATE -Wall -Wextra -Werror)
    endif()
endif()

include(CTest)
if(BUILD_TESTING)
    add_executable(power_key_tests tests/power_key_tests.cpp)
    target_include_directories(power_key_tests PRIVATE include)
    target_compile_options(power_key_tests PRIVATE -Wall -Wextra -Werror)
    add_test(NAME power_key_resume COMMAND power_key_tests)
    add_test(NAME power_control_helper COMMAND sh "${CMAKE_CURRENT_SOURCE_DIR}/tests/power_control.sh" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/power-control.sh")
    add_executable(hotkey_config_tests tests/hotkey_config_tests.cpp)
    target_link_libraries(hotkey_config_tests PRIVATE rmt_hotkeys)
    target_include_directories(hotkey_config_tests PRIVATE include)
    target_compile_options(hotkey_config_tests PRIVATE -Wall -Wextra -Werror)
    add_test(NAME global_shortcut_config COMMAND hotkey_config_tests)
    add_executable(core_tests tests/core_tests.c)
    target_link_libraries(core_tests PRIVATE rmt_core PNG::PNG)
    add_test(NAME core_graphics COMMAND core_tests)

    add_executable(sixel_tests tests/sixel_tests.cpp)
    target_link_libraries(sixel_tests PRIVATE rmt_sixel)
    add_test(NAME sixel_decoder COMMAND sixel_tests)

    add_executable(stream_tests tests/stream_tests.cpp)
    target_link_libraries(stream_tests PRIVATE rmt_stream)
    add_test(NAME terminal_stream COMMAND stream_tests)

    add_executable(pty_tests tests/pty_tests.cpp)
    target_link_libraries(pty_tests PRIVATE rmt_pty)
    add_test(NAME shell_pty COMMAND pty_tests)
    if(INKLINE_BUILD_APP)
        if(NOT CMAKE_CROSSCOMPILING)
            find_package(Python3 COMPONENTS Interpreter REQUIRED)
            add_test(NAME program_control_socket COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/control_socket_tests.py" "$<TARGET_FILE:inkline>")
            add_test(NAME hotkey_boot_installation COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/hotkey_service_tests.py")
            add_test(NAME app_release_cleanup COMMAND "${Python3_EXECUTABLE}" -B "${CMAKE_CURRENT_SOURCE_DIR}/tests/cleanup_app_tests.py")
            add_test(NAME usb_keyboard_encoding COMMAND "${Python3_EXECUTABLE}" -B "${CMAKE_CURRENT_SOURCE_DIR}/tests/usb_keyboard_tests.py")
            add_test(NAME usb_mode_switches COMMAND "${Python3_EXECUTABLE}" -B "${CMAKE_CURRENT_SOURCE_DIR}/tests/usb_mode_tests.py")
            add_test(NAME usb_tablet_reports COMMAND "${Python3_EXECUTABLE}" -B "${CMAKE_CURRENT_SOURCE_DIR}/tests/usb_tablet_tests.py")
            add_test(NAME touch_icon_installation COMMAND "${Python3_EXECUTABLE}" -B "${CMAKE_CURRENT_SOURCE_DIR}/tests/icon_tests.py")
        endif()
        add_executable(ui_tests tests/ui_tests.cpp)
        target_link_libraries(ui_tests PRIVATE rmt_ui)
        add_test(NAME renderer_keyboard COMMAND ui_tests)
        set_tests_properties(renderer_keyboard PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(image_store_tests tests/image_store_tests.cpp)
        target_link_libraries(image_store_tests PRIVATE rmt_images)
        add_test(NAME djvu_image_store COMMAND image_store_tests)
        set_tests_properties(djvu_image_store PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
        add_executable(input_tests tests/input_tests.cpp)
        target_link_libraries(input_tests PRIVATE rmt_ui)
        add_test(NAME keyboard_shortcuts COMMAND input_tests)
        set_tests_properties(keyboard_shortcuts PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(receive_input_tests tests/receive_input_tests.cpp)
        target_link_libraries(receive_input_tests PRIVATE rmt_ui)
        add_test(NAME receive_input COMMAND receive_input_tests)
        set_tests_properties(receive_input PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(battery_tests tests/battery_tests.cpp)
        target_link_libraries(battery_tests PRIVATE rmt_battery)
        add_test(NAME battery_status COMMAND battery_tests)
        add_executable(wifi_tests tests/wifi_tests.cpp)
        target_link_libraries(wifi_tests PRIVATE rmt_wifi)
        target_compile_options(wifi_tests PRIVATE -Wall -Wextra -Werror)
        add_test(NAME wifi_control COMMAND wifi_tests)
        add_executable(wifi_settings_tests tests/wifi_settings_tests.cpp)
        target_link_libraries(wifi_settings_tests PRIVATE rmt_ui)
        target_compile_options(wifi_settings_tests PRIVATE -Wall -Wextra -Werror)
        add_test(NAME wifi_settings_ui COMMAND wifi_settings_tests)
        set_tests_properties(wifi_settings_ui PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(view_tests tests/view_tests.cpp)
        target_link_libraries(view_tests PRIVATE rmt_ui)
        add_test(NAME terminal_sessions COMMAND view_tests)
        set_tests_properties(terminal_sessions PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(documents_tests tests/documents_tests.cpp)
        target_link_libraries(documents_tests PRIVATE rmt_ui)
        add_test(NAME document_library COMMAND documents_tests)
        set_tests_properties(document_library PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(legal_notices_tests tests/legal_notices_tests.cpp)
        target_link_libraries(legal_notices_tests PRIVATE rmt_ui)
        add_test(NAME offline_license_notices COMMAND legal_notices_tests)
        set_tests_properties(offline_license_notices PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(typewriter_pointer_tests tests/typewriter_pointer_tests.cpp)
        target_link_libraries(typewriter_pointer_tests PRIVATE rmt_ui)
        set_target_properties(typewriter_pointer_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/typewriter-pointer-tests")
        file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/typewriter-pointer-tests")
        file(CREATE_LINK "${CMAKE_CURRENT_BINARY_DIR}/assets" "${CMAKE_CURRENT_BINARY_DIR}/typewriter-pointer-tests/assets" SYMBOLIC)
        add_test(NAME typewriter_pointer_routing COMMAND typewriter_pointer_tests)
        set_tests_properties(typewriter_pointer_routing PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(usb_tools_tests tests/usb_tools_tests.cpp)
        target_link_libraries(usb_tools_tests PRIVATE rmt_ui)
        add_test(NAME usb_typewriter_ui COMMAND usb_tools_tests)
        set_tests_properties(usb_typewriter_ui PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(clipboard_tests tests/clipboard_tests.cpp)
        target_link_libraries(clipboard_tests PRIVATE rmt_ui)
        add_test(NAME clipboard_selection COMMAND clipboard_tests)
        set_tests_properties(clipboard_selection PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen;QT_QUICK_BACKEND=software")
        add_executable(input_method_tests tests/input_method_tests.cpp)
        target_link_libraries(input_method_tests PRIVATE rmt_ui)
        add_test(NAME input_methods COMMAND input_method_tests)
        if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
            add_executable(hotkey_probe tests/hotkey_probe.cpp)
            add_executable(hotkey_daemon_tests tests/hotkey_daemon_tests.cpp)
            target_link_libraries(hotkey_daemon_tests PRIVATE rmt_hotkeys)
            target_compile_options(hotkey_daemon_tests PRIVATE -Wall -Wextra -Werror)
            add_test(NAME global_shortcut_evdev COMMAND hotkey_daemon_tests)
        endif()
    endif()
endif()
