├── .gitignore
├── CMakeLists.txt
├── LICENSE.txt
├── README.md
├── cmake
├── build_icons.cmake
├── cmake_uninstall.cmake.in
├── compile_po.cmake
├── dist.cmake
├── dist_unix_bundle.cmake
├── dist_unix_bundle_script.cmake.in
├── dist_windows_iss.cmake
├── fixup_gnu_install_dirs.cmake
├── gen_desktop_entry.cmake
├── gen_manual.cmake
├── get_linguas.cmake
├── install.cmake
├── install_unix.cmake
├── install_unix_hicolor_icons.cmake.in
├── install_windows.cmake
├── install_windows_dlls.cmake.in
├── install_windows_msys2.cmake
├── install_windows_msys2_copy_dlls.cmake.in
├── line_endings_conversion.cmake
├── qt_utils.cmake
├── tesseract_utils.cmake
├── uninstall.cmake
└── uninstall_unix.cmake
├── data
├── dpscreenocr.desktop
├── icons
│ ├── dpscreenocr.ico
│ ├── icon-tool.py
│ ├── logo-design.svg
│ └── sizes
│ │ ├── 16
│ │ ├── dpscreenocr-busy.png
│ │ ├── dpscreenocr-busy.svg
│ │ ├── dpscreenocr-error.png
│ │ ├── dpscreenocr-error.svg
│ │ ├── dpscreenocr.png
│ │ └── dpscreenocr.svg
│ │ ├── 24
│ │ ├── dpscreenocr-busy.png
│ │ ├── dpscreenocr-error.png
│ │ └── dpscreenocr.png
│ │ ├── 32
│ │ ├── dpscreenocr-busy.png
│ │ ├── dpscreenocr-error.png
│ │ └── dpscreenocr.png
│ │ ├── 48
│ │ ├── dpscreenocr-busy.png
│ │ ├── dpscreenocr-error.png
│ │ └── dpscreenocr.png
│ │ ├── 64
│ │ ├── dpscreenocr-busy.png
│ │ ├── dpscreenocr-error.png
│ │ └── dpscreenocr.png
│ │ ├── 128
│ │ ├── dpscreenocr-busy.png
│ │ ├── dpscreenocr-error.png
│ │ └── dpscreenocr.png
│ │ └── scalable
│ │ ├── dpscreenocr-busy.svg
│ │ ├── dpscreenocr-error.svg
│ │ └── dpscreenocr.svg
└── sounds
│ └── done.wav
├── dist
└── windows
│ └── iss
│ ├── inno_setup.iss
│ ├── inno_setup_config.isi.in
│ ├── wizard.bmp
│ └── wizard_small.bmp
├── doc
├── building-unix.txt
├── building-windows-msys2.txt
├── changelog.txt
├── code-notes.txt
├── manual-data
│ ├── manual.css
│ ├── split.svg
│ └── template.html
├── manual-metadata.yaml.in
├── manual.md
└── translation-guide.txt
├── po
├── LINGUAS
├── POTFILES.in
├── bg.po
├── ca.po
├── de.po
├── es.po
├── fr.po
├── hr.po
├── nb_NO.po
├── pa_PK.po
├── pl.po
├── pt_BR.po
├── ru.po
├── tr.po
├── uk.po
├── update-po.py
└── zh_CN.po
├── src
├── dpso_example
│ ├── CMakeLists.txt
│ └── main.c
├── dpso_ext
│ ├── CMakeLists.txt
│ ├── cfg.cpp
│ ├── cfg.h
│ ├── cfg_ext.cpp
│ ├── cfg_ext.h
│ ├── dpso_ext.h
│ ├── history.cpp
│ ├── history.h
│ ├── history_export.cpp
│ ├── history_export.h
│ ├── user_dirs.h
│ ├── user_dirs_unix_xdg.cpp
│ └── user_dirs_windows.cpp
├── dpso_img
│ ├── CMakeLists.txt
│ ├── dpso_img.h
│ ├── img.cpp
│ ├── img.h
│ ├── ops.cpp
│ ├── ops.h
│ ├── ops_utils.h
│ ├── pnm.cpp
│ ├── pnm.h
│ ├── px_format.cpp
│ └── px_format.h
├── dpso_intl
│ ├── CMakeLists.txt
│ ├── bindtextdomain_utf8.cpp
│ ├── bindtextdomain_utf8.h
│ ├── dpso_intl.h
│ ├── helpers.cpp
│ └── helpers.h
├── dpso_json
│ ├── CMakeLists.txt
│ ├── json.cpp
│ └── json.h
├── dpso_net
│ ├── CMakeLists.txt
│ ├── download_file.cpp
│ ├── download_file.h
│ ├── error.h
│ ├── get_data.cpp
│ ├── get_data.h
│ ├── request.h
│ ├── request_curl.cpp
│ ├── request_curl_lib.cpp
│ ├── request_curl_lib.h
│ ├── request_curl_lib_utils.h
│ └── request_windows.cpp
├── dpso_ocr
│ ├── CMakeLists.txt
│ ├── data_lock.cpp
│ ├── data_lock.h
│ ├── dpso_ocr.h
│ ├── engine.cpp
│ ├── engine.h
│ ├── engine
│ │ ├── engine.cpp
│ │ ├── engine.h
│ │ ├── error.h
│ │ ├── lang_code_validator.cpp
│ │ ├── lang_code_validator.h
│ │ ├── lang_manager.h
│ │ ├── lang_manager_error.h
│ │ ├── recognizer.h
│ │ ├── recognizer_error.h
│ │ ├── remote_files_lang_manager.cpp
│ │ ├── remote_files_lang_manager.h
│ │ └── tesseract
│ │ │ ├── engine.cpp
│ │ │ ├── engine.h
│ │ │ ├── lang_manager.cpp
│ │ │ ├── lang_manager.h
│ │ │ ├── lang_manager_null.cpp
│ │ │ ├── lang_names.cpp
│ │ │ ├── lang_names.h
│ │ │ ├── lang_utils.cpp
│ │ │ ├── lang_utils.h
│ │ │ ├── recognizer.cpp
│ │ │ ├── recognizer.h
│ │ │ ├── utils.cpp
│ │ │ └── utils.h
│ ├── lang_manager.cpp
│ ├── lang_manager.h
│ ├── ocr.cpp
│ └── ocr.h
├── dpso_sound
│ ├── CMakeLists.txt
│ ├── error.h
│ ├── format_info.h
│ ├── sound.h
│ ├── sound_null.cpp
│ ├── sound_windows.cpp
│ └── unix
│ │ ├── audio_data.h
│ │ ├── lib
│ │ ├── pulse.cpp
│ │ ├── pulse.h
│ │ ├── sndfile.cpp
│ │ └── sndfile.h
│ │ ├── sndfile.cpp
│ │ ├── sndfile.h
│ │ └── sound_pulse.cpp
├── dpso_sys
│ ├── CMakeLists.txt
│ ├── backend
│ │ ├── backend.h
│ │ ├── backend_error.h
│ │ ├── key_manager.h
│ │ ├── screenshot_error.h
│ │ ├── selection.h
│ │ ├── unix
│ │ │ ├── backend.cpp
│ │ │ └── x11
│ │ │ │ ├── backend.cpp
│ │ │ │ ├── backend.h
│ │ │ │ ├── backend_component.h
│ │ │ │ ├── key_manager.cpp
│ │ │ │ ├── key_manager.h
│ │ │ │ ├── screenshot.cpp
│ │ │ │ ├── screenshot.h
│ │ │ │ ├── selection.cpp
│ │ │ │ ├── selection.h
│ │ │ │ └── utils.h
│ │ └── windows
│ │ │ ├── backend.cpp
│ │ │ ├── execution_layer
│ │ │ ├── action_executor.cpp
│ │ │ ├── action_executor.h
│ │ │ ├── backend_executor.cpp
│ │ │ ├── backend_executor.h
│ │ │ ├── key_manager_executor.cpp
│ │ │ ├── key_manager_executor.h
│ │ │ ├── selection_executor.cpp
│ │ │ └── selection_executor.h
│ │ │ ├── key_manager.cpp
│ │ │ ├── key_manager.h
│ │ │ ├── screenshot.cpp
│ │ │ ├── screenshot.h
│ │ │ ├── selection.cpp
│ │ │ └── selection.h
│ ├── dpso_sys.cpp
│ ├── dpso_sys.h
│ ├── dpso_sys_fwd.h
│ ├── dpso_sys_p.h
│ ├── key_manager.cpp
│ ├── key_manager.h
│ ├── keys.cpp
│ ├── keys.h
│ ├── screenshot.cpp
│ ├── screenshot.h
│ ├── selection.cpp
│ └── selection.h
├── dpso_utils
│ ├── CMakeLists.txt
│ ├── byte_order.h
│ ├── dpso_utils.h
│ ├── error.cpp
│ ├── error_get.h
│ ├── error_set.h
│ ├── geometry.cpp
│ ├── geometry.h
│ ├── geometry_c.cpp
│ ├── geometry_c.h
│ ├── line_reader.cpp
│ ├── line_reader.h
│ ├── os.h
│ ├── os_c.cpp
│ ├── os_c.h
│ ├── os_common.cpp
│ ├── os_stdio.h
│ ├── os_unix.cpp
│ ├── os_windows.cpp
│ ├── progress_tracker.cpp
│ ├── progress_tracker.h
│ ├── scope_exit.h
│ ├── sha256.cpp
│ ├── sha256.h
│ ├── sha256_file.cpp
│ ├── sha256_file.h
│ ├── str.cpp
│ ├── str.h
│ ├── str_format_core.h
│ ├── stream
│ │ ├── file_stream.cpp
│ │ ├── file_stream.h
│ │ ├── out_newline_conversion_stream.cpp
│ │ ├── out_newline_conversion_stream.h
│ │ ├── stream.h
│ │ ├── string_stream.cpp
│ │ ├── string_stream.h
│ │ ├── utils.cpp
│ │ └── utils.h
│ ├── strftime.cpp
│ ├── strftime.h
│ ├── synchronized.h
│ ├── timing.cpp
│ ├── timing.h
│ ├── unix
│ │ ├── dl.h
│ │ ├── exe_path.cpp
│ │ ├── exe_path.h
│ │ ├── path_env_search.cpp
│ │ ├── path_env_search.h
│ │ ├── xdg_dirs.cpp
│ │ └── xdg_dirs.h
│ ├── version_cmp.cpp
│ ├── version_cmp.h
│ └── windows
│ │ ├── cmdline.cpp
│ │ ├── cmdline.h
│ │ ├── com.h
│ │ ├── error.cpp
│ │ ├── error.h
│ │ ├── gdi.h
│ │ ├── handle.h
│ │ ├── module.h
│ │ ├── utf.cpp
│ │ ├── utf.h
│ │ └── window.h
├── thirdparty
│ └── stb_image_resize2
│ │ ├── CMakeLists.txt
│ │ ├── stb_image_resize2.c
│ │ └── stb_image_resize2.h
└── ui
│ ├── qt
│ ├── CMakeLists.txt
│ ├── about.cpp
│ ├── about.h
│ ├── action_chooser.cpp
│ ├── action_chooser.h
│ ├── error.h
│ ├── history.cpp
│ ├── history.h
│ ├── hotkey_editor.cpp
│ ├── hotkey_editor.h
│ ├── lang_browser.cpp
│ ├── lang_browser.h
│ ├── lang_manager
│ │ ├── install_mode.h
│ │ ├── install_progress_dialog.cpp
│ │ ├── install_progress_dialog.h
│ │ ├── lang_list.cpp
│ │ ├── lang_list.h
│ │ ├── lang_list_sort_filter_proxy.cpp
│ │ ├── lang_list_sort_filter_proxy.h
│ │ ├── lang_manager.cpp
│ │ ├── lang_manager.h
│ │ ├── lang_manager_page.cpp
│ │ ├── lang_manager_page.h
│ │ ├── lang_op_status_error.cpp
│ │ ├── lang_op_status_error.h
│ │ └── metatypes.h
│ ├── main.cpp
│ ├── main_window.cpp
│ ├── main_window.h
│ ├── status.h
│ ├── status_indicator.cpp
│ ├── status_indicator.h
│ ├── update_checker.cpp
│ ├── update_checker.h
│ ├── utils.cpp
│ └── utils.h
│ ├── ui_common
│ ├── CMakeLists.txt
│ ├── app_dirs.h
│ ├── app_dirs_unix.cpp
│ ├── app_dirs_unix_cfg.h.in
│ ├── app_dirs_windows.cpp
│ ├── app_info.cpp.in
│ ├── app_info.h
│ ├── autostart.h
│ ├── autostart_default.cpp
│ ├── autostart_default.h
│ ├── autostart_unix.cpp
│ ├── autostart_windows.cpp
│ ├── cfg_default_values.cpp
│ ├── cfg_default_values.h
│ ├── cfg_key_values.txt
│ ├── cfg_key_values_gen.py
│ ├── cfg_keys.cpp
│ ├── cfg_keys.h
│ ├── cmdline_cmd_autostart.cpp
│ ├── cmdline_cmd_autostart.h
│ ├── cmdline_opts.cpp
│ ├── cmdline_opts.h
│ ├── exe_path.h
│ ├── exe_path_unix.cpp
│ ├── exe_path_windows.cpp
│ ├── file_names.cpp.in
│ ├── file_names.h
│ ├── init.cpp
│ ├── init.h
│ ├── init_app_dirs.h
│ ├── init_extra.h
│ ├── init_extra_unix.cpp
│ ├── init_extra_windows.cpp
│ ├── init_intl.cpp
│ ├── init_intl.h
│ ├── init_startup_args.cpp
│ ├── init_startup_args.h
│ ├── init_user_data.cpp
│ ├── init_user_data.h
│ ├── ocr_default.cpp
│ ├── ocr_default.h
│ ├── ocr_default_data_dir.cpp
│ ├── ocr_default_data_dir.h
│ ├── single_instance_guard.h
│ ├── single_instance_guard_unix.cpp
│ ├── single_instance_guard_windows.cpp
│ ├── sound.cpp
│ ├── sound.h
│ ├── startup_args.h
│ ├── str_nformat.cpp
│ ├── str_nformat.h
│ ├── taskbar.h
│ ├── taskbar_config.h.in
│ ├── taskbar_null.cpp
│ ├── taskbar_windows.cpp
│ ├── toplevel_argv0.cpp
│ ├── toplevel_argv0.h
│ ├── ui_common.h
│ ├── update_checker.cpp
│ ├── update_checker.h
│ ├── update_checker_default.cpp
│ ├── update_checker_default.h
│ ├── update_checker_null.cpp
│ ├── update_checker_platform.h
│ ├── update_checker_platform_generic.cpp
│ ├── update_checker_platform_linux.cpp
│ ├── update_checker_platform_windows.cpp
│ ├── user_agent.cpp
│ └── user_agent.h
│ └── windows_rc
│ ├── CMakeLists.txt
│ ├── manifest.xml.in
│ └── resource.rc.in
├── tests
├── CMakeLists.txt
├── dpso_ext
│ ├── test_cfg.cpp
│ ├── test_history.cpp
│ └── test_history_export.cpp
├── dpso_ocr
│ └── test_tesseract_utils.cpp
├── dpso_sys
│ ├── test_keys.cpp
│ └── test_windows_action_executor.cpp
├── dpso_utils
│ ├── stream
│ │ ├── test_out_newline_conversion_stream.cpp
│ │ └── test_string_stream.cpp
│ ├── test_byte_order.cpp
│ ├── test_geometry.cpp
│ ├── test_line_reader.cpp
│ ├── test_os.cpp
│ ├── test_os_stdio.cpp
│ ├── test_progress_tracker.cpp
│ ├── test_sha256.cpp
│ ├── test_sha256_file.cpp
│ ├── test_str.cpp
│ ├── test_strftime.cpp
│ ├── test_version_cmp.cpp
│ └── windows
│ │ ├── test_cmdline.cpp
│ │ └── test_utf.cpp
├── flow.cpp
├── flow.h
├── main.cpp
├── test_c_compilation.c
├── ui
│ └── ui_common
│ │ └── test_str_nformat.cpp
├── utils.cpp
└── utils.h
└── tools
├── app_launcher_unix
├── CMakeLists.txt
├── main.c
└── readme.txt
├── docker_build_env
├── Dockerfile
├── include
│ ├── build-bundle.sh
│ └── qt-5.12.12-x11-client-leader-window.patch
└── readme.txt
├── gen_test_history.py
└── tessdata_info_gen
├── gen_c.py
├── gen_info.py
├── get_data_list.py
└── readme.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | po/dpscreenocr.pot
3 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # 3.22 is the version available in Ubuntu 22.04.
2 | cmake_minimum_required(VERSION 3.22)
3 |
4 | project(dpScreenOCR)
5 |
6 | set(DPSO_UI "qt" CACHE STRING "UI to use: qt or none")
7 | set_property(CACHE DPSO_UI PROPERTY STRINGS qt none)
8 | option(DPSO_GEN_HTML_MANUAL "Generate HTML manual using Pandoc" YES)
9 | option(DPSO_BUILD_EXAMPLE "Build example" NO)
10 | option(DPSO_BUILD_TESTS "Build tests" NO)
11 |
12 | set(APP_NAME "dpScreenOCR")
13 | set(APP_FILE_NAME "dpscreenocr")
14 |
15 | set(APP_VERSION_MAJOR "1")
16 | set(APP_VERSION_MINOR "5")
17 | set(APP_VERSION_PATCH "0")
18 | set(APP_VERSION
19 | "${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}.${APP_VERSION_PATCH}")
20 |
21 | set(APP_DESCRIPTION "Program to recognize text on screen")
22 |
23 | set(APP_AUTHOR "Daniel Plakhotich")
24 | set(APP_COPYRIGHT_YEAR "2019-2025")
25 | set(APP_URL "https://danpla.github.io/dpscreenocr/")
26 |
27 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
28 |
29 | include(fixup_gnu_install_dirs)
30 |
31 | if(DPSO_BUILD_EXAMPLE)
32 | add_subdirectory(src/dpso_example)
33 | endif()
34 |
35 | if(DPSO_UI STREQUAL "qt")
36 | add_subdirectory(src/ui/qt)
37 | elseif(NOT DPSO_UI STREQUAL "none")
38 | message(FATAL_ERROR "Unknown UI \"${DPSO_UI}\"")
39 | endif()
40 |
41 | if(DPSO_BUILD_TESTS)
42 | add_subdirectory(tests)
43 | endif()
44 |
45 | include(install)
46 | include(uninstall)
47 | include(dist)
48 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019-2025 Daniel Plakhotich
2 |
3 | This software is provided 'as-is', without any express or implied
4 | warranty. In no event will the authors be held liable for any damages
5 | arising from the use of this software.
6 |
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it
9 | freely, subject to the following restrictions:
10 |
11 | 1. The origin of this software must not be misrepresented; you must not
12 | claim that you wrote the original software. If you use this software
13 | in a product, an acknowledgement in the product documentation would be
14 | appreciated but is not required.
15 | 2. Altered source versions must be plainly marked as such, and must not be
16 | misrepresented as being the original software.
17 | 3. This notice may not be removed or altered from any source distribution.
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dpScreenOCR
2 |
3 | dpScreenOCR is a program to recognize text on the screen.
4 |
5 | https://danpla.github.io/dpscreenocr
6 |
7 |
8 | ## Docs
9 |
10 | * [Changelog](doc/changelog.txt)
11 | * [User manual](doc/manual.md)
12 | * Building instructions
13 | * [Unix-like systems](doc/building-unix.txt)
14 | * [Windows (MSYS2)](doc/building-windows-msys2.txt)
15 |
16 |
17 | ## Contributing
18 |
19 | * [Translate](https://hosted.weblate.org/engage/dpscreenocr/)
20 | the program into your language
21 | * Create a package for your system
22 |
--------------------------------------------------------------------------------
/cmake/cmake_uninstall.cmake.in:
--------------------------------------------------------------------------------
1 | # Based on:
2 | # https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake
3 |
4 | if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
5 | message(
6 | FATAL_ERROR
7 | "@CMAKE_BINARY_DIR@/install_manifest.txt does not exist")
8 | endif()
9 |
10 | file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" FILES)
11 | string(REPLACE "\n" ";" FILES "${FILES}")
12 |
13 | foreach(FILE ${FILES})
14 | set(FILE_PATH "$ENV{DESTDIR}${FILE}")
15 |
16 | if(NOT IS_SYMLINK "${FILE_PATH}" AND NOT EXISTS "${FILE_PATH}")
17 | message(STATUS "Does not exist: ${FILE_PATH}")
18 | continue()
19 | endif()
20 |
21 | message(STATUS "Uninstalling: ${FILE_PATH}")
22 |
23 | execute_process(
24 | COMMAND "@CMAKE_COMMAND@" -E rm "${FILE_PATH}"
25 | COMMAND_ERROR_IS_FATAL ANY)
26 | endforeach()
27 |
--------------------------------------------------------------------------------
/cmake/compile_po.cmake:
--------------------------------------------------------------------------------
1 | include(get_linguas)
2 |
3 | find_program(MSGFMT_EXE msgfmt REQUIRED)
4 |
5 | # The function compiles PO files for languages listed in po/LINGUAS,
6 | # writing MOs to DST_DIR.
7 | #
8 | # The full path of a MO file will be:
9 | #
10 | # DST_DIR/{LANGUAGE}/LC_MESSAGES/${MO_NAME}.mo
11 | function(compile_po DST_DIR MO_NAME)
12 | set(MO_FILES)
13 | get_linguas(LANGS)
14 | foreach(LANG ${LANGS})
15 | set(PO_FILE "${CMAKE_SOURCE_DIR}/po/${LANG}.po")
16 | set(MO_DIR "${DST_DIR}/${LANG}/LC_MESSAGES")
17 | set(MO_FILE "${MO_DIR}/${MO_NAME}.mo")
18 |
19 | add_custom_command(
20 | OUTPUT "${MO_FILE}"
21 | # msgfmt doesn't create intermediate directories.
22 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${MO_DIR}"
23 | COMMAND "${MSGFMT_EXE}" -o "${MO_FILE}" "${PO_FILE}"
24 | DEPENDS "${PO_FILE}"
25 | VERBATIM)
26 |
27 | list(APPEND MO_FILES "${MO_FILE}")
28 | endforeach()
29 |
30 | add_custom_target(mo_files ALL DEPENDS ${MO_FILES})
31 | endfunction()
32 |
--------------------------------------------------------------------------------
/cmake/dist.cmake:
--------------------------------------------------------------------------------
1 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${APP_DESCRIPTION}")
2 |
3 | set(CPACK_PACKAGE_VERSION_MAJOR "${APP_VERSION_MAJOR}")
4 | set(CPACK_PACKAGE_VERSION_MINOR "${APP_VERSION_MINOR}")
5 | set(CPACK_PACKAGE_VERSION_PATCH "${APP_VERSION_PATCH}")
6 | set(CPACK_PACKAGE_VERSION "${APP_VERSION}")
7 |
8 | set(CPACK_PACKAGE_VENDOR "${APP_AUTHOR}")
9 | set(CPACK_PACKAGE_HOMEPAGE_URL "${APP_URL}")
10 |
11 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE.txt")
12 |
13 | if(UNIX AND NOT APPLE)
14 | include(dist_unix_bundle)
15 | elseif(WIN32)
16 | include(dist_windows_iss)
17 | endif()
18 |
19 | include(CPack)
20 |
--------------------------------------------------------------------------------
/cmake/dist_unix_bundle.cmake:
--------------------------------------------------------------------------------
1 | set(BUNDLE_BUILD_SCRIPT "${CMAKE_BINARY_DIR}/build_bundle.cmake")
2 |
3 | configure_file(
4 | "${CMAKE_CURRENT_LIST_DIR}/dist_unix_bundle_script.cmake.in"
5 | "${BUNDLE_BUILD_SCRIPT}"
6 | @ONLY)
7 |
8 | string(TOLOWER "${CMAKE_SYSTEM_NAME}" OS_NAME)
9 | set(BUNDLE_DIR_NAME
10 | "${APP_NAME}-${APP_VERSION}-${OS_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
11 |
12 | set(BUNDLE_BUILD_DIR "${CMAKE_BINARY_DIR}/bundle_build")
13 | set(BUNDLE_DIR "${BUNDLE_BUILD_DIR}/${BUNDLE_DIR_NAME}")
14 |
15 | # Note that we intentionally use targets that are always out of date,
16 | # as CMake does not allow using the ALL target as a dependency.
17 |
18 | add_custom_target(
19 | bundle
20 | COMMAND
21 | "${CMAKE_COMMAND}"
22 | -D "BUNDLE_BUILD_DIR=${BUNDLE_BUILD_DIR}"
23 | -D "BUNDLE_DIR=${BUNDLE_DIR}"
24 | -P "${BUNDLE_BUILD_SCRIPT}"
25 | VERBATIM)
26 |
27 | set(BUNDLE_ARCHIVE_NAME "${BUNDLE_DIR_NAME}.tar.xz")
28 |
29 | add_custom_target(
30 | bundle_archive
31 | COMMENT "Creating ${BUNDLE_ARCHIVE_NAME}"
32 | COMMAND
33 | "${CMAKE_COMMAND}" -E
34 | tar cJ
35 | "${CMAKE_BINARY_DIR}/${BUNDLE_ARCHIVE_NAME}"
36 | "${BUNDLE_DIR_NAME}"
37 | WORKING_DIRECTORY "${BUNDLE_BUILD_DIR}"
38 | VERBATIM)
39 |
40 | add_dependencies(bundle_archive bundle)
41 |
--------------------------------------------------------------------------------
/cmake/fixup_gnu_install_dirs.cmake:
--------------------------------------------------------------------------------
1 | # By default, CMAKE_INSTALL_DOCDIR uses PROJECT_NAME, which is in
2 | # title case. We don't depend on PROJECT_NAME and use APP_FILE_NAME
3 | # instead.
4 | #
5 | # Note that we only overwrite the default CMAKE_INSTALL_DOCDIR, i.e.
6 | # when it's not set explicitly.
7 |
8 | if(UNIX AND NOT APPLE AND NOT CMAKE_INSTALL_DOCDIR)
9 | include(GNUInstallDirs)
10 | set(CMAKE_INSTALL_DOCDIR
11 | "${CMAKE_INSTALL_DATADIR}/doc/${APP_FILE_NAME}")
12 | endif()
13 |
--------------------------------------------------------------------------------
/cmake/gen_desktop_entry.cmake:
--------------------------------------------------------------------------------
1 | find_program(MSGFMT_EXE msgfmt REQUIRED)
2 |
3 | # Generates a desktop entry "${APP_FILE_NAME}.desktop" in DST_DIR.
4 | function(gen_desktop_entry DST_DIR)
5 | set(ENTRY_NAME "${APP_FILE_NAME}.desktop")
6 |
7 | set(SRC_ENTRY_PATH "${CMAKE_SOURCE_DIR}/data/${ENTRY_NAME}")
8 | set(DST_ENTRY_PATH "${DST_DIR}/${ENTRY_NAME}")
9 |
10 | add_custom_command(
11 | OUTPUT "${DST_ENTRY_PATH}"
12 | # msgfmt doesn't create intermediate directories.
13 | COMMAND "${CMAKE_COMMAND}" -E make_directory "${DST_DIR}"
14 | COMMAND
15 | "${MSGFMT_EXE}"
16 | --desktop
17 | # Disable default keywords since we only want "Comment" to
18 | # be translated. As of version 0.21, msgfmt has two bugs:
19 | # -k is not a recognized option, and --keyword without
20 | # argument doesn't work (so we use an explicit empty
21 | # string as a workaround).
22 | --keyword=
23 | --keyword=Comment
24 | "--template=${SRC_ENTRY_PATH}"
25 | -d "${CMAKE_SOURCE_DIR}/po"
26 | -o "${DST_ENTRY_PATH}"
27 | DEPENDS "${SRC_ENTRY_PATH}"
28 | VERBATIM)
29 |
30 | add_custom_target(desktop_entry ALL DEPENDS "${DST_ENTRY_PATH}")
31 | endfunction()
32 |
--------------------------------------------------------------------------------
/cmake/get_linguas.cmake:
--------------------------------------------------------------------------------
1 | # Get the list of languages from po/LINGUAS.
2 | function(get_linguas LANGUAGES)
3 | file(
4 | STRINGS "${CMAKE_SOURCE_DIR}/po/LINGUAS" LANGS
5 | REGEX "^[^#].*")
6 |
7 | set(${LANGUAGES} ${LANGS} PARENT_SCOPE)
8 | endfunction()
9 |
--------------------------------------------------------------------------------
/cmake/install.cmake:
--------------------------------------------------------------------------------
1 | if(UNIX AND NOT APPLE)
2 | include(install_unix)
3 | elseif(WIN32)
4 | include(install_windows)
5 | endif()
6 |
--------------------------------------------------------------------------------
/cmake/install_windows_dlls.cmake.in:
--------------------------------------------------------------------------------
1 | file(GLOB DLLS "@CMAKE_BINARY_DIR@/*.dll")
2 | file(INSTALL FILES ${DLLS} DESTINATION "${CMAKE_INSTALL_PREFIX}")
3 |
--------------------------------------------------------------------------------
/cmake/install_windows_msys2.cmake:
--------------------------------------------------------------------------------
1 | # Instructions specific to MSYS2/MinGW.
2 |
3 | configure_file(
4 | "${CMAKE_CURRENT_LIST_DIR}/install_windows_msys2_copy_dlls.cmake.in"
5 | "${CMAKE_BINARY_DIR}/install_windows_msys2_copy_dlls.cmake"
6 | @ONLY)
7 |
8 | add_custom_target(
9 | copy_dlls
10 | ALL
11 | COMMENT "Copying DLLs"
12 | COMMAND
13 | "${CMAKE_COMMAND}" -P
14 | "${CMAKE_BINARY_DIR}/install_windows_msys2_copy_dlls.cmake"
15 | VERBATIM)
16 |
17 | add_dependencies(copy_dlls "${APP_FILE_NAME}_${DPSO_UI}")
18 |
19 | include(tesseract_utils)
20 | get_tesseract_data_dir_name(TESSERACT_DATA_DIR_NAME)
21 | if(TESSERACT_DATA_DIR_NAME)
22 | copy_tessdata(
23 | "$ENV{MINGW_PREFIX}/share/tessdata"
24 | "${CMAKE_BINARY_DIR}/${TESSERACT_DATA_DIR_NAME}"
25 | LANGUAGES eng
26 | OPTIONAL)
27 | endif()
28 |
29 | if(DPSO_UI STREQUAL "qt")
30 | include(qt_utils)
31 |
32 | copy_qt_windows_plugins(
33 | "$ENV{MINGW_PREFIX}/share/qt${DPSO_QT_VERSION}/plugins"
34 | "${CMAKE_BINARY_DIR}/qt${DPSO_QT_VERSION}/plugins")
35 |
36 | include(get_linguas)
37 | get_linguas(LANGS)
38 |
39 | copy_qt_translations(
40 | "$ENV{MINGW_PREFIX}/share/qt${DPSO_QT_VERSION}/translations"
41 | "${CMAKE_BINARY_DIR}/qt${DPSO_QT_VERSION}/translations"
42 | LANGUAGES ${LANGS}
43 | COMPONENTS qt qtbase)
44 | endif()
45 |
--------------------------------------------------------------------------------
/cmake/install_windows_msys2_copy_dlls.cmake.in:
--------------------------------------------------------------------------------
1 | file(
2 | GET_RUNTIME_DEPENDENCIES
3 | EXECUTABLES "@CMAKE_BINARY_DIR@/@APP_FILE_NAME@.exe"
4 | DIRECTORIES "$ENV{MINGW_PREFIX}/bin"
5 | # As of version 3.23, CMake doesn't seem to handle Windows API
6 | # sets, so we filter them manually via PRE_EXCLUDE_REGEXES.
7 | # https://docs.microsoft.com/en-us/windows/win32/apiindex/windows-apisets
8 | # https://gitlab.kitware.com/cmake/cmake/-/issues/22006
9 | PRE_EXCLUDE_REGEXES "api-ms-.*" "ext-ms-.*"
10 | POST_INCLUDE_REGEXES "^$ENV{MINGW_PREFIX}/bin/.*"
11 | POST_EXCLUDE_REGEXES ".*"
12 | RESOLVED_DEPENDENCIES_VAR RESOLVED_DEPENDENCIES
13 | UNRESOLVED_DEPENDENCIES_VAR UNRESOLVED_DEPENDENCIES)
14 |
15 | if(UNRESOLVED_DEPENDENCIES)
16 | message(
17 | SEND_ERROR
18 | "Unresolved MSYS2 dependencies: ${UNRESOLVED_DEPENDENCIES}")
19 | endif()
20 |
21 | file(
22 | COPY ${RESOLVED_DEPENDENCIES}
23 | DESTINATION "@CMAKE_BINARY_DIR@")
24 |
--------------------------------------------------------------------------------
/cmake/line_endings_conversion.cmake:
--------------------------------------------------------------------------------
1 | # Convert line endings to NEWLINE_STYLE, which can be any value
2 | # accepted by the same option of file(GENERATE).
3 | function(convert_line_endings IN_FILE OUT_FILE NEWLINE_STYLE)
4 | file(
5 | GENERATE
6 | OUTPUT "${OUT_FILE}"
7 | INPUT "${IN_FILE}"
8 | NEWLINE_STYLE "${NEWLINE_STYLE}")
9 | endfunction()
10 |
--------------------------------------------------------------------------------
/cmake/uninstall.cmake:
--------------------------------------------------------------------------------
1 | if(UNIX AND NOT APPLE)
2 | include(uninstall_unix)
3 | endif()
4 |
--------------------------------------------------------------------------------
/cmake/uninstall_unix.cmake:
--------------------------------------------------------------------------------
1 | if(NOT TARGET uninstall)
2 | configure_file(
3 | "${CMAKE_CURRENT_LIST_DIR}/cmake_uninstall.cmake.in"
4 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
5 | @ONLY)
6 |
7 | add_custom_target(
8 | uninstall
9 | COMMAND
10 | "${CMAKE_COMMAND}" -P
11 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
12 | endif()
13 |
--------------------------------------------------------------------------------
/data/dpscreenocr.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Type=Application
3 | Name=dpScreenOCR
4 | Exec=dpscreenocr
5 | Icon=dpscreenocr
6 | Categories=Graphics;OCR;
7 | SingleMainWindow=true
8 | Terminal=false
9 | Comment=Program to recognize text on screen
10 |
--------------------------------------------------------------------------------
/data/icons/dpscreenocr.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/dpscreenocr.ico
--------------------------------------------------------------------------------
/data/icons/sizes/128/dpscreenocr-busy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/128/dpscreenocr-busy.png
--------------------------------------------------------------------------------
/data/icons/sizes/128/dpscreenocr-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/128/dpscreenocr-error.png
--------------------------------------------------------------------------------
/data/icons/sizes/128/dpscreenocr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/128/dpscreenocr.png
--------------------------------------------------------------------------------
/data/icons/sizes/16/dpscreenocr-busy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/16/dpscreenocr-busy.png
--------------------------------------------------------------------------------
/data/icons/sizes/16/dpscreenocr-busy.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/data/icons/sizes/16/dpscreenocr-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/16/dpscreenocr-error.png
--------------------------------------------------------------------------------
/data/icons/sizes/16/dpscreenocr-error.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/data/icons/sizes/16/dpscreenocr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/16/dpscreenocr.png
--------------------------------------------------------------------------------
/data/icons/sizes/16/dpscreenocr.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/data/icons/sizes/24/dpscreenocr-busy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/24/dpscreenocr-busy.png
--------------------------------------------------------------------------------
/data/icons/sizes/24/dpscreenocr-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/24/dpscreenocr-error.png
--------------------------------------------------------------------------------
/data/icons/sizes/24/dpscreenocr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/24/dpscreenocr.png
--------------------------------------------------------------------------------
/data/icons/sizes/32/dpscreenocr-busy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/32/dpscreenocr-busy.png
--------------------------------------------------------------------------------
/data/icons/sizes/32/dpscreenocr-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/32/dpscreenocr-error.png
--------------------------------------------------------------------------------
/data/icons/sizes/32/dpscreenocr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/32/dpscreenocr.png
--------------------------------------------------------------------------------
/data/icons/sizes/48/dpscreenocr-busy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/48/dpscreenocr-busy.png
--------------------------------------------------------------------------------
/data/icons/sizes/48/dpscreenocr-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/48/dpscreenocr-error.png
--------------------------------------------------------------------------------
/data/icons/sizes/48/dpscreenocr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/48/dpscreenocr.png
--------------------------------------------------------------------------------
/data/icons/sizes/64/dpscreenocr-busy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/64/dpscreenocr-busy.png
--------------------------------------------------------------------------------
/data/icons/sizes/64/dpscreenocr-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/64/dpscreenocr-error.png
--------------------------------------------------------------------------------
/data/icons/sizes/64/dpscreenocr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/icons/sizes/64/dpscreenocr.png
--------------------------------------------------------------------------------
/data/icons/sizes/scalable/dpscreenocr-busy.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/data/icons/sizes/scalable/dpscreenocr-error.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/data/icons/sizes/scalable/dpscreenocr.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/data/sounds/done.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/data/sounds/done.wav
--------------------------------------------------------------------------------
/dist/windows/iss/inno_setup_config.isi.in:
--------------------------------------------------------------------------------
1 | #cmakedefine APP_AUTHOR "@APP_AUTHOR@"
2 | #cmakedefine APP_COPYRIGHT_YEAR "@APP_COPYRIGHT_YEAR@"
3 | #cmakedefine APP_FILE_NAME "@APP_FILE_NAME@"
4 | #cmakedefine APP_NAME "@APP_NAME@"
5 | #cmakedefine APP_SOURCE_DIR "@APP_SOURCE_DIR@"
6 | #cmakedefine APP_TESSERACT_VERSION_MAJOR "@APP_TESSERACT_VERSION_MAJOR@"
7 | #cmakedefine APP_UI "@APP_UI@"
8 | #cmakedefine APP_URL "@APP_URL@"
9 | #cmakedefine APP_VERSION "@APP_VERSION@"
10 | #cmakedefine01 APP_IS_64_BIT
11 |
--------------------------------------------------------------------------------
/dist/windows/iss/wizard.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/dist/windows/iss/wizard.bmp
--------------------------------------------------------------------------------
/dist/windows/iss/wizard_small.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danpla/dpscreenocr/6b365f7ffdda4f17ec97459395d221222d358726/dist/windows/iss/wizard_small.bmp
--------------------------------------------------------------------------------
/doc/manual-data/manual.css:
--------------------------------------------------------------------------------
1 | body {
2 | max-width: 36em;
3 | margin: 0 auto;
4 | padding: 0 1em 0;
5 | font-family: sans-serif;
6 | line-height: 1.6;
7 | }
8 |
9 | #TOC ul {
10 | list-style-type: none;
11 | }
12 |
13 | code {
14 | font-family: monospace;
15 | background: #ddd;
16 | padding: 0.1em 0.2em;
17 | white-space: pre-wrap;
18 | }
19 |
20 | pre code {
21 | display: block;
22 | padding: 0.8em 1em;
23 | }
24 |
25 | img {
26 | max-width: 100%;
27 | }
28 |
--------------------------------------------------------------------------------
/doc/manual-data/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | $for(author-meta)$
8 |
9 | $endfor$
10 | $if(date-meta)$
11 |
12 | $endif$
13 | $if(keywords)$
14 |
15 | $endif$
16 | $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$
17 | $if(highlighting-css)$
18 |
21 | $endif$
22 | $for(css)$
23 |
24 | $endfor$
25 | $if(math)$
26 | $math$
27 | $endif$
28 | $for(header-includes)$
29 | $header-includes$
30 | $endfor$
31 |
32 |
33 | $for(include-before)$
34 | $include-before$
35 | $endfor$
36 | $if(title)$
37 |
38 | $title$
39 | $if(subtitle)$
40 | $subtitle$
41 | $endif$
42 | $for(author)$
43 | $author$
44 | $endfor$
45 | $if(date)$
46 | $date$
47 | $endif$
48 |
49 | $endif$
50 | $if(toc)$
51 |
57 | $endif$
58 | $body$
59 | $for(include-after)$
60 | $include-after$
61 | $endfor$
62 |
63 |
64 |
--------------------------------------------------------------------------------
/doc/manual-metadata.yaml.in:
--------------------------------------------------------------------------------
1 | ---
2 | lang: en
3 | title: dpScreenOCR User Manual
4 | subtitle: Version @APP_VERSION@
5 | toc-title: Table of contents
6 | ---
7 |
--------------------------------------------------------------------------------
/po/LINGUAS:
--------------------------------------------------------------------------------
1 | # Keep this file sorted alphabetically, one language code per line.
2 | bg
3 | ca
4 | de
5 | es
6 | fr
7 | hr
8 | nb_NO
9 | pa_PK
10 | pl
11 | pt_BR
12 | ru
13 | tr
14 | uk
15 | zh_CN
16 |
--------------------------------------------------------------------------------
/po/POTFILES.in:
--------------------------------------------------------------------------------
1 | src/dpso_ocr/engine/tesseract/lang_names.cpp
2 | src/ui/qt/about.cpp
3 | src/ui/qt/action_chooser.cpp
4 | src/ui/qt/history.cpp
5 | src/ui/qt/hotkey_editor.cpp
6 | src/ui/qt/lang_browser.cpp
7 | src/ui/qt/lang_manager/install_progress_dialog.cpp
8 | src/ui/qt/lang_manager/lang_list.cpp
9 | src/ui/qt/lang_manager/lang_list_sort_filter_proxy.cpp
10 | src/ui/qt/lang_manager/lang_manager.cpp
11 | src/ui/qt/lang_manager/lang_manager_page.cpp
12 | src/ui/qt/lang_manager/lang_op_status_error.cpp
13 | src/ui/qt/main.cpp
14 | src/ui/qt/main_window.cpp
15 | src/ui/qt/update_checker.cpp
16 | src/ui/qt/utils.cpp
17 |
--------------------------------------------------------------------------------
/src/dpso_example/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.22)
2 |
3 | project(dpso-example)
4 |
5 | add_executable(dpso_example main.c)
6 |
7 | set_target_properties(
8 | dpso_example PROPERTIES
9 | C_STANDARD 99
10 | C_STANDARD_REQUIRED YES
11 | C_EXTENSIONS NO
12 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
13 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
14 | OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
15 | target_compile_options(
16 | dpso_example
17 | PRIVATE -Wall -Wextra -pedantic -Wstrict-prototypes)
18 | endif()
19 |
20 | if(NOT TARGET dpso_ocr)
21 | add_subdirectory(../dpso_ocr "${CMAKE_BINARY_DIR}/src/dpso_ocr")
22 | endif()
23 |
24 | if(NOT TARGET dpso_sys)
25 | add_subdirectory(../dpso_sys "${CMAKE_BINARY_DIR}/src/dpso_sys")
26 | endif()
27 |
28 | if(NOT TARGET dpso_utils)
29 | add_subdirectory(
30 | ../dpso_utils "${CMAKE_BINARY_DIR}/src/dpso_utils")
31 | endif()
32 |
33 | target_link_libraries(dpso_example dpso_ocr dpso_sys dpso_utils)
34 |
--------------------------------------------------------------------------------
/src/dpso_ext/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.22)
2 |
3 | project(dpso_ext)
4 |
5 | add_library(
6 | dpso_ext
7 |
8 | cfg.cpp
9 | cfg_ext.cpp
10 | history.cpp
11 | history_export.cpp)
12 |
13 | if(UNIX AND NOT APPLE)
14 | target_sources(
15 | dpso_ext
16 | PRIVATE
17 | user_dirs_unix_xdg.cpp)
18 | elseif(WIN32)
19 | target_sources(
20 | dpso_ext
21 | PRIVATE
22 | user_dirs_windows.cpp)
23 | else()
24 | message(FATAL_ERROR "${CMAKE_SYSTEM_NAME} is not supported")
25 | endif()
26 |
27 | set_target_properties(
28 | dpso_ext PROPERTIES
29 | CXX_STANDARD 17
30 | CXX_STANDARD_REQUIRED YES
31 | CXX_EXTENSIONS NO
32 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
33 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
34 | OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
35 | target_compile_options(dpso_ext PRIVATE -Wall -Wextra -pedantic)
36 | endif()
37 |
38 | target_include_directories(dpso_ext PRIVATE . PUBLIC ..)
39 |
40 | if(NOT TARGET dpso_ocr)
41 | add_subdirectory(../dpso_ocr "${CMAKE_BINARY_DIR}/src/dpso_ocr")
42 | endif()
43 |
44 | if(NOT TARGET dpso_sys)
45 | add_subdirectory(../dpso_sys "${CMAKE_BINARY_DIR}/src/dpso_sys")
46 | endif()
47 |
48 | if(NOT TARGET dpso_utils)
49 | add_subdirectory(
50 | ../dpso_utils "${CMAKE_BINARY_DIR}/src/dpso_utils")
51 | endif()
52 |
53 | target_link_libraries(
54 | dpso_ext PUBLIC dpso_ocr dpso_sys PRIVATE dpso_utils)
55 |
--------------------------------------------------------------------------------
/src/dpso_ext/dpso_ext.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "cfg.h"
4 | #include "cfg_ext.h"
5 | #include "history.h"
6 | #include "history_export.h"
7 | #include "user_dirs.h"
8 |
--------------------------------------------------------------------------------
/src/dpso_ext/user_dirs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 |
9 | typedef enum {
10 | DpsoUserDirConfig,
11 | DpsoUserDirData
12 | } DpsoUserDir;
13 |
14 |
15 | /**
16 | * Get a path to a user directory.
17 | *
18 | * appName becomes a subdirectory of the path. On failure, and sets an
19 | * error message (dpsoGetError()) and returns null.
20 | */
21 | const char* dpsoGetUserDir(DpsoUserDir userDir, const char* appName);
22 |
23 |
24 | #ifdef __cplusplus
25 | }
26 | #endif
27 |
--------------------------------------------------------------------------------
/src/dpso_ext/user_dirs_unix_xdg.cpp:
--------------------------------------------------------------------------------
1 | #include "user_dirs.h"
2 |
3 | #include
4 | #include
5 |
6 | #include "dpso_utils/error_set.h"
7 | #include "dpso_utils/os.h"
8 | #include "dpso_utils/unix/xdg_dirs.h"
9 |
10 |
11 | using namespace dpso;
12 |
13 |
14 | static unix::XdgDir getXdgDir(DpsoUserDir userDir)
15 | {
16 | switch (userDir) {
17 | case DpsoUserDirConfig:
18 | return unix::XdgDir::configHome;
19 | case DpsoUserDirData:
20 | return unix::XdgDir::dataHome;
21 | }
22 |
23 | assert(false);
24 | return {};
25 | }
26 |
27 |
28 | const char* dpsoGetUserDir(DpsoUserDir userDir, const char* appName)
29 | {
30 | static std::string path;
31 |
32 | const auto xdgDir = getXdgDir(userDir);
33 |
34 | try {
35 | path = unix::getXdgDirPath(xdgDir);
36 | } catch (os::Error& e) {
37 | setError("unix::getXdgDirPath({}): {}", xdgDir, e.what());
38 | return {};
39 | }
40 |
41 | path += '/';
42 | path += appName;
43 |
44 | return path.c_str();
45 | }
46 |
--------------------------------------------------------------------------------
/src/dpso_ext/user_dirs_windows.cpp:
--------------------------------------------------------------------------------
1 | #include "user_dirs.h"
2 |
3 | #include
4 |
5 | #include
6 | #define WIN32_LEAN_AND_MEAN
7 | #include
8 |
9 | #include "dpso_utils/error_set.h"
10 | #include "dpso_utils/scope_exit.h"
11 | #include "dpso_utils/windows/error.h"
12 | #include "dpso_utils/windows/utf.h"
13 |
14 |
15 | using namespace dpso;
16 |
17 |
18 | const char* dpsoGetUserDir(DpsoUserDir userDir, const char* appName)
19 | {
20 | // FOLDERID_RoamingAppData is actually better path for config, but
21 | // we keep using FOLDERID_LocalAppData for backward compatibility.
22 | (void)userDir;
23 |
24 | wchar_t* appDataPathUtf16{};
25 | // Docs say that we should call CoTaskMemFree() even if
26 | // SHGetKnownFolderPath() fails.
27 | const ScopeExit taskMemFree{
28 | [&]{ CoTaskMemFree(appDataPathUtf16); }};
29 |
30 | const auto hresult = SHGetKnownFolderPath(
31 | FOLDERID_LocalAppData,
32 | KF_FLAG_DONT_VERIFY,
33 | nullptr,
34 | &appDataPathUtf16);
35 | if (FAILED(hresult)) {
36 | setError(
37 | "SHGetKnownFolderPath(FOLDERID_LocalAppData, ...): {}",
38 | windows::getHresultMessage(hresult));
39 | return {};
40 | }
41 |
42 | static std::string path;
43 | try {
44 | path = windows::utf16ToUtf8(appDataPathUtf16);
45 | } catch (windows::CharConversionError& e) {
46 | setError("Can't convert path to UTF-8: {}", e.what());
47 | return {};
48 | }
49 |
50 | path += '\\';
51 | path += appName;
52 |
53 | return path.c_str();
54 | }
55 |
--------------------------------------------------------------------------------
/src/dpso_img/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.22)
2 |
3 | project(dpso_img)
4 |
5 | add_library(dpso_img img.cpp ops.cpp pnm.cpp px_format.cpp)
6 |
7 | set_target_properties(
8 | dpso_img PROPERTIES
9 | CXX_STANDARD 17
10 | CXX_STANDARD_REQUIRED YES
11 | CXX_EXTENSIONS NO
12 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
13 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
14 | OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
15 | target_compile_options(dpso_img PRIVATE -Wall -Wextra -pedantic)
16 | endif()
17 |
18 | target_include_directories(dpso_img PRIVATE . PUBLIC ..)
19 |
20 | if(NOT TARGET dpso_utils)
21 | add_subdirectory(
22 | ../dpso_utils "${CMAKE_BINARY_DIR}/src/dpso_utils")
23 | endif()
24 |
25 | if(NOT TARGET stb_image_resize2)
26 | add_subdirectory(
27 | ../thirdparty/stb_image_resize2
28 | "${CMAKE_BINARY_DIR}/src/thirdparty/stb_image_resize2")
29 | endif()
30 |
31 | target_link_libraries(dpso_img PRIVATE dpso_utils stb_image_resize2)
32 |
--------------------------------------------------------------------------------
/src/dpso_img/dpso_img.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "img.h"
4 |
--------------------------------------------------------------------------------
/src/dpso_img/img.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "px_format.h"
6 |
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 |
13 | typedef struct DpsoImg DpsoImg;
14 |
15 |
16 | /**
17 | * Create a new image.
18 | *
19 | * The pitch is the byte size of the image row, which should be at
20 | * least w * dpsoPxFormatGetBytesPerPx(pxFormat). You can use 0 to
21 | * automatically calculate and use the minimal pitch.
22 | *
23 | * On failure, sets an error message (dpsoGetError()) and returns
24 | * null.
25 | */
26 | DpsoImg* dpsoImgCreate(
27 | DpsoPxFormat pxFormat, int w, int h, int pitch);
28 |
29 |
30 | void dpsoImgDelete(DpsoImg* img);
31 |
32 |
33 | DpsoPxFormat dpsoImgGetPxFormat(const DpsoImg* img);
34 | int dpsoImgGetWidth(const DpsoImg* img);
35 | int dpsoImgGetHeight(const DpsoImg* img);
36 | int dpsoImgGetPitch(const DpsoImg* img);
37 |
38 | const uint8_t* dpsoImgGetConstData(const DpsoImg* img);
39 | uint8_t* dpsoImgGetData(DpsoImg* img);
40 |
41 |
42 | #ifdef __cplusplus
43 | }
44 |
45 |
46 | #include
47 |
48 |
49 | namespace dpso::img {
50 |
51 |
52 | struct ImgDeleter {
53 | void operator()(DpsoImg* img) const
54 | {
55 | dpsoImgDelete(img);
56 | }
57 | };
58 |
59 |
60 | using ImgUPtr = std::unique_ptr;
61 |
62 |
63 | }
64 |
65 |
66 | #endif
67 |
--------------------------------------------------------------------------------
/src/dpso_img/ops.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "px_format.h"
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | class ProgressTracker;
12 |
13 |
14 | namespace img {
15 |
16 |
17 | template
18 | T getMaskRightShift(T mask)
19 | {
20 | if (mask == 0)
21 | return 0;
22 |
23 | T shift{};
24 | for (; !(mask & 1); mask >>= 1)
25 | ++shift;
26 |
27 | return shift;
28 | }
29 |
30 |
31 | void toGray(
32 | const std::uint8_t* src, int srcPitch, DpsoPxFormat srcPxFormat,
33 | std::uint8_t* dst, int dstPitch,
34 | int w, int h);
35 |
36 |
37 | void resize(
38 | const std::uint8_t* src, int srcW, int srcH, int srcPitch,
39 | std::uint8_t* dst, int dstW, int dstH, int dstPitch);
40 |
41 |
42 | void unsharpMask(
43 | const std::uint8_t* src, int srcPitch,
44 | std::uint8_t* dst, int dstPitch,
45 | std::uint8_t* tmp, int tmpPitch,
46 | int w, int h,
47 | int radius,
48 | float amount,
49 | ProgressTracker* progressTracker = nullptr);
50 |
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/dpso_img/ops_utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace dpso::img {
5 |
6 |
7 | enum class Axis {
8 | x,
9 | y
10 | };
11 |
12 |
13 | constexpr Axis getOpposite(Axis axis)
14 | {
15 | return axis == Axis::x ? Axis::y : Axis::x;
16 | }
17 |
18 |
19 | template
20 | int getSize(int w, int h)
21 | {
22 | return axis == Axis::x ? w : h;
23 | }
24 |
25 |
26 | template
27 | class Line {
28 | public:
29 | Line(int idx, Px* data, int pitch)
30 | : line{data + (axis == Axis::x ? idx * pitch : idx)}
31 | , pitch{pitch}
32 | {
33 | }
34 |
35 | Px& operator[](int px) const
36 | {
37 | return line[axis == Axis::x ? px : px * pitch];
38 | }
39 | private:
40 | Px* line;
41 | int pitch;
42 | };
43 |
44 |
45 | template
46 | auto makeLine(int idx, Px* data, int pitch)
47 | {
48 | return Line{idx, data, pitch};
49 | }
50 |
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/dpso_img/pnm.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "px_format.h"
6 |
7 |
8 | namespace dpso::img {
9 |
10 |
11 | const char* getPnmExt(DpsoPxFormat pxFormat);
12 |
13 |
14 | void savePnm(
15 | const char* filePath,
16 | DpsoPxFormat pxFormat,
17 | const std::uint8_t* data,
18 | int w,
19 | int h,
20 | int pitch);
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/dpso_img/px_format.cpp:
--------------------------------------------------------------------------------
1 | #include "px_format.h"
2 |
3 |
4 | const char* dpsoPxFormatToStr(DpsoPxFormat pxFormat)
5 | {
6 | switch (pxFormat) {
7 | case DpsoPxFormatGrayscale:
8 | return "Grayscale";
9 | case DpsoPxFormatRgb:
10 | return "RGB";
11 | case DpsoPxFormatBgr:
12 | return "BGR";
13 | case DpsoPxFormatRgba:
14 | return "RGBA";
15 | case DpsoPxFormatBgra:
16 | return "BGRA";
17 | case DpsoPxFormatArgb:
18 | return "ARGB";
19 | case DpsoPxFormatAbgr:
20 | return "ABGR";
21 | }
22 |
23 | return "";
24 | }
25 |
26 |
27 | int dpsoPxFormatGetBytesPerPx(DpsoPxFormat pxFormat)
28 | {
29 | switch (pxFormat) {
30 | case DpsoPxFormatGrayscale:
31 | return 1;
32 | case DpsoPxFormatRgb:
33 | case DpsoPxFormatBgr:
34 | return 3;
35 | case DpsoPxFormatRgba:
36 | case DpsoPxFormatBgra:
37 | case DpsoPxFormatArgb:
38 | case DpsoPxFormatAbgr:
39 | return 4;
40 | }
41 |
42 | return {};
43 | }
44 |
--------------------------------------------------------------------------------
/src/dpso_img/px_format.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 |
9 | typedef enum {
10 | DpsoPxFormatGrayscale,
11 | DpsoPxFormatRgb,
12 | DpsoPxFormatBgr,
13 | DpsoPxFormatRgba,
14 | DpsoPxFormatBgra,
15 | DpsoPxFormatArgb,
16 | DpsoPxFormatAbgr,
17 | } DpsoPxFormat;
18 |
19 |
20 | const char* dpsoPxFormatToStr(DpsoPxFormat pxFormat);
21 |
22 |
23 | int dpsoPxFormatGetBytesPerPx(DpsoPxFormat pxFormat);
24 |
25 |
26 | #ifdef __cplusplus
27 | }
28 | #endif
29 |
--------------------------------------------------------------------------------
/src/dpso_intl/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.22)
2 |
3 | project(dpso_intl)
4 |
5 | add_library(
6 | dpso_intl STATIC
7 |
8 | bindtextdomain_utf8.cpp
9 | helpers.cpp)
10 |
11 | set_target_properties(
12 | dpso_intl PROPERTIES
13 | CXX_STANDARD 11
14 | CXX_STANDARD_REQUIRED YES
15 | CXX_EXTENSIONS NO)
16 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
17 | OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
18 | target_compile_options(dpso_intl PRIVATE -Wall -Wextra -pedantic)
19 | endif()
20 |
21 | target_include_directories(dpso_intl PRIVATE . PUBLIC ..)
22 |
23 | if(WIN32)
24 | # We need at least 0.21 for wbindtextdomain()
25 | find_package(Intl 0.21.0 REQUIRED)
26 | else()
27 | find_package(Intl REQUIRED)
28 | endif()
29 |
30 | target_include_directories(dpso_intl PUBLIC ${Intl_INCLUDE_DIRS})
31 | target_link_libraries(dpso_intl PUBLIC ${Intl_LIBRARIES})
32 |
--------------------------------------------------------------------------------
/src/dpso_intl/bindtextdomain_utf8.cpp:
--------------------------------------------------------------------------------
1 | #include "bindtextdomain_utf8.h"
2 |
3 | #include
4 |
5 |
6 | #ifdef _WIN32
7 |
8 | #include
9 |
10 | #define WIN32_LEAN_AND_MEAN
11 | #include
12 |
13 |
14 | static std::wstring utf8ToUtf16(const char* utf8Str)
15 | {
16 | const auto sizeWithNull = MultiByteToWideChar(
17 | CP_UTF8, MB_ERR_INVALID_CHARS, utf8Str, -1, nullptr, 0);
18 | if (sizeWithNull <= 0)
19 | return {};
20 |
21 | std::wstring result(sizeWithNull - 1, 0);
22 |
23 | if (!MultiByteToWideChar(
24 | CP_UTF8, MB_ERR_INVALID_CHARS, utf8Str, -1,
25 | &result[0], sizeWithNull))
26 | return {};
27 |
28 | return result;
29 | }
30 |
31 |
32 | void bindtextdomainUtf8(const char* domainName, const char* dirName)
33 | {
34 | // dirName can be null to return the previously set directory. Our
35 | // UTF-8 wrapper returns nothing, so skip this case.
36 | if (!dirName)
37 | return;
38 |
39 | wbindtextdomain(domainName, utf8ToUtf16(dirName).c_str());
40 | }
41 |
42 |
43 | #else // _WIN32
44 |
45 |
46 | void bindtextdomainUtf8(const char* domainName, const char* dirName)
47 | {
48 | bindtextdomain(domainName, dirName);
49 | }
50 |
51 |
52 | #endif // !_WIN32
53 |
--------------------------------------------------------------------------------
/src/dpso_intl/bindtextdomain_utf8.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 |
9 | /**
10 | * bindtextdomain() that accepts dirName in UTF-8.
11 | *
12 | * This function is a wrapper that calls wbindtextdomain() on Windows
13 | * (requires libintl >= 0.21.0) and normal bindtextdomain() on other
14 | * platforms. It's mainly intended to support Windows older than 10;
15 | * since Windows 10 version 1903, the application manifest
16 | * () is a more robust and non-intrusive way to enable
17 | * Unicode support in all third-party libraries.
18 | *
19 | * The (w)bindtextdomain() documentation says that the returned string
20 | * is only invalidated if the function is called with the same domain
21 | * name. Emulating this behavior in our UTF-8 wrapper on Windows would
22 | * require maintaining a mapping of results from UTF-16 to UTF-8. This
23 | * complication is probably not worth the trouble, so the function
24 | * returns nothing.
25 | */
26 | void bindtextdomainUtf8(const char* domainName, const char* dirName);
27 |
28 |
29 | #ifdef __cplusplus
30 | }
31 | #endif
32 |
--------------------------------------------------------------------------------
/src/dpso_intl/dpso_intl.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "bindtextdomain_utf8.h"
6 | #include "helpers.h"
7 |
--------------------------------------------------------------------------------
/src/dpso_intl/helpers.cpp:
--------------------------------------------------------------------------------
1 | #include "helpers.h"
2 |
3 | #include
4 |
5 | #include
6 |
7 |
8 | static std::string getMsgCtxId(const char* msgCtx, const char* msgId)
9 | {
10 | return std::string{msgCtx} + '\004' + msgId;
11 | }
12 |
13 |
14 | const char* pgettext_aux(const char* msgCtxId, const char* msgId)
15 | {
16 | const auto* translated = gettext(msgCtxId);
17 | return translated == msgCtxId ? msgId : translated;
18 | }
19 |
20 |
21 | const char* pgettext_expr(const char* msgCtx, const char* msgId)
22 | {
23 | return pgettext_aux(getMsgCtxId(msgCtx, msgId).c_str(), msgId);
24 | }
25 |
26 |
27 | const char* npgettext_aux(
28 | const char* msgCtxId, const char* msgId1, const char* msgId2,
29 | unsigned long n)
30 | {
31 | const auto* translated = ngettext(msgCtxId, msgId2, n);
32 | if (translated == msgCtxId || translated == msgId2)
33 | return n == 1 ? msgId1 : msgId2;
34 |
35 | return translated;
36 | }
37 |
38 |
39 | const char* npgettext_expr(
40 | const char* msgCtx, const char* msgId1, const char* msgId2,
41 | unsigned long n)
42 | {
43 | return npgettext_aux(
44 | getMsgCtxId(msgCtx, msgId1).c_str(), msgId1, msgId2, n);
45 | }
46 |
--------------------------------------------------------------------------------
/src/dpso_intl/helpers.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * Helpers for libintl.
4 | *
5 | * This file provides implementations of functions from gettext.h,
6 | * but only those we actually use.
7 | */
8 |
9 | #pragma once
10 |
11 |
12 | #ifdef __cplusplus
13 | extern "C" {
14 | #endif
15 |
16 |
17 | #define pgettext(msgCtx, msgId) \
18 | pgettext_aux(msgCtx "\004" msgId, msgId)
19 |
20 |
21 | const char* pgettext_aux(const char* msgCtxId, const char* msgId);
22 |
23 |
24 | const char* pgettext_expr(const char* msgCtx, const char* msgId);
25 |
26 |
27 | #define npgettext(msgCtx, msgId1, msgId2, N) \
28 | npgettext_aux(msgCtx "\004" msgId1, msgId1, msgId2, N)
29 |
30 |
31 | const char* npgettext_aux(
32 | const char* msgCtxId, const char* msgId1, const char* msgId2,
33 | unsigned long n);
34 |
35 |
36 | const char* npgettext_expr(
37 | const char* msgCtx, const char* msgId1, const char* msgId2,
38 | unsigned long n);
39 |
40 |
41 | #ifdef __cplusplus
42 | }
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/dpso_json/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.22)
2 |
3 | project(dpso_json)
4 |
5 | add_library(dpso_json json.cpp)
6 |
7 | set_target_properties(
8 | dpso_json PROPERTIES
9 | CXX_STANDARD 17
10 | CXX_STANDARD_REQUIRED YES
11 | CXX_EXTENSIONS NO
12 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
13 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
14 | OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
15 | target_compile_options(dpso_json PRIVATE -Wall -Wextra -pedantic)
16 | endif()
17 |
18 | find_package(PkgConfig REQUIRED)
19 |
20 | # json_string_length() was added in 2.7.
21 | pkg_search_module(JANSSON REQUIRED jansson>=2.7)
22 |
23 | if(NOT TARGET dpso_utils)
24 | add_subdirectory(
25 | ../dpso_utils "${CMAKE_BINARY_DIR}/src/dpso_utils")
26 | endif()
27 |
28 | target_include_directories(
29 | dpso_json PUBLIC .. PRIVATE . ${JANSSON_INCLUDE_DIRS})
30 |
31 | target_link_libraries(
32 | dpso_json PRIVATE dpso_utils ${JANSSON_LIBRARIES})
33 |
--------------------------------------------------------------------------------
/src/dpso_net/download_file.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 |
8 | namespace dpso::net {
9 |
10 |
11 | // If the file size is unknown (e.g. the server does not provide
12 | // the Content-Length header), the function is called with nullopt
13 | // totalSize.
14 | //
15 | // Returns false to terminate downloading and remove a partially
16 | // downloaded file.
17 | using DownloadProgressHandler = std::function<
18 | bool(
19 | std::int64_t curSize,
20 | std::optional totalSize)>;
21 |
22 |
23 | // The function will not download the file directly to filePath, but
24 | // instead will use a temporary file named as filePath, but with an
25 | // additional extension. Once the temporary file is downloaded, it's
26 | // renamed to filePath, silently rewriting an existing file, if any.
27 | //
28 | // The function does not create the directory chain for filePath.
29 | //
30 | // Throws net::Error.
31 | void downloadFile(
32 | const char* url,
33 | const char* userAgent,
34 | const char* filePath,
35 | const DownloadProgressHandler& progressHandler);
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/dpso_net/error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::net {
7 |
8 |
9 | class Error : public std::runtime_error {
10 | using runtime_error::runtime_error;
11 | };
12 |
13 |
14 | // The connection either could not be established or was terminated.
15 | // This error is intended as a hint to show the end user a more
16 | // friendly error message, such as "check your network connection and
17 | // try again".
18 | class ConnectionError : public Error {
19 | using Error::Error;
20 | };
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/dpso_net/get_data.cpp:
--------------------------------------------------------------------------------
1 | #include "get_data.h"
2 |
3 | #include
4 |
5 | #include "dpso_utils/str.h"
6 |
7 | #include "error.h"
8 | #include "request.h"
9 |
10 |
11 | namespace dpso::net {
12 |
13 |
14 | std::string getData(
15 | const char* url, const char* userAgent, std::int64_t sizeLimit)
16 | {
17 | if (sizeLimit < 0)
18 | throw Error{"Size limit is < 0"};
19 |
20 | auto response = makeGetRequest(url, userAgent);
21 |
22 | if (const auto size = response->getSize();
23 | size && *size > sizeLimit)
24 | throw Error{str::format(
25 | "Response data size ({}) exceeds limit ({})",
26 | *size, sizeLimit)};
27 |
28 | std::string result;
29 |
30 | char buf[16 * 1024];
31 | while (true) {
32 | const auto numRead = response->read(buf, sizeof(buf));
33 | if (numRead == 0)
34 | break;
35 |
36 | if (std::numeric_limits::max() - result.size()
37 | < numRead
38 | || static_cast(result.size() + numRead)
39 | > sizeLimit)
40 | throw Error{str::format(
41 | "Response data size exceeds limit ({})", sizeLimit)};
42 |
43 | result.append(buf, numRead);
44 | }
45 |
46 | return result;
47 | }
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/dpso_net/get_data.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso::net {
8 |
9 |
10 | // Since the function is intended to download relatively small pieces
11 | // of data like JSON responses from various web APIs, it has the
12 | // sizeLimit argument to set a sane size limit on the downloaded data.
13 | // If the response provides the Content-Length header, the limit is
14 | // checked early. At the same time, the function doesn't trust
15 | // Content-Length, and will also check the limit during downloading
16 | // regardless of the presence of the header.
17 | //
18 | // Throws net::Error.
19 | std::string getData(
20 | const char* url,
21 | const char* userAgent,
22 | std::int64_t sizeLimit = 4 * 1024 * 1024);
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/dpso_net/request.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 |
9 | namespace dpso::net {
10 |
11 |
12 | class Response {
13 | public:
14 | virtual ~Response() = default;
15 |
16 | // Returns size of response data. This is a cached value of the
17 | // Content-Length header, if any.
18 | virtual std::optional getSize() const = 0;
19 |
20 | // Read up to dstSize bytes from the response. Returns 0 if the
21 | // end is reached. Throws net::Error on error.
22 | virtual std::size_t read(void* dst, std::size_t dstSize) = 0;
23 | };
24 |
25 |
26 | // Make HTTP GET request.
27 | //
28 | // Throws net::Error on error, or on any HTTP response code other than
29 | // 200.
30 | std::unique_ptr makeGetRequest(
31 | const char* url, const char* userAgent);
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/dpso_net/request_curl_lib.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::net {
7 |
8 |
9 | class LibCurl {
10 | LibCurl();
11 | public:
12 | // Throws net::Error if the curl library or one of its functions
13 | // cannot be loaded.
14 | static const LibCurl& get();
15 |
16 | #define DECL_FN(NAME) const decltype(&::curl_ ## NAME) NAME
17 |
18 | DECL_FN(easy_cleanup);
19 | DECL_FN(easy_init);
20 | DECL_FN(easy_setopt);
21 | DECL_FN(easy_strerror);
22 | DECL_FN(global_cleanup);
23 | DECL_FN(global_init);
24 | DECL_FN(multi_add_handle);
25 | DECL_FN(multi_cleanup);
26 | DECL_FN(multi_info_read);
27 | DECL_FN(multi_init);
28 | DECL_FN(multi_perform);
29 | DECL_FN(multi_remove_handle);
30 | DECL_FN(multi_strerror);
31 | DECL_FN(multi_wait);
32 |
33 | #undef DECL_FN
34 | };
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/dpso_ocr/data_lock.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 |
8 | namespace dpso::ocr {
9 |
10 |
11 | class DataLock {
12 | public:
13 | class DataLockedError : public std::runtime_error {
14 | using runtime_error::runtime_error;
15 | };
16 |
17 | DataLock();
18 |
19 | // Throws DataLockedError if data is already locked by another
20 | // DataLock.
21 | DataLock(const char* engineId, const char* dataDir);
22 |
23 | ~DataLock();
24 |
25 | DataLock(const DataLock&) = delete;
26 | DataLock& operator=(const DataLock&) = delete;
27 |
28 | DataLock(DataLock&& other) noexcept;
29 | DataLock& operator=(DataLock&& other) noexcept;
30 | private:
31 | struct Impl;
32 | std::unique_ptr impl;
33 | };
34 |
35 |
36 | class DataLockObserver {
37 | public:
38 | DataLockObserver();
39 | DataLockObserver(
40 | const char* engineId,
41 | const char* dataDir,
42 | const std::function& beforeLockCreated,
43 | const std::function& afterLockRemoved);
44 |
45 | ~DataLockObserver();
46 |
47 | DataLockObserver(const DataLockObserver&) = delete;
48 | DataLockObserver& operator=(const DataLockObserver&) = delete;
49 |
50 | DataLockObserver(DataLockObserver&& other) noexcept;
51 | DataLockObserver& operator=(DataLockObserver&& other) noexcept;
52 |
53 | bool getIsDataLocked() const;
54 | private:
55 | struct Impl;
56 | std::unique_ptr impl;
57 | };
58 |
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/dpso_ocr/dpso_ocr.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "ocr.h"
4 | #include "engine.h"
5 | #include "lang_manager.h"
6 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine.cpp:
--------------------------------------------------------------------------------
1 | #include "engine.h"
2 |
3 | #include "engine/engine.h"
4 |
5 |
6 | using namespace dpso;
7 |
8 |
9 | int dpsoOcrGetNumEngines(void)
10 | {
11 | return ocr::Engine::getCount();
12 | }
13 |
14 |
15 | void dpsoOcrGetEngineInfo(int idx, DpsoOcrEngineInfo* info)
16 | {
17 | if (idx < 0
18 | || static_cast(idx)
19 | >= ocr::Engine::getCount()
20 | || !info)
21 | return;
22 |
23 | const auto& internalInfo = ocr::Engine::get(idx).getInfo();
24 |
25 | DpsoOcrEngineDataDirPreference dataDirPreference{};
26 | switch (internalInfo.dataDirPreference) {
27 | case ocr::EngineInfo::DataDirPreference::noDataDir:
28 | dataDirPreference = DpsoOcrEngineDataDirPreferenceNoDataDir;
29 | break;
30 | case ocr::EngineInfo::DataDirPreference::preferDefault:
31 | dataDirPreference =
32 | DpsoOcrEngineDataDirPreferencePreferDefault;
33 | break;
34 | case ocr::EngineInfo::DataDirPreference::preferExplicit:
35 | dataDirPreference =
36 | DpsoOcrEngineDataDirPreferencePreferExplicit;
37 | break;
38 | }
39 |
40 | *info = {
41 | internalInfo.id.c_str(),
42 | internalInfo.name.c_str(),
43 | internalInfo.version.c_str(),
44 | dataDirPreference,
45 | internalInfo.hasLangManager};
46 | }
47 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/engine.cpp:
--------------------------------------------------------------------------------
1 | #include "engine/engine.h"
2 |
3 | #include
4 |
5 | #include "engine/tesseract/engine.h"
6 |
7 |
8 | namespace dpso::ocr {
9 |
10 |
11 | static const Engine* const engines[]{
12 | &tesseract::getEngine()
13 | };
14 |
15 |
16 | const Engine& Engine::get(std::size_t idx)
17 | {
18 | return *engines[idx];
19 | }
20 |
21 |
22 | std::size_t Engine::getCount()
23 | {
24 | return std::size(engines);
25 | }
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/engine.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 |
8 | namespace dpso::ocr {
9 |
10 |
11 | class LangManager;
12 | class Recognizer;
13 |
14 |
15 | // See DpsoOcrEngineInfo
16 | struct EngineInfo {
17 | std::string id;
18 | std::string name;
19 | std::string version;
20 |
21 | // See DpsoOcrEngineDataDirPreference
22 | enum class DataDirPreference {
23 | noDataDir,
24 | preferDefault,
25 | preferExplicit,
26 | };
27 |
28 | DataDirPreference dataDirPreference;
29 | bool hasLangManager;
30 | };
31 |
32 |
33 | class Engine {
34 | public:
35 | static const Engine& get(std::size_t idx);
36 | static std::size_t getCount();
37 |
38 | virtual ~Engine() = default;
39 |
40 | virtual const EngineInfo& getInfo() const = 0;
41 |
42 | // Throws RecognizerError
43 | virtual std::unique_ptr createRecognizer(
44 | const char* dataDir) const = 0;
45 |
46 | // See dpsoOcrLangManagerCreate(). Throws LangManagerError.
47 | virtual std::unique_ptr createLangManager(
48 | const char* dataDir,
49 | const char* userAgent,
50 | const char* infoFileUrl) const = 0;
51 | };
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::ocr {
7 |
8 |
9 | class Error : public std::runtime_error {
10 | using runtime_error::runtime_error;
11 | };
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/lang_code_validator.cpp:
--------------------------------------------------------------------------------
1 | #include "engine/lang_code_validator.h"
2 |
3 | #include "dpso_utils/str.h"
4 |
5 |
6 | namespace dpso::ocr {
7 |
8 |
9 | static bool isValidLangCodeChar(char c)
10 | {
11 | return
12 | (c >= '0' && c <= '9')
13 | || (c >= 'a' && c <= 'z')
14 | || (c >= 'A' && c <= 'Z')
15 | || c == '.'
16 | || c == '-'
17 | || c == '_';
18 | }
19 |
20 |
21 | void validateLangCode(const char* langCode)
22 | {
23 | if (!*langCode)
24 | throw LangCodeError{"Language code is empty"};
25 |
26 | for (const auto* s = langCode; *s; ++s)
27 | if (!isValidLangCodeChar(*s))
28 | throw LangCodeError{str::format(
29 | "Invalid character at index {}", s - langCode)};
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/lang_code_validator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "engine/error.h"
4 |
5 |
6 | namespace dpso::ocr {
7 |
8 |
9 | class LangCodeError : public Error {
10 | using Error::Error;
11 | };
12 |
13 |
14 | // Throws LangCodeError.
15 | void validateLangCode(const char* langCode);
16 |
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/lang_manager_error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "engine/error.h"
4 |
5 |
6 | namespace dpso::ocr {
7 |
8 |
9 | class LangManagerError : public Error {
10 | using Error::Error;
11 | };
12 |
13 |
14 | // The connection either could not be established or was terminated.
15 | // This error is intended as a hint to show the end user a more
16 | // friendly error message, such as "check your network connection and
17 | // try again".
18 | class LangManagerNetworkConnectionError : public LangManagerError {
19 | using LangManagerError::LangManagerError;
20 | };
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/recognizer_error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "engine/error.h"
4 |
5 |
6 | namespace dpso::ocr {
7 |
8 |
9 | class RecognizerError : public Error {
10 | using Error::Error;
11 | };
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/tesseract/engine.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace dpso::ocr {
5 |
6 |
7 | class Engine;
8 |
9 |
10 | namespace tesseract {
11 |
12 |
13 | const Engine& getEngine();
14 |
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/tesseract/lang_manager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "engine/lang_manager.h"
6 |
7 |
8 | namespace dpso::ocr::tesseract {
9 |
10 |
11 | bool hasLangManager();
12 |
13 |
14 | std::unique_ptr createLangManager(
15 | const char* dataDir,
16 | const char* userAgent,
17 | const char* infoFileUrl);
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/tesseract/lang_manager_null.cpp:
--------------------------------------------------------------------------------
1 | // This file is used when the language manager is disabled at compile
2 | // time.
3 |
4 | #include "engine/tesseract/lang_manager.h"
5 |
6 | #include "engine/lang_manager_error.h"
7 |
8 |
9 | namespace dpso::ocr::tesseract {
10 |
11 |
12 | bool hasLangManager()
13 | {
14 | return false;
15 | }
16 |
17 |
18 | std::unique_ptr createLangManager(
19 | const char* dataDir,
20 | const char* userAgent,
21 | const char* infoFileUrl)
22 | {
23 | (void)dataDir;
24 | (void)userAgent;
25 | (void)infoFileUrl;
26 |
27 | throw LangManagerError{"Language manager is not available"};
28 | }
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/tesseract/lang_names.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace dpso::ocr::tesseract {
5 |
6 |
7 | // Returns null if the language with the given code is not found.
8 | const char* getLangName(const char* langCode);
9 |
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/tesseract/lang_utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso::ocr::tesseract {
8 |
9 |
10 | extern const char* const traineddataExt;
11 |
12 |
13 | // Returns true if the language should be ignored, e.g., when it's not
14 | // a real language but an auxiliary data, such as "equ" or "osd".
15 | bool isIgnoredLang(const char* lang);
16 |
17 |
18 | // Returns languages from TessBaseAPI::GetAvailableLanguagesAsVector,
19 | // excluding those that are ignored by isIgnoredLang().
20 | //
21 | // Throws ocr::Error.
22 | std::vector getAvailableLangs(const char* dataDir);
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/tesseract/recognizer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "engine/recognizer.h"
6 |
7 |
8 | namespace dpso::ocr::tesseract {
9 |
10 |
11 | std::unique_ptr createRecognizer(const char* dataDir);
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/dpso_ocr/engine/tesseract/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::ocr::tesseract {
7 |
8 |
9 | // Prettify text returned by Tesseract.
10 | //
11 | // The function will:
12 | // * Trim whitespace.
13 | // * Split fi and fl ligatures.
14 | // * Remove paragraphs consisting of a single space, which are
15 | // sometimes created when page segmentation is enabled.
16 | //
17 | // Returns the new length of the text.
18 | std::size_t prettifyText(char* text);
19 |
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/dpso_sound/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.22)
2 |
3 | project(dpso_sound)
4 |
5 | add_library(dpso_sound)
6 |
7 | if(UNIX AND NOT APPLE)
8 | target_sources(
9 | dpso_sound
10 | PRIVATE
11 | unix/lib/pulse.cpp
12 | unix/lib/sndfile.cpp
13 | unix/sndfile.cpp
14 | unix/sound_pulse.cpp)
15 |
16 | find_package(Threads REQUIRED)
17 |
18 | target_link_libraries(
19 | dpso_sound PRIVATE dl ${CMAKE_THREAD_LIBS_INIT})
20 | elseif(WIN32)
21 | target_sources(dpso_sound PRIVATE sound_windows.cpp)
22 | target_link_libraries(dpso_sound PRIVATE winmm)
23 | else()
24 | target_sources(dpso_sound PRIVATE sound_null.cpp)
25 | endif()
26 |
27 | set_target_properties(
28 | dpso_sound PROPERTIES
29 | CXX_STANDARD 17
30 | CXX_STANDARD_REQUIRED YES
31 | CXX_EXTENSIONS NO
32 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
33 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
34 | OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
35 | target_compile_options(dpso_sound PRIVATE -Wall -Wextra -pedantic)
36 | endif()
37 |
38 | include(TestBigEndian)
39 | test_big_endian(IS_BIG_ENDIAN)
40 |
41 | target_compile_definitions(
42 | dpso_sound
43 | PRIVATE DPSO_SOUND_IS_BIG_ENDIAN=$)
44 |
45 | if(NOT TARGET dpso_utils)
46 | add_subdirectory(
47 | ../dpso_utils "${CMAKE_BINARY_DIR}/src/dpso_utils")
48 | endif()
49 |
50 | target_include_directories(dpso_sound PUBLIC .. PRIVATE .)
51 |
--------------------------------------------------------------------------------
/src/dpso_sound/error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::sound {
7 |
8 |
9 | class Error : public std::runtime_error {
10 | using runtime_error::runtime_error;
11 | };
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/dpso_sound/format_info.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::sound {
7 |
8 |
9 | struct FormatInfo {
10 | const char* name;
11 | // The list of possible file extensions for the format. Each
12 | // extension has a leading period.
13 | std::vector extensions;
14 | };
15 |
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/dpso_sound/sound.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include "format_info.h"
7 |
8 |
9 | namespace dpso::sound {
10 |
11 |
12 | bool isAvailable();
13 |
14 |
15 | // Return a path to a directory containing system sound files, or an
16 | // empty string if no such directory is defined for the current
17 | // platform. The function only returns a string and does not query the
18 | // file system to check if the directory actually exists.
19 | const char* getSystemSoundsDirPath();
20 |
21 |
22 | // Return the list of audio file formats supported by Player. The list
23 | // will be empty if isAvailable() is false or on error.
24 | const std::vector& getSupportedFormats();
25 |
26 |
27 | // The Player class is intended to play short notification sounds.
28 | class Player {
29 | public:
30 | // Throws sound:::Error.
31 | static std::unique_ptr create(const char* filePath);
32 |
33 | virtual ~Player() = default;
34 |
35 | // play() will stop a currently playing sound, even if it was
36 | // started by another Player instance. Throws sound:::Error.
37 | virtual void play() = 0;
38 | };
39 |
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/dpso_sound/sound_null.cpp:
--------------------------------------------------------------------------------
1 | #include "sound.h"
2 |
3 |
4 | namespace dpso::sound {
5 |
6 |
7 | bool isAvailable()
8 | {
9 | return false;
10 | }
11 |
12 |
13 | const char* getSystemSoundsDirPath()
14 | {
15 | return "";
16 | }
17 |
18 |
19 | const std::vector& getSupportedFormats()
20 | {
21 | static const std::vector result;
22 | return result;
23 | }
24 |
25 |
26 | std::unique_ptr Player::create(const char* filePath)
27 | {
28 | (void)filePath;
29 |
30 | throw Error{"Sound library is not available"};
31 | }
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/dpso_sound/unix/audio_data.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::sound {
7 |
8 |
9 | struct AudioData {
10 | int numChannels;
11 | int rate;
12 | std::vector samples;
13 | };
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/dpso_sound/unix/lib/sndfile.cpp:
--------------------------------------------------------------------------------
1 | #include "unix/lib/sndfile.h"
2 |
3 | #include
4 |
5 | #include "dpso_utils/str.h"
6 | #include "dpso_utils/unix/dl.h"
7 |
8 | #include "error.h"
9 |
10 |
11 | namespace dpso::sound {
12 | namespace {
13 |
14 |
15 | unix::DlHandleUPtr loadLib(const char* soName)
16 | {
17 | if (auto* handle = dlopen(soName, RTLD_NOW | RTLD_LOCAL))
18 | return unix::DlHandleUPtr{handle};
19 |
20 | throw Error{str::format("Can't load {}: {}", soName, dlerror())};
21 | }
22 |
23 |
24 | void* loadFn(const char* name)
25 | {
26 | static const auto* libName = "libsndfile.so.1";
27 | static const auto dlHandle = loadLib(libName);
28 |
29 | if (auto* result = dlsym(dlHandle.get(), name))
30 | return result;
31 |
32 | throw Error{str::format(
33 | "dlsym for \"{}\" from \"{}\": {}",
34 | name, libName, dlerror())};
35 | }
36 |
37 |
38 | }
39 |
40 |
41 | const LibSndfile& LibSndfile::get()
42 | {
43 | static const LibSndfile lib;
44 | return lib;
45 | }
46 |
47 |
48 | #define LOAD_FN(NAME) NAME{(decltype(NAME))loadFn("sf_" #NAME)}
49 |
50 |
51 | LibSndfile::LibSndfile()
52 | : LOAD_FN(open)
53 | , LOAD_FN(command)
54 | , LOAD_FN(readf_short)
55 | , LOAD_FN(close)
56 | , LOAD_FN(strerror)
57 | {
58 | }
59 |
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/dpso_sound/unix/sndfile.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "format_info.h"
4 | #include "unix/audio_data.h"
5 |
6 |
7 | namespace dpso::sound::sndfile {
8 |
9 |
10 | // Implementation of sound::getSystemSoundsDirPath(). Doesn't throw.
11 | std::vector getSupportedFormats();
12 |
13 |
14 | // Throws sound::Error.
15 | AudioData loadAudioData(const char* filePath);
16 |
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/backend.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "dpso_img/img.h"
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | struct Rect;
12 |
13 |
14 | namespace backend {
15 |
16 |
17 | class KeyManager;
18 | class Selection;
19 | class Screenshot;
20 |
21 |
22 | class Backend {
23 | public:
24 | // The concrete backend should provide definition of this method.
25 | // Throws BackendError.
26 | static std::unique_ptr create();
27 |
28 | virtual ~Backend() = default;
29 |
30 | virtual KeyManager& getKeyManager() = 0;
31 | virtual Selection& getSelection() = 0;
32 |
33 | // The method will clamp the rect to screen. Throws
34 | // ScreenshotError.
35 | virtual img::ImgUPtr takeScreenshot(const Rect& rect) = 0;
36 |
37 | virtual void update() = 0;
38 | };
39 |
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/backend_error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::backend {
7 |
8 |
9 | class BackendError : public std::runtime_error {
10 | using runtime_error::runtime_error;
11 | };
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/key_manager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "keys.h"
4 |
5 |
6 | namespace dpso::backend {
7 |
8 |
9 | struct HotkeyBinding {
10 | DpsoHotkey hotkey;
11 | DpsoHotkeyAction action;
12 | };
13 |
14 |
15 | // Key manager.
16 | //
17 | // See key_manager.h for more information. Preconditions:
18 | //
19 | // * bindHotkey():
20 | // * hotkey.key >= 0 and < dpsoNumKeys
21 | // * action >= 0
22 | // * getBinding(), removeBinding():
23 | // * idx >= 0 and < getNumBindings()
24 | class KeyManager {
25 | public:
26 | virtual ~KeyManager() = default;
27 |
28 | // See dpsoKeyManagerGetIsEnabled()
29 | virtual bool getIsEnabled() const = 0;
30 |
31 | // See dpsoKeyManagerSetIsEnabled()
32 | virtual void setIsEnabled(bool newIsEnabled) = 0;
33 |
34 | // See dpsoKeyManagerGetLastHotkeyAction()
35 | virtual DpsoHotkeyAction getLastHotkeyAction() const = 0;
36 |
37 | // See dpsoKeyManagerBindHotkey()
38 | virtual void bindHotkey(
39 | const DpsoHotkey& hotkey, DpsoHotkeyAction action) = 0;
40 |
41 | virtual int getNumBindings() const = 0;
42 | virtual HotkeyBinding getBinding(int idx) const = 0;
43 | virtual void removeBinding(int idx) = 0;
44 | };
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/screenshot_error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "backend/backend_error.h"
4 |
5 |
6 | namespace dpso::backend {
7 |
8 |
9 | class ScreenshotError : public BackendError {
10 | using BackendError::BackendError;
11 | };
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/selection.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "dpso_utils/geometry.h"
4 |
5 |
6 | namespace dpso::backend {
7 |
8 |
9 | // See selection.h for more information.
10 | class Selection {
11 | public:
12 | // Default border width at base (e.g. 96) DPI.
13 | static const auto defaultBorderWidth = 3;
14 |
15 | // The selection border is filled with a pattern of black and
16 | // white dashes. The dash length defines the number of squares in
17 | // a single dash.
18 | static const auto dashLen = 3;
19 |
20 | virtual ~Selection() = default;
21 |
22 | // See dpsoSelectionGetIsEnabled()
23 | virtual bool getIsEnabled() const = 0;
24 |
25 | // See dpsoSelectionSetIsEnabled()
26 | virtual void setIsEnabled(bool newIsEnabled) = 0;
27 |
28 | // See dpsoSelectionSetBorderWidth()
29 | //
30 | // The method is always called with newBorderWidth > 0.
31 | virtual void setBorderWidth(int newBorderWidth) = 0;
32 |
33 | // See dpsoSelectionGetGeometry()
34 | virtual Rect getGeometry() const = 0;
35 | };
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/unix/backend.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "backend/backend_error.h"
5 | #include "backend/unix/x11/backend.h"
6 |
7 |
8 | namespace dpso::backend {
9 |
10 |
11 | std::unique_ptr Backend::create()
12 | {
13 | // Although X11 code on Wayland runs on top of XWayland, there
14 | // will still be neither global hotkeys nor screenshots since
15 | // Wayland doesn't support them by design.
16 | //
17 | // While an attempt to take a screenshot will fail explicitly
18 | // (i.e. XGrabImage() will return null), the global hotkeys
19 | // (XGrabKey()) will just silently do nothing. Therefore, it's
20 | // better not to rely on X11 failures and report an explicit error
21 | // as early as possible, especially for the use case when a hotkey
22 | // triggers a screenshot.
23 | const auto* xdgSessionType = std::getenv("XDG_SESSION_TYPE");
24 | if (xdgSessionType && std::strcmp(xdgSessionType, "wayland") == 0)
25 | throw BackendError(
26 | "Wayland is not supported. Please switch to the X11/Xorg "
27 | "session.");
28 |
29 | return x11::createBackend();
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/unix/x11/backend.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "backend/backend.h"
4 |
5 |
6 | namespace dpso::backend::x11 {
7 |
8 |
9 | std::unique_ptr createBackend();
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/unix/x11/backend_component.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::backend::x11 {
7 |
8 |
9 | class BackendComponent {
10 | public:
11 | virtual ~BackendComponent() = default;
12 |
13 | virtual void updateStart() {}
14 | virtual void handleEvent(const XEvent& event) { (void)event; }
15 | };
16 |
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/unix/x11/key_manager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 |
7 | #include "backend/key_manager.h"
8 | #include "backend/unix/x11/backend_component.h"
9 |
10 |
11 | namespace dpso::backend::x11 {
12 |
13 |
14 | class KeyManager
15 | : public backend::KeyManager
16 | , public BackendComponent {
17 | public:
18 | explicit KeyManager(Display* display);
19 | ~KeyManager();
20 |
21 | bool getIsEnabled() const override;
22 | void setIsEnabled(bool newIsEnabled) override;
23 | DpsoHotkeyAction getLastHotkeyAction() const override;
24 |
25 | void bindHotkey(
26 | const DpsoHotkey& hotkey, DpsoHotkeyAction action) override;
27 |
28 | int getNumBindings() const override;
29 | HotkeyBinding getBinding(int idx) const override;
30 | void removeBinding(int idx) override;
31 |
32 | void updateStart() override;
33 | void handleEvent(const XEvent& event) override;
34 | private:
35 | Display* display;
36 | bool isEnabled{};
37 |
38 | struct X11HotkeyBinding {
39 | HotkeyBinding binding;
40 | KeyCode keyCode;
41 | };
42 | std::vector x11bindings;
43 |
44 | DpsoHotkeyAction hotkeyAction{dpsoNoHotkeyAction};
45 |
46 | static void changeGrab(
47 | Display* display,
48 | const X11HotkeyBinding& x11binding,
49 | bool grab);
50 | };
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/unix/x11/screenshot.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "dpso_img/img.h"
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | struct Rect;
12 |
13 |
14 | namespace backend::x11 {
15 |
16 |
17 | img::ImgUPtr takeScreenshot(Display* display, const Rect& rect);
18 |
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/unix/x11/selection.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "backend/selection.h"
6 | #include "backend/unix/x11/backend_component.h"
7 | #include "backend/unix/x11/utils.h"
8 |
9 |
10 | namespace dpso::backend::x11 {
11 |
12 |
13 | class Selection : public backend::Selection, public BackendComponent {
14 | public:
15 | explicit Selection(Display* display);
16 |
17 | bool getIsEnabled() const override;
18 | void setIsEnabled(bool newIsEnabled) override;
19 |
20 | void setBorderWidth(int newBorderWidth) override;
21 |
22 | Rect getGeometry() const override;
23 |
24 | void updateStart() override;
25 | void handleEvent(const XEvent& event) override;
26 | private:
27 | Display* display;
28 | WindowHandle window{};
29 | GcHandle gc{};
30 |
31 | bool isEnabled{};
32 | int baseBorderWidth{defaultBorderWidth};
33 | int borderWidth{baseBorderWidth};
34 | Point origin;
35 | Rect geom;
36 |
37 | void updateBorderWidth();
38 | void updateWindowGeometry();
39 | void updateWindowShape();
40 | void setGeometry(const Rect& newGeom);
41 | void draw();
42 | };
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/execution_layer/action_executor.cpp:
--------------------------------------------------------------------------------
1 | #include "backend/windows/execution_layer/action_executor.h"
2 |
3 |
4 | namespace dpso::backend {
5 |
6 |
7 | ActionExecutor::ActionExecutor()
8 | : thread{&ActionExecutor::threadLoop, this}
9 | {
10 | }
11 |
12 |
13 | ActionExecutor::~ActionExecutor()
14 | {
15 | backend::execute(*this, [&]{ terminate = true; });
16 | thread.join();
17 | }
18 |
19 |
20 | void ActionExecutor::execute(Action& action)
21 | {
22 | {
23 | const std::lock_guard guard{mutex};
24 | currentAction = &action;
25 | }
26 |
27 | actionSetCondVar.notify_one();
28 |
29 | {
30 | std::unique_lock lock{mutex};
31 | actionDoneCondVar.wait(lock, [&]{ return !currentAction; });
32 | }
33 |
34 | if (actionException)
35 | std::rethrow_exception(
36 | std::exchange(actionException, nullptr));
37 | }
38 |
39 |
40 | void ActionExecutor::threadLoop()
41 | {
42 | // No need to protect "terminate" since it's set from within an
43 | // action.
44 | while (!terminate) {
45 | std::unique_lock lock{mutex};
46 | actionSetCondVar.wait(lock, [&]{ return currentAction; });
47 |
48 | try {
49 | currentAction->action();
50 | } catch (...) {
51 | actionException = std::current_exception();
52 | }
53 |
54 | currentAction = nullptr;
55 |
56 | // Unlock manually to avoid waking up the caller's thread only
57 | // to block again.
58 | lock.unlock();
59 | actionDoneCondVar.notify_one();
60 | }
61 | }
62 |
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/execution_layer/backend_executor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "backend/backend.h"
6 |
7 |
8 | namespace dpso::backend {
9 |
10 |
11 | using BackendCreatorFn = std::unique_ptr (&)();
12 | std::unique_ptr createBackendExecutor(
13 | BackendCreatorFn creatorFn);
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/execution_layer/key_manager_executor.cpp:
--------------------------------------------------------------------------------
1 | #include "backend/windows/execution_layer/key_manager_executor.h"
2 |
3 | #include "backend/windows/execution_layer/action_executor.h"
4 |
5 |
6 | namespace dpso::backend {
7 |
8 |
9 | #define EXECUTE(CALL) \
10 | execute(actionExecutor, [&]{ return keyManager.CALL; })
11 |
12 |
13 | KeyManagerExecutor::KeyManagerExecutor(
14 | KeyManager& keyManager, ActionExecutor& actionExecutor)
15 | : keyManager{keyManager}
16 | , actionExecutor{actionExecutor}
17 | {
18 | }
19 |
20 |
21 | bool KeyManagerExecutor::getIsEnabled() const
22 | {
23 | return EXECUTE(getIsEnabled());
24 | }
25 |
26 |
27 | void KeyManagerExecutor::setIsEnabled(bool newIsEnabled)
28 | {
29 | EXECUTE(setIsEnabled(newIsEnabled));
30 | }
31 |
32 |
33 | DpsoHotkeyAction KeyManagerExecutor::getLastHotkeyAction() const
34 | {
35 | return EXECUTE(getLastHotkeyAction());
36 | }
37 |
38 |
39 | void KeyManagerExecutor::bindHotkey(
40 | const DpsoHotkey& hotkey, DpsoHotkeyAction action)
41 | {
42 | EXECUTE(bindHotkey(hotkey, action));
43 | }
44 |
45 |
46 | int KeyManagerExecutor::getNumBindings() const
47 | {
48 | return EXECUTE(getNumBindings());
49 | }
50 |
51 |
52 | HotkeyBinding KeyManagerExecutor::getBinding(int idx) const
53 | {
54 | return EXECUTE(getBinding(idx));
55 | }
56 |
57 |
58 | void KeyManagerExecutor::removeBinding(int idx)
59 | {
60 | EXECUTE(removeBinding(idx));
61 | }
62 |
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/execution_layer/key_manager_executor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "backend/key_manager.h"
4 |
5 |
6 | namespace dpso::backend {
7 |
8 |
9 | class ActionExecutor;
10 |
11 |
12 | class KeyManagerExecutor : public KeyManager {
13 | public:
14 | KeyManagerExecutor(
15 | KeyManager& keyManager, ActionExecutor& actionExecutor);
16 |
17 | bool getIsEnabled() const override;
18 | void setIsEnabled(bool newIsEnabled) override;
19 | DpsoHotkeyAction getLastHotkeyAction() const override;
20 |
21 | void bindHotkey(
22 | const DpsoHotkey& hotkey, DpsoHotkeyAction action) override;
23 |
24 | int getNumBindings() const override;
25 | HotkeyBinding getBinding(int idx) const override;
26 | void removeBinding(int idx) override;
27 | private:
28 | KeyManager& keyManager;
29 | ActionExecutor& actionExecutor;
30 | };
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/execution_layer/selection_executor.cpp:
--------------------------------------------------------------------------------
1 | #include "backend/windows/execution_layer/selection_executor.h"
2 |
3 | #include "backend/windows/execution_layer/action_executor.h"
4 |
5 |
6 | namespace dpso::backend {
7 |
8 |
9 | #define EXECUTE(CALL) \
10 | execute(actionExecutor, [&]{ return selection.CALL; })
11 |
12 |
13 | SelectionExecutor::SelectionExecutor(
14 | Selection& selection, ActionExecutor& actionExecutor)
15 | : selection{selection}
16 | , actionExecutor{actionExecutor}
17 | {
18 | }
19 |
20 |
21 | bool SelectionExecutor::getIsEnabled() const
22 | {
23 | return EXECUTE(getIsEnabled());
24 | }
25 |
26 |
27 | void SelectionExecutor::setIsEnabled(bool newIsEnabled)
28 | {
29 | EXECUTE(setIsEnabled(newIsEnabled));
30 | }
31 |
32 |
33 | void SelectionExecutor::setBorderWidth(int newBorderWidth)
34 | {
35 | EXECUTE(setBorderWidth(newBorderWidth));
36 | }
37 |
38 |
39 | Rect SelectionExecutor::getGeometry() const
40 | {
41 | return EXECUTE(getGeometry());
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/execution_layer/selection_executor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "backend/selection.h"
4 |
5 |
6 | namespace dpso::backend {
7 |
8 |
9 | class ActionExecutor;
10 |
11 |
12 | class SelectionExecutor : public Selection {
13 | public:
14 | SelectionExecutor(
15 | Selection& selection, ActionExecutor& actionExecutor);
16 |
17 | bool getIsEnabled() const override;
18 | void setIsEnabled(bool newIsEnabled) override;
19 |
20 | void setBorderWidth(int newBorderWidth) override;
21 |
22 | Rect getGeometry() const override;
23 | private:
24 | Selection& selection;
25 | ActionExecutor& actionExecutor;
26 | };
27 |
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/key_manager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #define WIN32_LEAN_AND_MEAN
6 | #include
7 |
8 | #include "backend/key_manager.h"
9 |
10 |
11 | namespace dpso::backend::windows {
12 |
13 |
14 | class KeyManager : public backend::KeyManager {
15 | public:
16 | KeyManager() = default;
17 | ~KeyManager();
18 |
19 | bool getIsEnabled() const override;
20 | void setIsEnabled(bool newIsEnabled) override;
21 | DpsoHotkeyAction getLastHotkeyAction() const override;
22 |
23 | void bindHotkey(
24 | const DpsoHotkey& hotkey, DpsoHotkeyAction action) override;
25 |
26 | int getNumBindings() const override;
27 | HotkeyBinding getBinding(int idx) const override;
28 | void removeBinding(int idx) override;
29 |
30 | void clearLastHotkeyAction();
31 | void handleWmHotkey(const MSG& msg);
32 | private:
33 | bool isEnabled{};
34 | std::vector bindings;
35 | DpsoHotkeyAction hotkeyAction{dpsoNoHotkeyAction};
36 |
37 | HotkeyBinding* findBinding(const DpsoHotkey& hotkey);
38 | };
39 |
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/screenshot.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "dpso_img/img.h"
4 |
5 |
6 | namespace dpso {
7 |
8 |
9 | struct Rect;
10 |
11 |
12 | namespace backend::windows {
13 |
14 |
15 | img::ImgUPtr takeScreenshot(const Rect& rect);
16 |
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/dpso_sys/backend/windows/selection.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define WIN32_LEAN_AND_MEAN
4 | #include
5 |
6 | #include "backend/selection.h"
7 | #include "dpso_utils/windows/gdi.h"
8 | #include "dpso_utils/windows/window.h"
9 |
10 |
11 | namespace dpso::backend::windows {
12 |
13 |
14 | class Selection : public backend::Selection {
15 | public:
16 | explicit Selection(HINSTANCE instance);
17 | ~Selection();
18 |
19 | bool getIsEnabled() const override;
20 | void setIsEnabled(bool newIsEnabled) override;
21 |
22 | void setBorderWidth(int newBorderWidth) override;
23 |
24 | Rect getGeometry() const override;
25 |
26 | void update();
27 | private:
28 | bool isEnabled{};
29 | int dpi{};
30 | int baseBorderWidth{defaultBorderWidth};
31 | int borderWidth{baseBorderWidth};
32 | Point origin;
33 | Rect geom;
34 |
35 | dpso::windows::WindowUPtr window;
36 |
37 | dpso::windows::ObjectUPtr pens[2];
38 |
39 | static LRESULT CALLBACK wndProc(
40 | HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
41 | LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
42 |
43 | void updateBorderWidth();
44 | void updatePens();
45 | void updateWindowGeometry();
46 | void updateWindowRegion();
47 | void setGeometry(const Rect& newGeom);
48 | void draw(HDC dc);
49 | };
50 |
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/dpso_sys/dpso_sys.cpp:
--------------------------------------------------------------------------------
1 | #include "dpso_sys.h"
2 |
3 | #include "dpso_utils/error_set.h"
4 |
5 | #include "backend/backend.h"
6 | #include "backend/backend_error.h"
7 | #include "dpso_sys_fwd.h"
8 | #include "dpso_sys_p.h"
9 |
10 |
11 | DpsoSys* dpsoSysCreate(void)
12 | {
13 | try {
14 | return new DpsoSys{};
15 | } catch (dpso::backend::BackendError& e) {
16 | dpso::setError("{}", e.what());
17 | return {};
18 | }
19 | }
20 |
21 |
22 | void dpsoSysDelete(DpsoSys* sys)
23 | {
24 | delete sys;
25 | }
26 |
27 |
28 | void dpsoSysUpdate(DpsoSys* sys)
29 | {
30 | if (sys)
31 | sys->backend->update();
32 | }
33 |
34 |
35 | DpsoKeyManager* dpsoSysGetKeyManager(DpsoSys* sys)
36 | {
37 | return sys ? &sys->keyManager : nullptr;
38 | }
39 |
40 |
41 | DpsoSelection* dpsoSysGetSelection(DpsoSys* sys)
42 | {
43 | return sys ? &sys->selection : nullptr;
44 | }
45 |
--------------------------------------------------------------------------------
/src/dpso_sys/dpso_sys.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "dpso_sys_fwd.h"
4 | #include "key_manager.h"
5 | #include "screenshot.h"
6 | #include "selection.h"
7 |
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 |
14 | /**
15 | * Create a system backend.
16 | *
17 | * On failure, sets an error message (dpsoGetError()) and returns
18 | * null.
19 | */
20 | DpsoSys* dpsoSysCreate(void);
21 |
22 |
23 | void dpsoSysDelete(DpsoSys* sys);
24 |
25 |
26 | /**
27 | * Update the system backend.
28 | *
29 | * The function process system events, like mouse motion, key press,
30 | * etc., for hotkey handling (key_manager.h) and interactive selection
31 | * (selection.h). Call this function at a frequency close to the
32 | * monitor refresh rate, which is usually 60 times per second.
33 | */
34 | void dpsoSysUpdate(DpsoSys* sys);
35 |
36 |
37 | DpsoKeyManager* dpsoSysGetKeyManager(DpsoSys* sys);
38 | DpsoSelection* dpsoSysGetSelection(DpsoSys* sys);
39 |
40 |
41 | #ifdef __cplusplus
42 | }
43 |
44 |
45 | #include
46 |
47 |
48 | namespace dpso {
49 |
50 |
51 | struct SysDeleter {
52 | void operator()(DpsoSys* sys) const
53 | {
54 | dpsoSysDelete(sys);
55 | }
56 | };
57 |
58 |
59 | using SysUPtr = std::unique_ptr;
60 |
61 |
62 | }
63 |
64 |
65 | #endif
66 |
--------------------------------------------------------------------------------
/src/dpso_sys/dpso_sys_fwd.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | typedef struct DpsoSys DpsoSys;
5 |
--------------------------------------------------------------------------------
/src/dpso_sys/dpso_sys_p.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "backend/backend.h"
4 |
5 |
6 | struct DpsoKeyManager {
7 | dpso::backend::KeyManager& impl;
8 | };
9 |
10 |
11 | struct DpsoSelection {
12 | dpso::backend::Selection& impl;
13 | };
14 |
15 |
16 | struct DpsoSys {
17 | std::unique_ptr backend{
18 | dpso::backend::Backend::create()};
19 | DpsoKeyManager keyManager{backend->getKeyManager()};
20 | DpsoSelection selection{backend->getSelection()};
21 | };
22 |
--------------------------------------------------------------------------------
/src/dpso_sys/screenshot.cpp:
--------------------------------------------------------------------------------
1 | #include "screenshot.h"
2 |
3 | #include "dpso_utils/error_set.h"
4 | #include "dpso_utils/geometry.h"
5 |
6 | #include "backend/backend.h"
7 | #include "backend/screenshot_error.h"
8 | #include "dpso_sys_p.h"
9 |
10 |
11 | DpsoImg* dpsoTakeScreenshot(DpsoSys* sys, const DpsoRect* rect)
12 | {
13 | if (!sys) {
14 | dpso::setError("sys is null");
15 | return {};
16 | }
17 |
18 | if (!rect) {
19 | dpso::setError("rect is null");
20 | return {};
21 | }
22 |
23 | try {
24 | return sys->backend->takeScreenshot(
25 | dpso::Rect{*rect}).release();
26 | } catch (dpso::backend::ScreenshotError& e) {
27 | dpso::setError("Backend::takeScreenshot(): {}", e.what());
28 | return {};
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/dpso_sys/screenshot.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "dpso_img/img.h"
4 | #include "dpso_utils/geometry_c.h"
5 |
6 | #include "dpso_sys_fwd.h"
7 |
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 |
14 | /**
15 | * Take a screenshot.
16 | *
17 | * The screenshot is be taken from an intersection of the given rect
18 | * with the actual screen geometry.
19 | *
20 | * On failure, sets an error message (dpsoGetError()) and returns
21 | * null.
22 | */
23 | DpsoImg* dpsoTakeScreenshot(DpsoSys* sys, const DpsoRect* rect);
24 |
25 |
26 | #ifdef __cplusplus
27 | }
28 | #endif
29 |
--------------------------------------------------------------------------------
/src/dpso_sys/selection.cpp:
--------------------------------------------------------------------------------
1 | #include "selection.h"
2 |
3 | #include "backend/selection.h"
4 | #include "dpso_sys_p.h"
5 |
6 |
7 | bool dpsoSelectionGetIsEnabled(const DpsoSelection* selection)
8 | {
9 | return selection && selection->impl.getIsEnabled();
10 | }
11 |
12 |
13 | void dpsoSelectionSetIsEnabled(
14 | DpsoSelection* selection, bool newIsEnabled)
15 | {
16 | if (selection)
17 | selection->impl.setIsEnabled(newIsEnabled);
18 | }
19 |
20 |
21 | int dpsoSelectionGetDefaultBorderWidth(void)
22 | {
23 | return dpso::backend::Selection::defaultBorderWidth;
24 | }
25 |
26 |
27 | void dpsoSelectionSetBorderWidth(
28 | DpsoSelection* selection, int newBorderWidth)
29 | {
30 | if (selection)
31 | selection->impl.setBorderWidth(
32 | newBorderWidth < 1 ? 1 : newBorderWidth);
33 | }
34 |
35 |
36 | void dpsoSelectionGetGeometry(
37 | const DpsoSelection* selection, DpsoRect* rect)
38 | {
39 | if (!rect)
40 | return;
41 |
42 | *rect = selection
43 | ? toCRect(selection->impl.getGeometry()) : DpsoRect{};
44 | }
45 |
--------------------------------------------------------------------------------
/src/dpso_utils/byte_order.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso {
8 |
9 |
10 | enum class ByteOrder {
11 | little,
12 | big
13 | };
14 |
15 |
16 | template
17 | void iLoop(Fn fn)
18 | {
19 | if (byteOrder == ByteOrder::little)
20 | for (std::size_t i = 0; i < n; i++)
21 | fn(i);
22 | else
23 | for (auto i = n; i--;)
24 | fn(i);
25 | }
26 |
27 |
28 | template
29 | void store(T v, void* data)
30 | {
31 | const auto uv = static_cast>(v);
32 | auto* dst = static_cast(data);
33 |
34 | iLoop(
35 | [&](std::size_t i)
36 | {
37 | *dst++ = (uv >> (i * 8)) & 0xff;
38 | });
39 | }
40 |
41 |
42 | template
43 | void load(T& v, const void* data)
44 | {
45 | static_assert(numBytes <= sizeof(T));
46 |
47 | using UT = std::make_unsigned_t;
48 | const auto* src = static_cast(data);
49 |
50 | UT uv{};
51 |
52 | iLoop(
53 | [&](std::size_t i)
54 | {
55 | uv |= static_cast(*src++) << (i * 8);
56 | });
57 |
58 | v = static_cast(uv);
59 | }
60 |
61 |
62 | template
63 | void load(T& v, const void* data)
64 | {
65 | load(v, data);
66 | }
67 |
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/dpso_utils/dpso_utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "error_get.h"
4 | #include "geometry_c.h"
5 | #include "os_c.h"
6 |
--------------------------------------------------------------------------------
/src/dpso_utils/error.cpp:
--------------------------------------------------------------------------------
1 | #include "error_get.h"
2 | #include "error_set.h"
3 |
4 | #include
5 |
6 | #include "str.h"
7 |
8 |
9 | static thread_local std::string error;
10 |
11 |
12 | const char* dpsoGetError(void)
13 | {
14 | return error.c_str();
15 | }
16 |
17 |
18 | namespace dpso {
19 |
20 |
21 | void setError(
22 | const char* fmt, std::initializer_list args)
23 | {
24 | error = str::format(fmt, args);
25 | }
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/dpso_utils/error_get.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * Error message handling for C APIs.
4 | */
5 |
6 | #pragma once
7 |
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 |
14 | /**
15 | * Get the last error message for the current thread.
16 | *
17 | * The message is only applicable when a function signals an error. By
18 | * convention, if a function doesn't explicitly mention dpsoGetError()
19 | * in its documentation, this implies that the function doesn't set an
20 | * error message on failure and dpsoGetError() should not be used.
21 | */
22 | const char* dpsoGetError(void);
23 |
24 |
25 | #ifdef __cplusplus
26 | }
27 | #endif
28 |
--------------------------------------------------------------------------------
/src/dpso_utils/error_set.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "str.h"
4 |
5 |
6 | namespace dpso {
7 |
8 |
9 | // Set an error message to be returned by dpsoGetError().
10 | void setError(
11 | const char* fmt, std::initializer_list args);
12 |
13 |
14 | template
15 | void setError(const char* fmt, const Args&... args)
16 | {
17 | setError(fmt, {str::formatArg::get(args)...});
18 | }
19 |
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/dpso_utils/geometry_c.cpp:
--------------------------------------------------------------------------------
1 | #include "geometry_c.h"
2 |
3 |
4 | bool dpsoRectIsEmpty(const DpsoRect* rect)
5 | {
6 | return !rect || rect->w <= 0 || rect->h <= 0;
7 | }
8 |
--------------------------------------------------------------------------------
/src/dpso_utils/geometry_c.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 |
11 | typedef struct DpsoRect {
12 | int x;
13 | int y;
14 | int w;
15 | int h;
16 | } DpsoRect;
17 |
18 |
19 | /**
20 | * Rect is empty if w or h is <= 0.
21 | */
22 | bool dpsoRectIsEmpty(const DpsoRect* rect);
23 |
24 |
25 | #ifdef __cplusplus
26 | }
27 | #endif
28 |
--------------------------------------------------------------------------------
/src/dpso_utils/line_reader.cpp:
--------------------------------------------------------------------------------
1 | #include "line_reader.h"
2 |
3 | #include
4 |
5 | #include "stream/stream.h"
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | LineReader::LineReader(Stream& stream)
12 | : stream{stream}
13 | , bufFill{}
14 | , bufPos{}
15 | {
16 | }
17 |
18 |
19 | bool LineReader::readLine(std::string& line)
20 | {
21 | line.clear();
22 |
23 | auto wasCr = bufPos > 0 && buf[bufPos - 1] == '\r';
24 |
25 | while (true) {
26 | assert(bufPos <= bufFill);
27 |
28 | if (bufPos == bufFill) {
29 | bufFill = stream.readSome(buf, sizeof(buf));
30 | bufPos = 0;
31 |
32 | if (bufFill == 0)
33 | break;
34 | }
35 |
36 | if (wasCr) {
37 | wasCr = false;
38 | if (buf[bufPos] == '\n') {
39 | ++bufPos;
40 | continue;
41 | }
42 | }
43 |
44 | auto partEnd = bufPos;
45 | for (; partEnd < bufFill; ++partEnd)
46 | if (buf[partEnd] == '\r' || buf[partEnd] == '\n')
47 | break;
48 |
49 | line.append(buf + bufPos, buf + partEnd);
50 | bufPos = partEnd;
51 |
52 | if (bufPos < bufFill) {
53 | ++bufPos;
54 | break;
55 | }
56 | }
57 |
58 | return !line.empty() || bufFill > 0;
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/dpso_utils/line_reader.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso {
8 |
9 |
10 | class Stream;
11 |
12 |
13 | class LineReader {
14 | public:
15 | explicit LineReader(Stream& stream);
16 |
17 | // Read the next line from the stream, terminating on either a
18 | // line break (\r, \n, or \r\n) or the end of the stream. Returns
19 | // false if the line cannot be read because the end of the stream
20 | // is reached.
21 | //
22 | // The function clears the line before performing any action.
23 | //
24 | // Throws StreamError.
25 | bool readLine(std::string& line);
26 | private:
27 | Stream& stream;
28 | char buf[1024];
29 | std::size_t bufFill;
30 | std::size_t bufPos;
31 | };
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/dpso_utils/os_c.cpp:
--------------------------------------------------------------------------------
1 | #include "os_c.h"
2 |
3 | #include
4 | #include
5 |
6 | #include "error_set.h"
7 | #include "os.h"
8 |
9 |
10 | const char* const dpsoDirSeparators = dpso::os::dirSeparators;
11 |
12 |
13 | void dpsoSleep(int milliseconds)
14 | {
15 | std::this_thread::sleep_for(
16 | std::chrono::milliseconds{milliseconds});
17 | }
18 |
19 |
20 | bool dpsoExec(
21 | const char* exePath, const char* const args[], size_t numArgs)
22 | {
23 | try {
24 | dpso::os::exec(exePath, args, numArgs);
25 | return true;
26 | } catch (dpso::os::Error& e) {
27 | dpso::setError("{}", e.what());
28 | return false;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/dpso_utils/os_c.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 |
12 | /**
13 | * Directory separators for the current platform.
14 | *
15 | * The primary separator is first in the list.
16 | */
17 | extern const char* const dpsoDirSeparators;
18 |
19 |
20 | /**
21 | * Block the current thread for the given number of milliseconds.
22 | */
23 | void dpsoSleep(int milliseconds);
24 |
25 |
26 | /**
27 | * Run an executable.
28 | *
29 | * If supported by the platform, exePath may be just the name of the
30 | * executable (e.g., to look up in the PATH environment variable).
31 | *
32 | * The function blocks the caller's thread until the executable exits.
33 | *
34 | * On failure, sets an error message (dpsoGetError()) and returns
35 | * false.
36 | */
37 | bool dpsoExec(
38 | const char* exePath, const char* const args[], size_t numArgs);
39 |
40 |
41 | #ifdef __cplusplus
42 | }
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/dpso_utils/os_stdio.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::os {
7 |
8 |
9 | // fopen() that accepts filePath in UTF-8.
10 | std::FILE* fopen(const char* filePath, const char* mode);
11 |
12 |
13 | // Deleter for a FILE* smart pointer.
14 | struct StdFileCloser {
15 | void operator()(std::FILE* fp) const
16 | {
17 | if (fp)
18 | std::fclose(fp);
19 | }
20 | };
21 |
22 |
23 | using StdFileUPtr = std::unique_ptr;
24 |
25 |
26 | // Synchronize file state with storage device.
27 | //
28 | // The function transfers all modified data (and possibly file
29 | // attributes) to the permanent storage device. It should normally be
30 | // preceded by fflush().
31 | //
32 | // Throws os::Error.
33 | void syncFile(std::FILE* fp);
34 |
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/dpso_utils/scope_exit.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso {
7 |
8 |
9 | template
10 | class ScopeExit {
11 | public:
12 | explicit ScopeExit(Fn&& fn)
13 | : fn{std::move(fn)}
14 | {
15 | }
16 |
17 | ~ScopeExit()
18 | {
19 | fn();
20 | }
21 |
22 | ScopeExit(const ScopeExit&) = delete;
23 | ScopeExit& operator=(const ScopeExit&) = delete;
24 |
25 | ScopeExit(ScopeExit&&) = delete;
26 | ScopeExit& operator=(ScopeExit&&) = delete;
27 | private:
28 | Fn fn;
29 | };
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/dpso_utils/sha256.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 |
9 | namespace dpso {
10 |
11 |
12 | class Sha256 {
13 | public:
14 | static constexpr std::size_t digestSize = 32;
15 | using Digest = std::array;
16 |
17 | void update(const void* data, std::size_t size);
18 | Digest getDigest() const;
19 | private:
20 | class Context {
21 | public:
22 | Context();
23 | void update(const std::uint8_t* data, std::size_t size);
24 | Digest finalize();
25 | private:
26 | static constexpr auto stateSize = 8;
27 | static constexpr auto blockSize = 64;
28 |
29 | std::uint32_t state[stateSize];
30 | std::uint64_t numTransformedBytes;
31 | std::uint8_t buf[blockSize];
32 | std::uint32_t bufLen;
33 |
34 | void transform(const std::uint8_t block[blockSize]);
35 | };
36 |
37 | Context context;
38 | };
39 |
40 |
41 | std::string toHex(const Sha256::Digest& digest);
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/dpso_utils/sha256_file.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso {
8 |
9 |
10 | class Sha256FileError : public std::runtime_error {
11 | using runtime_error::runtime_error;
12 | };
13 |
14 |
15 | extern const char* const sha256FileExt;
16 |
17 |
18 | // Throws Sha256FileError.
19 | std::string calcFileSha256(const char* filePath);
20 |
21 |
22 | // Save the SHA-256 hex digest of the digestSourceFilePath file to the
23 | // associated ".sha256" file (the path of this file is
24 | // digestSourceFilePath + ".sha256").
25 | // Throws Sha256FileError.
26 | void saveSha256File(
27 | const char* digestSourceFilePath, const char* digest);
28 |
29 |
30 | // Load the SHA-256 hex digest previously saved by saveSha256File().
31 | // Returns an empty string if the ".sha256" file for the given file
32 | // does not exist.
33 | // Throws Sha256FileError.
34 | std::string loadSha256File(const char* digestSourceFilePath);
35 |
36 |
37 | // Does nothing if the ".sha256" file for the given file does not
38 | // exist.
39 | // Throws Sha256FileError.
40 | void removeSha256File(const char* digestSourceFilePath);
41 |
42 |
43 | // Get the SHA-256 hex digest of the file from its ".sha256" file,
44 | // creating ".sha256" if it doesn't exist.
45 | //
46 | // The function first tries to load the digest with loadSha256File().
47 | // If the digest file does not exist, the digest is calculated with
48 | // calcFileSha256(), saved with saveSha256File(), and returned.
49 | //
50 | // Throws Sha256FileError.
51 | std::string getSha256HexDigestWithCaching(const char* filePath);
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/dpso_utils/stream/file_stream.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "dpso_utils/stream/stream.h"
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | class FileStream : public Stream {
12 | public:
13 | enum class Mode {
14 | // Open an existing file for reading.
15 | read,
16 |
17 | // Open a file for writing. If the file already exists, it
18 | // will be truncated.
19 | write,
20 |
21 | // Open a file for appending: all write operations will always
22 | // occur at the end of the file. If the file already exists,
23 | // its contents are preserved.
24 | append
25 | };
26 |
27 | // Throws os::Error.
28 | FileStream(const char* fileName, Mode mode);
29 | ~FileStream();
30 |
31 | FileStream(const FileStream&) = delete;
32 | FileStream& operator=(const FileStream&) = delete;
33 |
34 | FileStream(FileStream&&) = delete;
35 | FileStream& operator=(FileStream&&) = delete;
36 |
37 | std::size_t readSome(void* dst, std::size_t dstSize) override;
38 |
39 | void write(const void* src, std::size_t srcSize) override;
40 |
41 | // Synchronize the file state with the storage device.
42 | //
43 | // Throws os::Error.
44 | void sync();
45 | private:
46 | struct Impl;
47 | std::unique_ptr impl;
48 | };
49 |
50 |
51 | const char* toStr(FileStream::Mode mode);
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/dpso_utils/stream/out_newline_conversion_stream.cpp:
--------------------------------------------------------------------------------
1 | #include "stream/out_newline_conversion_stream.h"
2 |
3 | #include
4 |
5 | #include "os.h"
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | OutNewlineConversionStream::OutNewlineConversionStream(
12 | Stream& base, const char* newline)
13 | : base{base}
14 | , newline{newline ? newline : os::newline}
15 | {
16 | }
17 |
18 |
19 | std::size_t OutNewlineConversionStream::readSome(
20 | void* dst, std::size_t dstSize)
21 | {
22 | return base.readSome(dst, dstSize);
23 | }
24 |
25 |
26 | static bool isLf(char c)
27 | {
28 | return c == '\n';
29 | }
30 |
31 |
32 | void OutNewlineConversionStream::write(
33 | const void* src, std::size_t srcSize)
34 | {
35 | if (newline.size() == 1 && isLf(newline[0])) {
36 | base.write(src, srcSize);
37 | return;
38 | }
39 |
40 | const auto* s = static_cast(src);
41 | const auto* sEnd = s + srcSize;
42 |
43 | while (s < sEnd) {
44 | const auto* lfsBegin = std::find_if(s, sEnd, isLf);
45 | base.write(s, lfsBegin - s);
46 |
47 | const auto* lfsEnd = std::find_if_not(lfsBegin, sEnd, isLf);
48 |
49 | if (!newline.empty())
50 | for (auto i = lfsEnd - lfsBegin; i--;)
51 | base.write(newline.data(), newline.size());
52 |
53 | s = lfsEnd;
54 | }
55 | }
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/dpso_utils/stream/out_newline_conversion_stream.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "dpso_utils/stream/stream.h"
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | // A stream that replaces all line feeds (\n) with the given newline
12 | // string when writing. Does no conversion when reading.
13 | class OutNewlineConversionStream : public Stream {
14 | public:
15 | // The newline can be any string. If null, the native newline for
16 | // the current platform is used.
17 | explicit OutNewlineConversionStream(
18 | Stream& base, const char* newline = nullptr);
19 |
20 | std::size_t readSome(void* dst, std::size_t dstSize) override;
21 | void write(const void* src, std::size_t srcSize) override;
22 | private:
23 | Stream& base;
24 | std::string newline;
25 | };
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/dpso_utils/stream/stream.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso {
8 |
9 |
10 | class StreamError : public std::runtime_error {
11 | using runtime_error::runtime_error;
12 | };
13 |
14 |
15 | class Stream {
16 | public:
17 | virtual ~Stream() = default;
18 |
19 | // Read up to dstSize bytes from the stream. Returns the number of
20 | // bytes read, which may be less than dstSize if the end of the
21 | // stream is reached.
22 | //
23 | // Throws StreamError.
24 | virtual std::size_t readSome(void* dst, std::size_t dstSize) = 0;
25 |
26 | // Throws StreamError.
27 | virtual void write(const void* src, std::size_t srcSize) = 0;
28 | };
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/dpso_utils/stream/string_stream.cpp:
--------------------------------------------------------------------------------
1 | #include "stream/string_stream.h"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | StringStream::StringStream(const char* str)
12 | : str{str}
13 | {
14 | }
15 |
16 |
17 | StringStream::StringStream(StringStream&& other) noexcept
18 | {
19 | *this = std::move(other);
20 | }
21 |
22 |
23 | StringStream& StringStream::operator=(StringStream&& other) noexcept
24 | {
25 | if (this != &other) {
26 | str = std::exchange(other.str, {});
27 | pos = std::exchange(other.pos, {});
28 | }
29 |
30 | return *this;
31 | }
32 |
33 |
34 | const std::string& StringStream::getStr() const
35 | {
36 | return str;
37 | }
38 |
39 |
40 | std::string StringStream::takeStr()
41 | {
42 | pos = 0;
43 | return std::exchange(str, {});
44 | }
45 |
46 |
47 | std::size_t StringStream::readSome(void* dst, std::size_t dstSize)
48 | {
49 | assert(pos <= str.size());
50 | const auto numRead = std::min(dstSize, str.size() - pos);
51 |
52 | std::copy_n(str.data() + pos, numRead, static_cast(dst));
53 | pos += numRead;
54 |
55 | return numRead;
56 | }
57 |
58 |
59 | void StringStream::write(const void* src, std::size_t srcSize)
60 | {
61 | str.resize(std::max(pos + srcSize, str.size()));
62 | std::copy_n(
63 | static_cast(src), srcSize, str.data() + pos);
64 | pos += srcSize;
65 | }
66 |
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/dpso_utils/stream/string_stream.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include "dpso_utils/stream/stream.h"
7 |
8 |
9 | namespace dpso {
10 |
11 |
12 | class StringStream : public Stream {
13 | public:
14 | StringStream() = default;
15 |
16 | // Construct the stream with initial data. The stream position
17 | // will be 0.
18 | explicit StringStream(const char* str);
19 | ~StringStream() = default;
20 |
21 | StringStream(const StringStream&) = default;
22 | StringStream& operator=(const StringStream&) = default;
23 |
24 | StringStream(StringStream&& other) noexcept;
25 | StringStream& operator=(StringStream&& other) noexcept;
26 |
27 | const std::string& getStr() const;
28 | std::string takeStr();
29 |
30 | std::size_t readSome(void* dst, std::size_t dstSize) override;
31 | void write(const void* src, std::size_t srcSize) override;
32 | private:
33 | std::string str;
34 | std::size_t pos{};
35 | };
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/dpso_utils/stream/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "stream/utils.h"
2 |
3 | #include
4 |
5 | #include "stream/stream.h"
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | void read(Stream& stream, void* dst, std::size_t dstSize)
12 | {
13 | if (stream.readSome(dst, dstSize) != dstSize)
14 | throw StreamError{"Unexpected end of stream"};
15 | }
16 |
17 |
18 | void write(Stream& stream, const std::string& str)
19 | {
20 | stream.write(str.data(), str.size());
21 | }
22 |
23 |
24 | void write(Stream& stream, const char* str)
25 | {
26 | stream.write(str, std::strlen(str));
27 | }
28 |
29 |
30 | void write(Stream& stream, char c)
31 | {
32 | stream.write(&c, 1);
33 | }
34 |
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/dpso_utils/stream/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso {
8 |
9 |
10 | class Stream;
11 |
12 |
13 | // Read the given number of bytes from a stream. Throws StreamError.
14 | void read(Stream& stream, void* dst, std::size_t dstSize);
15 |
16 |
17 | // Write data to a stream. Throws StreamError.
18 | void write(Stream& stream, const std::string& str);
19 | void write(Stream& stream, const char* str);
20 | void write(Stream& stream, char c);
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/dpso_utils/strftime.cpp:
--------------------------------------------------------------------------------
1 | #include "strftime.h"
2 |
3 |
4 | namespace dpso {
5 |
6 |
7 | std::string strftime(const char* fmt, const std::tm* time)
8 | {
9 | // strftime() does not set errno if the destination buffer is too
10 | // small, making it impossible to distinguish this error from
11 | // cases when the result string is empty (for example, %p yields
12 | // an empty string in many locales). As a workaround, we append an
13 | // extra character to the format string, and then remove it from
14 | // the result before returning.
15 | const auto fmtEx = std::string{fmt} + ' ';
16 |
17 | std::string result;
18 |
19 | while (true) {
20 | // Try to detect the case when strftime() on the current
21 | // system always returns 0 for the given format string, e.g.
22 | // due to unsupported format specifiers.
23 | if (result.size() > fmtEx.size() * 100)
24 | return fmt;
25 |
26 | result.reserve(result.size() + 8);
27 | result.resize(result.capacity());
28 |
29 | const auto numWritten = std::strftime(
30 | result.data(), result.size(), fmtEx.c_str(), time);
31 | if (numWritten == 0)
32 | continue;
33 |
34 | result.resize(numWritten - 1);
35 | break;
36 | }
37 |
38 | return result;
39 | }
40 |
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/dpso_utils/strftime.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso {
8 |
9 |
10 | #if defined(__GNUC__) || defined(__clang__)
11 | /* Old MinGW versions don't define __MINGW_STRFTIME_FORMAT. */
12 | #if defined(__MINGW32__) && defined(__MINGW_STRFTIME_FORMAT)
13 | #define DPSO_STRFTIME_FN(N) \
14 | __attribute__((format(__MINGW_STRFTIME_FORMAT, N, 0)))
15 | #else
16 | #define DPSO_STRFTIME_FN(N) \
17 | __attribute__((format(strftime, N, 0)))
18 | #endif
19 | #else
20 | #define DPSO_STRFTIME_FN(N)
21 | #endif
22 |
23 |
24 | std::string strftime(
25 | const char* fmt, const std::tm* time) DPSO_STRFTIME_FN(1);
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/dpso_utils/timing.cpp:
--------------------------------------------------------------------------------
1 | #include "timing.h"
2 |
3 |
4 | #if DPSO_FORCE_TIMING || !defined(NDEBUG)
5 |
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | #include "str.h"
12 |
13 |
14 | namespace dpso::timing {
15 |
16 |
17 | float getTime()
18 | {
19 | using Clock = std::chrono::steady_clock;
20 | using FloatMs = std::chrono::duration;
21 |
22 | return FloatMs{Clock::now().time_since_epoch()}.count();
23 | }
24 |
25 |
26 | void report(
27 | float startTime,
28 | const char* fmt,
29 | std::initializer_list args)
30 | {
31 | const auto duration = getTime() - startTime;
32 |
33 | std::fputs("Timing: ", stdout);
34 | std::fputs(str::format(fmt, args).c_str(), stdout);
35 | std::fputs(str::format(": {} ms\n", duration).c_str(), stdout);
36 |
37 | std::fflush(stdout);
38 | }
39 |
40 |
41 | }
42 |
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/src/dpso_utils/timing.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #if DPSO_FORCE_TIMING || !defined(NDEBUG)
5 |
6 | #include "str.h"
7 |
8 |
9 | namespace dpso::timing {
10 |
11 |
12 | float getTime();
13 |
14 | void report(
15 | float startTime,
16 | const char* fmt,
17 | std::initializer_list args);
18 |
19 | template
20 | void report(float startTime, const char* fmt, const Args&... args)
21 | {
22 | report(startTime, fmt, {str::formatArg::get(args)...});
23 | }
24 |
25 |
26 | }
27 |
28 |
29 | #define DPSO_START_TIMING(name) \
30 | const float name ## TimingStartTime = dpso::timing::getTime();
31 |
32 | #define DPSO_END_TIMING(name, fmt, ...) \
33 | dpso::timing::report(name ## TimingStartTime, fmt, __VA_ARGS__)
34 |
35 |
36 | #else
37 |
38 |
39 | #define DPSO_START_TIMING(name)
40 | #define DPSO_END_TIMING(name, fmt, ...)
41 |
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/dpso_utils/unix/dl.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 |
7 |
8 | namespace dpso::unix {
9 |
10 |
11 | struct DlHandleCloser {
12 | void operator()(void* handle) const
13 | {
14 | if (handle)
15 | dlclose(handle);
16 | }
17 | };
18 |
19 |
20 | using DlHandleUPtr = std::unique_ptr;
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/dpso_utils/unix/exe_path.cpp:
--------------------------------------------------------------------------------
1 | #include "unix/exe_path.h"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "os.h"
8 | #include "str.h"
9 | #include "unix/path_env_search.h"
10 |
11 |
12 | namespace dpso::unix {
13 |
14 |
15 | std::string getExePath(const char* name)
16 | {
17 | std::string path;
18 |
19 | if (strchr(name, '/'))
20 | path = name;
21 | else {
22 | path = findInPathEnv(name);
23 | if (path.empty())
24 | throw os::Error{str::format(
25 | "Can't find \"{}\" in $PATH", name)};
26 | }
27 |
28 | auto* realPath = realpath(path.c_str(), nullptr);
29 | if (!realPath)
30 | throw os::Error{str::format(
31 | "realpath(\"{}\"): {}", path, os::getErrnoMsg(errno))};
32 |
33 | std::string result = realPath;
34 | free(realPath);
35 |
36 | return result;
37 | }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/dpso_utils/unix/exe_path.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::unix {
7 |
8 |
9 | // Return a canonical absolute path of the given executable. The name
10 | // can be either a basename (to be searched in $PATH) or a path
11 | // (absolute or relative). Throws os::Error.
12 | std::string getExePath(const char* name);
13 |
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/dpso_utils/unix/path_env_search.cpp:
--------------------------------------------------------------------------------
1 | #include "unix/path_env_search.h"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 |
8 | namespace dpso::unix {
9 |
10 |
11 | std::string findInPathEnv(const char* name)
12 | {
13 | if (strchr(name, '/'))
14 | return {};
15 |
16 | const auto* p = getenv("PATH");
17 | if (!p || !*p)
18 | return {};
19 |
20 | std::string path;
21 | while (true) {
22 | const auto* pathBegin = p;
23 | while (*p && *p != ':')
24 | ++p;
25 | const auto* pathEnd = p;
26 |
27 | path.assign(pathBegin, pathEnd);
28 |
29 | // An empty path is a legacy feature indicating the current
30 | // working directory. It can appear as two colons in the
31 | // middle of the list, as well a colon at the beginning or end
32 | // of the list.
33 | if (!path.empty() && path.back() != '/')
34 | path += '/';
35 |
36 | path += name;
37 |
38 | if (access(path.c_str(), X_OK) == 0)
39 | return path;
40 |
41 | if (!*p)
42 | break;
43 |
44 | ++p;
45 | }
46 |
47 | return {};
48 | }
49 |
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/dpso_utils/unix/path_env_search.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::unix {
7 |
8 |
9 | // Search for the given executable in the paths from the PATH
10 | // environment variable. Returns an empty string if the executable is
11 | // not found, or if the executable name contains slashes.
12 | std::string findInPathEnv(const char* name);
13 |
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/dpso_utils/unix/xdg_dirs.cpp:
--------------------------------------------------------------------------------
1 | #include "unix/xdg_dirs.h"
2 |
3 | #include
4 | #include
5 |
6 | #include "os.h"
7 | #include "str.h"
8 |
9 |
10 | namespace dpso::unix {
11 |
12 |
13 | const char* toStr(XdgDir dir)
14 | {
15 | #define CASE(DIR) case DIR: return #DIR
16 |
17 | switch (dir) {
18 | CASE(XdgDir::dataHome);
19 | CASE(XdgDir::configHome);
20 | }
21 |
22 | #undef CASE
23 |
24 | assert(false);
25 | return "";
26 | }
27 |
28 |
29 | static std::string getDir(
30 | const char* xdgHomeEnv, const char* homeFallbackDir)
31 | {
32 | if (const auto* xdgHome = std::getenv(xdgHomeEnv);
33 | // According to the specification, a XDG_*_HOME variable:
34 | // * Should be treated as unset if empty
35 | // * Invalid if contains a relative path
36 | xdgHome && *xdgHome == '/')
37 | return xdgHome;
38 |
39 | if (const auto* home = std::getenv("HOME"))
40 | return std::string{home} + '/' + homeFallbackDir;
41 |
42 | throw os::Error{str::format(
43 | "Neither {} nor HOME environment variable is set",
44 | xdgHomeEnv)};
45 | }
46 |
47 |
48 | std::string getXdgDirPath(XdgDir dir)
49 | {
50 | switch (dir) {
51 | case XdgDir::dataHome:
52 | return getDir("XDG_DATA_HOME", ".local/share");
53 | case XdgDir::configHome:
54 | return getDir("XDG_CONFIG_HOME", ".config");
55 | }
56 |
57 | assert(false);
58 | return {};
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/dpso_utils/unix/xdg_dirs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace dpso::unix {
7 |
8 |
9 | enum class XdgDir {
10 | dataHome,
11 | configHome
12 | };
13 |
14 |
15 | const char* toStr(XdgDir dir);
16 |
17 |
18 | // Return an absolute path of a directory defined by XDG Base
19 | // Directory Specification:
20 | // https://specifications.freedesktop.org/basedir-spec/latest/
21 | // Throws os::Error if neither a corresponding XDG_* nor HOME
22 | // environment variable is set.
23 | std::string getXdgDirPath(XdgDir dir);
24 |
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/dpso_utils/version_cmp.cpp:
--------------------------------------------------------------------------------
1 | #include "version_cmp.h"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 |
8 | namespace dpso {
9 |
10 |
11 | VersionCmp::VersionCmp(const char* str)
12 | {
13 | const auto* s = str;
14 | const auto* sEnd = s + std::strlen(s);
15 |
16 | while (s < sEnd) {
17 | // Use unsigned so that from_chars() doesn't accept the minus
18 | // sign.
19 | unsigned num;
20 | const auto [end, ec] = std::from_chars(s, sEnd, num);
21 | if (ec != std::errc{}) {
22 | if (s > str) {
23 | // Make the preceding period a part of the extra
24 | // string.
25 | --s;
26 | assert(!nums.empty());
27 | assert(*s == '.');
28 | }
29 |
30 | break;
31 | }
32 |
33 | nums.push_back(num);
34 |
35 | s = end;
36 |
37 | if (*s == '.')
38 | ++s;
39 | else
40 | break;
41 | }
42 |
43 | extra = s;
44 | }
45 |
46 |
47 | bool VersionCmp::operator<(const VersionCmp& other) const
48 | {
49 | if (nums < other.nums)
50 | return true;
51 |
52 | if (nums > other.nums)
53 | return false;
54 |
55 | // 1.0-rc1 < 1.0
56 | if (!extra.empty() && other.extra.empty())
57 | return true;
58 |
59 | // 1.0 > 1.0-rc1
60 | if (extra.empty() && !other.extra.empty())
61 | return false;
62 |
63 | // 1.0-rc1 < 1.0-rc2
64 | return extra < other.extra;
65 | }
66 |
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/dpso_utils/version_cmp.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso {
8 |
9 |
10 | // A helper to compare version strings.
11 | //
12 | // A version string can contain zero or more numbers separated by
13 | // periods, and an optional trailing text. Leading zeros in numbers
14 | // are ignored. Trailing texts are compared lexicographically, but a
15 | // version with extra text is considered to be less than the same
16 | // version without extra text. For example:
17 | //
18 | // 1.0-rc1 < 1.0-rc2 < 1.0
19 | class VersionCmp {
20 | public:
21 | VersionCmp() = default;
22 | explicit VersionCmp(const char* str);
23 |
24 | bool operator<(const VersionCmp& other) const;
25 | private:
26 | std::vector nums;
27 | std::string extra;
28 | };
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/dpso_utils/windows/cmdline.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso::windows {
8 |
9 |
10 | // Create a command line using CommandLineToArgv() rules.
11 | //
12 | // Note that on Windows the program name is parsed differently from
13 | // the other parameters, and therefore comes as a separate programName
14 | // argument in this function. If you need to build the command-line
15 | // arguments without the program name (for example, to be used as
16 | // lpCommandLine for CreateProcess() when lpApplicationName is not
17 | // null), leave programName empty.
18 | std::string createCmdLine(
19 | const char* programName,
20 | const char* const* args, std::size_t numArgs);
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/dpso_utils/windows/error.cpp:
--------------------------------------------------------------------------------
1 | #include "windows/error.h"
2 |
3 | #include "str.h"
4 |
5 |
6 | namespace dpso::windows {
7 |
8 |
9 | std::string getErrorMessage(DWORD error, HMODULE module)
10 | {
11 | char* messageBuf{};
12 | auto size = FormatMessageA(
13 | FORMAT_MESSAGE_ALLOCATE_BUFFER
14 | | (module ? FORMAT_MESSAGE_FROM_HMODULE : 0)
15 | | FORMAT_MESSAGE_FROM_SYSTEM
16 | | FORMAT_MESSAGE_IGNORE_INSERTS,
17 | module,
18 | error,
19 | MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
20 | reinterpret_cast(&messageBuf),
21 | 0, nullptr);
22 |
23 | if (size == 0)
24 | return str::format("Windows error {}", error);
25 |
26 | if (size > 1
27 | && messageBuf[size - 2] == '\r'
28 | && messageBuf[size - 1] == '\n')
29 | size -= 2;
30 |
31 | std::string message{messageBuf, size};
32 |
33 | LocalFree(messageBuf);
34 |
35 | return message;
36 | }
37 |
38 |
39 | std::string getHresultMessage(HRESULT hresult)
40 | {
41 | // It seems that FormatMessage() accepts HRESULT, at least
42 | // _com_error::ErrorMessage() relies on that. Still, this is not
43 | // documented, so we extract the system error code manually.
44 | if (HRESULT_FACILITY(hresult) == FACILITY_WIN32)
45 | return getErrorMessage(HRESULT_CODE(hresult));
46 |
47 | return
48 | "HRESULT 0x"
49 | + str::rightJustify(str::toStr(hresult, 16), 8, '0');
50 | }
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/dpso_utils/windows/error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #define WIN32_LEAN_AND_MEAN
6 | #include
7 |
8 |
9 | namespace dpso::windows {
10 |
11 |
12 | std::string getErrorMessage(DWORD error, HMODULE module = {});
13 | std::string getHresultMessage(HRESULT hresult);
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/dpso_utils/windows/module.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #define WIN32_LEAN_AND_MEAN
6 | #include
7 |
8 |
9 | namespace dpso::windows {
10 |
11 |
12 | struct LibraryFreer {
13 | using pointer = HMODULE;
14 |
15 | void operator()(HMODULE module) const
16 | {
17 | FreeLibrary(module);
18 | }
19 | };
20 |
21 |
22 | using ModuleUPtr = std::unique_ptr;
23 |
24 |
25 | // We use an intermediate cast to void* to silence GCC warnings about
26 | // converting FARPROC to an incompatible function type.
27 | #define DPSO_WIN_DLL_FN(MODULE, NAME, SIGN) \
28 | auto NAME ## Fn = (SIGN)(void*)GetProcAddress(MODULE, #NAME)
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/dpso_utils/windows/utf.cpp:
--------------------------------------------------------------------------------
1 | #include "windows/utf.h"
2 |
3 | #define WIN32_LEAN_AND_MEAN
4 | #include
5 |
6 | #include "windows/error.h"
7 |
8 |
9 | namespace dpso::windows {
10 |
11 |
12 | static int utf8ToUtf16(const char* utf8Str, wchar_t* dst, int dstSize)
13 | {
14 | const auto sizeWithNull = MultiByteToWideChar(
15 | CP_UTF8, MB_ERR_INVALID_CHARS, utf8Str, -1, dst, dstSize);
16 | if (sizeWithNull <= 0)
17 | throw CharConversionError(getErrorMessage(GetLastError()));
18 |
19 | return sizeWithNull;
20 | }
21 |
22 |
23 | std::wstring utf8ToUtf16(const char* utf8Str)
24 | {
25 | const auto sizeWithNull = utf8ToUtf16(utf8Str, nullptr, 0);
26 | std::wstring result(sizeWithNull - 1, 0);
27 | utf8ToUtf16(utf8Str, result.data(), sizeWithNull);
28 | return result;
29 | }
30 |
31 |
32 | static int utf16ToUtf8(
33 | const wchar_t* utf16Str, char* dst, int dstSize)
34 | {
35 | const auto sizeWithNull = WideCharToMultiByte(
36 | CP_UTF8, WC_ERR_INVALID_CHARS,
37 | utf16Str, -1,
38 | dst, dstSize,
39 | nullptr, nullptr);
40 | if (sizeWithNull <= 0)
41 | throw CharConversionError(getErrorMessage(GetLastError()));
42 |
43 | return sizeWithNull;
44 | }
45 |
46 |
47 | std::string utf16ToUtf8(const wchar_t* utf16Str)
48 | {
49 | const auto sizeWithNull = utf16ToUtf8(utf16Str, nullptr, 0);
50 | std::string result(sizeWithNull - 1, 0);
51 | utf16ToUtf8(utf16Str, result.data(), sizeWithNull);
52 | return result;
53 | }
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/dpso_utils/windows/utf.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 |
7 | namespace dpso::windows {
8 |
9 |
10 | class CharConversionError : public std::runtime_error {
11 | using runtime_error::runtime_error;
12 | };
13 |
14 |
15 | // Throws CharConversionError on invalid UTF-8 sequence.
16 | std::wstring utf8ToUtf16(const char* utf8Str);
17 |
18 |
19 | // Throws CharConversionError on invalid UTF-16 sequence.
20 | std::string utf16ToUtf8(const wchar_t* utf16Str);
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/dpso_utils/windows/window.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #define WIN32_LEAN_AND_MEAN
6 | #include
7 |
8 |
9 | namespace dpso::windows {
10 |
11 |
12 | struct WindowDestroyer {
13 | using pointer = HWND;
14 |
15 | void operator()(HWND window) const
16 | {
17 | DestroyWindow(window);
18 | }
19 | };
20 |
21 |
22 | using WindowUPtr = std::unique_ptr;
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/thirdparty/stb_image_resize2/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(stb_image_resize2 STATIC stb_image_resize2.c)
2 | target_include_directories(stb_image_resize2 PUBLIC .)
3 |
--------------------------------------------------------------------------------
/src/thirdparty/stb_image_resize2/stb_image_resize2.c:
--------------------------------------------------------------------------------
1 | // AVX2 is available since 2013, so disable it in case someone runs
2 | // our binaries on an older hardware.
3 | #define STBIR_NO_AVX2
4 |
5 | #define STB_IMAGE_RESIZE_IMPLEMENTATION
6 | #include "stb_image_resize2.h"
7 |
--------------------------------------------------------------------------------
/src/ui/qt/about.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | class QTextEdit;
7 |
8 |
9 | namespace ui::qt {
10 |
11 |
12 | class About : public QWidget {
13 | Q_OBJECT
14 | public:
15 | About();
16 | signals:
17 | void checkUpdates();
18 | private slots:
19 | void handleLinkActivation(const QString &link);
20 | void handleLinkHover(const QString &link);
21 | private:
22 | QString currentTextLink;
23 | QTextEdit* textEdit;
24 | };
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/ui/qt/action_chooser.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "dpso_ext/dpso_ext.h"
8 |
9 |
10 | class QCheckBox;
11 | class QLineEdit;
12 |
13 |
14 | namespace ui::qt {
15 |
16 |
17 | class ActionChooser : public QWidget {
18 | Q_OBJECT
19 | public:
20 | enum Action {
21 | none = 0,
22 | copyToClipboard = 1 << 0,
23 | addToHistory = 1 << 1,
24 | runExe = 1 << 2
25 | };
26 |
27 | Q_DECLARE_FLAGS(Actions, Action)
28 |
29 | ActionChooser();
30 |
31 | Actions getSelectedActions() const;
32 | const char* getExePath() const;
33 |
34 | void loadState(const DpsoCfg* cfg);
35 | void saveState(DpsoCfg* cfg) const;
36 | signals:
37 | void actionsChanged();
38 | private slots:
39 | void chooseExe();
40 | private:
41 | QCheckBox* copyToClipboardCheck;
42 | QCheckBox* addToHistoryCheck;
43 | QCheckBox* runExeCheck;
44 | QLineEdit* exeLineEdit;
45 | QByteArray exePath;
46 | };
47 |
48 | Q_DECLARE_OPERATORS_FOR_FLAGS(ActionChooser::Actions)
49 |
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/ui/qt/error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace ui::qt {
7 |
8 |
9 | class Error : public std::runtime_error {
10 | using runtime_error::runtime_error;
11 | };
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/ui/qt/history.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "dpso_ext/dpso_ext.h"
10 |
11 |
12 | class QPushButton;
13 | class QTextEdit;
14 |
15 |
16 | namespace ui::qt {
17 |
18 |
19 | class History : public QWidget {
20 | Q_OBJECT
21 | public:
22 | explicit History(const std::string& dirPath);
23 |
24 | void append(const char* timestamp, const char* text);
25 |
26 | void loadState(const DpsoCfg* cfg);
27 | void saveState(DpsoCfg* cfg) const;
28 | private slots:
29 | void doExport();
30 | void clear();
31 | private:
32 | std::string historyFilePath;
33 | dpso::HistoryUPtr history;
34 |
35 | bool wrapWords{};
36 |
37 | QTextEdit* textEdit;
38 | QTextCharFormat charFormat;
39 | QTextBlockFormat blockFormat;
40 | int blockMargin{};
41 |
42 | QPushButton* exportButton;
43 | QPushButton* clearButton;
44 |
45 | QString lastDirPath;
46 | QString lastFileName;
47 | QString selectedNameFilter;
48 |
49 | void setButtonsEnabled(bool enabled);
50 | void appendToTextEdit(const char* timestamp, const char* text);
51 | };
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_browser.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "dpso_ext/dpso_ext.h"
6 | #include "dpso_ocr/dpso_ocr.h"
7 |
8 |
9 | class QTreeWidgetItem;
10 |
11 |
12 | namespace ui::qt {
13 |
14 |
15 | class LangBrowser : public QTreeWidget {
16 | Q_OBJECT
17 | public:
18 | explicit LangBrowser(DpsoOcr* ocr);
19 |
20 | void reloadLangs();
21 |
22 | void loadState(const DpsoCfg* cfg);
23 | void saveState(DpsoCfg* cfg) const;
24 | private slots:
25 | void updateLangState(QTreeWidgetItem* item, int column);
26 | void selectCheckboxColumn(QTreeWidgetItem* current);
27 | private:
28 | DpsoOcr* ocr;
29 | };
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/install_mode.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace ui::qt::langManager {
5 |
6 |
7 | // The installation and update are the same in terms of the language
8 | // manager API. We use this enum when we need to parameterize widgets
9 | // that work with installation and therefore only differ visually,
10 | // e.g. showing different text depending on the mode.
11 | enum class InstallMode {
12 | install,
13 | update
14 | };
15 |
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/install_progress_dialog.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "dpso_ocr/dpso_ocr.h"
4 |
5 | #include "lang_manager/install_mode.h"
6 |
7 |
8 | class QWidget;
9 |
10 |
11 | namespace ui::qt::langManager {
12 |
13 |
14 | void runInstallProgressDialog(
15 | QWidget* parent,
16 | DpsoOcrLangManager* langManager,
17 | InstallMode installMode);
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/lang_list.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include "dpso_ocr/dpso_ocr.h"
7 |
8 |
9 | namespace ui::qt::langManager {
10 |
11 |
12 | class LangList : public QAbstractTableModel {
13 | Q_OBJECT
14 | public:
15 | enum {
16 | columnIdxName,
17 | columnIdxCode,
18 | columnIdxState,
19 | columnIdxExternalSize,
20 | columnIdxLocalSize,
21 | };
22 |
23 | explicit LangList(
24 | DpsoOcrLangManager* langManager, QObject* parent = nullptr);
25 |
26 | DpsoOcrLangManager* getLangManager();
27 |
28 | void reloadLangs();
29 |
30 | QVariant data(
31 | const QModelIndex& index,
32 | int role = Qt::DisplayRole) const override;
33 |
34 | QVariant headerData(
35 | int section,
36 | Qt::Orientation orientation,
37 | int role = Qt::DisplayRole) const override;
38 |
39 | int rowCount(
40 | const QModelIndex& parent = QModelIndex()) const override;
41 |
42 | int columnCount(
43 | const QModelIndex& parent = QModelIndex()) const override;
44 | private:
45 | DpsoOcrLangManager* langManager;
46 |
47 | struct LangInfo {
48 | QString name;
49 | QString code;
50 | DpsoOcrLangState state;
51 | DpsoOcrLangSize size;
52 | };
53 | QList langInfos;
54 | };
55 |
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/lang_list_sort_filter_proxy.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace ui::qt::langManager {
7 |
8 |
9 | class LangListSortFilterProxy : public QSortFilterProxyModel {
10 | Q_OBJECT
11 | public:
12 | enum {
13 | columnIdxName,
14 | columnIdxCode,
15 | columnIdxSize,
16 | };
17 |
18 | enum class LangGroup {
19 | installable,
20 | updatable,
21 | removable
22 | };
23 |
24 | explicit LangListSortFilterProxy(
25 | LangGroup langGroup, QObject* parent = nullptr);
26 |
27 | QVariant headerData(
28 | int section,
29 | Qt::Orientation orientation,
30 | int role = Qt::DisplayRole) const override;
31 | public slots:
32 | void setFilterText(const QString& newFilterText);
33 | protected:
34 | bool filterAcceptsColumn(
35 | int sourceColumn,
36 | const QModelIndex& sourceParent) const override;
37 |
38 | bool filterAcceptsRow(
39 | int sourceRow,
40 | const QModelIndex& sourceParent) const override;
41 |
42 | bool lessThan(
43 | const QModelIndex& sourceLeft,
44 | const QModelIndex& sourceRight) const override;
45 | private:
46 | LangGroup langGroup;
47 | QString filterText;
48 | };
49 |
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/lang_manager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | class QWidget;
7 |
8 |
9 | namespace ui::qt::langManager {
10 |
11 |
12 | void runLangManager(QWidget* parent, int ocrEngineIdx);
13 |
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/lang_manager_page.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | class QWidget;
5 |
6 |
7 | namespace ui::qt::langManager {
8 |
9 |
10 | class LangList;
11 |
12 |
13 | QWidget* createLangManagerInstallPage(LangList& langList);
14 | QWidget* createLangManagerUpdatePage(LangList& langList);
15 | QWidget* createLangManagerRemovePage(LangList& langList);
16 |
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/lang_op_status_error.cpp:
--------------------------------------------------------------------------------
1 | #include "lang_manager/lang_op_status_error.h"
2 |
3 | #include
4 |
5 | #include "dpso_intl/dpso_intl.h"
6 |
7 | #include "utils.h"
8 |
9 |
10 | #define _(S) gettext(S)
11 |
12 |
13 | namespace ui::qt::langManager {
14 |
15 |
16 | void showLangOpStatusError(
17 | QWidget* parent,
18 | const QString& text,
19 | const DpsoOcrLangOpStatus& status)
20 | {
21 | QString informativeText;
22 |
23 | switch (status.code) {
24 | case DpsoOcrLangOpStatusCodeNone:
25 | case DpsoOcrLangOpStatusCodeProgress:
26 | case DpsoOcrLangOpStatusCodeSuccess:
27 | return;
28 | case DpsoOcrLangOpStatusCodeGenericError:
29 | break;
30 | case DpsoOcrLangOpStatusCodeNetworkConnectionError:
31 | informativeText =
32 | _("Check your network connection and try again.");
33 | break;
34 | }
35 |
36 | showError(parent, text, informativeText, status.errorText);
37 | }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/lang_op_status_error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "dpso_ocr/dpso_ocr.h"
4 |
5 |
6 | class QString;
7 | class QWidget;
8 |
9 |
10 | namespace ui::qt::langManager {
11 |
12 |
13 | // Does nothing if the status code is not an error.
14 | void showLangOpStatusError(
15 | QWidget* parent,
16 | const QString& text,
17 | const DpsoOcrLangOpStatus& status);
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/ui/qt/lang_manager/metatypes.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "dpso_ocr/dpso_ocr.h"
6 |
7 |
8 | Q_DECLARE_METATYPE(DpsoOcrLangState)
9 |
--------------------------------------------------------------------------------
/src/ui/qt/status.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace ui::qt {
5 |
6 |
7 | enum class Status {
8 | ok,
9 | busy,
10 | error
11 | };
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/ui/qt/status_indicator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "status.h"
6 |
7 |
8 | namespace ui::qt {
9 |
10 |
11 | class StatusIndicator: public QWidget {
12 | Q_OBJECT
13 | public:
14 | void setStatus(Status newStatus);
15 |
16 | QSize minimumSizeHint() const override;
17 | QSize sizeHint() const override;
18 | protected:
19 | void paintEvent(QPaintEvent* event) override;
20 | private:
21 | Status status{};
22 | };
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/ui/qt/update_checker.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "dpso_ext/dpso_ext.h"
10 | #include "ui_common/ui_common.h"
11 |
12 |
13 | class QWidget;
14 |
15 |
16 | namespace ui::qt {
17 |
18 |
19 | class UpdateChecker : public QObject {
20 | Q_OBJECT
21 | public:
22 | // UpdateChecker will not display an update info window while a
23 | // modal or popup widget is active. The isBusy() function allows
24 | // you to add additional checks for this case.
25 | explicit UpdateChecker(
26 | QWidget* parent, const std::function& isBusy = {});
27 |
28 | bool getAutoCheckIsEnabled() const;
29 | int getAutoCheckIntervalDays() const;
30 |
31 | void loadState(const DpsoCfg* cfg);
32 | void saveState(DpsoCfg* cfg) const;
33 | public slots:
34 | void setAutoCheckIsEnabled(bool isEnabled);
35 | void checkUpdates();
36 | protected:
37 | void timerEvent(QTimerEvent* event) override;
38 | private:
39 | QWidget* parentWidget;
40 | std::function isBusy;
41 | int timerId{};
42 | UpdateCheckerUPtr autoChecker;
43 | bool autoCheck{};
44 | int autoCheckIntervalDays{};
45 | std::optional lastCheckTime;
46 |
47 | void handleAutoCheck();
48 | void stopAutoCheck();
49 | };
50 |
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/ui/qt/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "ui_common/ui_common.h"
6 |
7 | #include
8 |
9 |
10 | class QFont;
11 | class QMargins;
12 | class QWidget;
13 |
14 |
15 | // Formatting support for ui::strNFormat().
16 | std::string toStr(const QString& s);
17 |
18 |
19 | namespace ui::qt {
20 |
21 |
22 | QString strNFormat(
23 | const char* str, std::initializer_list args);
24 |
25 |
26 | QString formatDataSize(qint64 size);
27 |
28 |
29 | QString joinInLayoutDirection(
30 | const QString& separator, const QStringList& list);
31 |
32 |
33 | QMargins makeSubordinateControlMargins();
34 |
35 |
36 | QIcon getIcon(const QString &name);
37 |
38 |
39 | // The function is the same as getIcon(), except that on Unix-like
40 | // systems it first tries to load the icon from the current theme.
41 | QIcon getThemeIcon(const QString &name);
42 |
43 |
44 | // Display a progress dialog that will be closed when the callback
45 | // returns false.
46 | void showProgressDialog(
47 | QWidget* parent,
48 | const QString& text,
49 | const std::function& callback);
50 |
51 |
52 | bool confirmDestructiveAction(
53 | QWidget* parent,
54 | const QString& question,
55 | const QString& cancelText,
56 | const QString& okText);
57 |
58 |
59 | void showError(
60 | QWidget* parent,
61 | const QString& text,
62 | const QString& informativeText = {},
63 | const QString& detailedText = {});
64 |
65 |
66 | void setMonospace(QFont& font);
67 |
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/ui/ui_common/app_dirs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 |
9 | typedef enum {
10 | /**
11 | * General data directory.
12 | */
13 | UiAppDirData,
14 |
15 | /**
16 | * Directory with documents like the user manual, license, etc.
17 | */
18 | UiAppDirDoc,
19 |
20 | /**
21 | * Localization data for bindtextdomain().
22 | */
23 | UiAppDirLocale
24 | } UiAppDir;
25 |
26 |
27 | /**
28 | * Get app directory path.
29 | *
30 | * The returned string is valid till the next call to uiGetDir().
31 | */
32 | const char* uiGetAppDir(UiAppDir dir);
33 |
34 |
35 | #ifdef __cplusplus
36 | }
37 | #endif
38 |
--------------------------------------------------------------------------------
/src/ui/ui_common/app_dirs_unix_cfg.h.in:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | const char* const unixAppDirData =
5 | "@CMAKE_INSTALL_DATADIR@/@APP_FILE_NAME@";
6 | const char* const unixAppDirDoc = "@CMAKE_INSTALL_DOCDIR@";
7 | const char* const unixAppDirLocale = "@CMAKE_INSTALL_LOCALEDIR@";
8 |
--------------------------------------------------------------------------------
/src/ui/ui_common/app_dirs_windows.cpp:
--------------------------------------------------------------------------------
1 | #include "app_dirs.h"
2 | #include "init_app_dirs.h"
3 |
4 | #include "exe_path.h"
5 |
6 |
7 | static std::string baseDirPath;
8 |
9 |
10 | namespace ui {
11 |
12 |
13 | bool initAppDirs()
14 | {
15 | baseDirPath = getExePath();
16 |
17 | const auto slashPos = baseDirPath.rfind('\\');
18 | if (slashPos != baseDirPath.npos)
19 | baseDirPath.resize(slashPos);
20 |
21 | return true;
22 | }
23 |
24 |
25 | }
26 |
27 |
28 | const char* uiGetAppDir(UiAppDir dir)
29 | {
30 | static std::string result;
31 | result = baseDirPath;
32 |
33 | switch (dir) {
34 | case UiAppDirData:
35 | break;
36 | case UiAppDirDoc:
37 | result += "\\doc";
38 | break;
39 | case UiAppDirLocale:
40 | result += "\\locale";
41 | break;
42 | }
43 |
44 | return result.c_str();
45 | }
46 |
--------------------------------------------------------------------------------
/src/ui/ui_common/app_info.cpp.in:
--------------------------------------------------------------------------------
1 | #include "app_info.h"
2 |
3 |
4 | const char* const uiAppName = "@APP_NAME@";
5 | const char* const uiAppVersion = "@APP_VERSION@";
6 | const char* const uiAppWebsite = "@APP_URL@";
7 |
8 | #define COPYRIGHT "\302\251 @APP_COPYRIGHT_YEAR@ @APP_AUTHOR@"
9 | const char* const uiAppCopyright = COPYRIGHT;
10 | const char* const uiAppLicense =
11 | COPYRIGHT "\n"
12 | "\n"
13 | "This software is provided 'as-is', without any express or implied\n"
14 | "warranty. In no event will the authors be held liable for any damages\n"
15 | "arising from the use of this software.\n"
16 | "\n"
17 | "Permission is granted to anyone to use this software for any purpose,\n"
18 | "including commercial applications, and to alter it and redistribute it\n"
19 | "freely, subject to the following restrictions:\n"
20 | "\n"
21 | "1. The origin of this software must not be misrepresented; you must not\n"
22 | " claim that you wrote the original software. If you use this software\n"
23 | " in a product, an acknowledgement in the product documentation would be\n"
24 | " appreciated but is not required.\n"
25 | "2. Altered source versions must be plainly marked as such, and must not be\n"
26 | " misrepresented as being the original software.\n"
27 | "3. This notice may not be removed or altered from any source distribution.\n"
28 | ;
29 |
--------------------------------------------------------------------------------
/src/ui/ui_common/app_info.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 |
9 | extern const char* const uiAppName;
10 | extern const char* const uiAppVersion;
11 | extern const char* const uiAppWebsite;
12 | extern const char* const uiAppCopyright;
13 | extern const char* const uiAppLicense;
14 |
15 |
16 | #ifdef __cplusplus
17 | }
18 | #endif
19 |
--------------------------------------------------------------------------------
/src/ui/ui_common/autostart_default.cpp:
--------------------------------------------------------------------------------
1 | #include "autostart_default.h"
2 |
3 | #include
4 |
5 | #include "app_info.h"
6 | #include "cmdline_opts.h"
7 | #include "exe_path.h"
8 | #include "file_names.h"
9 |
10 |
11 | UiAutostart* uiAutostartCreateDefault(void)
12 | {
13 | const char* args[]{
14 | ui::getToplevelExePath().c_str(), ui::cmdLineOptHide};
15 |
16 | const UiAutostartArgs autostartArgs{
17 | uiAppName, uiAppFileName, args, std::size(args)};
18 |
19 | return uiAutostartCreate(&autostartArgs);
20 | }
21 |
--------------------------------------------------------------------------------
/src/ui/ui_common/autostart_default.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "autostart.h"
4 |
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 |
11 | UiAutostart* uiAutostartCreateDefault(void);
12 |
13 |
14 | #ifdef __cplusplus
15 | }
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/ui/ui_common/cfg_default_values.cpp:
--------------------------------------------------------------------------------
1 | /* This file was automatically generated. Do not edit. */
2 |
3 | #include "cfg_default_values.h"
4 |
5 |
6 | bool const cfgDefaultValueActionAddToHistory =
7 | true;
8 | bool const cfgDefaultValueActionCopyToClipboard =
9 | false;
10 | const char* const cfgDefaultValueActionCopyToClipboardTextSeparator =
11 | "\n\n\n";
12 | bool const cfgDefaultValueActionRunExecutable =
13 | false;
14 | bool const cfgDefaultValueActionsDonePlaySound =
15 | false;
16 | bool const cfgDefaultValueActionsDonePlaySoundCustom =
17 | false;
18 | bool const cfgDefaultValueHistoryWrapWords =
19 | true;
20 | DpsoHotkey const cfgDefaultValueHotkeyCancelSelection =
21 | {dpsoKeyEscape, dpsoNoKeyMods};
22 | DpsoHotkey const cfgDefaultValueHotkeyToggleSelection =
23 | {dpsoKeyGrave, dpsoKeyModCtrl};
24 | bool const cfgDefaultValueOcrAllowQueuing =
25 | true;
26 | bool const cfgDefaultValueOcrSplitTextBlocks =
27 | true;
28 | bool const cfgDefaultValueUiTrayIconVisible =
29 | true;
30 | bool const cfgDefaultValueUiWindowCloseToTray =
31 | false;
32 | bool const cfgDefaultValueUiWindowMinimizeOnStart =
33 | false;
34 | bool const cfgDefaultValueUiWindowMinimizeToTray =
35 | false;
36 | bool const cfgDefaultValueUpdateCheckAuto =
37 | true;
38 | int const cfgDefaultValueUpdateCheckAutoIntervalDays =
39 | 7;
40 |
--------------------------------------------------------------------------------
/src/ui/ui_common/cfg_default_values.h:
--------------------------------------------------------------------------------
1 | /* This file was automatically generated. Do not edit. */
2 |
3 | #pragma once
4 |
5 | #include
6 |
7 | #include "dpso_sys/dpso_sys.h"
8 |
9 |
10 | #ifdef __cplusplus
11 | extern "C" {
12 | #endif
13 |
14 |
15 | extern bool const cfgDefaultValueActionAddToHistory;
16 | extern bool const cfgDefaultValueActionCopyToClipboard;
17 | extern const char* const cfgDefaultValueActionCopyToClipboardTextSeparator;
18 | extern bool const cfgDefaultValueActionRunExecutable;
19 | extern bool const cfgDefaultValueActionsDonePlaySound;
20 | extern bool const cfgDefaultValueActionsDonePlaySoundCustom;
21 | extern bool const cfgDefaultValueHistoryWrapWords;
22 | extern DpsoHotkey const cfgDefaultValueHotkeyCancelSelection;
23 | extern DpsoHotkey const cfgDefaultValueHotkeyToggleSelection;
24 | extern bool const cfgDefaultValueOcrAllowQueuing;
25 | extern bool const cfgDefaultValueOcrSplitTextBlocks;
26 | extern bool const cfgDefaultValueUiTrayIconVisible;
27 | extern bool const cfgDefaultValueUiWindowCloseToTray;
28 | extern bool const cfgDefaultValueUiWindowMinimizeOnStart;
29 | extern bool const cfgDefaultValueUiWindowMinimizeToTray;
30 | extern bool const cfgDefaultValueUpdateCheckAuto;
31 | extern int const cfgDefaultValueUpdateCheckAutoIntervalDays;
32 |
33 |
34 | #ifdef __cplusplus
35 | }
36 | #endif
37 |
--------------------------------------------------------------------------------
/src/ui/ui_common/cfg_key_values.txt:
--------------------------------------------------------------------------------
1 | action_add_to_history | bool | true
2 | action_copy_to_clipboard | bool | false
3 | action_copy_to_clipboard_text_separator | const char* | "\n\n\n"
4 | action_run_executable | bool | false
5 | action_run_executable_path
6 | actions_done_play_sound | bool | false
7 | actions_done_play_sound_custom | bool | false
8 | actions_done_play_sound_custom_path
9 | history_export_dir
10 | history_wrap_words | bool | true
11 | hotkey_cancel_selection | DpsoHotkey | {dpsoKeyEscape, dpsoNoKeyMods}
12 | hotkey_toggle_selection | DpsoHotkey | {dpsoKeyGrave, dpsoKeyModCtrl}
13 | ocr_allow_queuing | bool | true
14 | ocr_languages
15 | ocr_split_text_blocks | bool | true
16 | selection_border_width
17 | ui_active_tab
18 | ui_languages_sort_column
19 | ui_languages_sort_descending
20 | ui_tray_icon_visible | bool | true
21 | ui_window_close_to_tray | bool | false
22 | ui_window_height
23 | ui_window_maximized
24 | ui_window_minimize_on_start | bool | false
25 | ui_window_minimize_to_tray | bool | false
26 | ui_window_width
27 | ui_window_x
28 | ui_window_y
29 | update_check_auto | bool | true
30 | update_check_auto_interval_days | int | 7
31 | update_check_last_time
32 |
--------------------------------------------------------------------------------
/src/ui/ui_common/cmdline_cmd_autostart.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace ui {
5 |
6 |
7 | // On failure, sets an error message (dpsoGetError()) and returns
8 | // false.
9 | bool cmdLineCmdAutostart(const char* argv0, const char* action);
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/ui/ui_common/cmdline_opts.cpp:
--------------------------------------------------------------------------------
1 | #include "cmdline_opts.h"
2 |
3 |
4 | namespace ui {
5 |
6 |
7 | const char* const cmdLineOptHide = "-hide";
8 |
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/ui/ui_common/cmdline_opts.h:
--------------------------------------------------------------------------------
1 | // Names of command line options used in more than one file.
2 |
3 | #pragma once
4 |
5 |
6 | namespace ui {
7 |
8 |
9 | extern const char* const cmdLineOptHide;
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/ui/ui_common/exe_path.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | namespace ui {
7 |
8 |
9 | // This function is called as a part of uiInit(). On failure, sets an
10 | // error message (dpsoGetError()) and returns false.
11 | bool initExePath(const char* argv0);
12 |
13 |
14 | // Return a canonical absolute path of the toplevel executable
15 | // launched by the user.
16 | //
17 | // On some platforms, an application may be packaged in a way that
18 | // requires the use of a launcher program that sets up an environment
19 | // for the final executable. This function is intended for cases where
20 | // it's important to use the path of the launcher rather than the
21 | // final executable, such as when adding the application to the
22 | // autostart.
23 | //
24 | // If the application doesn't use a launcher, the function returns the
25 | // path of the running executable, i.e. the same as getExePath().
26 | const std::string& getToplevelExePath();
27 |
28 |
29 | // Return a canonical absolute path of the current executable, or an
30 | // empty string if uiInit() wasn't called.
31 | const std::string& getExePath();
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/ui/ui_common/exe_path_unix.cpp:
--------------------------------------------------------------------------------
1 | #include "exe_path.h"
2 |
3 | #include "dpso_utils/error_set.h"
4 | #include "dpso_utils/os.h"
5 | #include "dpso_utils/unix/exe_path.h"
6 |
7 | #include "toplevel_argv0.h"
8 |
9 |
10 | namespace ui {
11 | namespace {
12 |
13 |
14 | std::string toplevelExePath;
15 | std::string exePath;
16 |
17 |
18 | bool initExePath(std::string& path, const char* argv0)
19 | {
20 | try {
21 | path = dpso::unix::getExePath(argv0);
22 | return true;
23 | } catch (dpso::os::Error& e) {
24 | dpso::setError(
25 | "unix::getExePath(\"{}\"): {}", argv0, e.what());
26 | return false;
27 | }
28 | }
29 |
30 |
31 | }
32 |
33 |
34 | bool initExePath(const char* argv0)
35 | {
36 | return
37 | initExePath(toplevelExePath, getToplevelArgv0(argv0))
38 | && initExePath(exePath, argv0);
39 | }
40 |
41 |
42 | const std::string& getToplevelExePath()
43 | {
44 | return toplevelExePath;
45 | }
46 |
47 |
48 | const std::string& getExePath()
49 | {
50 | return exePath;
51 | }
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/ui/ui_common/exe_path_windows.cpp:
--------------------------------------------------------------------------------
1 | #include "exe_path.h"
2 |
3 | #include
4 |
5 | #define WIN32_LEAN_AND_MEAN
6 | #include
7 |
8 | #include "dpso_utils/error_set.h"
9 | #include "dpso_utils/windows/error.h"
10 | #include "dpso_utils/windows/utf.h"
11 |
12 |
13 | namespace ui {
14 |
15 |
16 | static std::string exePath;
17 |
18 |
19 | bool initExePath(const char* argv0)
20 | {
21 | (void)argv0;
22 |
23 | std::wstring path;
24 |
25 | while (true) {
26 | path.reserve(path.size() + 32);
27 | path.resize(path.capacity());
28 |
29 | const auto size = GetModuleFileNameW(
30 | nullptr, path.data(), path.size());
31 |
32 | if (size == 0) {
33 | dpso::setError(
34 | "GetModuleFileNameW(): {}",
35 | dpso::windows::getErrorMessage(GetLastError()));
36 | return false;
37 | }
38 |
39 | if (size < path.size()) {
40 | path.resize(size);
41 | break;
42 | }
43 | }
44 |
45 | exePath = dpso::windows::utf16ToUtf8(path.c_str());
46 | return true;
47 | }
48 |
49 |
50 | const std::string& getToplevelExePath()
51 | {
52 | return exePath;
53 | }
54 |
55 |
56 | const std::string& getExePath()
57 | {
58 | return exePath;
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/ui/ui_common/file_names.cpp.in:
--------------------------------------------------------------------------------
1 | #include "file_names.h"
2 |
3 |
4 | #define APP_FILE_NAME "@APP_FILE_NAME@"
5 |
6 | const char* const uiAppFileName = APP_FILE_NAME;
7 | const char* const uiCfgFileName = "settings.cfg";
8 | const char* const uiHistoryFileName = "history.txt";
9 |
10 | const char* const uiIconNameApp = APP_FILE_NAME;
11 | const char* const uiIconNameAppBusy = APP_FILE_NAME "-busy";
12 | const char* const uiIconNameAppError = APP_FILE_NAME "-error";
13 |
--------------------------------------------------------------------------------
/src/ui/ui_common/file_names.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 |
9 | extern const char* const uiAppFileName;
10 | extern const char* const uiCfgFileName;
11 | extern const char* const uiHistoryFileName;
12 |
13 | /* Main app icon. */
14 | extern const char* const uiIconNameApp;
15 |
16 | /* uiIconNameApp variants adjusted to display status. */
17 | extern const char* const uiIconNameAppBusy;
18 | extern const char* const uiIconNameAppError;
19 |
20 |
21 | #ifdef __cplusplus
22 | }
23 | #endif
24 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init.cpp:
--------------------------------------------------------------------------------
1 | #include "init.h"
2 |
3 | #include "exe_path.h"
4 | #include "init_app_dirs.h"
5 | #include "init_extra.h"
6 | #include "init_intl.h"
7 | #include "init_startup_args.h"
8 | #include "init_user_data.h"
9 |
10 | #include "dpso_utils/error_get.h"
11 | #include "dpso_utils/error_set.h"
12 |
13 |
14 | bool uiInit(int argc, char* argv[], UiStartupArgs* startupArgs)
15 | {
16 | if (!startupArgs) {
17 | dpso::setError("startupArgs is null");
18 | return false;
19 | }
20 |
21 | *startupArgs = ui::initStartupArgs(argc, argv);
22 |
23 | if (!ui::initStart(argc, argv)) {
24 | dpso::setError("ui::initStart: {}", dpsoGetError());
25 | return false;
26 | }
27 |
28 | if (!ui::initExePath(argv[0])) {
29 | dpso::setError("ui::initExePath: {}", dpsoGetError());
30 | return false;
31 | }
32 |
33 | if (!ui::initAppDirs()) {
34 | dpso::setError("ui::initAppDirs: {}", dpsoGetError());
35 | return false;
36 | }
37 |
38 | ui::initIntl();
39 |
40 | if (!ui::initUserData()) {
41 | dpso::setError("ui::initUserData: {}", dpsoGetError());
42 | return false;
43 | }
44 |
45 | if (!ui::initEnd(argc, argv)) {
46 | dpso::setError("ui::initEnd: {}", dpsoGetError());
47 | return false;
48 | }
49 |
50 | return true;
51 | }
52 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "startup_args.h"
6 |
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 |
13 | /**
14 | * Initialize the UI library.
15 | *
16 | * On failure, sets an error message (dpsoGetError()) and returns
17 | * false.
18 | */
19 | bool uiInit(int argc, char* argv[], UiStartupArgs* startupArgs);
20 |
21 |
22 | #ifdef __cplusplus
23 | }
24 | #endif
25 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init_app_dirs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace ui {
5 |
6 |
7 | // Initialize app directory paths.
8 | //
9 | // On failure, sets an error message (dpsoGetError()) and returns
10 | // false.
11 | bool initAppDirs();
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init_extra.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace ui {
5 |
6 |
7 | // The initStart/End() functions are the place for additional
8 | // platform-specific logic during uiInit(). initStart() is the first
9 | // function called by uiInit(); initEnd() is the last. On failure,
10 | // both should set an error message (dpsoGetError()) and return false.
11 | bool initStart(int argc, char* argv[]);
12 | bool initEnd(int argc, char* argv[]);
13 |
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init_extra_windows.cpp:
--------------------------------------------------------------------------------
1 | #include "init_extra.h"
2 |
3 | #define WIN32_LEAN_AND_MEAN
4 | #include
5 |
6 |
7 | namespace ui {
8 |
9 |
10 | // The main goal of registering restart is to give the installer
11 | // (e.g. Inno Setup) an ability to restart our application in case it
12 | // was automatically closed before installing an update.
13 | static void registerApplicationRestart()
14 | {
15 | const auto* cmdLine = GetCommandLineW();
16 | // The command line is actually never empty, but check anyway for
17 | // the code below.
18 | if (!*cmdLine)
19 | return;
20 |
21 | // RegisterApplicationRestart() doesn't need the path to the
22 | // executable, so skip it. It may be in double quotes if it
23 | // contains spaces.
24 | const auto endChar = *cmdLine++ == L'\"' ? L'\"' : L' ';
25 | while (*cmdLine)
26 | if (*cmdLine++ == endChar)
27 | break;
28 |
29 | while (*cmdLine == L' ')
30 | ++cmdLine;
31 |
32 | RegisterApplicationRestart(
33 | cmdLine, RESTART_NO_CRASH | RESTART_NO_HANG);
34 | }
35 |
36 |
37 | bool initStart(int argc, char* argv[])
38 | {
39 | (void)argc;
40 | (void)argv;
41 |
42 | return true;
43 | }
44 |
45 |
46 | bool initEnd(int argc, char* argv[])
47 | {
48 | (void)argc;
49 | (void)argv;
50 |
51 | registerApplicationRestart();
52 | return true;
53 | }
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init_intl.cpp:
--------------------------------------------------------------------------------
1 | #include "init_intl.h"
2 |
3 | // On Windows, libintl patches setlocale with a macro that expands to
4 | // libintl_setlocale. std::setlocale becomes std::libintl_setlocale,
5 | // so we must use rather than .
6 | #include
7 |
8 | #include "dpso_intl/dpso_intl.h"
9 |
10 | #include "app_dirs.h"
11 | #include "file_names.h"
12 |
13 |
14 | namespace ui {
15 |
16 |
17 | void initIntl(void)
18 | {
19 | setlocale(LC_ALL, "");
20 |
21 | bindtextdomainUtf8(uiAppFileName, uiGetAppDir(UiAppDirLocale));
22 | bind_textdomain_codeset(uiAppFileName, "UTF-8");
23 | textdomain(uiAppFileName);
24 | }
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init_intl.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace ui {
5 |
6 |
7 | // Initialize libintl.
8 | //
9 | // The function performs all steps needed to set up libintl, such as
10 | // calling setlocale(), bindtextdomain(), etc. It depends on
11 | // UiAppDirLocale, so uiInitAppDirs() must be called before use.
12 | void initIntl();
13 |
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init_startup_args.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "startup_args.h"
4 |
5 |
6 | namespace ui {
7 |
8 |
9 | UiStartupArgs initStartupArgs(int argc, char* argv[]);
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/ui/ui_common/init_user_data.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace ui {
5 |
6 |
7 | // Initialize default data in the user data directory, such as OCR
8 | // engine language files. On failure, sets an error message
9 | // (dpsoGetError()) and returns false.
10 | bool initUserData();
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/ui/ui_common/ocr_default.cpp:
--------------------------------------------------------------------------------
1 | #include "ocr_default.h"
2 |
3 | #include
4 |
5 | #include "app_info.h"
6 | #include "ocr_default_data_dir.h"
7 | #include "user_agent.h"
8 |
9 |
10 | DpsoOcr* dpsoOcrCreateDefault(int engineIdx)
11 | {
12 | DpsoOcrEngineInfo engineInfo;
13 | dpsoOcrGetEngineInfo(engineIdx, &engineInfo);
14 |
15 | const auto dataDir = ui::getDefaultOcrDataDir(engineInfo);
16 | if (!dataDir)
17 | return {};
18 |
19 | return dpsoOcrCreate(engineIdx, dataDir->c_str());
20 | }
21 |
22 |
23 | static std::string getInfoFileUrl(const DpsoOcrEngineInfo& engineInfo)
24 | {
25 | std::string result{uiAppWebsite};
26 | assert(!result.empty());
27 |
28 | if (result.back() != '/')
29 | result += '/';
30 |
31 | result += "ocr_engine_data/";
32 | result += engineInfo.id;
33 | result += "_data.json";
34 |
35 | return result;
36 | }
37 |
38 |
39 | DpsoOcrLangManager* dpsoOcrLangManagerCreateDefault(int engineIdx)
40 | {
41 | DpsoOcrEngineInfo engineInfo;
42 | dpsoOcrGetEngineInfo(engineIdx, &engineInfo);
43 |
44 | const auto dataDir = ui::getDefaultOcrDataDir(engineInfo);
45 | if (!dataDir)
46 | return {};
47 |
48 | return dpsoOcrLangManagerCreate(
49 | engineIdx,
50 | dataDir->c_str(),
51 | ui::getUserAgent().c_str(),
52 | getInfoFileUrl(engineInfo).c_str());
53 | }
54 |
--------------------------------------------------------------------------------
/src/ui/ui_common/ocr_default.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "dpso_ocr/dpso_ocr.h"
4 |
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 |
11 | DpsoOcr* dpsoOcrCreateDefault(int engineIdx);
12 | DpsoOcrLangManager* dpsoOcrLangManagerCreateDefault(int engineIdx);
13 |
14 |
15 | #ifdef __cplusplus
16 | }
17 | #endif
18 |
--------------------------------------------------------------------------------
/src/ui/ui_common/ocr_default_data_dir.cpp:
--------------------------------------------------------------------------------
1 | #include "ocr_default_data_dir.h"
2 |
3 | #include "dpso_ext/dpso_ext.h"
4 | #include "dpso_utils/error_get.h"
5 | #include "dpso_utils/error_set.h"
6 | #include "dpso_utils/os.h"
7 |
8 | #include "file_names.h"
9 |
10 |
11 | namespace ui {
12 |
13 |
14 | std::optional getDefaultOcrDataDir(
15 | const DpsoOcrEngineInfo& engineInfo)
16 | {
17 | std::string result;
18 |
19 | switch (engineInfo.dataDirPreference) {
20 | case DpsoOcrEngineDataDirPreferenceNoDataDir:
21 | case DpsoOcrEngineDataDirPreferencePreferDefault:
22 | break;
23 | case DpsoOcrEngineDataDirPreferencePreferExplicit: {
24 | const auto* dataPath = dpsoGetUserDir(
25 | DpsoUserDirData, uiAppFileName);
26 | if (!dataPath) {
27 | dpso::setError(
28 | "Can't get user data dir: {}", dpsoGetError());
29 | return {};
30 | }
31 |
32 | result = dataPath;
33 | result += *dpso::os::dirSeparators;
34 | result += engineInfo.id;
35 | result += "_data";
36 | break;
37 | }
38 | }
39 |
40 | return result;
41 | }
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/ui/ui_common/ocr_default_data_dir.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include "dpso_ocr/engine.h"
7 |
8 |
9 | namespace ui {
10 |
11 |
12 | // Return an absolute path of the OCR data directory for the given
13 | // engine. The path will be empty if
14 | // DpsoOcrEngineInfo::dataDirPreference is not
15 | // DpsoOcrEngineDataDirPreferencePreferExplicit.
16 | //
17 | // On failure, sets an error message (dpsoGetError()) and returns
18 | // nullopt.
19 | std::optional getDefaultOcrDataDir(
20 | const DpsoOcrEngineInfo& engineInfo);
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/ui/ui_common/single_instance_guard.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 |
11 | /**
12 | * A single instance guard allows to check whether the application is
13 | * a primary or a secondary instance.
14 | */
15 | typedef struct UiSingleInstanceGuard UiSingleInstanceGuard;
16 |
17 |
18 | /**
19 | * Create a single instance guard.
20 | *
21 | * Id is a unique identifier of the application (like application name
22 | * or UUID) that should be the same for all instances.
23 | *
24 | * On failure, sets an error message (dpsoGetError()) and returns
25 | * null.
26 | */
27 | UiSingleInstanceGuard* uiSingleInstanceGuardCreate(const char* id);
28 |
29 |
30 | void uiSingleInstanceGuardDelete(UiSingleInstanceGuard* guard);
31 |
32 |
33 | bool uiSingleInstanceGuardIsPrimary(
34 | const UiSingleInstanceGuard* guard);
35 |
36 |
37 | #ifdef __cplusplus
38 | }
39 |
40 |
41 | #include
42 |
43 |
44 | namespace ui {
45 |
46 |
47 | struct SingleInstanceGuardDeleter {
48 | void operator()(UiSingleInstanceGuard* guard) const
49 | {
50 | uiSingleInstanceGuardDelete(guard);
51 | }
52 | };
53 |
54 |
55 | using SingleInstanceGuardUPtr =
56 | std::unique_ptr<
57 | UiSingleInstanceGuard, SingleInstanceGuardDeleter>;
58 |
59 |
60 | }
61 |
62 |
63 | #endif
64 |
--------------------------------------------------------------------------------
/src/ui/ui_common/startup_args.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 |
6 | /**
7 | * Program startup arguments from the command line options.
8 | */
9 | typedef struct UiStartupArgs {
10 | /**
11 | * Start the program with the hidden window.
12 | */
13 | bool hide;
14 | } UiStartupArgs;
15 |
--------------------------------------------------------------------------------
/src/ui/ui_common/str_nformat.cpp:
--------------------------------------------------------------------------------
1 | #include "str_nformat.h"
2 |
3 | #include "dpso_utils/str_format_core.h"
4 |
5 |
6 | namespace ui {
7 |
8 |
9 | std::string strNFormat(
10 | const char* str, std::initializer_list args)
11 | {
12 | return dpso::str::format(
13 | str,
14 | [&](const auto* name, std::size_t nameLen) -> const char*
15 | {
16 | for (const auto& arg : args)
17 | if (dpso::str::cmpSubStr(
18 | arg.name, name, nameLen) == 0)
19 | return arg.str.c_str();
20 |
21 | return {};
22 | });
23 | }
24 |
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/ui/ui_common/str_nformat.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include "dpso_utils/str.h"
7 |
8 |
9 | namespace ui {
10 |
11 |
12 | struct StrNFormatArg {
13 | StrNFormatArg(const char* name, const char* str)
14 | : name{name}
15 | , str{str}
16 | {
17 | }
18 |
19 | StrNFormatArg(const char* name, char* str)
20 | : name{name}
21 | , str{str}
22 | {
23 | }
24 |
25 | StrNFormatArg(const char* name, std::string str)
26 | : name{name}
27 | , str{std::move(str)}
28 | {
29 | }
30 |
31 | template
32 | StrNFormatArg(const char* name, const T& v)
33 | : name{name}
34 | {
35 | using namespace dpso::str;
36 | str = toStr(v);
37 | }
38 |
39 | const char* name;
40 | std::string str;
41 | };
42 |
43 |
44 | // Python-style named string formatting.
45 | //
46 | // The function formats string similar to Python's str.format(),
47 | // except it only supports named arguments. A partition in the str
48 | // enclosed in braces defines a name to be replaced with the
49 | // corresponding entry in the args array. To insert a brace as is,
50 | // mention it twice.
51 | std::string strNFormat(
52 | const char* str, std::initializer_list args);
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/ui/ui_common/taskbar_config.h.in:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #cmakedefine01 UI_TASKBAR_WIN
5 | #cmakedefine01 UI_TASKBAR_NULL
6 |
--------------------------------------------------------------------------------
/src/ui/ui_common/taskbar_null.cpp:
--------------------------------------------------------------------------------
1 | #include "taskbar.h"
2 |
3 |
4 | void uiTaskbarDelete(UiTaskbar* tb)
5 | {
6 | (void)tb;
7 | }
8 |
9 |
10 | void uiTaskbarSetState(UiTaskbar* tb, UiTaskbarState newState)
11 | {
12 | (void)tb;
13 | (void)newState;
14 | }
15 |
16 |
17 | void uiTaskbarSetProgress(UiTaskbar* tb, int newProgress)
18 | {
19 | (void)tb;
20 | (void)newProgress;
21 | }
22 |
--------------------------------------------------------------------------------
/src/ui/ui_common/toplevel_argv0.cpp:
--------------------------------------------------------------------------------
1 | #include "toplevel_argv0.h"
2 |
3 | #include
4 |
5 |
6 | namespace ui {
7 |
8 |
9 | const char* getToplevelArgv0(const char* argv0)
10 | {
11 | const auto* launcherArgv0 = std::getenv("LAUNCHER_ARGV0");
12 | return launcherArgv0 && *launcherArgv0 ? launcherArgv0 : argv0;
13 | }
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/ui/ui_common/toplevel_argv0.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | namespace ui {
5 |
6 |
7 | // Return a value of the LAUNCHER_ARGV0 environment variable, or argv0
8 | // if LAUNCHER_ARGV0 either not set or empty.
9 | const char* getToplevelArgv0(const char* argv0);
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/ui/ui_common/ui_common.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "app_dirs.h"
4 | #include "app_info.h"
5 | #include "autostart.h"
6 | #include "autostart_default.h"
7 | #include "cfg_default_values.h"
8 | #include "cfg_keys.h"
9 | #include "file_names.h"
10 | #include "init.h"
11 | #include "ocr_default.h"
12 | #include "single_instance_guard.h"
13 | #include "sound.h"
14 | #include "taskbar.h"
15 | #include "update_checker.h"
16 | #include "update_checker_default.h"
17 |
18 | #ifdef __cplusplus
19 | #include "str_nformat.h"
20 | #endif
21 |
--------------------------------------------------------------------------------
/src/ui/ui_common/update_checker_default.cpp:
--------------------------------------------------------------------------------
1 | #include "update_checker_default.h"
2 |
3 | #include