From 4826afe75d8153f3471c16dca4e545f44c7b655a Mon Sep 17 00:00:00 2001 From: paw5zx <1694470114@qq.com> Date: Tue, 12 Nov 2024 01:00:44 +0800 Subject: [PATCH] Site updated: 2024-11-12 01:00:44 --- .../11/28/single-and-multi-inherit/index.html | 1082 ------------- .../multi_inherit.png | Bin 46562 -> 0 bytes .../11/28/single-and-multi-inherit/result.png | Bin 31823 -> 0 bytes .../28/single-and-multi-inherit/result2.png | Bin 163224 -> 0 bytes .../single_inherit.png | Bin 22338 -> 0 bytes .../single_inherit2.png | Bin 22708 -> 0 bytes .../12/06/diamond-inherit/diamond_inherit.png | Bin 63016 -> 0 bytes 2023/12/06/diamond-inherit/index.html | 1019 ------------- 404.html | 168 +- .../index.html | 201 ++- GObject-tutorial-beginner-01/index.html | 1160 ++++++++++++++ GObject-tutorial-beginner-02/index.html | 1261 +++++++++++++++ .../do_select.png | Bin .../index.html | 213 ++- .../poll_table_page.png | Bin .../pollwait.png | Bin .../pollwake.png | Bin .../struct.png | Bin .../doselect.png | Bin .../index.html | 201 ++- .../pollwait.png | Bin .../10_rice_cooker.png | Bin .../11_sanguo.png | Bin .../12_coconut.png | Bin .../1_wukong_face.png | Bin .../2_chiguo.png | Bin .../3_duowen.png | Bin .../4_guangmu.png | Bin .../5_zengzhang.png | Bin .../6_dog.png | Bin .../7_name.png | Bin .../8_name_hard.png | Bin .../9_version_solution.png | Bin .../index.html | 264 +++- .../10_usmap.png | Bin .../11_injector.png | Bin .../12_dll.png | Bin .../13_select_pid.png | Bin .../14_inject.png | Bin .../1_fmodel.png | Bin .../2_first_time.png | Bin .../3_aes.png | Bin .../4_aes2.png | Bin .../5_path.png | Bin .../6_unpack.png | Bin .../7_result.png | Bin .../8_viewer.png | Bin .../9_menu.png | Bin .../index.html | 253 ++- aravis-GVCP-packets/index.html | 1356 +++++++++++++++++ .../index.html | 203 ++- .../result.png | Bin .../index.html | 203 ++- .../result.png | Bin .../index.html | 197 ++- .../aravis_info.png | Bin .../cmake.png | Bin .../gstreamer.png | Bin .../index.html | 213 ++- .../meson.png | Bin .../result.png | Bin .../video_viewer.png | Bin .../index.html | 205 ++- .../result.png | Bin .../index.html | 203 ++- .../result.png | Bin .../index.html | 209 ++- .../result.png | Bin .../solution.png | Bin .../index.html | 187 ++- .../index.html | 203 ++- .../result.png | Bin archives/2023/10/index.html | 309 ++-- archives/2023/index.html | 309 ++-- archives/2024/03/index.html | 309 ++-- archives/2024/04/index.html | 309 ++-- archives/2024/05/index.html | 309 ++-- archives/2024/06/index.html | 309 ++-- archives/2024/07/index.html | 309 ++-- archives/2024/08/index.html | 309 ++-- archives/{2023/11 => 2024/10}/index.html | 313 ++-- archives/{2023/12 => 2024/11}/index.html | 313 ++-- archives/2024/index.html | 309 ++-- archives/2024/page/2/index.html | 309 ++-- archives/2024/page/3/index.html | 309 ++-- archives/2024/page/4/index.html | 309 ++-- archives/index.html | 309 ++-- archives/page/2/index.html | 309 ++-- archives/page/3/index.html | 309 ++-- archives/page/4/index.html | 309 ++-- assets/build/styles.css | 334 ++-- categories/C/index.html | 843 ++++++++++ .../GObject/index.html" | 843 ++++++++++ .../index.html" | 843 ++++++++++ .../index.html" | 167 +- .../Linux\346\223\215\344\275\234/index.html" | 171 ++- categories/Linux/index.html | 175 ++- .../index.html" | 167 +- .../index.html" | 179 ++- .../C-\350\257\255\346\263\225/index.html" | 199 ++- categories/c-plus-plus/Tools/index.html | 831 ++++++++++ categories/c-plus-plus/index.html | 205 ++- categories/c-plus-plus/page/2/index.html | 225 ++- .../index.html" | 167 +- .../index.html" | 171 ++- categories/git/index.html | 165 +- categories/index.html | 170 ++- .../Aravis/index.html" | 195 ++- .../index.html" | 195 ++- .../UE/index.html" | 167 +- .../index.html" | 167 +- .../index.html | 187 ++- .../index.html | 199 ++- .../10_l_default_result.png | Bin .../11_l_default_readelf.png | Bin .../12_debug_compiler_info.png | Bin .../13_deliver.png | Bin .../14_debug_linker_info.png | Bin .../15_result.png | Bin .../1_none.png | Bin .../2_default_result.png | Bin .../3_default_readelf.png | Bin .../4_libpath_result.png | Bin .../5_libpath_readelf.png | Bin .../6_l_result.png | Bin .../7_l_readelf.png | Bin .../8_default_libpath_result.png | Bin .../9_default_libpath_readelf.png | Bin .../index.html | 249 ++- .../index.html | 187 ++- .../index.html | 187 ++- .../index.html | 193 ++- .../readelf.png | Bin css/common/animated.css | 6 - css/common/basic.css | 49 +- css/common/codeblock/code-theme.css | 100 +- css/common/codeblock/highlight.css | 108 +- .../codeblock/hljs-themes/dark/a11y-dark.css | 0 .../codeblock/hljs-themes/dark/agate.css | 0 .../hljs-themes/dark/atom-one-dark.css | 0 .../hljs-themes/dark/github-dark.css | 0 .../hljs-themes/dark/monokai-sublime.css | 0 .../codeblock/hljs-themes/dark/night-owl.css | 0 .../codeblock/hljs-themes/dark/nord.css | 0 .../hljs-themes/dark/tokyo-night-dark.css | 0 .../codeblock/hljs-themes/dark/vs2015.css | 0 .../hljs-themes/light/atom-one-light.css | 0 .../codeblock/hljs-themes/light/default.css | 0 .../codeblock/hljs-themes/light/github.css | 0 css/common/markdown.css | 55 +- css/style.css | 438 +++--- .../index.html | 193 ++- .../uml.png | Bin .../index.html | 197 ++- .../uml.png | Bin .../uml_factory.png | Bin .../index.html | 193 ++- .../uml.png | Bin .../index.html | 193 ++- .../uml.png | Bin .../index.html | 193 ++- .../uml.png | Bin .../index.html | 191 ++- index.html | 365 +++-- js/layouts/essays.js | 25 + js/libs/moment-with-locales.min.js | 2 + js/libs/moment.min.js | 2 + js/plugins/hbe.js | 34 +- js/plugins/typed.js | 6 +- js/tools/imageViewer.js | 92 +- js/utils.js | 14 +- lib/hbe.js | 347 ----- links/index.html | 163 +- .../index.html | 193 ++- .../result.png | Bin .../confirm.png | Bin .../gcc_version.png | Bin .../index.html | 201 ++- .../result.png | Bin {images => logos}/O7_allmode.png | Bin {images => logos}/O7_allmode.svg | 0 .../index.html | 211 ++- .../net_config.png | Bin .../net_config2.png | Bin .../port_name.png | Bin .../result.png | Bin .../result2.png | Bin page/2/index.html | 321 ++-- page/3/index.html | 317 ++-- page/4/index.html | 395 +++-- .../ctr_block.png | Bin .../index.html | 201 ++- search.xml | 998 ++++++++---- .../index.html | 197 ++- .../result_garbo.png | Bin .../result_shared_ptr.png | Bin .../index.html | 187 ++- .../03/18/singleton => singleton}/index.html | 209 ++- .../singleton => singleton}/result_CRTP.png | Bin .../singleton => singleton}/result_DCLP.png | Bin .../singleton => singleton}/result_hungry.png | Bin .../singleton => singleton}/result_lazy.png | Bin .../singleton => singleton}/result_meyers.png | Bin tags/index.html | 163 +- .../apt.png | Bin .../index.html | 225 ++- .../libfile.png | Bin .../location.png | Bin .../result_read.png | Bin .../result_write.png | Bin .../source_location.png | Bin .../source_soname.png | Bin .../index.html | 213 ++- .../location.png | Bin .../location2.png | Bin .../result.png | Bin tools-pahole/index.html | 1105 ++++++++++++++ 217 files changed, 21938 insertions(+), 8516 deletions(-) delete mode 100644 2023/11/28/single-and-multi-inherit/index.html delete mode 100644 2023/11/28/single-and-multi-inherit/multi_inherit.png delete mode 100644 2023/11/28/single-and-multi-inherit/result.png delete mode 100644 2023/11/28/single-and-multi-inherit/result2.png delete mode 100644 2023/11/28/single-and-multi-inherit/single_inherit.png delete mode 100644 2023/11/28/single-and-multi-inherit/single_inherit2.png delete mode 100644 2023/12/06/diamond-inherit/diamond_inherit.png delete mode 100644 2023/12/06/diamond-inherit/index.html rename {2023/10/09/Centos8-install => Centos8-install}/index.html (77%) create mode 100644 GObject-tutorial-beginner-01/index.html create mode 100644 GObject-tutorial-beginner-02/index.html rename {2024/03/08/IO-Multiplexing-do-select => IO-Multiplexing-do-select}/do_select.png (100%) rename {2024/03/08/IO-Multiplexing-do-select => IO-Multiplexing-do-select}/index.html (88%) rename {2024/03/08/IO-Multiplexing-do-select => IO-Multiplexing-do-select}/poll_table_page.png (100%) rename {2024/03/08/IO-Multiplexing-do-select => IO-Multiplexing-do-select}/pollwait.png (100%) rename {2024/03/08/IO-Multiplexing-do-select => IO-Multiplexing-do-select}/pollwake.png (100%) rename {2024/03/08/IO-Multiplexing-do-select => IO-Multiplexing-do-select}/struct.png (100%) rename {2024/03/05/IO-Multiplexing-select => IO-Multiplexing-select}/doselect.png (100%) rename {2024/03/05/IO-Multiplexing-select => IO-Multiplexing-select}/index.html (76%) rename {2024/03/05/IO-Multiplexing-select => IO-Multiplexing-select}/pollwait.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/10_rice_cooker.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/11_sanguo.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/12_coconut.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/1_wukong_face.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/2_chiguo.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/3_duowen.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/4_guangmu.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/5_zengzhang.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/6_dog.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/7_name.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/8_name_hard.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/9_version_solution.png (100%) rename {2024/08/21/UE-fmodel-blackmyth-wukong => UE-fmodel-blackmyth-wukong}/index.html (72%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/10_usmap.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/11_injector.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/12_dll.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/13_select_pid.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/14_inject.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/1_fmodel.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/2_first_time.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/3_aes.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/4_aes2.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/5_path.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/6_unpack.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/7_result.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/8_viewer.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/9_menu.png (100%) rename {2024/07/16/UE-fmodel-usage => UE-fmodel-usage}/index.html (76%) create mode 100644 aravis-GVCP-packets/index.html rename {2024/04/28/aravis-camera-api => aravis-camera-api}/index.html (70%) rename {2024/04/28/aravis-camera-api => aravis-camera-api}/result.png (100%) rename {2024/05/01/aravis-camera-features => aravis-camera-features}/index.html (72%) rename {2024/05/01/aravis-camera-features => aravis-camera-features}/result.png (100%) rename {2024/05/10/aravis-chunk-parser => aravis-chunk-parser}/index.html (75%) rename {2024/03/30/aravis-install => aravis-install}/aravis_info.png (100%) rename {2024/03/30/aravis-install => aravis-install}/cmake.png (100%) rename {2024/03/30/aravis-install => aravis-install}/gstreamer.png (100%) rename {2024/03/30/aravis-install => aravis-install}/index.html (79%) rename {2024/03/30/aravis-install => aravis-install}/meson.png (100%) rename {2024/03/30/aravis-install => aravis-install}/result.png (100%) rename {2024/03/30/aravis-install => aravis-install}/video_viewer.png (100%) rename {2024/04/15/aravis-multiple-acquisition-callback => aravis-multiple-acquisition-callback}/index.html (64%) rename {2024/04/15/aravis-multiple-acquisition-callback => aravis-multiple-acquisition-callback}/result.png (100%) rename {2024/04/15/aravis-multiple-acquisition-main-thread => aravis-multiple-acquisition-main-thread}/index.html (70%) rename {2024/04/15/aravis-multiple-acquisition-main-thread => aravis-multiple-acquisition-main-thread}/result.png (100%) rename {2024/04/25/aravis-multiple-acquisition-signal => aravis-multiple-acquisition-signal}/index.html (64%) rename {2024/04/25/aravis-multiple-acquisition-signal => aravis-multiple-acquisition-signal}/result.png (100%) rename {2024/04/25/aravis-multiple-acquisition-signal => aravis-multiple-acquisition-signal}/solution.png (100%) rename {2024/04/28/aravis-pixelformat => aravis-pixelformat}/index.html (79%) rename {2024/04/10/aravis-single-acquisition => aravis-single-acquisition}/index.html (72%) rename {2024/04/10/aravis-single-acquisition => aravis-single-acquisition}/result.png (100%) rename archives/{2023/11 => 2024/10}/index.html (73%) rename archives/{2023/12 => 2024/11}/index.html (73%) create mode 100644 categories/C/index.html create mode 100644 "categories/C/\344\270\211\346\226\271\345\272\223/GObject/index.html" create mode 100644 "categories/C/\344\270\211\346\226\271\345\272\223/index.html" create mode 100644 categories/c-plus-plus/Tools/index.html rename {2024/04/03/cpp-development-components-singleton-CRTP => cpp-development-components-singleton-CRTP}/index.html (77%) rename {2024/04/03/cpp-development-components-threadsafe-queue => cpp-development-components-threadsafe-queue}/index.html (83%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/10_l_default_result.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/11_l_default_readelf.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/12_debug_compiler_info.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/13_deliver.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/14_debug_linker_info.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/15_result.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/1_none.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/2_default_result.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/3_default_readelf.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/4_libpath_result.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/5_libpath_readelf.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/6_l_result.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/7_l_readelf.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/8_default_libpath_result.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/9_default_libpath_readelf.png (100%) rename {2024/07/29/cpp-shared-lib-search-priority-test-linking => cpp-shared-lib-search-priority-test-linking}/index.html (83%) rename {2024/08/01/cpp-shared-lib-search-priority-test-loading => cpp-shared-lib-search-priority-test-loading}/index.html (86%) rename {2024/07/15/cpp-shared-lib-search-priority => cpp-shared-lib-search-priority}/index.html (77%) rename {2024/07/16/cpp-shared-lib-soname => cpp-shared-lib-soname}/index.html (78%) rename {2024/07/16/cpp-shared-lib-soname => cpp-shared-lib-soname}/readelf.png (100%) create mode 100644 css/common/codeblock/hljs-themes/dark/a11y-dark.css create mode 100644 css/common/codeblock/hljs-themes/dark/agate.css create mode 100644 css/common/codeblock/hljs-themes/dark/atom-one-dark.css create mode 100644 css/common/codeblock/hljs-themes/dark/github-dark.css create mode 100644 css/common/codeblock/hljs-themes/dark/monokai-sublime.css create mode 100644 css/common/codeblock/hljs-themes/dark/night-owl.css create mode 100644 css/common/codeblock/hljs-themes/dark/nord.css create mode 100644 css/common/codeblock/hljs-themes/dark/tokyo-night-dark.css create mode 100644 css/common/codeblock/hljs-themes/dark/vs2015.css create mode 100644 css/common/codeblock/hljs-themes/light/atom-one-light.css create mode 100644 css/common/codeblock/hljs-themes/light/default.css create mode 100644 css/common/codeblock/hljs-themes/light/github.css rename {2024/07/09/design-pattern-2-abstract-factory-reflect => design-pattern-2-abstract-factory-reflect}/index.html (80%) rename {2024/07/09/design-pattern-2-abstract-factory-reflect => design-pattern-2-abstract-factory-reflect}/uml.png (100%) rename {2024/07/05/design-pattern-2-abstract-factory => design-pattern-2-abstract-factory}/index.html (85%) rename {2024/07/05/design-pattern-2-abstract-factory => design-pattern-2-abstract-factory}/uml.png (100%) rename {2024/07/05/design-pattern-2-abstract-factory => design-pattern-2-abstract-factory}/uml_factory.png (100%) rename {2024/06/03/design-pattern-2-factory-method-reflect => design-pattern-2-factory-method-reflect}/index.html (81%) rename {2024/06/03/design-pattern-2-factory-method-reflect => design-pattern-2-factory-method-reflect}/uml.png (100%) rename {2024/05/17/design-pattern-2-factory-method => design-pattern-2-factory-method}/index.html (81%) rename {2024/05/17/design-pattern-2-factory-method => design-pattern-2-factory-method}/uml.png (100%) rename {2024/05/14/design-pattern-2-simple-factory => design-pattern-2-simple-factory}/index.html (83%) rename {2024/05/14/design-pattern-2-simple-factory => design-pattern-2-simple-factory}/uml.png (100%) rename {2024/05/10/git-code-migration => git-code-migration}/index.html (76%) create mode 100644 js/layouts/essays.js create mode 100644 js/libs/moment-with-locales.min.js create mode 100644 js/libs/moment.min.js delete mode 100644 lib/hbe.js rename {2024/05/16/linux-centos-boot-time-optimization => linux-centos-boot-time-optimization}/index.html (79%) rename {2024/05/16/linux-centos-boot-time-optimization => linux-centos-boot-time-optimization}/result.png (100%) rename {2024/07/29/linux-update-alternatives => linux-update-alternatives}/confirm.png (100%) rename {2024/07/29/linux-update-alternatives => linux-update-alternatives}/gcc_version.png (100%) rename {2024/07/29/linux-update-alternatives => linux-update-alternatives}/index.html (75%) rename {2024/07/29/linux-update-alternatives => linux-update-alternatives}/result.png (100%) rename {images => logos}/O7_allmode.png (100%) rename {images => logos}/O7_allmode.svg (100%) rename {2024/03/04/network-bridging => network-bridging}/index.html (76%) rename {2024/03/04/network-bridging => network-bridging}/net_config.png (100%) rename {2024/03/04/network-bridging => network-bridging}/net_config2.png (100%) rename {2024/03/04/network-bridging => network-bridging}/port_name.png (100%) rename {2024/03/04/network-bridging => network-bridging}/result.png (100%) rename {2024/03/04/network-bridging => network-bridging}/result2.png (100%) rename {2024/04/07/reference-counting => reference-counting}/ctr_block.png (100%) rename {2024/04/07/reference-counting => reference-counting}/index.html (88%) rename {2024/03/19/singleton-destruct => singleton-destruct}/index.html (83%) rename {2024/03/19/singleton-destruct => singleton-destruct}/result_garbo.png (100%) rename {2024/03/19/singleton-destruct => singleton-destruct}/result_shared_ptr.png (100%) rename {2024/03/19/singleton-reorder => singleton-reorder}/index.html (82%) rename {2024/03/18/singleton => singleton}/index.html (84%) rename {2024/03/18/singleton => singleton}/result_CRTP.png (100%) rename {2024/03/18/singleton => singleton}/result_DCLP.png (100%) rename {2024/03/18/singleton => singleton}/result_hungry.png (100%) rename {2024/03/18/singleton => singleton}/result_lazy.png (100%) rename {2024/03/18/singleton => singleton}/result_meyers.png (100%) rename {2024/06/13/thirdlib-jsoncpp => thirdlib-jsoncpp}/apt.png (100%) rename {2024/06/13/thirdlib-jsoncpp => thirdlib-jsoncpp}/index.html (79%) rename {2024/06/13/thirdlib-jsoncpp => thirdlib-jsoncpp}/libfile.png (100%) rename {2024/06/13/thirdlib-jsoncpp => thirdlib-jsoncpp}/location.png (100%) rename {2024/06/13/thirdlib-jsoncpp => thirdlib-jsoncpp}/result_read.png (100%) rename {2024/06/13/thirdlib-jsoncpp => thirdlib-jsoncpp}/result_write.png (100%) rename {2024/06/13/thirdlib-jsoncpp => thirdlib-jsoncpp}/source_location.png (100%) rename {2024/06/13/thirdlib-jsoncpp => thirdlib-jsoncpp}/source_soname.png (100%) rename {2024/07/15/thirdlib-log4cpp => thirdlib-log4cpp}/index.html (78%) rename {2024/07/15/thirdlib-log4cpp => thirdlib-log4cpp}/location.png (100%) rename {2024/07/15/thirdlib-log4cpp => thirdlib-log4cpp}/location2.png (100%) rename {2024/07/15/thirdlib-log4cpp => thirdlib-log4cpp}/result.png (100%) create mode 100644 tools-pahole/index.html diff --git a/2023/11/28/single-and-multi-inherit/index.html b/2023/11/28/single-and-multi-inherit/index.html deleted file mode 100644 index b201030..0000000 --- a/2023/11/28/single-and-multi-inherit/index.html +++ /dev/null @@ -1,1082 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - C++多态学习(一)单继承与多重继承 - - - Paw5zx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- - - - - -
-

- Paw5zx -

- -
- -
- - - -
- - -
- - - -
- -
- - - -
- - -
-
- -
- -
-

C++多态学习(一)单继承与多重继承

-
- -
- - -
-
- -
-
-
- paw5zx - - Lv4 - -
-
- - -
-
-
- - - - - -
-

简介

最近在学习虚函数相关的知识,发现理解C++继承在内存中的表现以及多态性在底层的实现原理还是有点必要的,故在此写个小笔记,记录一些小知识点。
本文相关测试的机器环境:

-
1
Linux Qcumber 5.4.0-84-generic #94~18.04.1-Ubuntu SMP Thu Aug 26 23:17:46 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
-

gcc版本:

-
1
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
-

单一继承

首先从单一继承开始

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base
{
public:
virtual void func1() { cout << "Base::func1" << endl; }
virtual void func2() { cout << "Base::func2" << endl; }

int b;
};

class Derived : public Base
{
public:
void func1() override { cout << "Derived::func1" << endl; }
virtual void func3() { cout << "Derived::func3" << endl; }

int d;
};
-

内存布局

Derived继承了Base所有成员变量和函数,并且重写了func1()Derived对象内存布局应该是这样的:

-

对虚函数的调用,比如像这样:

-
1
2
Derived* d_ptr = new Derived();
d_ptr->func1();
-

其实是等价于*((d_ptr->vptr)[0])(d_ptr)

-
    -
  • d_ptr->vptr:获取虚表地址;
  • -
  • (d_ptr->vptr)[0]:获取虚表第一个槽的地址;
  • -
  • *((d_ptr->vptr)[0]):解引用,获取Derived虚表上的第一个元素,里面存着Derived::func1()的地址;
  • -
  • *((d_ptr->vptr)[0])(d_ptr):调用Derived::func1(),并隐式地将this指针传递给Derived::func1()
  • -
-

当然,我们无法访问vptr,因此这种等价只是理论上的,有助于理解底层的原理。

-

指针向上转型

在C++多态中,支持父类的指针指向子类的对象:

-
1
2
Derived d;
Base* b_ptr = &d;
-

这是因为所有派生类对象都可以视作基类的对象(因为派生类继承了基类的函数和变量),但并非所有基类的对象都可以视作派生类的对象。

-

如果你有一个Base指针,你可以调用在Base中声明的函数。而如果有一个Derived指针,由于Derived继承了Base的所有函数和变量,因此Derived也能够访问Base的函数和变量。

-

当使用基类的指针指向派生类对象时,基类指针可访问的部分如下图红框:

-

注意:

-
    -
  • 虚表第一个槽中函数地址已经被替换为Derived::func1()的地址,因此无论是b_ptr->func1()还是d_ptr->func1()都会调用Derived::func1()
  • -
-

多重继承

当多重继承时,内存模型就变得稍微复杂一点了;

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Base1 {
public:
Base1()
{
printf("Base1的this指针是:%p!\n", this);
}
//虚表指针8字节
virtual void func1() { cout << "Base1::func1" << endl; }
virtual void func2() { cout << "Base1::func2" << endl; }

int b1; //4字节

};

class Base2 {
public:
Base2()
{
printf("Base2的this指针是:%p!\n", this);
}
virtual void func3() { cout << "Base2::func3" << endl; }
virtual void func4() { cout << "Base2::func4" << endl; }

int b2;
};

class Derived : public Base1, public Base2 {
public:
Derived()
{
printf("Derive的this指针是:%p!\n", this);
}
void func1() override { cout << "Derived::func1" << endl; }
void func3() override { cout << "Derived::func3" << endl; }
virtual void func5() { cout << "Derived::func5" << endl; }

int d;
};
-

多重继承中主要关注两个方面:内存布局和虚表

-

内存布局

Derived对象内存布局如下:

-

可以观察到Derived对象的内存布局由上到下依次是:Base1,Base2,Derived。因为在内存布局中,首先是基类按照它们在继承列表中的顺序由上到下排列,然后是派生类。

-

尾部填充(tail padding)

待补充。

-

this指针调整

在C++中,一个对象的 this 指针默认指向该对象的起始地址。this指针可以使成员函数能够知道它们是在为哪个具体的对象实例工作,从而可以访问和修改该对象的成员变量。
然而在多重继承中会涉及到this指针的偏移:

-
1
2
3
4
5
6
Derived d;
Base1* pb1 = &d;
Base2* pb2 = &d;
cout<<"d的地址"<<&d<<endl;
cout<<"pb1指向的地址"<<pb1<<endl;
cout<<"pb2指向的地址"<<pb2<<endl;
-

输出的结果是:

可以看到静态类型为Base2*pb2指向的地址与d的地址并不相同。这是因为在指针向上转换时,对于继承列表中非首位的基类,编译器会自动将对象的this指针进行偏移,然后赋值给基类的指针。在上述例子中,this指针的偏移量为16字节(正好等于sizeof(Base1)),然后将偏移后的地址赋予了pb2

-

值得注意的是这种指针偏移现象也会出现在调用函数时:

-
1
2
Derived* d = new Derived();
d->func4();
-

当通过指向Derived对象的指针调用func4()时,传入的this指针也会被调整。

-

虚表指针

多重继承中的虚表指针和虚表也是要特别注意的。
可以观察到内存布局中有两个虚表指针,数量与Derived的直接基类数量相等。

-

为什么上述例子中要有两个虚表指针呢?
因为与单继承不同,Base1Base2完全独立,他们的虚函数没有顺序关系,即func1()func3()有着相同的对虚表起始位置的偏移量。不可以按序排在一起。而且Base1Base2中的成员变量也是无关的。所以使得Base1Base2Derived中必须要处于两个不相交的区域中,同时需要有两个虚指针分别对它们虚函数进行索引。

-

non-virtual thunk

现在我们关注func3()Derived中重写了Base2func3()。根据内存布局图,在虚表中,Base2部分的func3()并没有被Derived::func3()覆盖,而是产生了一个non-virtual thunk,真正的Derived::func3()地址被放在了虚表中Derived的部分下。这个non-virtual thunk的本质是根据top_offset调整this指针,然后调用真正的函数。

-

下面解释一下原因,考虑以下情况:

-
1
2
Base2* p = new Derived();
p->func3();
-

我们主要关注的就是两点:①调用正确版本的func3()②传入正确的this指针
若仅是要调用正确的func3(),那我们完全可以不用生成non-virtual thunk,直接把将Base2中的&Base2::func3()覆盖为&Derived::func3()即可,但是由于我们期望传入的是指向Derived起始地址的this指针,因此就还需要对this指针进行调整。

-

由上面的this指针讨论结果可知p指向DerivedBase2部分的起始地址。通过反汇编发现,non-virtual thunk正好将this指针向上调整了16B(sizeof(Base1)),使其指向了正确的位置(Derived的起始地址),然后调用了’真正’的func3()

-

小结

本文简单讨论了
1.单继承和多重继承下类对象的内存布局
2.多态下指针的行为
3.non-virtual thunk的实现机制

-

参考文章

1.C++ vtables - Part 2 - Multiple Inheritance
2.VTable Notes on Multiple Inheritance in GCC C++ Compiler v4.0.1
3.C++ Inheritance Memory Model

- -
- - -
-
-
    -
  • 标题: C++多态学习(一)单继承与多重继承
  • -
  • 作者: paw5zx
  • -
  • 创建于 - : 2023-11-28 22:11:00
  • - -
  • - 更新于 - : 2024-08-22 13:51:04 -
  • - -
  • - 链接: https://paw5zx.github.io/2023/11/28/single-and-multi-inherit/ -
  • -
  • - - 版权声明: - - - - - 本文章采用 CC BY-NC-SA 4.0 进行许可。 - -
  • -
-
- -
- - - - - -
- - -
- - -
- -
- -
- - -
- -
- -
- - - - -
-
-
-
- 评论 -
- - - - -
- - - - - - -
- -
- -
- - - - -
- - - - - -
- - - -
- - -
- - -
-
-
    - - -
  • - -
  • - - - - -
  • - -
  • - -
-
- -
- - -
-
-
    -
  • - -
  • - -
  • - -
  • - -
  • - -
  • - - - - - - -
  • - -
  • -
- -
    -
  • - -
  • - -
  • - - -
  • - - -
-
- -
- -
- -
- - - -
- -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - -
- - - - diff --git a/2023/11/28/single-and-multi-inherit/multi_inherit.png b/2023/11/28/single-and-multi-inherit/multi_inherit.png deleted file mode 100644 index d14536aa420fa7319c1284874a674ecc40322622..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46562 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

c 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 RNN67%I9(H+!n4*P{{i4FL9qY; diff --git a/2023/11/28/single-and-multi-inherit/result.png b/2023/11/28/single-and-multi-inherit/result.png deleted file mode 100644 index a656336549eb08d71f6e20fc779f9f25a81ec836..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31823 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 D3hMLX diff --git a/2023/11/28/single-and-multi-inherit/single_inherit2.png b/2023/11/28/single-and-multi-inherit/single_inherit2.png deleted file mode 100644 index c69bde5647e0e78686ddc9dfdb2aa5f74f4d6e9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22708 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 Rq8jlU4;MD0%GvMJe*y7_y;%SN diff --git a/2023/12/06/diamond-inherit/diamond_inherit.png b/2023/12/06/diamond-inherit/diamond_inherit.png deleted file mode 100644 index c43a0d187cfcc03a0801bee0c9e4e4da23781b06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63016 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - C++多态学习(二)菱形继承 - - - Paw5zx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - -
-

- Paw5zx -

- -
- -
- - - -
- - -
- - - -
- -
- - - -
- - -
-
- -
- -
-

C++多态学习(二)菱形继承

-
- -
- - -
-
- -
-
-
- paw5zx - - Lv4 - -
-
- - -
-
-
- - - - - -
-

简介

在前一篇笔记C++多态学习(一)单继承与多重继承 中讨论了单继承和多重继承,本文将针对菱形继承进行讨论

-

菱形继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Base
{
public:
Base()
{
printf("Base的this指针是:%p!\n", this);
}
virtual void func() { cout << "Base::func" << endl; }
virtual void func1() { cout << "Base::func1" << endl; }
virtual void func2() { cout << "Base::func2" << endl; }

int b; //4字节
};

class Base1 : public Base
{
public:
Base1()
{
printf("Base1的this指针是:%p!\n", this);
}
//虚表指针8字节
void func() override { cout << "Base1::func" << endl; }
void func1() override { cout << "Base1::func1" << endl; }
virtual void func3() { cout << "Base1::func3" << endl; }

int b1; //4字节
};

class Base2 : public Base
{
public:
Base2()
{
printf("Base2的this指针是:%p!\n", this);
}
void func() override { cout << "Base2::func" << endl; }
void func2() override { cout << "Base2::func2" << endl; }
virtual void func4() { cout << "Base2::func4" << endl; }

int b2;
};

class Derived : public Base1, public Base2
{
public:
Derived()
{
printf("Derive的this指针是:%p!\n", this);
}
void func() override { cout << "Derived::func" << endl; }
void func4() override { cout << "Derived::func4" << endl; }
void func3() override { cout << "Derived::func3" << endl; }
virtual void func5() { cout << "Derived::func5" << endl; }

int d;
};
-

内存布局

-

基类冗余

我们知道Derived继承自Base1Base2,而Base1Base2又继承自Base。这意味着Derived的内存布局中会有两份Base的拷贝。这会引起数据的不一致性和资源的浪费。

-

二义性

1
2
3
Derived obj;
obj.b = 1; //Derived::b不明确
Base* p = &obj; //基类Base不明确
-

对于obj.b,编译器无法确定在通过Dervide访问Base的成员b时应该选择哪条路径。
对于Base* p = &obj,编译器无法确定p应该指向通过Derived1继承的Base还是通过Derived2继承的Base

-

小结

本文简单讨论了菱形继承的内存布局以及其可能导致的问题。针对上述问题,可以采用虚继承解决,虚继承将在下一篇笔记中讨论。

-

参考文章

1.VTable Notes on Multiple Inheritance in GCC C++ Compiler v4.0.1

- -
- - -
-
-
    -
  • 标题: C++多态学习(二)菱形继承
  • -
  • 作者: paw5zx
  • -
  • 创建于 - : 2023-12-06 13:59:00
  • - -
  • - 更新于 - : 2024-08-22 13:51:30 -
  • - -
  • - 链接: https://paw5zx.github.io/2023/12/06/diamond-inherit/ -
  • -
  • - - 版权声明: - - - - - 本文章采用 CC BY-NC-SA 4.0 进行许可。 - -
  • -
-
- -
- - - - - -
- - -
- - -
- -
- -
- - -
- -
- -
- - - - -
-
-
-
- 评论 -
- - - - -
- - - - - - -
- -
- -
- - -
-
-
-
此页目录
-
C++多态学习(二)菱形继承
- - -
-
-
- -
- - - - - -
- - - -
- - -
- - -
-
-
    - - -
  • - -
  • - - - - -
  • - -
  • - -
-
- -
- - -
-
-
    -
  • - -
  • - -
  • - -
  • - -
  • - -
  • - - - - - - -
  • - -
  • -
- -
    -
  • - -
  • - -
  • - - -
  • - - -
-
- -
- -
- -
- - - -
- -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - -
- - - - diff --git a/404.html b/404.html index 7e72a0b..7a87e1e 100644 --- a/404.html +++ b/404.html @@ -28,17 +28,16 @@ - - + + - + - Page Not Found - + Page Not Found | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2023/10/09/Centos8-install/index.html b/Centos8-install/index.html similarity index 77% rename from 2023/10/09/Centos8-install/index.html rename to Centos8-install/index.html index 989f414..6d4f292 100644 --- a/2023/10/09/Centos8-install/index.html +++ b/Centos8-install/index.html @@ -13,7 +13,7 @@ - + @@ -21,28 +21,27 @@ - + - + - - + + - + - CentOS8系统换源安装(带GUI) - + CentOS8系统换源安装(带GUI) | Paw5zx - Paw5zx @@ -73,7 +72,7 @@ - + @@ -82,7 +81,7 @@ @@ -192,7 +191,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/GObject-tutorial-beginner-01/index.html b/GObject-tutorial-beginner-01/index.html new file mode 100644 index 0000000..a009fb7 --- /dev/null +++ b/GObject-tutorial-beginner-01/index.html @@ -0,0 +1,1160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GObject学习笔记(一)类和实例 | Paw5zx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + +
+

+ Paw5zx's Blog +

+ +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+ + +
+
+ +
+ +
+

GObject学习笔记(一)类和实例

+
+ +
+ + +
+
+ +
+
+
+ paw5zx + + Lv4 + +
+
+ + +
+
+
+ + + + + +
+

前言

最近阅读Aravis 源码,其中大量运用了GObject,于是打算学习一下。

+

此系列笔记仅主要面向初学者,不会很深入探讨源码的细节,专注于介绍GObject的基本用法。

+

此系列笔记参考GObject Tutorial for beginners

+ +
+

套个盾:文中定义的名词只是为了更好地理解GObject,不具备权威性。

+ +
+ + +

类和实例

在GObject中,每个可实例化类类型都与两个结构体相关联:一个是类结构体,一个是实例结构体。

+
    +
  • 类结构体会被注册到类型系统中(具体注册方式在下一节讨论),在g_object_new首次调用时,类型系统会检查相应的类结构体是否已经被初始化为一个类变量,没有则创建并初始化。此后所有该类的实例变量都将共享这个已初始化的类变量。每个类变量只会被创建一次。
  • +
  • 每次调用g_object_new时都会创建实例变量。
  • +
+ +
+

在GObject系统中,类结构体和实例结构体都会被实例化,在内存中占有特定的空间。为了便于描述,我们将分配给类结构体的实例称为“类变量”,而分配给实例结构体的实例称为“实例变量”。

+ +
+ + + +

GObject实例的结构体定义如下

+
1
2
3
4
5
6
7
8
9
10
//file: gobject.h
typedef struct _GObject GObject;
struct _GObject
{
GTypeInstance g_type_instance;

/*< private >*/
guint ref_count; /* (atomic) */
GData *qdata;
};
+ +

GObject类的结构体定义如下(我们可以先不用了解结构的细节):

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//file: gobject.h
typedef struct _GObjectClass GObjectClass;
struct _GObjectClass
{
GTypeClass g_type_class;

/*< private >*/
GSList *construct_properties;

/*< public >*/
/* seldom overridden */
GObject* (*constructor) (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties);
/* overridable methods */
void (*set_property) (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
void (*get_property) (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
void (*dispose) (GObject *object);
void (*finalize) (GObject *object);
/* seldom overridden */
void (*dispatch_properties_changed) (GObject *object,
guint n_pspecs,
GParamSpec **pspecs);
/* signals */
void (*notify) (GObject *object,
GParamSpec *pspec);

/* called when done constructing */
void (*constructed) (GObject *object);

/*< private >*/
gsize flags;

gsize n_construct_properties;

gpointer pspecs;
gsize n_pspecs;

/* padding */
gpointer pdummy[3];
};
+ +

下面使用一个简单示例,来演示GObject的类和实例的使用

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//file: example01.c
#include <glib-object.h>

int main (int argc, char **argv)
{

GObject *instance1, *instance2; //指向实例的指针
GObjectClass *class1, *class2; //指向类的指针

instance1 = g_object_new (G_TYPE_OBJECT, NULL);
instance2 = g_object_new (G_TYPE_OBJECT, NULL);
g_print ("The address of instance1 is %p\n", instance1);
g_print ("The address of instance2 is %p\n", instance2);

class1 = G_OBJECT_GET_CLASS (instance1);
class2 = G_OBJECT_GET_CLASS (instance2);
g_print ("The address of the class of instance1 is %p\n", class1);
g_print ("The address of the class of instance2 is %p\n", class2);

g_object_unref (instance1);
g_object_unref (instance2);

return 0;
}
+

其中:

+
    +
  • g_object_new函数创建实例变量并返回指向它的指针。在实例变量第一次被创建之前,它对应的类变量也会被创建并初始化。
  • +
  • 参数G_TYPE_OBJECT是GObject基类的类型标识符,这是GObject类型系统的核心,所有其他GObject类型都从这个基类型派生。
  • +
  • G_OBJECT_GET_CLASS返回指向参数所属类变量的指针
  • +
  • g_object_unref会销毁实例变量并释放内存。
  • +
+

输出:

+
1
2
3
4
The address of instance1 is 0x55d3ddc05600
The address of instance2 is 0x55d3ddc05620
The address of the class of instance1 is 0x55d3ddc05370
The address of the class of instance2 is 0x55d3ddc05370
+ +

可以发现,两个实例变量的地址不同,但两个实例变量对应的类变量的地址相同,因为两个实例变量共享一个类变量

+

引用计数

引用计数机制的概念在此不做介绍

+

在GObject中,GObject实例具有引用计数机制:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//file: example02.c
#include <glib-object.h>

static void show_ref_count (GObject *instance)
{
if (G_IS_OBJECT (instance))
/* Users should not use ref_count member in their program. */
/* This is only for demonstration. */
g_print ("Reference count is %d.\n", instance->ref_count);
else
g_print ("Instance is not GObject.\n");
}

int main (int argc, char **argv)
{
GObject *instance;

instance = g_object_new (G_TYPE_OBJECT, NULL);
g_print ("Call g_object_new.\n");
show_ref_count (instance);
g_object_ref (instance);
g_print ("Call g_object_ref.\n");
show_ref_count (instance);
g_object_unref (instance);
g_print ("Call g_object_unref.\n");
show_ref_count (instance);
g_object_unref (instance);
g_print ("Call g_object_unref.\n");
g_print ("Now the reference count is zero and the instance is destroyed.\n");
g_print ("The instance memories are possibly returned to the system.\n");
g_print ("Therefore, the access to the same address may cause a segmentation error.\n");

return 0;
}
+ +

其中:

+
    +
  • g_object_new创建一个实例变量,然后将变量的引用计数置为1
  • +
  • g_object_ref将其引用计数加1
  • +
  • g_object_unref将引用计数减1,如果此时引用计数为0,则析构变量。
  • +
+

输出:

+
1
2
3
4
5
6
7
8
9
10
Call g_object_new.
Reference count is 1.
Call g_object_ref.
Reference count is 2.
Call g_object_unref.
Reference count is 1.
Call g_object_unref.
Now the reference count is zero and the instance is destroyed.
The instance memories are possibly returned to the system.
Therefore, the access to the same address may cause a segmentation error.
+ +

初始化和析构过程

GObject初始化和销毁的实际过程比较复杂。以下是简单的描述,不做详细说明.

+

初始化

1.用类型系统注册GObject类型。这是在调用main函数之前的GLib的初始化过程中完成的。(如果编译器是gcc,则__attribute__ ((constructor))用于限定初始化函数。)
2.为GObjectClass和GObject结构分配内存
3.初始化GObjectClass结构内存。这个内存将是GObject的类变量。
4.初始化GObject结构内存。这个内存将是GObject的实例变量。

+

上述初始化过程在第一次调用g_object_new函数时执行。在第二次及后续调用g_object_new时,它只执行两个过程:①为GObject结构分配内存②初始化内存。

+

析构

1.销毁GObject实例。释放实例的内存

+

GObject变量类型是静态类型。静态类型永远不会破坏它的类。因此,即使被销毁的实例变量是最后一个,类变量仍然存在,直到程序终止。

+

参考文章

1.GObject Tutorial for beginners

+ +
+ + +
+
+
    +
  • 标题: GObject学习笔记(一)类和实例
  • +
  • 作者: paw5zx
  • +
  • 创建于 + : 2024-11-02 19:49:38
  • + +
  • + 更新于 + : 2024-11-11 13:52:26 +
  • + +
  • + 链接: https://paw5zx.github.io/GObject-tutorial-beginner-01/ +
  • +
  • + + 版权声明: + + + + + 本文章采用 CC BY-NC-SA 4.0 进行许可。 + +
  • +
+
+ +
+ + + + + +
+ + +
+ + +
+ +
+ +
+ + +
+ +
+ +
+ + + + +
+
+
+
+ 评论 +
+ + + + +
+ + + + + + +
+ +
+ +
+ + +
+
+
+
目录
+
GObject学习笔记(一)类和实例
+ + +
+
+
+ +
+ + + + + +
+ + + +
+ + +
+ + +
+
+
    + + +
  • + +
  • + + + + +
  • + +
  • + +
+
+ +
+ + +
+
+
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + + + + + + +
  • + +
  • +
+ +
    +
  • + +
  • + +
  • + + +
  • + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GObject-tutorial-beginner-02/index.html b/GObject-tutorial-beginner-02/index.html new file mode 100644 index 0000000..f5cefab --- /dev/null +++ b/GObject-tutorial-beginner-02/index.html @@ -0,0 +1,1261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GObject学习笔记(二)类型创建与注册 | Paw5zx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + +
+

+ Paw5zx's Blog +

+ +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+ + +
+
+ +
+ +
+

GObject学习笔记(二)类型创建与注册

+
+ +
+ + +
+
+ +
+
+
+ paw5zx + + Lv4 + +
+
+ + +
+
+
+ + + + + +
+

前言

上一节中我们介绍了GObject类型的类和实例变量的创建和使用。GObject是一个基本的可实例化类类型,是所有使用GObject系统的类型的基类,提供了继承、封装、多态等面向对象的核心特性。不过我们一般不直接使用GObject本身,而是通过继承GObject来创建新的类型。

+ +
+

对于GObject官方文档中:

+

可实例化的类类型:object(Instantiatable classed types: objects),本文以及后文中称其为类型。
不可实例化的类类型:interface(Non-instantiatable classed types: interfaces),本文以及后文中称其为接口。

+ +
+ +

本文中我们主要介绍一下GObject类型系统中的命名约定,以及介绍如何创建一个自定义的类型。

+

命名约定

+
+

命名约定贯穿整个GObject类型系统。

+ +
+ +

首先,我们先了解基本的命名约定:一个对象名由命名空间(也可称为moudle)和名称组成。例如,GObject由命名空间“G”和名称“Object”组成。GtkWidget由命名空间“Gtk”和名称“Widget”组成。在本文中,为了更好的演示,我们将定义一个新类型,其命名空间为“Paw”,名称为“Double”,用于表示一个浮点数据。

+

好了,你现在已了解了基本的命名约定,下面我们来看一下更多的命名约定:

+
    +
  • 类型名称必须至少有三个字符长,并以a-z, A-Z或_开头。
  • +
  • 函数名使用object_method模式:要在类型为Double的实例上定义名为add的函数,则函数名为double_save
  • +
  • 使用前缀可以避免与其他项目的名称空间冲突。如我的库(或应用程序)名为Paw,就在所有函数名前加上paw_。例如:paw_double_add。前缀应该是一个词,即在第一个字母之后不应该包含任何大写字母。例如,应该是Exampleprefix而不是ExamplePrefix。
  • +
+

除了上述约定,本文还将介绍更多命名约定,将在文中适时描述。

+

类型创建和注册

类型的创建是指定义一个新的GObject类型,包括其所有的数据和行为。这会涉及到:

+
    +
  • 定义类结构体和实例结构体
  • +
  • 定义类型相关的函数:如类初始化(class_init)、实例初始化(instance_init)等函数。
  • +
+

类型的注册是将创建的新GObject类型在GObject类型系统中注册,使其成为GObject系统可识别和使用的一部分。这会涉及到:

+
    +
  • 调用类型注册函数:g_type_register_staticg_type_register_dynamic,这些函数负责在GObject类型系统中注册新创建的类型
  • +
+

在我们平时的使用中,类型的创建和注册通常可以通过GObject提供的一些便利宏来完成,如G_DECLARE_FINAL_TYPEG_DEFINE_TYPE等。这些便利宏可以让用户不用关心一些类型创建和注册的具体细节。

+

在本文中,为了更好地理解GObject类型系统,会先展示不使用便利宏的类型创建和注册过程,之后再介绍便利宏。

+ +
+

GObject类型系统中有两种类型:静态类型和动态类型。

+

对于静态类型,即使所有实例都被销毁后也不会销毁其类。对于动态类型,在最后一个实例被销毁时销毁其类。GObject的类型是静态的,其派生的类型也是静态的。

+ +
+ + + +

手动

定义类型的类和实例结构体

类和实例结构体命名约定如下:

+
    +
  • 类结构体的命名为:<Moudle><Name>Class,如PawDoubleClass。
  • +
  • 实例结构体的命名为:<Moudle><Name>,如PawDouble。
  • +
+
1
2
3
4
5
6
//类结构体
typedef struct _PawDoubleClass PawDoubleClass;
struct _PawDoubleClass
{
GObjectClass parent_class;
};
+

PawDoubleClass的第一个成员必须是其父类型的类结构体

+
1
2
3
4
5
6
7
//实例结构体
typedef struct _PawDouble PawDouble;
struct _PawDouble
{
GObject parent;
double value;
};
+

PawDouble的第一个成员必须是其父类型的实例结构体。
PawDouble有自己的成员value,是PawDouble类型代表的浮点数据的值

+

定义初始化函数

类和实例的初始化函数命名约定如下:

+
    +
  • 类初始化函数的命名为:<moudle>_<name>_class_init,如paw_double_class_init。
  • +
  • 实例初始化函数的命名为:<moudle>_<name>_init,如paw_double_init。
  • +
+
1
2
3
4
5
6
7
8
9
//类构造函数
static void paw_double_class_init(PawDoubleClass *class)
{
}

//实例构造函数
static void paw_double_init(PawDouble *self)
{
}
+ +

类型注册

对于静态类型,我们使用g_type_register_static将其注册至GObject的类型系统中

+
1
2
3
4
5
6
//file: gtype.h
GType
g_type_register_static (GType parent_type,
const gchar* type_name,
const GTypeInfo* info,
GTypeFlags flags);
+

其中:

+
    +
  • parent_type:父类类型
  • +
  • type_name:类型名称,如PawDouble
  • +
  • info:向类型系统传递类型初始化和销毁的相关信息。GTypeInfo结构体将在下文中介绍
  • +
  • flags:如果类型是抽象类型或抽象值类型,则设置它们的标志位。否则,将其设为0。
  • +
+

GTyepInfo结构体:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef struct _GTypeInfo  GTypeInfo;

struct _GTypeInfo
{
/* interface types, classed types, instantiated types */
guint16 class_size;

GBaseInitFunc base_init;
GBaseFinalizeFunc base_finalize;

/* interface types, classed types, instantiated types */
GClassInitFunc class_init;
GClassFinalizeFunc class_finalize;
gconstpointer class_data;

/* instantiated types */
guint16 instance_size;
guint16 n_preallocs;
GInstanceInitFunc instance_init;

/* value handling */
const GTypeValueTable *value_table;
};
+

此结构必须在类型注册前创建,其中:

+
    +
  • class_size: 类的大小。例如,PawDouble类型的类大小为sizeof(PawDoubleClass)
  • +
  • base_init, base_finalize: 这些函数初始化/销毁类的动态成员。在许多情况下,它们不是必需的,被赋值为NULL。详见GObject.BaseInitFunc GObject.ClassInitFunc
  • +
  • class_init: 类的初始化函数。用户需要将定义的类初始化函数赋值给class_init成员。按照命名约定,类初始化函数名称为<moudle>_<name>_class_init,例如paw_double_class_init
  • +
  • class_finalize: 类的销毁函数。因为GObject的子类类型是静态的,所以它没有销毁函数。将class_finalize成员赋值为NULL即可。
  • +
  • class_data: 用户提供数据,传递给类的初始化/销毁函数。通常赋值为 NULL。
  • +
  • instance_size: 实例的大小。例如,PawDouble类型的实例大小为sizeof(PawDouble)
  • +
  • n_preallocs: 用于指定预分配的实例数量。自GLib 2.10以来,该字段被忽略。
  • +
  • instance_init: 实例的初始化函数。用户需要将定义的实例初始化函数赋值给instance_init成员。按照命名约定,实例初始化函数名称为<moudle>_<name>_init,例如 paw_double_init
  • +
  • value_table: 这通常只对基本类型有用。如果类型是GObject的后代,赋值为NULL。
  • +
+

我们将编写一个函数paw_double_get_type,用于向GObject类型系统注册新类型,并返回所注册类型的id

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GType paw_double_get_type(void) 
{
static GType type = 0;
GTypeInfo info;

if(type == 0)
{
//赋值
info.class_size = sizeof(PawDoubleClass);
info.base_init = NULL;
info.base_finalize = NULL;
info.class_init = (GClassInitFunc) paw_double_class_init;
info.class_finalize = NULL;
info.class_data = NULL;
info.instance_size = sizeof(PawDouble);
info.n_preallocs = 0;
info.instance_init = (GInstanceInitFunc) paw_double_init;
info.value_table = NULL;
//注册类型
type = g_type_register_static(G_TYPE_OBJECT, "PawDouble", &info, 0);
}
return type;
}
+ + + +

汇总

上述的类型创建和注册过程汇总如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <glib-object.h>

#define PAW_TYPE_DOUBLE (paw_double_get_type())

//定义实例结构体
typedef struct _PawDouble PawDouble;
struct _PawDouble
{
GObject parent;
double value;
};

//定义类结构体
typedef struct _PawDoubleClass PawDoubleClass;
struct _PawDoubleClass
{
GObjectClass parent_class;
};

//类构造函数
static void paw_double_class_init(PawDoubleClass *class)
{
}

//实例构造函数
static void paw_double_init(PawDouble *self)
{
}

//首次调用时注册类型
//返回类型
GType paw_double_get_type(void)
{
static GType type = 0;
GTypeInfo info;

if(type == 0)
{
info.class_size = sizeof(PawDoubleClass);
info.base_init = NULL;
info.base_finalize = NULL;
info.class_init = (GClassInitFunc) paw_double_class_init;
info.class_finalize = NULL;
info.class_data = NULL;
info.instance_size = sizeof(PawDouble);
info.n_preallocs = 0;
info.instance_init = (GInstanceInitFunc) paw_double_init;
info.value_table = NULL;
type = g_type_register_static(G_TYPE_OBJECT, "PawDouble", &info, 0);
}
return type;
}

int main(int argc, char **argv)
{
GType dtype;
PawDouble *d;

dtype = paw_double_get_type(); /* or dtype = PAW_TYPE_DOUBLE */
if(dtype)
g_print("Registration was a success. The type is %lx.\n", dtype);
else
g_print("Registration failed.\n");

d = g_object_new(PAW_TYPE_DOUBLE, NULL);
if(d)
g_print("Instantiation was a success. The instance address is %p.\n", d);
else
g_print("Instantiation failed.\n");
g_object_unref(d); /* Releases the object d. */

return 0;
}
+ +
    +
  • 20-28:类初始化函数和实例初始化函数,参数class是指类结构体,参数self是指实例结构体。这两个函数在示例中内容为空,但他们是注册过程必须的。

    +
  • +
  • 30-52:paw_double_get_type函数,返回PawDouble类型的id。这种函数的命名总是遵循<moudle>_<name>_get_type。同时,宏<MOUDLE>_TYPE_<NAME>(所有字符都是大写)是这个函数的别名。paw_double_get_type函数有一个静态变量type来存储对象的类型。在此函数的第一次调用时,type是零。然后函数内调用 g_type_register_static将新类型注册到类型系统中。在第二次和之后的调用中,该函数只是返回type,因为静态变量type已经被g_type_register_static赋予了非零值,并且它保持该值。

    +
  • +
  • 39-49:设置info结构体并调用g_type_register_static注册。

    +
  • +
  • 54-73:主函数。获取PawDouble类型id并显示它。函数g_object_new被用来创建类型实例。GObject API文档中表示g_object_new返回一个指向GObject实例的指针,但实际上它返回的是一个gpointergpointer基本等同于void*,可以被赋值给指向任何类型的指针。因此,语句d = g_object_new(PAW_TYPE_DOUBLE, NULL);是正确的。如果函数g_object_new返回的是GObject*,那么就需要对返回的指针进行类型转换。在创建完成后,我们打印了实例的地址。最后,使用函数g_object_unref释放并销毁实例。

    +
  • +
+

便利宏

注册的过程总是可以使用相同的算法完成,因此可以被定义为宏。

+

GObject提供了一些宏:

+

G_DEFINE_TYPE

1
#define G_DEFINE_TYPE(TN, t_n, T_P)
+

其中:

+
    +
  • TN:新类型的名称,驼峰形式,如PawDouble
  • +
  • t_n:新类型的名称,全小写,单词之间使用下划线分隔。如paw_double
  • +
  • T_P:父类的类型,GType
  • +
+

G_DEFINE_TYPE内部完成了以下操作:

+
    +
  • 声明一个类初始化函数。其名称为<moudle>_<name>_class_init。例如,如果类型名称是PawDouble,它就是paw_double_class_init。这只是一个声明,不是定义。用户需要定义它。
  • +
  • 声明一个实例初始化函数。其名称为<moudle>_<name>_init。例如,如果类型名称是PawDouble,它就是paw_double_init。这只是一个声明,不是定义。用户需要定义它。
  • +
  • 声明一个指向父类的静态变量。其名称为<moudle>_<name>_parent_class。例如,如果对象名称是PawDouble,它就是paw_double_parent_class
  • +
  • 定义一个<moudle>_<name>_get_type()函数。例如,如果对象名称是PawDouble,它就是paw_double_get_type。在这个函数中完成类型注册,就像前面描述的那样。
  • +
+

要使用此宏完成类型的创建和注册,我们只需要再手动提供

+
    +
  • 类和实例结构体的定义(必须在使用G_DEFINE_TYPE之前完成)
  • +
  • 类和实例初始化函数的定义(通常在使用G_DEFINE_TYPE之后完成)
  • +
+

因此,我们可以将手动创建和注册类型的代码简化如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <glib-object.h>

#define PAW_TYPE_DOUBLE (paw_double_get_type())

typedef struct _PawDouble PawDouble;
struct _PawDouble
{
GObject parent;
double value;
};

typedef struct _PawDoubleClass PawDoubleClass;
struct _PawDoubleClass
{
GObjectClass parent_class;
};

G_DEFINE_TYPE(PawDouble, paw_double, G_TYPE_OBJECT)

static void paw_double_class_init(PawDoubleClass *class)
{
}

static void paw_double_init(PawDouble *self)
{
}

int main(int argc, char **argv)
{
GType dtype;
PawDouble *d;

dtype = paw_double_get_type(); /* or dtype = PAW_TYPE_DOUBLE */
if(dtype)
g_print("Registration was a success. The type is %lx.\n", dtype);
else
g_print("Registration failed.\n");

d = g_object_new(PAW_TYPE_DOUBLE, NULL);
if(d)
g_print("Instantiation was a success. The instance address is %p.\n", d);
else
g_print("Instantiation failed.\n");
g_object_unref(d);

return 0;
}
+

G_DECLARE_FINAL_TYPE

另一个有用的宏是G_DECLARE_FINAL_TYPE。这个宏可以用于声明最派生类型(final type)。如果想声明一个可派生类型,可使用G_DECLARE_DERIVABLE_TYPE(会在后面介绍)。然而,在大多数情况下,我们都是需要创建最派生类型。

+

其声明为:

+
1
#define G_DECLARE_FINAL_TYPE(ModuleObjName, module_obj_name, MODULE, OBJ_NAME, ParentName)
+

其中:

+
    +
  • ModuleObjName:新类型的名称,驼峰形式(如PawDouble
  • +
  • module_obj_name:新类型名称,全小写,单词之间使用下划线分隔(如paw_double
  • +
  • MODULE:模块的名称,全大写(如PAW
  • +
  • OBJ_NAME:新类型的名称,去除修饰,全大写如(DOUBLE
  • +
  • ParentName:父类型的名称,驼峰形式(如GObject
  • +
+

G_DECLARE_FINAL_TYPE内部完成以下操作:

+
    +
  • 声明返回类型为GType<moudle>_<name>_get_type()函数。这只是声明,用户需要定义它。但其实可以使用G_DEFINE_TYPE,其扩展包括该函数的定义。所以,实际上用户不需要手动编写定义。
  • +
  • 对象的C类型被定义为结构体的typedef。例如,如果类型名称是PawDouble,那么内部有typedef struct _PawDouble PawDouble。但是_PawDouble结构体本身并没有定义,应该在使用G_DEFINE_TYPE()之前定义。
  • +
  • 定义<MOUDLE>_<NAME>宏。例如,如果类型是PawDouble,则宏是PAW_DOUBLE。它会被扩展为一个将参数转换为指向该类型实例的指针的函数。例如,PAW_DOUBLE(obj)obj的类型转换为PawDouble*
  • +
  • 定义<MOUDLE>_IS_<NAME>宏。例如,如果对象是PawDouble,则宏是PAW_IS_DOUBLE。它会被扩展为一个检查参数是否为指向PawDouble类型实例的函数。如果参数指向PawDouble及其后代,则宏返回真。
  • +
  • 定义类结构体。最派生类型不需要在类结构中有自己的成员。
  • +
+

在使用G_DECLARE_FINAL_TYPE之前,我们还要手动定义<MOUDLE>_TYPE_<NAME>,如

+
1
#define PAW_TYPE_DOUBLE paw_double_get_type
+

知道了G_DECLARE_FINAL_TYPE的使用方法,我们就可以将声明和实现分离了

+

声明和实现分离

现在将上面的示例拆分到PawDouble.cPawDouble.hmain.c

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//file: PawDouble.h
#ifndef PAW_DOUBLE_H
#define PAW_DOUBLE_H

#include <glib-object.h>
G_BEGIN_DECLS

#define PAW_TYPE_DOUBLE (paw_double_get_type())
G_DECLARE_FINAL_TYPE(PawDouble, paw_double, PAW, DOUBLE, GObject)

gboolean paw_double_get_value(PawDouble *self, double *value);

void paw_double_set_value(PawDouble *self, double value);

PawDouble * paw_double_new(double value);

G_END_DECLS

#endif /* PAW_DOUBLE_H */
+ +
    +
  • 头文件是公开的的,即对任何文件都是开放的。
  • +
  • 2-3:预处理器指令,用于防止头文件的内容被多次包含。
  • +
  • 6,17:GObject库中的宏,用于确保当GObject库的头文件被C++编译器包含时,内部声明的C函数不会被当作C++函数进行名称修饰,从而可以在C++代码中正常调用C函数。
  • +
  • 8-9:PAW_TYPE_DOUBLE是公开的。G_DECLARE_FINAL_TYPE展开为公开定义。
  • +
  • 11-13:公共函数声明。它们是对象值的获取器和设置器,被称为“实例方法”,这是面向对象语言中使用的。
  • +
  • 15:对象实例化函数。
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//file: PawDouble.c
#include "PawDouble.h"

struct _PawDouble
{
GObject parent;
double value;
};

G_DEFINE_TYPE(PawDouble, paw_double, G_TYPE_OBJECT)

static void paw_double_class_init(PawDoubleClass *class)
{
}

static void paw_double_init(PawDouble *self)
{
}

gboolean paw_double_get_value(PawDouble *self, double *value)
{
g_return_val_if_fail(PAW_IS_DOUBLE(self), FALSE);

*value = self->value;
return TRUE;
}

void paw_double_set_value(PawDouble *self, double value)
{
g_return_if_fail(PAW_IS_DOUBLE(self));

self->value = value;
}

PawDouble * paw_double_new(double value)
{
PawDouble *d;

d = g_object_new(PAW_TYPE_DOUBLE, NULL);
d->value = value;
return d;
}
+ +
    +
  • 4-8:实例结构的声明。由于G_DECLARE_FINAL_TYPE宏定义了typedef struct _PawDouble PawDouble,因此结构的标签名必须是_PawDouble
  • +
  • 10:G_DEFINE_TYPE 宏。
  • +
  • 12-18:类和实例初始化函数。目前,它们不执行任何操作。
  • +
  • 20-26:获取器。参数值是指向双精度类型变量的指针。将对象值(self->value)赋给该变量。如果成功,则返回TRUE。函数g_return_val_if_fail用于检查参数类型。如果参数self不是PawDouble类型,它会输出错误到日志并立即返回FALSE。在静态类函数中不需要使用g_return_val_if_fail,因为静态函数的作用域局限于定义它们的同一源文件内,且通常由同一文件内的其他函数调用,因此调用者对于需要传递给静态函数的参数类型已经有了充分的了解。在这种情况下,使用g_return_val_if_fail进行参数有效性检查可能是多余的(待验证)。
  • +
  • 28-33:设置器。这个函数不返回任何值。因此,我们使用g_return_if_fail而不是g_return_val_if_fail
  • +
  • 35-42:实例化函数。它的参数值用来设置实例表示的值。
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//file: main.c
#include <glib-object.h>
#include "PawDouble.h"

int main(int argc, char **argv)
{
PawDouble *d;
double value;

d = paw_double_new(10.0);
if(paw_double_get_value(d, &value))
g_print("paw_double_get_value succesfully assigned %lf to value.\n", value);
else
g_print("paw_double_get_value failed.\n");

paw_double_set_value(d, -20.0);
g_print("Now, set d(PawDouble object) with %lf.\n", -20.0);
if(paw_double_get_value(d, &value))
g_print("paw_double_get_value succesfully assigned %lf to value.\n", value);
else
g_print("paw_double_get_value failed.\n");
g_object_unref(d);

return 0;
}
+ +
    +
  • 3:包含PawDouble.h。这是获取PawDouble类型的必要步骤
  • +
  • 9:实例化PawDouble类型实例并使用指针d指向对象
  • +
  • 11-14:测试获取器
  • +
  • 16-21:测试设置器
  • +
  • 22:释放d
  • +
+

在实际的使用中,任何一个类型都会有这样一个头文件和对应的源文件。

+

参考文章

1.GObject Tutorial for beginners

+ +
+ + +
+
+
    +
  • 标题: GObject学习笔记(二)类型创建与注册
  • +
  • 作者: paw5zx
  • +
  • 创建于 + : 2024-11-05 23:23:41
  • + +
  • + 更新于 + : 2024-11-12 00:55:51 +
  • + +
  • + 链接: https://paw5zx.github.io/GObject-tutorial-beginner-02/ +
  • +
  • + + 版权声明: + + + + + 本文章采用 CC BY-NC-SA 4.0 进行许可。 + +
  • +
+
+ +
+ + + + + +
+ + +
+ + +
+ + +
+ +
+ +
+ + + + +
+
+
+
+ 评论 +
+ + + + +
+ + + + + + +
+ +
+ +
+ + + + +
+ + + + + +
+ + + +
+ + +
+ + +
+
+
    + + +
  • + +
  • + + + + +
  • + +
  • + +
+
+ +
+ + +
+
+
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + + + + + + +
  • + +
  • +
+ +
    +
  • + +
  • + +
  • + + +
  • + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2024/03/08/IO-Multiplexing-do-select/do_select.png b/IO-Multiplexing-do-select/do_select.png similarity index 100% rename from 2024/03/08/IO-Multiplexing-do-select/do_select.png rename to IO-Multiplexing-do-select/do_select.png diff --git a/2024/03/08/IO-Multiplexing-do-select/index.html b/IO-Multiplexing-do-select/index.html similarity index 88% rename from 2024/03/08/IO-Multiplexing-do-select/index.html rename to IO-Multiplexing-do-select/index.html index 2d265df..2ee21c8 100644 --- a/2024/03/08/IO-Multiplexing-do-select/index.html +++ b/IO-Multiplexing-do-select/index.html @@ -13,7 +13,7 @@ - + @@ -21,34 +21,33 @@ - + - - - - - + + + + + - + - - + + - + - I/O多路复用学习(二)do_select分析 - + I/O多路复用学习(二)do_select分析 | Paw5zx - Paw5zx @@ -79,7 +78,7 @@ - + @@ -88,7 +87,7 @@ @@ -198,7 +197,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/03/08/IO-Multiplexing-do-select/poll_table_page.png b/IO-Multiplexing-do-select/poll_table_page.png similarity index 100% rename from 2024/03/08/IO-Multiplexing-do-select/poll_table_page.png rename to IO-Multiplexing-do-select/poll_table_page.png diff --git a/2024/03/08/IO-Multiplexing-do-select/pollwait.png b/IO-Multiplexing-do-select/pollwait.png similarity index 100% rename from 2024/03/08/IO-Multiplexing-do-select/pollwait.png rename to IO-Multiplexing-do-select/pollwait.png diff --git a/2024/03/08/IO-Multiplexing-do-select/pollwake.png b/IO-Multiplexing-do-select/pollwake.png similarity index 100% rename from 2024/03/08/IO-Multiplexing-do-select/pollwake.png rename to IO-Multiplexing-do-select/pollwake.png diff --git a/2024/03/08/IO-Multiplexing-do-select/struct.png b/IO-Multiplexing-do-select/struct.png similarity index 100% rename from 2024/03/08/IO-Multiplexing-do-select/struct.png rename to IO-Multiplexing-do-select/struct.png diff --git a/2024/03/05/IO-Multiplexing-select/doselect.png b/IO-Multiplexing-select/doselect.png similarity index 100% rename from 2024/03/05/IO-Multiplexing-select/doselect.png rename to IO-Multiplexing-select/doselect.png diff --git a/2024/03/05/IO-Multiplexing-select/index.html b/IO-Multiplexing-select/index.html similarity index 76% rename from 2024/03/05/IO-Multiplexing-select/index.html rename to IO-Multiplexing-select/index.html index a1144c8..f198333 100644 --- a/2024/03/05/IO-Multiplexing-select/index.html +++ b/IO-Multiplexing-select/index.html @@ -13,7 +13,7 @@ - + @@ -21,31 +21,30 @@ - + - - + + - + - - + + - + - I/O多路复用学习(一)select - + I/O多路复用学习(一)select | Paw5zx - Paw5zx @@ -76,7 +75,7 @@ - + @@ -85,7 +84,7 @@ @@ -195,7 +194,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/03/05/IO-Multiplexing-select/pollwait.png b/IO-Multiplexing-select/pollwait.png similarity index 100% rename from 2024/03/05/IO-Multiplexing-select/pollwait.png rename to IO-Multiplexing-select/pollwait.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/10_rice_cooker.png b/UE-fmodel-blackmyth-wukong/10_rice_cooker.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/10_rice_cooker.png rename to UE-fmodel-blackmyth-wukong/10_rice_cooker.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/11_sanguo.png b/UE-fmodel-blackmyth-wukong/11_sanguo.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/11_sanguo.png rename to UE-fmodel-blackmyth-wukong/11_sanguo.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/12_coconut.png b/UE-fmodel-blackmyth-wukong/12_coconut.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/12_coconut.png rename to UE-fmodel-blackmyth-wukong/12_coconut.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/1_wukong_face.png b/UE-fmodel-blackmyth-wukong/1_wukong_face.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/1_wukong_face.png rename to UE-fmodel-blackmyth-wukong/1_wukong_face.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/2_chiguo.png b/UE-fmodel-blackmyth-wukong/2_chiguo.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/2_chiguo.png rename to UE-fmodel-blackmyth-wukong/2_chiguo.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/3_duowen.png b/UE-fmodel-blackmyth-wukong/3_duowen.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/3_duowen.png rename to UE-fmodel-blackmyth-wukong/3_duowen.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/4_guangmu.png b/UE-fmodel-blackmyth-wukong/4_guangmu.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/4_guangmu.png rename to UE-fmodel-blackmyth-wukong/4_guangmu.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/5_zengzhang.png b/UE-fmodel-blackmyth-wukong/5_zengzhang.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/5_zengzhang.png rename to UE-fmodel-blackmyth-wukong/5_zengzhang.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/6_dog.png b/UE-fmodel-blackmyth-wukong/6_dog.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/6_dog.png rename to UE-fmodel-blackmyth-wukong/6_dog.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/7_name.png b/UE-fmodel-blackmyth-wukong/7_name.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/7_name.png rename to UE-fmodel-blackmyth-wukong/7_name.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/8_name_hard.png b/UE-fmodel-blackmyth-wukong/8_name_hard.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/8_name_hard.png rename to UE-fmodel-blackmyth-wukong/8_name_hard.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/9_version_solution.png b/UE-fmodel-blackmyth-wukong/9_version_solution.png similarity index 100% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/9_version_solution.png rename to UE-fmodel-blackmyth-wukong/9_version_solution.png diff --git a/2024/08/21/UE-fmodel-blackmyth-wukong/index.html b/UE-fmodel-blackmyth-wukong/index.html similarity index 72% rename from 2024/08/21/UE-fmodel-blackmyth-wukong/index.html rename to UE-fmodel-blackmyth-wukong/index.html index b0a10f8..2a76a18 100644 --- a/2024/08/21/UE-fmodel-blackmyth-wukong/index.html +++ b/UE-fmodel-blackmyth-wukong/index.html @@ -13,7 +13,7 @@ - + @@ -21,41 +21,40 @@ - + - - - - - - - - - - - - + + + + + + + + + + + + - + - + - - + + - + - 使用FModel提取《黑神话:悟空》的资产 - + 使用FModel提取《黑神话:悟空》的资产 | Paw5zx - Paw5zx @@ -86,7 +85,7 @@ - + @@ -95,7 +94,7 @@ @@ -205,7 +204,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/07/16/UE-fmodel-usage/10_usmap.png b/UE-fmodel-usage/10_usmap.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/10_usmap.png rename to UE-fmodel-usage/10_usmap.png diff --git a/2024/07/16/UE-fmodel-usage/11_injector.png b/UE-fmodel-usage/11_injector.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/11_injector.png rename to UE-fmodel-usage/11_injector.png diff --git a/2024/07/16/UE-fmodel-usage/12_dll.png b/UE-fmodel-usage/12_dll.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/12_dll.png rename to UE-fmodel-usage/12_dll.png diff --git a/2024/07/16/UE-fmodel-usage/13_select_pid.png b/UE-fmodel-usage/13_select_pid.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/13_select_pid.png rename to UE-fmodel-usage/13_select_pid.png diff --git a/2024/07/16/UE-fmodel-usage/14_inject.png b/UE-fmodel-usage/14_inject.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/14_inject.png rename to UE-fmodel-usage/14_inject.png diff --git a/2024/07/16/UE-fmodel-usage/1_fmodel.png b/UE-fmodel-usage/1_fmodel.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/1_fmodel.png rename to UE-fmodel-usage/1_fmodel.png diff --git a/2024/07/16/UE-fmodel-usage/2_first_time.png b/UE-fmodel-usage/2_first_time.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/2_first_time.png rename to UE-fmodel-usage/2_first_time.png diff --git a/2024/07/16/UE-fmodel-usage/3_aes.png b/UE-fmodel-usage/3_aes.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/3_aes.png rename to UE-fmodel-usage/3_aes.png diff --git a/2024/07/16/UE-fmodel-usage/4_aes2.png b/UE-fmodel-usage/4_aes2.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/4_aes2.png rename to UE-fmodel-usage/4_aes2.png diff --git a/2024/07/16/UE-fmodel-usage/5_path.png b/UE-fmodel-usage/5_path.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/5_path.png rename to UE-fmodel-usage/5_path.png diff --git a/2024/07/16/UE-fmodel-usage/6_unpack.png b/UE-fmodel-usage/6_unpack.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/6_unpack.png rename to UE-fmodel-usage/6_unpack.png diff --git a/2024/07/16/UE-fmodel-usage/7_result.png b/UE-fmodel-usage/7_result.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/7_result.png rename to UE-fmodel-usage/7_result.png diff --git a/2024/07/16/UE-fmodel-usage/8_viewer.png b/UE-fmodel-usage/8_viewer.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/8_viewer.png rename to UE-fmodel-usage/8_viewer.png diff --git a/2024/07/16/UE-fmodel-usage/9_menu.png b/UE-fmodel-usage/9_menu.png similarity index 100% rename from 2024/07/16/UE-fmodel-usage/9_menu.png rename to UE-fmodel-usage/9_menu.png diff --git a/2024/07/16/UE-fmodel-usage/index.html b/UE-fmodel-usage/index.html similarity index 76% rename from 2024/07/16/UE-fmodel-usage/index.html rename to UE-fmodel-usage/index.html index 040eca2..06dd40d 100644 --- a/2024/07/16/UE-fmodel-usage/index.html +++ b/UE-fmodel-usage/index.html @@ -13,7 +13,7 @@ - + @@ -21,43 +21,42 @@ - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - + - - + + - + - 使用FModel提取UE4/5游戏资产 - + 使用FModel提取UE4/5游戏资产 | Paw5zx - Paw5zx @@ -88,7 +87,7 @@ - + @@ -97,7 +96,7 @@ @@ -207,7 +206,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/aravis-GVCP-packets/index.html b/aravis-GVCP-packets/index.html new file mode 100644 index 0000000..7984b39 --- /dev/null +++ b/aravis-GVCP-packets/index.html @@ -0,0 +1,1356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GVCP数据包 | Paw5zx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + +
+

+ Paw5zx's Blog +

+ +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+ + +
+
+ +
+ +
+

GVCP数据包

+
+ +
+ + +
+
+ +
+
+
+ paw5zx + + Lv4 + +
+
+ + +
+
+
+ + + + + +
+

简述

设备通过监听GVCP端口(3956)等待GVCP数据包。当客户端(如:PC设备)向设备(如:相机)发送一个GVCP命令数据包时,设备会回复一个确认数据包。每个命令/确认对(command/acknowledge pair)都使用一个16 bit的值来标识(就相当于ID),这样可以检查确认数据包是否与之前发送的命令对应。0是这个标识符的错误值。如果在给定的超时时间后没有收到确认,将再次发送命令数据包,直到达到最大重试次数。

+

ArvGvcp API提供了一系列处理GVCP包的函数。

+

GVCP数据包的内容由一个64 bit的头部组成,头部后面可能跟着一个数据字节数组(也可能没有,具体取决于GVCP数据包的类型)。多字节值采用大端编码。

+ + + + + + + + + + + + + + + + + + + + + + + + +
表格1.GVCP packet
015163132474863
ArvGvcpPacketTypeArvGvcpCommandData sizePacket id
Optional data
...
+ +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//version: 0.8.31
//file: arvgvcpprivate.h
typedef struct {
guint8 packet_type;
guint8 packet_flags;
guint16 command; //a ArvGvcpCommand identifier
guint16 size; //data size
guint16 id; //packet identifier
} ArvGvcpHeader;

typedef enum {
ARV_GVCP_PACKET_TYPE_ACK = 0x00, //acknowledge packet
ARV_GVCP_PACKET_TYPE_CMD = 0x42, //command packet
ARV_GVCP_PACKET_TYPE_ERROR = 0x80, //error packet
ARV_GVCP_PACKET_TYPE_UNKNOWN_ERROR = 0x8f //unknown error
} ArvGvcpPacketType;

typedef enum {
ARV_GVCP_COMMAND_DISCOVERY_CMD = 0x0002, //discovery command
ARV_GVCP_COMMAND_DISCOVERY_ACK = 0x0003, //discovery acknowledge
ARV_GVCP_COMMAND_BYE_CMD = 0x0004, //goodbye command, for connection termination
ARV_GVCP_COMMAND_BYE_ACK = 0x0005, //goodbye acknowledge
ARV_GVCP_COMMAND_PACKET_RESEND_CMD = 0x0040, //packet resend request
ARV_GVCP_COMMAND_PACKET_RESEND_ACK = 0x0041, //packet resend acknowledge (not used ?)
ARV_GVCP_COMMAND_READ_REGISTER_CMD = 0x0080, //read register command
ARV_GVCP_COMMAND_READ_REGISTER_ACK = 0x0081, //read register acknowledge
ARV_GVCP_COMMAND_WRITE_REGISTER_CMD = 0x0082, //write register command
ARV_GVCP_COMMAND_WRITE_REGISTER_ACK = 0x0083, //write register acknowledge
ARV_GVCP_COMMAND_READ_MEMORY_CMD = 0x0084, //read memory command
ARV_GVCP_COMMAND_READ_MEMORY_ACK = 0x0085, //read memory acknowledge
ARV_GVCP_COMMAND_WRITE_MEMORY_CMD = 0x0086, //write memory command
ARV_GVCP_COMMAND_WRITE_MEMORY_ACK = 0x0087, //write memory acknowledge
ARV_GVCP_COMMAND_PENDING_ACK = 0x0089 //pending command acknowledge
} ArvGvcpCommand;
+ + +

发现设备

设备发现机制是通过客户端向GVCP端口广播一个发现GVCP数据包来实现的。每个可用的设备都会对这个发现数据包响应一个确认数据包,其中包含了设备的描述(设备名称、型号名称、制造商名称、MAC地址等)。

+

设备发现命令的数据包中,data size为0(这里估计是作者写错了,data size是248也就是0xf8),packet id为0xffff。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
表格2.设备发现确认数据包
Address0151631
0x00000x0003
0x00f80xffff
0x0000Version majorVersion minor
0x0004EndiannessCharacter set
0x0008MAC address high
0x000cMAC address low
0x0010Supported IP configuration
0x0014Current IP configuration
0x0018
0x001c
0x0020
0x0024Current IP address
0x0028
0x002c
0x0030
0x0034Current subnet mask
0x0038
0x003c
0x0040
0x0044Current gateway
0x0048Manufacturer name
0x004c
0x0050
0x0054
0x0058
0x005c
0x0060
0x0064
0x0068Model name
0x006c
0x0070
0x0074
0x0078
0x007c
0x0080
0x0084
0x0088Device version
0x008c
0x0090
0x0094
0x0098
0x009c
0x00a0
0x00a4
0x00a8Manufacturer informations
0x00ac
0x00b0
0x00b4
0x00b8
0x00bc
0x00c0
0x00c4
0x00c8
0x00cc
0x00d0
0x00d4
0x00d8User defined name
0x00dc
0x00e0
0x00e4
0x00e8
0x00ec
0x00f0
0x00f4
+ +
1
2
3
4
5
6
//version: 0.8.31
//file: arvgvcpprivate.h
typedef struct {
ArvGvcpHeader header; //packet header
unsigned char data[]; //variable size byte array
} ArvGvcpPacket;
+ + +

读写寄存器

这些数据包用于读写32位寄存器,通过32位地址访问。对于读命令,向客户端发送一个地址列表,客户端返回一个32位值的列表。对于写命令,向客户端发送一个地址/值对(address/value pair)的列表,客户端返回一个32位值的列表。

+

地址和数据在数据包中以大端值的形式编码。

+

读写内存

写内存数据包的数据区包含一个32位地址,后跟要写入的数据。客户端返回一个带有目标地址的确认包。
对于读内存命令,发送一个地址/大小对(address/size pair)到设备,设备返回给定内存区域的内容

+

参考文章

1.《GVCP packets》

+ +
+ + +
+
+
    +
  • 标题: GVCP数据包
  • +
  • 作者: paw5zx
  • +
  • 创建于 + : 2024-11-01 11:58:27
  • + +
  • + 更新于 + : 2024-11-02 14:08:33 +
  • + +
  • + 链接: https://paw5zx.github.io/aravis-GVCP-packets/ +
  • +
  • + + 版权声明: + + + + + 本文章采用 CC BY-NC-SA 4.0 进行许可。 + +
  • +
+
+ +
+ + + + + +
+ + +
+ + +
+ +
+ +
+ + +
+ +
+ +
+ + + + +
+
+
+
+ 评论 +
+ + + + +
+ + + + + + +
+ +
+ +
+ + +
+
+
+
目录
+
GVCP数据包
+ + +
+
+
+ +
+ + + + + +
+ + + +
+ + +
+ + +
+
+
    + + +
  • + +
  • + + + + +
  • + +
  • + +
+
+ +
+ + +
+
+
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + + + + + + +
  • + +
  • +
+ +
    +
  • + +
  • + +
  • + + +
  • + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2024/04/28/aravis-camera-api/index.html b/aravis-camera-api/index.html similarity index 70% rename from 2024/04/28/aravis-camera-api/index.html rename to aravis-camera-api/index.html index 3360533..96846c7 100644 --- a/2024/04/28/aravis-camera-api/index.html +++ b/aravis-camera-api/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - + - - + + - + - 开源相机管理库Aravis例程学习(五)——camera-api - + 开源相机管理库Aravis例程学习(五)——camera-api | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/28/aravis-camera-api/result.png b/aravis-camera-api/result.png similarity index 100% rename from 2024/04/28/aravis-camera-api/result.png rename to aravis-camera-api/result.png diff --git a/2024/05/01/aravis-camera-features/index.html b/aravis-camera-features/index.html similarity index 72% rename from 2024/05/01/aravis-camera-features/index.html rename to aravis-camera-features/index.html index aaf7c30..5f68499 100644 --- a/2024/05/01/aravis-camera-features/index.html +++ b/aravis-camera-features/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - + - - + + - + - 开源相机管理库Aravis例程学习(六)——camera-features - + 开源相机管理库Aravis例程学习(六)——camera-features | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/05/01/aravis-camera-features/result.png b/aravis-camera-features/result.png similarity index 100% rename from 2024/05/01/aravis-camera-features/result.png rename to aravis-camera-features/result.png diff --git a/2024/05/10/aravis-chunk-parser/index.html b/aravis-chunk-parser/index.html similarity index 75% rename from 2024/05/10/aravis-chunk-parser/index.html rename to aravis-chunk-parser/index.html index 145432e..a63defb 100644 --- a/2024/05/10/aravis-chunk-parser/index.html +++ b/aravis-chunk-parser/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - - + + - + - 开源相机管理库Aravis例程学习(七)——chunk-parser - + 开源相机管理库Aravis例程学习(七)——chunk-parser | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/03/30/aravis-install/aravis_info.png b/aravis-install/aravis_info.png similarity index 100% rename from 2024/03/30/aravis-install/aravis_info.png rename to aravis-install/aravis_info.png diff --git a/2024/03/30/aravis-install/cmake.png b/aravis-install/cmake.png similarity index 100% rename from 2024/03/30/aravis-install/cmake.png rename to aravis-install/cmake.png diff --git a/2024/03/30/aravis-install/gstreamer.png b/aravis-install/gstreamer.png similarity index 100% rename from 2024/03/30/aravis-install/gstreamer.png rename to aravis-install/gstreamer.png diff --git a/2024/03/30/aravis-install/index.html b/aravis-install/index.html similarity index 79% rename from 2024/03/30/aravis-install/index.html rename to aravis-install/index.html index e458202..1ac0014 100644 --- a/2024/03/30/aravis-install/index.html +++ b/aravis-install/index.html @@ -13,7 +13,7 @@ - + @@ -21,35 +21,34 @@ - + - - - - - - + + + + + + - + - - + + - + - 开源相机管理库Aravis学习——安装 - + 开源相机管理库Aravis学习——安装 | Paw5zx - Paw5zx @@ -80,7 +79,7 @@ - + @@ -89,7 +88,7 @@ @@ -199,7 +198,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/03/30/aravis-install/meson.png b/aravis-install/meson.png similarity index 100% rename from 2024/03/30/aravis-install/meson.png rename to aravis-install/meson.png diff --git a/2024/03/30/aravis-install/result.png b/aravis-install/result.png similarity index 100% rename from 2024/03/30/aravis-install/result.png rename to aravis-install/result.png diff --git a/2024/03/30/aravis-install/video_viewer.png b/aravis-install/video_viewer.png similarity index 100% rename from 2024/03/30/aravis-install/video_viewer.png rename to aravis-install/video_viewer.png diff --git a/2024/04/15/aravis-multiple-acquisition-callback/index.html b/aravis-multiple-acquisition-callback/index.html similarity index 64% rename from 2024/04/15/aravis-multiple-acquisition-callback/index.html rename to aravis-multiple-acquisition-callback/index.html index 5bba795..b0fe83d 100644 --- a/2024/04/15/aravis-multiple-acquisition-callback/index.html +++ b/aravis-multiple-acquisition-callback/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - + - - + + - + - 开源相机管理库Aravis例程学习(三)——注册回调multiple-acquisition-callback - + 开源相机管理库Aravis例程学习(三)——注册回调multiple-acquisition-callback | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/15/aravis-multiple-acquisition-callback/result.png b/aravis-multiple-acquisition-callback/result.png similarity index 100% rename from 2024/04/15/aravis-multiple-acquisition-callback/result.png rename to aravis-multiple-acquisition-callback/result.png diff --git a/2024/04/15/aravis-multiple-acquisition-main-thread/index.html b/aravis-multiple-acquisition-main-thread/index.html similarity index 70% rename from 2024/04/15/aravis-multiple-acquisition-main-thread/index.html rename to aravis-multiple-acquisition-main-thread/index.html index 926f44d..6c6c065 100644 --- a/2024/04/15/aravis-multiple-acquisition-main-thread/index.html +++ b/aravis-multiple-acquisition-main-thread/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - + - - + + - + - 开源相机管理库Aravis例程学习(二)——连续采集multiple-acquisition-main-thread - + 开源相机管理库Aravis例程学习(二)——连续采集multiple-acquisition-main-thread | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/15/aravis-multiple-acquisition-main-thread/result.png b/aravis-multiple-acquisition-main-thread/result.png similarity index 100% rename from 2024/04/15/aravis-multiple-acquisition-main-thread/result.png rename to aravis-multiple-acquisition-main-thread/result.png diff --git a/2024/04/25/aravis-multiple-acquisition-signal/index.html b/aravis-multiple-acquisition-signal/index.html similarity index 64% rename from 2024/04/25/aravis-multiple-acquisition-signal/index.html rename to aravis-multiple-acquisition-signal/index.html index ccc7d28..90be912 100644 --- a/2024/04/25/aravis-multiple-acquisition-signal/index.html +++ b/aravis-multiple-acquisition-signal/index.html @@ -13,7 +13,7 @@ - + @@ -21,31 +21,30 @@ - + - - + + - + - + - - + + - + - 开源相机管理库Aravis例程学习(四)——multiple-acquisition-signal - + 开源相机管理库Aravis例程学习(四)——multiple-acquisition-signal | Paw5zx - Paw5zx @@ -76,7 +75,7 @@ - + @@ -85,7 +84,7 @@ @@ -195,7 +194,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/25/aravis-multiple-acquisition-signal/result.png b/aravis-multiple-acquisition-signal/result.png similarity index 100% rename from 2024/04/25/aravis-multiple-acquisition-signal/result.png rename to aravis-multiple-acquisition-signal/result.png diff --git a/2024/04/25/aravis-multiple-acquisition-signal/solution.png b/aravis-multiple-acquisition-signal/solution.png similarity index 100% rename from 2024/04/25/aravis-multiple-acquisition-signal/solution.png rename to aravis-multiple-acquisition-signal/solution.png diff --git a/2024/04/28/aravis-pixelformat/index.html b/aravis-pixelformat/index.html similarity index 79% rename from 2024/04/28/aravis-pixelformat/index.html rename to aravis-pixelformat/index.html index cc0302d..4ca5a0b 100644 --- a/2024/04/28/aravis-pixelformat/index.html +++ b/aravis-pixelformat/index.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -32,17 +32,16 @@ - - + + - + - 开源相机管理库Aravis学习——PixelFormat编码规则 - + 开源相机管理库Aravis学习——PixelFormat编码规则 | Paw5zx - Paw5zx @@ -73,7 +72,7 @@ - + @@ -82,7 +81,7 @@ @@ -192,7 +191,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/10/aravis-single-acquisition/index.html b/aravis-single-acquisition/index.html similarity index 72% rename from 2024/04/10/aravis-single-acquisition/index.html rename to aravis-single-acquisition/index.html index 9a0f389..101dc8d 100644 --- a/2024/04/10/aravis-single-acquisition/index.html +++ b/aravis-single-acquisition/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - + - - + + - + - 开源相机管理库Aravis例程学习(一)——单帧采集single-acquisition - + 开源相机管理库Aravis例程学习(一)——单帧采集single-acquisition | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/10/aravis-single-acquisition/result.png b/aravis-single-acquisition/result.png similarity index 100% rename from 2024/04/10/aravis-single-acquisition/result.png rename to aravis-single-acquisition/result.png diff --git a/archives/2023/10/index.html b/archives/2023/10/index.html index 9639312..25e1cae 100644 --- a/archives/2023/10/index.html +++ b/archives/2023/10/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2023/10 - + 归档: 2023/10 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2023/index.html b/archives/2023/index.html index ed2b859..5ab0784 100644 --- a/archives/2023/index.html +++ b/archives/2023/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2023 - + 归档: 2023 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/03/index.html b/archives/2024/03/index.html index b958e6c..09dcaf5 100644 --- a/archives/2024/03/index.html +++ b/archives/2024/03/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024/3 - + 归档: 2024/3 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/04/index.html b/archives/2024/04/index.html index 4f37cb5..81edecd 100644 --- a/archives/2024/04/index.html +++ b/archives/2024/04/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024/4 - + 归档: 2024/4 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/05/index.html b/archives/2024/05/index.html index 9ba6bc0..5ea9ce8 100644 --- a/archives/2024/05/index.html +++ b/archives/2024/05/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024/5 - + 归档: 2024/5 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/06/index.html b/archives/2024/06/index.html index 135260b..e24554c 100644 --- a/archives/2024/06/index.html +++ b/archives/2024/06/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024/6 - + 归档: 2024/6 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/07/index.html b/archives/2024/07/index.html index de55d9c..7e8e92b 100644 --- a/archives/2024/07/index.html +++ b/archives/2024/07/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024/7 - + 归档: 2024/7 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/08/index.html b/archives/2024/08/index.html index 4065f61..cfc1951 100644 --- a/archives/2024/08/index.html +++ b/archives/2024/08/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024/8 - + 归档: 2024/8 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2023/11/index.html b/archives/2024/10/index.html similarity index 73% rename from archives/2023/11/index.html rename to archives/2024/10/index.html index 9aa544b..747be5a 100644 --- a/archives/2023/11/index.html +++ b/archives/2024/10/index.html @@ -13,14 +13,14 @@ - + - + @@ -28,17 +28,16 @@ - - + + - + - 归档: 2023/11 - + 归档: 2024/10 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2023/12/index.html b/archives/2024/11/index.html similarity index 73% rename from archives/2023/12/index.html rename to archives/2024/11/index.html index 02d3636..4d6f340 100644 --- a/archives/2023/12/index.html +++ b/archives/2024/11/index.html @@ -13,14 +13,14 @@ - + - + @@ -28,17 +28,16 @@ - - + + - + - 归档: 2023/12 - + 归档: 2024/11 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/index.html b/archives/2024/index.html index e7268f6..1b15d73 100644 --- a/archives/2024/index.html +++ b/archives/2024/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024 - + 归档: 2024 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/page/2/index.html b/archives/2024/page/2/index.html index 58ec7f5..795b9b0 100644 --- a/archives/2024/page/2/index.html +++ b/archives/2024/page/2/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024 - + 归档: 2024 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/page/3/index.html b/archives/2024/page/3/index.html index cc68154..804a736 100644 --- a/archives/2024/page/3/index.html +++ b/archives/2024/page/3/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024 - + 归档: 2024 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/2024/page/4/index.html b/archives/2024/page/4/index.html index 8dbfd8d..555dbf0 100644 --- a/archives/2024/page/4/index.html +++ b/archives/2024/page/4/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档: 2024 - + 归档: 2024 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/index.html b/archives/index.html index 6e1b832..a82781a 100644 --- a/archives/index.html +++ b/archives/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档 - + 归档 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/page/2/index.html b/archives/page/2/index.html index e307823..64b6f54 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档 - + 归档 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 61b9cba..ad969b7 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档 - + 归档 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/archives/page/4/index.html b/archives/page/4/index.html index 6f328c3..7eef14b 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -28,17 +28,16 @@ - - + + - + - 归档 - + 归档 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/assets/build/styles.css b/assets/build/styles.css index 35576a1..b97bea2 100644 --- a/assets/build/styles.css +++ b/assets/build/styles.css @@ -1,5 +1,113 @@ +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + /* -! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com +! tailwindcss v3.4.14 | MIT License | https://tailwindcss.com */ /* @@ -32,9 +140,11 @@ 4. Use the user's configured `sans` font-family by default. 5. Use the user's configured `sans` font-feature-settings by default. 6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS */ -html { +html, +:host { line-height: 1.5; /* 1 */ -webkit-text-size-adjust: 100%; @@ -44,12 +154,14 @@ html { -o-tab-size: 4; tab-size: 4; /* 3 */ - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ font-feature-settings: normal; /* 5 */ font-variation-settings: normal; /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ } /* @@ -121,8 +233,10 @@ strong { } /* -1. Use the user's configured `mono` font family by default. -2. Correct the odd `em` font sizing in all browsers. +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. */ code, @@ -131,8 +245,12 @@ samp, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ - font-size: 1em; + font-feature-settings: normal; /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ } /* @@ -201,6 +319,8 @@ textarea { /* 1 */ line-height: inherit; /* 1 */ + letter-spacing: inherit; + /* 1 */ color: inherit; /* 1 */ margin: 0; @@ -224,9 +344,9 @@ select { */ button, -[type='button'], -[type='reset'], -[type='submit'] { +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { -webkit-appearance: button; /* 1 */ background-color: transparent; @@ -430,110 +550,10 @@ video { /* Make elements with the HTML hidden attribute stay hidden by default */ -[hidden] { +[hidden]:where(:not([hidden="until-found"])) { display: none; } -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - .container { width: 100%; } @@ -668,11 +688,6 @@ video { margin-right: 1.5rem; } -.my-0 { - margin-top: 0px; - margin-bottom: 0px; -} - .my-0\.5 { margin-top: 0.125rem; margin-bottom: 0.125rem; @@ -688,11 +703,6 @@ video { margin-bottom: 0.375rem; } -.my-2 { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} - .my-2\.5 { margin-top: 0.625rem; margin-bottom: 0.625rem; @@ -732,18 +742,10 @@ video { margin-bottom: 38px; } -.ml-1 { - margin-left: 0.25rem; -} - .ml-1\.5 { margin-left: 0.375rem; } -.mr-0 { - margin-right: 0px; -} - .mr-0\.5 { margin-right: 0.125rem; } @@ -752,6 +754,10 @@ video { margin-right: 0.5rem; } +.mr-3 { + margin-right: 0.75rem; +} + .mr-4 { margin-right: 1rem; } @@ -864,6 +870,10 @@ video { height: 15rem; } +.h-8 { + height: 2rem; +} + .h-\[150px\] { height: 150px; } @@ -876,6 +886,10 @@ video { height: auto; } +.h-dvh { + height: 100dvh; +} + .h-full { height: 100%; } @@ -884,6 +898,10 @@ video { height: 100vh; } +.min-h-dvh { + min-height: 100dvh; +} + .w-10 { width: 2.5rem; } @@ -904,6 +922,10 @@ video { width: 16rem; } +.w-8 { + width: 2rem; +} + .w-\[1px\] { width: 1px; } @@ -949,11 +971,6 @@ video { flex-shrink: 1; } -.translate-y-0 { - --tw-translate-y: 0px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} - .translate-y-0\.5 { --tw-translate-y: 0.125rem; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -1060,12 +1077,6 @@ video { gap: 1.5rem; } -.space-x-0 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0px * var(--tw-space-x-reverse)); - margin-left: calc(0px * calc(1 - var(--tw-space-x-reverse))); -} - .space-x-0\.5 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.125rem * var(--tw-space-x-reverse)); @@ -1112,6 +1123,10 @@ video { border-radius: 14px; } +.rounded-sm { + border-radius: 0.125rem; +} + .rounded-small { border-radius: 9px; } @@ -1279,21 +1294,11 @@ video { padding-right: 10px; } -.py-0 { - padding-top: 0px; - padding-bottom: 0px; -} - .py-0\.5 { padding-top: 0.125rem; padding-bottom: 0.125rem; } -.py-1 { - padding-top: 0.25rem; - padding-bottom: 0.25rem; -} - .py-1\.5 { padding-top: 0.375rem; padding-bottom: 0.375rem; @@ -1518,12 +1523,12 @@ video { .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter { -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .transition { @@ -1641,33 +1646,33 @@ video { opacity: 1; } -:is(.dark .dark\:block) { +.dark\:block:is(.dark *) { display: block; } -:is(.dark .dark\:hidden) { +.dark\:hidden:is(.dark *) { display: none; } -:is(.dark .dark\:border-gray-500\/30) { +.dark\:border-gray-500\/30:is(.dark *) { border-color: rgb(107 114 128 / 0.3); } -:is(.dark .dark\:bg-gray-500\/40) { +.dark\:bg-gray-500\/40:is(.dark *) { background-color: rgb(107 114 128 / 0.4); } -:is(.dark .dark\:bg-zinc-800) { +.dark\:bg-zinc-800:is(.dark *) { --tw-bg-opacity: 1; background-color: rgb(39 39 42 / var(--tw-bg-opacity)); } -:is(.dark .dark\:text-red-400) { +.dark\:text-red-400:is(.dark *) { --tw-text-opacity: 1; color: rgb(248 113 113 / var(--tw-text-opacity)); } -:is(.dark .dark\:brightness-75) { +.dark\:brightness-75:is(.dark *) { --tw-brightness: brightness(.75); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } @@ -1678,10 +1683,18 @@ video { margin-right: 1.5rem; } + .sm\:h-10 { + height: 2.5rem; + } + .sm\:h-72 { height: 18rem; } + .sm\:w-10 { + width: 2.5rem; + } + .sm\:scale-110 { --tw-scale-x: 1.1; --tw-scale-y: 1.1; @@ -1740,11 +1753,6 @@ video { margin-right: 2rem; } - .md\:my-2 { - margin-top: 0.5rem; - margin-bottom: 0.5rem; - } - .md\:my-2\.5 { margin-top: 0.625rem; margin-bottom: 0.625rem; diff --git a/categories/C/index.html b/categories/C/index.html new file mode 100644 index 0000000..fb80610 --- /dev/null +++ b/categories/C/index.html @@ -0,0 +1,843 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: C | Paw5zx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + +
+

+ Paw5zx's Blog +

+ +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+ + +
+
+  C +
+
+ +
+ +
+
+ 2024 + 2 +
+ + +
+ +
+ +
+
+
+
+ 1 +
+ +
+ + + + + +
+ + + +
+ + +
+ + + +
+
+
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + + + + + + +
  • + +
  • +
+ +
    +
  • + +
  • + +
  • + + +
  • + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/C/\344\270\211\346\226\271\345\272\223/GObject/index.html" "b/categories/C/\344\270\211\346\226\271\345\272\223/GObject/index.html" new file mode 100644 index 0000000..62ad1b4 --- /dev/null +++ "b/categories/C/\344\270\211\346\226\271\345\272\223/GObject/index.html" @@ -0,0 +1,843 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: GObject | Paw5zx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + +
+

+ Paw5zx's Blog +

+ +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+ + +
+
+  GObject +
+
+ +
+ +
+
+ 2024 + 2 +
+ + +
+ +
+ +
+
+
+
+ 1 +
+ +
+ + + + + +
+ + + +
+ + +
+ + + +
+
+
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + + + + + + +
  • + +
  • +
+ +
    +
  • + +
  • + +
  • + + +
  • + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/C/\344\270\211\346\226\271\345\272\223/index.html" "b/categories/C/\344\270\211\346\226\271\345\272\223/index.html" new file mode 100644 index 0000000..9e4c603 --- /dev/null +++ "b/categories/C/\344\270\211\346\226\271\345\272\223/index.html" @@ -0,0 +1,843 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: 三方库 | Paw5zx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + +
+

+ Paw5zx's Blog +

+ +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+ + +
+
+  三方库 +
+
+ +
+ +
+
+ 2024 + 2 +
+ + +
+ +
+ +
+
+
+
+ 1 +
+ +
+ + + + + +
+ + + +
+ + +
+ + + +
+
+
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + + + + + + +
  • + +
  • +
+ +
    +
  • + +
  • + +
  • + + +
  • + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/categories/Linux/Linux\345\206\205\346\240\270\346\272\220\347\240\201/index.html" "b/categories/Linux/Linux\345\206\205\346\240\270\346\272\220\347\240\201/index.html" index e8237fe..ed379ca 100644 --- "a/categories/Linux/Linux\345\206\205\346\240\270\346\272\220\347\240\201/index.html" +++ "b/categories/Linux/Linux\345\206\205\346\240\270\346\272\220\347\240\201/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: Linux内核源码 - + 分类: Linux内核源码 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/Linux/Linux\346\223\215\344\275\234/index.html" "b/categories/Linux/Linux\346\223\215\344\275\234/index.html" index 24d7c13..b69a5a9 100644 --- "a/categories/Linux/Linux\346\223\215\344\275\234/index.html" +++ "b/categories/Linux/Linux\346\223\215\344\275\234/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: Linux操作 - + 分类: Linux操作 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/categories/Linux/index.html b/categories/Linux/index.html index 796ea46..17a2172 100644 --- a/categories/Linux/index.html +++ b/categories/Linux/index.html @@ -28,17 +28,16 @@ - - + + - + - 分类: Linux - + 分类: Linux | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/c-plus-plus/C-\345\260\217\350\275\256\345\255\220/index.html" "b/categories/c-plus-plus/C-\345\260\217\350\275\256\345\255\220/index.html" index fc87ea4..b3c94d0 100644 --- "a/categories/c-plus-plus/C-\345\260\217\350\275\256\345\255\220/index.html" +++ "b/categories/c-plus-plus/C-\345\260\217\350\275\256\345\255\220/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: C++小轮子 - + 分类: C++小轮子 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/c-plus-plus/C-\350\256\276\350\256\241\346\250\241\345\274\217/index.html" "b/categories/c-plus-plus/C-\350\256\276\350\256\241\346\250\241\345\274\217/index.html" index a150447..77b8e13 100644 --- "a/categories/c-plus-plus/C-\350\256\276\350\256\241\346\250\241\345\274\217/index.html" +++ "b/categories/c-plus-plus/C-\350\256\276\350\256\241\346\250\241\345\274\217/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: C++设计模式 - + 分类: C++设计模式 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/c-plus-plus/C-\350\257\255\346\263\225/index.html" "b/categories/c-plus-plus/C-\350\257\255\346\263\225/index.html" index c5eedc9..2ede9d1 100644 --- "a/categories/c-plus-plus/C-\350\257\255\346\263\225/index.html" +++ "b/categories/c-plus-plus/C-\350\257\255\346\263\225/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: C++语法 - + 分类: C++语法 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/categories/c-plus-plus/Tools/index.html b/categories/c-plus-plus/Tools/index.html new file mode 100644 index 0000000..5d36f72 --- /dev/null +++ b/categories/c-plus-plus/Tools/index.html @@ -0,0 +1,831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类: Tools | Paw5zx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + +
+

+ Paw5zx's Blog +

+ +
+ +
+ + + +
+ + +
+ + + +
+ +
+ + + +
+ + +
+
+  Tools +
+
+ +
+ +
+
+ 2024 + 1 +
+ + +
+ +
+ +
+
+
+
+ 1 +
+ +
+ + + + + +
+ + + +
+ + +
+ + + +
+
+
    +
  • + +
  • + +
  • + +
  • + +
  • + +
  • + + + + + + +
  • + +
  • +
+ +
    +
  • + +
  • + +
  • + + +
  • + + +
+
+ +
+ +
+ +
+ + + +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/categories/c-plus-plus/index.html b/categories/c-plus-plus/index.html index e9bd10d..9292357 100644 --- a/categories/c-plus-plus/index.html +++ b/categories/c-plus-plus/index.html @@ -28,17 +28,16 @@ - - + + - + - 分类: C++ - + 分类: C++ | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/categories/c-plus-plus/page/2/index.html b/categories/c-plus-plus/page/2/index.html index a029da9..9604234 100644 --- a/categories/c-plus-plus/page/2/index.html +++ b/categories/c-plus-plus/page/2/index.html @@ -28,17 +28,16 @@ - - + + - + - 分类: C++ - + 分类: C++ | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/c-plus-plus/\344\270\211\346\226\271\345\272\223/index.html" "b/categories/c-plus-plus/\344\270\211\346\226\271\345\272\223/index.html" index d47b914..f89967b 100644 --- "a/categories/c-plus-plus/\344\270\211\346\226\271\345\272\223/index.html" +++ "b/categories/c-plus-plus/\344\270\211\346\226\271\345\272\223/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: 三方库 - + 分类: 三方库 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/c-plus-plus/\347\274\226\350\257\221\351\223\276\346\216\245/index.html" "b/categories/c-plus-plus/\347\274\226\350\257\221\351\223\276\346\216\245/index.html" index 076388b..fc49005 100644 --- "a/categories/c-plus-plus/\347\274\226\350\257\221\351\223\276\346\216\245/index.html" +++ "b/categories/c-plus-plus/\347\274\226\350\257\221\351\223\276\346\216\245/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: 编译链接 - + 分类: 编译链接 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/categories/git/index.html b/categories/git/index.html index 213aba7..5c55a7c 100644 --- a/categories/git/index.html +++ b/categories/git/index.html @@ -28,17 +28,16 @@ - - + + - + - 分类: git - + 分类: git | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/categories/index.html b/categories/index.html index fb729a5..f56dd34 100644 --- a/categories/index.html +++ b/categories/index.html @@ -30,17 +30,16 @@ - - + + - + - 分类 - + 分类 | Paw5zx - Paw5zx @@ -71,7 +70,7 @@ - + @@ -80,7 +79,7 @@ @@ -190,7 +189,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Aravis/index.html" "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Aravis/index.html" index f129cbe..1a1a3a2 100644 --- "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Aravis/index.html" +++ "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/Aravis/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: Aravis - + 分类: Aravis | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/index.html" "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/index.html" index d2c3cb5..b131610 100644 --- "a/categories/\345\267\245\344\270\232\347\233\270\346\234\272/index.html" +++ "b/categories/\345\267\245\344\270\232\347\233\270\346\234\272/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: 工业相机 - + 分类: 工业相机 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/\351\232\217\344\276\277\347\216\251\347\216\251/UE/index.html" "b/categories/\351\232\217\344\276\277\347\216\251\347\216\251/UE/index.html" index d950de3..dad7c68 100644 --- "a/categories/\351\232\217\344\276\277\347\216\251\347\216\251/UE/index.html" +++ "b/categories/\351\232\217\344\276\277\347\216\251\347\216\251/UE/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: UE - + 分类: UE | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git "a/categories/\351\232\217\344\276\277\347\216\251\347\216\251/index.html" "b/categories/\351\232\217\344\276\277\347\216\251\347\216\251/index.html" index 81e1e20..28d45d6 100644 --- "a/categories/\351\232\217\344\276\277\347\216\251\347\216\251/index.html" +++ "b/categories/\351\232\217\344\276\277\347\216\251\347\216\251/index.html" @@ -28,17 +28,16 @@ - - + + - + - 分类: 随便玩玩 - + 分类: 随便玩玩 | Paw5zx - Paw5zx @@ -69,7 +68,7 @@ - + @@ -78,7 +77,7 @@ @@ -188,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/03/cpp-development-components-singleton-CRTP/index.html b/cpp-development-components-singleton-CRTP/index.html similarity index 77% rename from 2024/04/03/cpp-development-components-singleton-CRTP/index.html rename to cpp-development-components-singleton-CRTP/index.html index 1efce0b..5fd1b24 100644 --- a/2024/04/03/cpp-development-components-singleton-CRTP/index.html +++ b/cpp-development-components-singleton-CRTP/index.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -32,17 +32,16 @@ - - + + - + - C++自用小轮子——单例模板 - + C++自用小轮子——单例模板 | Paw5zx - Paw5zx @@ -73,7 +72,7 @@ - + @@ -82,7 +81,7 @@ @@ -192,7 +191,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/03/cpp-development-components-threadsafe-queue/index.html b/cpp-development-components-threadsafe-queue/index.html similarity index 83% rename from 2024/04/03/cpp-development-components-threadsafe-queue/index.html rename to cpp-development-components-threadsafe-queue/index.html index 820c3b3..bef2ab6 100644 --- a/2024/04/03/cpp-development-components-threadsafe-queue/index.html +++ b/cpp-development-components-threadsafe-queue/index.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -32,17 +32,16 @@ - - + + - + - C++自用小轮子——线程安全队列 - + C++自用小轮子——线程安全队列 | Paw5zx - Paw5zx @@ -73,7 +72,7 @@ - + @@ -82,7 +81,7 @@ @@ -192,7 +191,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/10_l_default_result.png b/cpp-shared-lib-search-priority-test-linking/10_l_default_result.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/10_l_default_result.png rename to cpp-shared-lib-search-priority-test-linking/10_l_default_result.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/11_l_default_readelf.png b/cpp-shared-lib-search-priority-test-linking/11_l_default_readelf.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/11_l_default_readelf.png rename to cpp-shared-lib-search-priority-test-linking/11_l_default_readelf.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/12_debug_compiler_info.png b/cpp-shared-lib-search-priority-test-linking/12_debug_compiler_info.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/12_debug_compiler_info.png rename to cpp-shared-lib-search-priority-test-linking/12_debug_compiler_info.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/13_deliver.png b/cpp-shared-lib-search-priority-test-linking/13_deliver.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/13_deliver.png rename to cpp-shared-lib-search-priority-test-linking/13_deliver.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/14_debug_linker_info.png b/cpp-shared-lib-search-priority-test-linking/14_debug_linker_info.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/14_debug_linker_info.png rename to cpp-shared-lib-search-priority-test-linking/14_debug_linker_info.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/15_result.png b/cpp-shared-lib-search-priority-test-linking/15_result.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/15_result.png rename to cpp-shared-lib-search-priority-test-linking/15_result.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/1_none.png b/cpp-shared-lib-search-priority-test-linking/1_none.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/1_none.png rename to cpp-shared-lib-search-priority-test-linking/1_none.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/2_default_result.png b/cpp-shared-lib-search-priority-test-linking/2_default_result.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/2_default_result.png rename to cpp-shared-lib-search-priority-test-linking/2_default_result.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/3_default_readelf.png b/cpp-shared-lib-search-priority-test-linking/3_default_readelf.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/3_default_readelf.png rename to cpp-shared-lib-search-priority-test-linking/3_default_readelf.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/4_libpath_result.png b/cpp-shared-lib-search-priority-test-linking/4_libpath_result.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/4_libpath_result.png rename to cpp-shared-lib-search-priority-test-linking/4_libpath_result.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/5_libpath_readelf.png b/cpp-shared-lib-search-priority-test-linking/5_libpath_readelf.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/5_libpath_readelf.png rename to cpp-shared-lib-search-priority-test-linking/5_libpath_readelf.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/6_l_result.png b/cpp-shared-lib-search-priority-test-linking/6_l_result.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/6_l_result.png rename to cpp-shared-lib-search-priority-test-linking/6_l_result.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/7_l_readelf.png b/cpp-shared-lib-search-priority-test-linking/7_l_readelf.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/7_l_readelf.png rename to cpp-shared-lib-search-priority-test-linking/7_l_readelf.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/8_default_libpath_result.png b/cpp-shared-lib-search-priority-test-linking/8_default_libpath_result.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/8_default_libpath_result.png rename to cpp-shared-lib-search-priority-test-linking/8_default_libpath_result.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/9_default_libpath_readelf.png b/cpp-shared-lib-search-priority-test-linking/9_default_libpath_readelf.png similarity index 100% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/9_default_libpath_readelf.png rename to cpp-shared-lib-search-priority-test-linking/9_default_libpath_readelf.png diff --git a/2024/07/29/cpp-shared-lib-search-priority-test-linking/index.html b/cpp-shared-lib-search-priority-test-linking/index.html similarity index 83% rename from 2024/07/29/cpp-shared-lib-search-priority-test-linking/index.html rename to cpp-shared-lib-search-priority-test-linking/index.html index 3837965..94d06c1 100644 --- a/2024/07/29/cpp-shared-lib-search-priority-test-linking/index.html +++ b/cpp-shared-lib-search-priority-test-linking/index.html @@ -13,7 +13,7 @@ - + @@ -21,44 +21,43 @@ - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - - + + - + - 编译期链接时共享库路径搜索优先级实验 - + 编译期链接时共享库路径搜索优先级实验 | Paw5zx - Paw5zx @@ -89,7 +88,7 @@ - + @@ -98,7 +97,7 @@ @@ -208,7 +207,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/08/01/cpp-shared-lib-search-priority-test-loading/index.html b/cpp-shared-lib-search-priority-test-loading/index.html similarity index 86% rename from 2024/08/01/cpp-shared-lib-search-priority-test-loading/index.html rename to cpp-shared-lib-search-priority-test-loading/index.html index 10d8590..197de21 100644 --- a/2024/08/01/cpp-shared-lib-search-priority-test-loading/index.html +++ b/cpp-shared-lib-search-priority-test-loading/index.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -32,17 +32,16 @@ - - + + - + - 运行期加载时共享库路径搜索优先级实验 - + 运行期加载时共享库路径搜索优先级实验 | Paw5zx - Paw5zx @@ -73,7 +72,7 @@ - + @@ -82,7 +81,7 @@ @@ -192,7 +191,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/07/15/cpp-shared-lib-search-priority/index.html b/cpp-shared-lib-search-priority/index.html similarity index 77% rename from 2024/07/15/cpp-shared-lib-search-priority/index.html rename to cpp-shared-lib-search-priority/index.html index 15940b2..e011b6c 100644 --- a/2024/07/15/cpp-shared-lib-search-priority/index.html +++ b/cpp-shared-lib-search-priority/index.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -32,17 +32,16 @@ - - + + - + - 共享库链接和加载时的路径搜索优先级 - + 共享库链接和加载时的路径搜索优先级 | Paw5zx - Paw5zx @@ -73,7 +72,7 @@ - + @@ -82,7 +81,7 @@ @@ -192,7 +191,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/07/16/cpp-shared-lib-soname/index.html b/cpp-shared-lib-soname/index.html similarity index 78% rename from 2024/07/16/cpp-shared-lib-soname/index.html rename to cpp-shared-lib-soname/index.html index 87f7861..3e7343e 100644 --- a/2024/07/16/cpp-shared-lib-soname/index.html +++ b/cpp-shared-lib-soname/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - - + + - + - 共享库soname机制 - + 共享库soname机制 | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/07/16/cpp-shared-lib-soname/readelf.png b/cpp-shared-lib-soname/readelf.png similarity index 100% rename from 2024/07/16/cpp-shared-lib-soname/readelf.png rename to cpp-shared-lib-soname/readelf.png diff --git a/css/common/animated.css b/css/common/animated.css index 5fa75c4..62ab293 100644 --- a/css/common/animated.css +++ b/css/common/animated.css @@ -1,9 +1,3 @@ -.fade-in-down-animation { - animation-fill-mode: both; - animation-duration: 1s; - animation-name: fade-in-down; - will-change: transform; -} .title-hover-animation { display: inline-block; position: relative; diff --git a/css/common/basic.css b/css/common/basic.css index 9fb8898..814ddcd 100644 --- a/css/common/basic.css +++ b/css/common/basic.css @@ -237,12 +237,6 @@ --redefine-box-shadow-flat-hover: var(--shadow-color-2) 0px 1px 4px 0px, var(--shadow-color-1) 0px 0px 0px 1px, var(--shadow-color-1) 0px 0px 0px 1px inset; --mermaid-theme: ''; } -.fade-in-down-animation { - animation-fill-mode: both; - animation-duration: 1s; - animation-name: fade-in-down; - will-change: transform; -} .title-hover-animation { display: inline-block; position: relative; @@ -368,28 +362,6 @@ transition-duration: 0.2s, 0.2s, 0.2s, 0.2s; transition-timing-function: ease, ease, ease, ease; } -*::-webkit-scrollbar { - width: 6px; - height: 6px; - transition: all 0.2s ease; - display: block; -} -*::-webkit-scrollbar-thumb { - background: var(--scrollbar-color); - border-radius: 18px; - background-clip: content-box; - border: 3px solid transparent; -} -*::-webkit-scrollbar-track { - background-color: var(--scroll-bar-bg-color); - border: 1px solid var(--shadow-color-1); -} -*::-webkit-scrollbar-thumb:hover { - background: var(--scrollbar-color-hover); - border-radius: 18px; - background-clip: content-box; - border: 3px solid transparent; -} html, body { position: relative; @@ -408,6 +380,27 @@ html::-webkit-scrollbar, body::-webkit-scrollbar { width: 14px; height: 8px; + transition: all 0.2s ease; + display: block; +} +html::-webkit-scrollbar-thumb, +body::-webkit-scrollbar-thumb { + background: var(--scrollbar-color); + border-radius: 18px; + background-clip: content-box; + border: 3px solid transparent; +} +html::-webkit-scrollbar-track, +body::-webkit-scrollbar-track { + background-color: var(--scroll-bar-bg-color); + border: 1px solid var(--shadow-color-1); +} +html::-webkit-scrollbar-thumb:hover, +body::-webkit-scrollbar-thumb:hover { + background: var(--scrollbar-color-hover); + border-radius: 18px; + background-clip: content-box; + border: 3px solid transparent; } @media (max-width: 768px) { html, diff --git a/css/common/codeblock/code-theme.css b/css/common/codeblock/code-theme.css index cd15dc6..2e741d5 100644 --- a/css/common/codeblock/code-theme.css +++ b/css/common/codeblock/code-theme.css @@ -238,57 +238,57 @@ --mermaid-theme: ''; } :root { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } @media (prefers-color-scheme: light) { :root { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } } @media (prefers-color-scheme: dark) { :root { - --code-foreground: #bfbfc7; - --code-background: #35363b; - --highlight-background: #21252b; - --highlight-foreground: #bfbfc7; + --inline-code-foreground: #c9d1d9; + --inline-code-background: #313131; + --highlight-background: #1e1e1e; + --highlight-foreground: #dcdcdc; --highlight-keyword: #569cd6; --highlight-link: #569cd6; --highlight-built-in: #4ec9b0; @@ -308,32 +308,32 @@ } } .light-mode { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } .dark-mode { - --code-foreground: #bfbfc7; - --code-background: #35363b; - --highlight-background: #21252b; - --highlight-foreground: #bfbfc7; + --inline-code-foreground: #c9d1d9; + --inline-code-background: #313131; + --highlight-background: #1e1e1e; + --highlight-foreground: #dcdcdc; --highlight-keyword: #569cd6; --highlight-link: #569cd6; --highlight-built-in: #4ec9b0; diff --git a/css/common/codeblock/highlight.css b/css/common/codeblock/highlight.css index 03c573e..a57dfaa 100644 --- a/css/common/codeblock/highlight.css +++ b/css/common/codeblock/highlight.css @@ -238,57 +238,57 @@ --mermaid-theme: ''; } :root { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } @media (prefers-color-scheme: light) { :root { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } } @media (prefers-color-scheme: dark) { :root { - --code-foreground: #bfbfc7; - --code-background: #35363b; - --highlight-background: #21252b; - --highlight-foreground: #bfbfc7; + --inline-code-foreground: #c9d1d9; + --inline-code-background: #313131; + --highlight-background: #1e1e1e; + --highlight-foreground: #dcdcdc; --highlight-keyword: #569cd6; --highlight-link: #569cd6; --highlight-built-in: #4ec9b0; @@ -308,32 +308,32 @@ } } .light-mode { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } .dark-mode { - --code-foreground: #bfbfc7; - --code-background: #35363b; - --highlight-background: #21252b; - --highlight-foreground: #bfbfc7; + --inline-code-foreground: #c9d1d9; + --inline-code-background: #313131; + --highlight-background: #1e1e1e; + --highlight-foreground: #dcdcdc; --highlight-keyword: #569cd6; --highlight-link: #569cd6; --highlight-built-in: #4ec9b0; @@ -378,9 +378,11 @@ code { padding: 3px 4px; word-wrap: break-word; border-radius: 4px; - font-size: 0.875rem !important; - color: var(--code-foreground); - background: var(--code-background); + color: var(--inline-code-foreground); + background: var(--inline-code-background); +} +.main-content code { + font-size: 0.9em; } pre { font-size: 0.9rem !important; diff --git a/css/common/codeblock/hljs-themes/dark/a11y-dark.css b/css/common/codeblock/hljs-themes/dark/a11y-dark.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/dark/agate.css b/css/common/codeblock/hljs-themes/dark/agate.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/dark/atom-one-dark.css b/css/common/codeblock/hljs-themes/dark/atom-one-dark.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/dark/github-dark.css b/css/common/codeblock/hljs-themes/dark/github-dark.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/dark/monokai-sublime.css b/css/common/codeblock/hljs-themes/dark/monokai-sublime.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/dark/night-owl.css b/css/common/codeblock/hljs-themes/dark/night-owl.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/dark/nord.css b/css/common/codeblock/hljs-themes/dark/nord.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/dark/tokyo-night-dark.css b/css/common/codeblock/hljs-themes/dark/tokyo-night-dark.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/dark/vs2015.css b/css/common/codeblock/hljs-themes/dark/vs2015.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/light/atom-one-light.css b/css/common/codeblock/hljs-themes/light/atom-one-light.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/light/default.css b/css/common/codeblock/hljs-themes/light/default.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/codeblock/hljs-themes/light/github.css b/css/common/codeblock/hljs-themes/light/github.css new file mode 100644 index 0000000..e69de29 diff --git a/css/common/markdown.css b/css/common/markdown.css index 8c6c10f..40bd17b 100644 --- a/css/common/markdown.css +++ b/css/common/markdown.css @@ -235,13 +235,60 @@ redefine-tablet() background-color: var(--second-background-color); } .markdown-body mjx-container { - display: inline-block; - vertical-align: baseline; + display: inline; + overflow-x: auto; + white-space: nowrap; + margin: 0 0.2rem; +} +.markdown-body mjx-container:hover::-webkit-scrollbar-thumb { + border: 3px solid rgba(183,183,183,0.3); +} +.markdown-body mjx-container::-webkit-scrollbar { + width: 6px; + height: 6px; + transition: all 0.2s ease; + display: block; +} +.markdown-body mjx-container::-webkit-scrollbar-track { + background: transparent; + border: none; +} +.markdown-body mjx-container::-webkit-scrollbar-thumb { + border-radius: 20px; + border: 3px solid rgba(183,183,183,0); + transition: all 0.2s ease; } .markdown-body mjx-container svg { - display: inline; + display: inline-block /* Allow content to be centered properly */; } .markdown-body mjx-container[display="true"] { - display: flex !important; + display: block; justify-content: center; + vertical-align: baseline; + overflow-x: auto; + text-align: center; + white-space: nowrap; + scrollbar-width: thin; + padding-bottom: 8px; +} +.markdown-body mjx-container[display="true"]:hover::-webkit-scrollbar-thumb { + border: 3px solid rgba(183,183,183,0.3); +} +.markdown-body mjx-container[display="true"]::-webkit-scrollbar { + width: 6px; + height: 6px; + transition: all 0.2s ease; + display: block; +} +.markdown-body mjx-container[display="true"]::-webkit-scrollbar-track { + background: transparent; + border: none; +} +.markdown-body mjx-container[display="true"]::-webkit-scrollbar-thumb { + border-radius: 20px; + border: 3px solid rgba(183,183,183,0); + transition: all 0.2s ease; +} +.markdown-body mjx-container[display="true"] svg { + display: inline-block; } diff --git a/css/style.css b/css/style.css index 2f18a7e..a6e0d80 100644 --- a/css/style.css +++ b/css/style.css @@ -1,12 +1,6 @@ @tailwind base; @tailwind components; @tailwind utilities; -.fade-in-down-animation { - animation-fill-mode: both; - animation-duration: 1s; - animation-name: fade-in-down; - will-change: transform; -} .title-hover-animation { display: inline-block; position: relative; @@ -604,12 +598,6 @@ --redefine-box-shadow-flat-hover: var(--shadow-color-2) 0px 1px 4px 0px, var(--shadow-color-1) 0px 0px 0px 1px, var(--shadow-color-1) 0px 0px 0px 1px inset; --mermaid-theme: ''; } -.fade-in-down-animation { - animation-fill-mode: both; - animation-duration: 1s; - animation-name: fade-in-down; - will-change: transform; -} .title-hover-animation { display: inline-block; position: relative; @@ -735,28 +723,6 @@ transition-duration: 0.2s, 0.2s, 0.2s, 0.2s; transition-timing-function: ease, ease, ease, ease; } -*::-webkit-scrollbar { - width: 6px; - height: 6px; - transition: all 0.2s ease; - display: block; -} -*::-webkit-scrollbar-thumb { - background: var(--scrollbar-color); - border-radius: 18px; - background-clip: content-box; - border: 3px solid transparent; -} -*::-webkit-scrollbar-track { - background-color: var(--scroll-bar-bg-color); - border: 1px solid var(--shadow-color-1); -} -*::-webkit-scrollbar-thumb:hover { - background: var(--scrollbar-color-hover); - border-radius: 18px; - background-clip: content-box; - border: 3px solid transparent; -} html, body { position: relative; @@ -775,6 +741,27 @@ html::-webkit-scrollbar, body::-webkit-scrollbar { width: 14px; height: 8px; + transition: all 0.2s ease; + display: block; +} +html::-webkit-scrollbar-thumb, +body::-webkit-scrollbar-thumb { + background: var(--scrollbar-color); + border-radius: 18px; + background-clip: content-box; + border: 3px solid transparent; +} +html::-webkit-scrollbar-track, +body::-webkit-scrollbar-track { + background-color: var(--scroll-bar-bg-color); + border: 1px solid var(--shadow-color-1); +} +html::-webkit-scrollbar-thumb:hover, +body::-webkit-scrollbar-thumb:hover { + background: var(--scrollbar-color-hover); + border-radius: 18px; + background-clip: content-box; + border: 3px solid transparent; } @media (max-width: 768px) { html, @@ -1197,15 +1184,62 @@ button { background-color: var(--second-background-color); } .markdown-body mjx-container { - display: inline-block; - vertical-align: baseline; + display: inline; + overflow-x: auto; + white-space: nowrap; + margin: 0 0.2rem; +} +.markdown-body mjx-container:hover::-webkit-scrollbar-thumb { + border: 3px solid rgba(183,183,183,0.3); +} +.markdown-body mjx-container::-webkit-scrollbar { + width: 6px; + height: 6px; + transition: all 0.2s ease; + display: block; +} +.markdown-body mjx-container::-webkit-scrollbar-track { + background: transparent; + border: none; +} +.markdown-body mjx-container::-webkit-scrollbar-thumb { + border-radius: 20px; + border: 3px solid rgba(183,183,183,0); + transition: all 0.2s ease; } .markdown-body mjx-container svg { - display: inline; + display: inline-block /* Allow content to be centered properly */; } .markdown-body mjx-container[display="true"] { - display: flex !important; + display: block; justify-content: center; + vertical-align: baseline; + overflow-x: auto; + text-align: center; + white-space: nowrap; + scrollbar-width: thin; + padding-bottom: 8px; +} +.markdown-body mjx-container[display="true"]:hover::-webkit-scrollbar-thumb { + border: 3px solid rgba(183,183,183,0.3); +} +.markdown-body mjx-container[display="true"]::-webkit-scrollbar { + width: 6px; + height: 6px; + transition: all 0.2s ease; + display: block; +} +.markdown-body mjx-container[display="true"]::-webkit-scrollbar-track { + background: transparent; + border: none; +} +.markdown-body mjx-container[display="true"]::-webkit-scrollbar-thumb { + border-radius: 20px; + border: 3px solid rgba(183,183,183,0); + transition: all 0.2s ease; +} +.markdown-body mjx-container[display="true"] svg { + display: inline-block; } :root { --background-color: #fff; @@ -1447,57 +1481,57 @@ button { --mermaid-theme: ''; } :root { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } @media (prefers-color-scheme: light) { :root { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } } @media (prefers-color-scheme: dark) { :root { - --code-foreground: #bfbfc7; - --code-background: #35363b; - --highlight-background: #21252b; - --highlight-foreground: #bfbfc7; + --inline-code-foreground: #c9d1d9; + --inline-code-background: #313131; + --highlight-background: #1e1e1e; + --highlight-foreground: #dcdcdc; --highlight-keyword: #569cd6; --highlight-link: #569cd6; --highlight-built-in: #4ec9b0; @@ -1517,32 +1551,32 @@ button { } } .light-mode { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } .dark-mode { - --code-foreground: #bfbfc7; - --code-background: #35363b; - --highlight-background: #21252b; - --highlight-foreground: #bfbfc7; + --inline-code-foreground: #c9d1d9; + --inline-code-background: #313131; + --highlight-background: #1e1e1e; + --highlight-foreground: #dcdcdc; --highlight-keyword: #569cd6; --highlight-link: #569cd6; --highlight-built-in: #4ec9b0; @@ -1587,9 +1621,11 @@ code { padding: 3px 4px; word-wrap: break-word; border-radius: 4px; - font-size: 0.875rem !important; - color: var(--code-foreground); - background: var(--code-background); + color: var(--inline-code-foreground); + background: var(--inline-code-background); +} +.main-content code { + font-size: 0.9em; } pre { font-size: 0.9rem !important; @@ -2120,57 +2156,57 @@ pre .deletion { --mermaid-theme: ''; } :root { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } @media (prefers-color-scheme: light) { :root { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } } @media (prefers-color-scheme: dark) { :root { - --code-foreground: #bfbfc7; - --code-background: #35363b; - --highlight-background: #21252b; - --highlight-foreground: #bfbfc7; + --inline-code-foreground: #c9d1d9; + --inline-code-background: #313131; + --highlight-background: #1e1e1e; + --highlight-foreground: #dcdcdc; --highlight-keyword: #569cd6; --highlight-link: #569cd6; --highlight-built-in: #4ec9b0; @@ -2190,32 +2226,32 @@ pre .deletion { } } .light-mode { - --code-foreground: #3b4143; - --code-background: #f2f2f2; - --highlight-background: #fafafa; - --highlight-foreground: #3b4143; + --inline-code-foreground: #24292e; + --inline-code-background: #f1f1f1; + --highlight-background: #fdfdfd; + --highlight-foreground: #24292e; --highlight-keyword: #d73a49; - --highlight-link: #d73a49; - --highlight-built-in: #6f42c1; + --highlight-link: #d73a49 /* Following the pattern, link should have the same color as keyword */; + --highlight-built-in: #e36209; --highlight-number: #005cc5; --highlight-string: #032f62; - --highlight-regexp: #e36209; + --highlight-regexp: #032f62; --highlight-subst: #24292e; --highlight-comment: #6a737d; - --highlight-doctag: #22863a; - --highlight-meta: $highlight-meta; + --highlight-doctag: #d73a49; + --highlight-meta: #005cc5 /* Mapped based on the pattern for constant */; --highlight-variable: #005cc5; - --highlight-attr: #22863a; - --highlight-section: $highlight-section; - --highlight-bullet: #6f42c1; - --highlight-addition: #abe338; - --highlight-deletion: #ffa07a; + --highlight-attr: #005cc5; + --highlight-section: #005cc5; + --highlight-bullet: #735c0f; + --highlight-addition: #22863a; + --highlight-deletion: #b31d28; } .dark-mode { - --code-foreground: #bfbfc7; - --code-background: #35363b; - --highlight-background: #21252b; - --highlight-foreground: #bfbfc7; + --inline-code-foreground: #c9d1d9; + --inline-code-background: #313131; + --highlight-background: #1e1e1e; + --highlight-foreground: #dcdcdc; --highlight-keyword: #569cd6; --highlight-link: #569cd6; --highlight-built-in: #4ec9b0; @@ -3454,14 +3490,14 @@ html.is-animating .scroll-progress-bar { display: flex; align-items: center; } -.navbar-container .navbar-content .left .logo-title { +.navbar-container .navbar-content .logo-title { font-size: 1.7rem; font-weight: 520; line-height: 1; color: var(--first-text-color); transform: translateY(1px); } -.navbar-container .navbar-content .left .logo-title h1 { +.navbar-container .navbar-content .logo-title h1 { margin: 0; font-size: 1.7rem; font-weight: 520; @@ -3470,36 +3506,36 @@ html.is-animating .scroll-progress-bar { transform: translateY(1px); } @media (max-width: 768px) { - .navbar-container .navbar-content .left .logo-title h1 { + .navbar-container .navbar-content .logo-title h1 { font-size: 1.53rem; } } @media (max-width: 640px) { - .navbar-container .navbar-content .left .logo-title h1 { + .navbar-container .navbar-content .logo-title h1 { font-size: 1.36rem; } } @media (max-width: 768px) { - .navbar-container .navbar-content .left .logo-title { + .navbar-container .navbar-content .logo-title { font-size: 1.53rem; } } @media (max-width: 640px) { - .navbar-container .navbar-content .left .logo-title { + .navbar-container .navbar-content .logo-title { font-size: 1.36rem; } } -.navbar-container .navbar-content .right .desktop .navbar-list { +.navbar-container .right .desktop .navbar-list { display: flex; gap: 24px; align-items: center; } @media (max-width: 768px) { - .navbar-container .navbar-content .right .desktop .navbar-list { + .navbar-container .right .desktop .navbar-list { display: none; } } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item { +.navbar-container .right .desktop .navbar-list .navbar-item { float: left; position: relative; font-size: 1rem; @@ -3507,16 +3543,16 @@ html.is-animating .scroll-progress-bar { cursor: pointer; color: var(--default-text-color); } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item a { +.navbar-container .right .desktop .navbar-list .navbar-item a { display: block; padding: 5px; } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item a .fa-chevron-down { +.navbar-container .right .desktop .navbar-list .navbar-item a .fa-chevron-down { transform: rotate(0deg); transition: transform 0.3s ease; } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item a::after, -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item .active::after { +.navbar-container .right .desktop .navbar-list .navbar-item a::after, +.navbar-container .right .desktop .navbar-list .navbar-item .active::after { content: ''; position: absolute; bottom: -5px; @@ -3532,18 +3568,18 @@ html.is-animating .scroll-progress-bar { transition-duration: 0.2s, 0.2s, 0.2s, 0.2s, 0.2s, 0.2s, 0.2s; transition-timing-function: ease, ease, ease, ease, ease, ease, ease; } -.navbar-shrink .navbar-container .navbar-content .right .desktop .navbar-list .navbar-item a::after, -.navbar-shrink .navbar-container .navbar-content .right .desktop .navbar-list .navbar-item .active::after { +.navbar-shrink .navbar-container .right .desktop .navbar-list .navbar-item a::after, +.navbar-shrink .navbar-container .right .desktop .navbar-list .navbar-item .active::after { bottom: -8.2px; } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover a .fa-chevron-down { +.navbar-container .right .desktop .navbar-list .navbar-item:hover a .fa-chevron-down { transform: rotate(180deg); } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover .has-dropdown::after { +.navbar-container .right .desktop .navbar-list .navbar-item:hover .has-dropdown::after { display: none !important; } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover a::after, -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item .active::after { +.navbar-container .right .desktop .navbar-list .navbar-item:hover a::after, +.navbar-container .right .desktop .navbar-list .navbar-item .active::after { transform: translate3d(-50%, 0, 0); opacity: 1; transition-property: color, background, box-shadow, border-color, transform, bottom, opacity; @@ -3551,18 +3587,18 @@ html.is-animating .scroll-progress-bar { transition-duration: 0.2s, 0.2s, 0.2s, 0.2s, 0.2s, 0.2s, 0.2s; transition-timing-function: ease, ease, ease, ease, ease, ease, ease; } -.navbar-shrink .navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover a::after, -.navbar-shrink .navbar-container .navbar-content .right .desktop .navbar-list .navbar-item .active::after { +.navbar-shrink .navbar-container .right .desktop .navbar-list .navbar-item:hover a::after, +.navbar-shrink .navbar-container .right .desktop .navbar-list .navbar-item .active::after { bottom: -8.2px; } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item.search { +.navbar-container .right .desktop .navbar-list .navbar-item.search { font-size: 1.5rem; margin-left: 26px; } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item.search i { +.navbar-container .right .desktop .navbar-list .navbar-item.search i { color: var(--default-text-color); } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item .sub-menu { +.navbar-container .right .desktop .navbar-list .navbar-item .sub-menu { position: absolute; right: auto; left: 50%; @@ -3582,7 +3618,7 @@ html.is-animating .scroll-progress-bar { transition-duration: 0.2s, 0.2s, 0.2s, 0.2s, 0.2s; transition-timing-function: ease, ease, ease, ease, linear; } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item .sub-menu li a { +.navbar-container .right .desktop .navbar-list .navbar-item .sub-menu li a { white-space: nowrap; color: var(--default-text-color); font-size: 1rem; @@ -3595,11 +3631,11 @@ html.is-animating .scroll-progress-bar { transition-duration: 0.2s, 0.2s, 0.2s, 0.2s, 0.2s; transition-timing-function: ease, ease, ease, ease, linear; } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item .sub-menu li a:hover { +.navbar-container .right .desktop .navbar-list .navbar-item .sub-menu li a:hover { color: var(--primary-color); background-color: var(--third-background-color); } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover .sub-menu { +.navbar-container .right .desktop .navbar-list .navbar-item:hover .sub-menu { max-height: 500px; transition-property: color, background, box-shadow, border-color, all; transition-delay: 0s, 0s, 0s, 0s, 0s; @@ -3613,36 +3649,36 @@ html.is-animating .scroll-progress-bar { box-shadow: var(--redefine-box-shadow); } @media (max-width: 768px) { - .navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover .sub-menu { + .navbar-container .right .desktop .navbar-list .navbar-item:hover .sub-menu { margin-bottom: 4px; } } @media (max-width: 640px) { - .navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover .sub-menu { + .navbar-container .right .desktop .navbar-list .navbar-item:hover .sub-menu { margin-bottom: 3px; } } -.navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover .sub-menu:hover { +.navbar-container .right .desktop .navbar-list .navbar-item:hover .sub-menu:hover { box-shadow: var(--redefine-box-shadow-hover); } @media (max-width: 768px) { - .navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover .sub-menu { + .navbar-container .right .desktop .navbar-list .navbar-item:hover .sub-menu { padding: 6px; border-radius: 18px; } } @media (max-width: 640px) { - .navbar-container .navbar-content .right .desktop .navbar-list .navbar-item:hover .sub-menu { + .navbar-container .right .desktop .navbar-list .navbar-item:hover .sub-menu { padding: 2px; border-radius: 18px; } } -.navbar-container .navbar-content .right .mobile { +.navbar-container .right .mobile { display: flex; justify-content: space-between; align-items: center; } -.navbar-container .navbar-content .right .mobile .icon-item { +.navbar-container .right .mobile .icon-item { display: none; position: relative; cursor: pointer; @@ -3652,30 +3688,30 @@ html.is-animating .scroll-progress-bar { height: 20px; color: var(--default-text-color); } -.navbar-container .navbar-content .right .mobile .icon-item i { +.navbar-container .right .mobile .icon-item i { color: var(--default-text-color); } -.navbar-container .navbar-content .right .mobile .icon-item:first-child { +.navbar-container .right .mobile .icon-item:first-child { margin-left: 0; } @media (max-width: 768px) { - .navbar-container .navbar-content .right .mobile .icon-item { + .navbar-container .right .mobile .icon-item { display: flex; justify-content: center; align-items: center; } } -.navbar-container .navbar-content .right .mobile .navbar-bar .navbar-bar-middle { +.navbar-container .right .mobile .navbar-bar .navbar-bar-middle { width: 18px; height: 2.5px; position: relative; background: var(--default-text-color); } -.navbar-drawer-show .navbar-container .navbar-content .right .mobile .navbar-bar .navbar-bar-middle { +.navbar-drawer-show .navbar-container .right .mobile .navbar-bar .navbar-bar-middle { background: transparent; } -.navbar-container .navbar-content .right .mobile .navbar-bar .navbar-bar-middle::before, -.navbar-container .navbar-content .right .mobile .navbar-bar .navbar-bar-middle::after { +.navbar-container .right .mobile .navbar-bar .navbar-bar-middle::before, +.navbar-container .right .mobile .navbar-bar .navbar-bar-middle::after { content: ''; position: absolute; left: 0; @@ -3687,19 +3723,19 @@ html.is-animating .scroll-progress-bar { transition-duration: 0.2s, 0.2s, 0.2s, 0.2s, 0.38s; transition-timing-function: ease, ease, ease, ease, ease; } -.navbar-container .navbar-content .right .mobile .navbar-bar .navbar-bar-middle::before { +.navbar-container .right .mobile .navbar-bar .navbar-bar-middle::before { top: -6px; } -.navbar-drawer-show .navbar-container .navbar-content .right .mobile .navbar-bar .navbar-bar-middle::before { +.navbar-drawer-show .navbar-container .right .mobile .navbar-bar .navbar-bar-middle::before { transform: translateY(6px) rotate(45deg); } -.navbar-container .navbar-content .right .mobile .navbar-bar .navbar-bar-middle::after { +.navbar-container .right .mobile .navbar-bar .navbar-bar-middle::after { bottom: -6px; } -.navbar-drawer-show .navbar-container .navbar-content .right .mobile .navbar-bar .navbar-bar-middle::after { +.navbar-drawer-show .navbar-container .right .mobile .navbar-bar .navbar-bar-middle::after { transform: translateY(-6px) rotate(-45deg); } -.navbar-container .navbar-drawer { +.navbar-drawer { padding: 70px 0 20px 0; transform: translateX(100%); transform-origin: top; @@ -3711,10 +3747,10 @@ html.is-animating .scroll-progress-bar { transition-duration: 0.2s, 0.2s, 0.2s, 0.2s, 0.38s; transition-timing-function: ease, ease, ease, ease, ease; } -.navbar-drawer-show .navbar-container .navbar-drawer { +.navbar-drawer-show .navbar-drawer { transform: translateX(0); } -.navbar-container .window-mask { +.window-mask { position: absolute; top: 0; width: 100%; @@ -3728,7 +3764,7 @@ html.is-animating .scroll-progress-bar { transition-duration: 0.2s, 0.2s, 0.2s, 0.2s, 0.38s, 0.38s; transition-timing-function: ease, ease, ease, ease, ease, ease; } -.navbar-drawer-show .navbar-container .window-mask { +.navbar-drawer-show .window-mask { visibility: visible; opacity: 1; } @@ -3745,6 +3781,13 @@ html.is-animating .scroll-progress-bar { .icon-rotated { transform: rotate(90deg); } +.transition-navbar { + transition: max-width 0.3s ease-out; +} +html.is-animating .transition-navbar { + max-width: 1000px !important; + transition: max-width 0.2s ease-out; +} .post-tools-container .article-tools-list li { cursor: pointer; width: 42px; @@ -4114,12 +4157,12 @@ html.is-animating .scroll-progress-bar { color: var(--third-text-color); } .archive-list-container .article-item::after { - width: 10px; - height: 10px; + width: 12px; + height: 12px; display: block; - top: 1em; + top: 20px; position: absolute; - left: -6px; + left: -7px; border-radius: 10px; content: ''; border: 2px solid var(--third-text-color); @@ -4131,17 +4174,16 @@ html.is-animating .scroll-progress-bar { } .archive-list-container .article-item span.article-title { position: relative; - padding-left: 15px; display: block; } .archive-list-container .article-item span.article-title::after { content: ""; width: 7px; height: 7px; - background: var(--background-color); - border: 2px solid var(--third-text-color); + background: var(--fourth-text-color); + border: 1px solid var(--border-color); position: absolute; - left: 0; + left: -1.79rem; top: 0.5em; border-radius: 50px; } diff --git a/2024/07/09/design-pattern-2-abstract-factory-reflect/index.html b/design-pattern-2-abstract-factory-reflect/index.html similarity index 80% rename from 2024/07/09/design-pattern-2-abstract-factory-reflect/index.html rename to design-pattern-2-abstract-factory-reflect/index.html index 6d3585a..cce45e8 100644 --- a/2024/07/09/design-pattern-2-abstract-factory-reflect/index.html +++ b/design-pattern-2-abstract-factory-reflect/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - - + + - + - 设计模式学习(二)工厂模式——抽象工厂模式+注册表 - + 设计模式学习(二)工厂模式——抽象工厂模式+注册表 | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/07/09/design-pattern-2-abstract-factory-reflect/uml.png b/design-pattern-2-abstract-factory-reflect/uml.png similarity index 100% rename from 2024/07/09/design-pattern-2-abstract-factory-reflect/uml.png rename to design-pattern-2-abstract-factory-reflect/uml.png diff --git a/2024/07/05/design-pattern-2-abstract-factory/index.html b/design-pattern-2-abstract-factory/index.html similarity index 85% rename from 2024/07/05/design-pattern-2-abstract-factory/index.html rename to design-pattern-2-abstract-factory/index.html index 532dc81..3437f18 100644 --- a/2024/07/05/design-pattern-2-abstract-factory/index.html +++ b/design-pattern-2-abstract-factory/index.html @@ -13,7 +13,7 @@ - + @@ -21,31 +21,30 @@ - + - - + + - + - - + + - + - 设计模式学习(二)工厂模式——抽象工厂模式 - + 设计模式学习(二)工厂模式——抽象工厂模式 | Paw5zx - Paw5zx @@ -76,7 +75,7 @@ - + @@ -85,7 +84,7 @@ @@ -195,7 +194,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/07/05/design-pattern-2-abstract-factory/uml.png b/design-pattern-2-abstract-factory/uml.png similarity index 100% rename from 2024/07/05/design-pattern-2-abstract-factory/uml.png rename to design-pattern-2-abstract-factory/uml.png diff --git a/2024/07/05/design-pattern-2-abstract-factory/uml_factory.png b/design-pattern-2-abstract-factory/uml_factory.png similarity index 100% rename from 2024/07/05/design-pattern-2-abstract-factory/uml_factory.png rename to design-pattern-2-abstract-factory/uml_factory.png diff --git a/2024/06/03/design-pattern-2-factory-method-reflect/index.html b/design-pattern-2-factory-method-reflect/index.html similarity index 81% rename from 2024/06/03/design-pattern-2-factory-method-reflect/index.html rename to design-pattern-2-factory-method-reflect/index.html index 02319f6..8d67648 100644 --- a/2024/06/03/design-pattern-2-factory-method-reflect/index.html +++ b/design-pattern-2-factory-method-reflect/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - - + + - + - 设计模式学习(二)工厂模式——工厂方法模式+注册表 - + 设计模式学习(二)工厂模式——工厂方法模式+注册表 | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/06/03/design-pattern-2-factory-method-reflect/uml.png b/design-pattern-2-factory-method-reflect/uml.png similarity index 100% rename from 2024/06/03/design-pattern-2-factory-method-reflect/uml.png rename to design-pattern-2-factory-method-reflect/uml.png diff --git a/2024/05/17/design-pattern-2-factory-method/index.html b/design-pattern-2-factory-method/index.html similarity index 81% rename from 2024/05/17/design-pattern-2-factory-method/index.html rename to design-pattern-2-factory-method/index.html index b66b9f9..830e9c5 100644 --- a/2024/05/17/design-pattern-2-factory-method/index.html +++ b/design-pattern-2-factory-method/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - - + + - + - 设计模式学习(二)工厂模式——工厂方法模式 - + 设计模式学习(二)工厂模式——工厂方法模式 | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/05/17/design-pattern-2-factory-method/uml.png b/design-pattern-2-factory-method/uml.png similarity index 100% rename from 2024/05/17/design-pattern-2-factory-method/uml.png rename to design-pattern-2-factory-method/uml.png diff --git a/2024/05/14/design-pattern-2-simple-factory/index.html b/design-pattern-2-simple-factory/index.html similarity index 83% rename from 2024/05/14/design-pattern-2-simple-factory/index.html rename to design-pattern-2-simple-factory/index.html index 3077b12..16ce3aa 100644 --- a/2024/05/14/design-pattern-2-simple-factory/index.html +++ b/design-pattern-2-simple-factory/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - - + + - + - 设计模式学习(二)工厂模式——简单工厂模式 - + 设计模式学习(二)工厂模式——简单工厂模式 | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/05/14/design-pattern-2-simple-factory/uml.png b/design-pattern-2-simple-factory/uml.png similarity index 100% rename from 2024/05/14/design-pattern-2-simple-factory/uml.png rename to design-pattern-2-simple-factory/uml.png diff --git a/2024/05/10/git-code-migration/index.html b/git-code-migration/index.html similarity index 76% rename from 2024/05/10/git-code-migration/index.html rename to git-code-migration/index.html index bc748cf..28147c7 100644 --- a/2024/05/10/git-code-migration/index.html +++ b/git-code-migration/index.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -32,17 +32,16 @@ - - + + - + - Git学习——迁移单一仓库至其他代码托管平台 - + Git学习——迁移单一仓库至其他代码托管平台 | Paw5zx - Paw5zx @@ -73,7 +72,7 @@ - + @@ -82,7 +81,7 @@ @@ -192,7 +191,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/index.html b/index.html index b9bb625..1dcf1f9 100644 --- a/index.html +++ b/index.html @@ -28,15 +28,16 @@ - - + + - + - Paw5zx + Paw5zx - Redefine Your Hexo Journey. + @@ -67,7 +68,7 @@ - + @@ -76,7 +77,7 @@ @@ -186,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/js/layouts/essays.js b/js/layouts/essays.js new file mode 100644 index 0000000..568bcd7 --- /dev/null +++ b/js/layouts/essays.js @@ -0,0 +1,25 @@ +// Function to format the dates +function formatEssayDates() { + const dateElements = document.querySelectorAll(".essay-date"); + + if (!dateElements) { + return; + } + + dateElements.forEach(function (element) { + const rawDate = element.getAttribute("data-date"); + const locale = config.language || "en"; + + const formattedDate = moment(rawDate).locale(locale).calendar(); + element.textContent = formattedDate; + }); +} + +try { + swup.hooks.on("page:view", formatEssayDates); +} catch (e) { + console.error(e); +} + +// Initial call for the first page load +document.addEventListener("DOMContentLoaded", formatEssayDates); diff --git a/js/libs/moment-with-locales.min.js b/js/libs/moment-with-locales.min.js new file mode 100644 index 0000000..8a6c9b4 --- /dev/null +++ b/js/libs/moment-with-locales.min.js @@ -0,0 +1,2 @@ +!function(e,a){"object"==typeof exports&&"undefined"!=typeof module?module.exports=a():"function"==typeof define&&define.amd?define(a):e.moment=a()}(this,function(){"use strict";var E;function c(){return E.apply(null,arguments)}function F(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function z(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function l(e,a){return Object.prototype.hasOwnProperty.call(e,a)}function N(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;for(var a in e)if(l(e,a))return;return 1}function L(e){return void 0===e}function J(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function R(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function C(e,a){for(var t=[],s=e.length,n=0;n>>0,s=0;sFe(e)?(r=e+1,a-Fe(e)):(r=e,a);return{year:r,dayOfYear:t}}function aa(e,a,t){var s,n,r=Xe(e.year(),a,t),r=Math.floor((e.dayOfYear()-r-1)/7)+1;return r<1?s=r+ta(n=e.year()-1,a,t):r>ta(e.year(),a,t)?(s=r-ta(e.year(),a,t),n=e.year()+1):(n=e.year(),s=r),{week:s,year:n}}function ta(e,a,t){var s=Xe(e,a,t),a=Xe(e+1,a,t);return(Fe(e)-s+a)/7}s("w",["ww",2],"wo","week"),s("W",["WW",2],"Wo","isoWeek"),h("w",r,u),h("ww",r,a),h("W",r,u),h("WW",r,a),Se(["w","ww","W","WW"],function(e,a,t,s){a[s.substr(0,1)]=f(e)});function sa(e,a){return e.slice(a,7).concat(e.slice(0,a))}s("d",0,"do","day"),s("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),s("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),s("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),s("e",0,0,"weekday"),s("E",0,0,"isoWeekday"),h("d",r),h("e",r),h("E",r),h("dd",function(e,a){return a.weekdaysMinRegex(e)}),h("ddd",function(e,a){return a.weekdaysShortRegex(e)}),h("dddd",function(e,a){return a.weekdaysRegex(e)}),Se(["dd","ddd","dddd"],function(e,a,t,s){s=t._locale.weekdaysParse(e,s,t._strict);null!=s?a.d=s:Y(t).invalidWeekday=e}),Se(["d","e","E"],function(e,a,t,s){a[s]=f(e)});var na="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),ra="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),da="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),_a=m,ia=m,oa=m;function ma(){function e(e,a){return a.length-e.length}for(var a,t,s,n=[],r=[],d=[],_=[],i=0;i<7;i++)s=U([2e3,1]).day(i),a=we(this.weekdaysMin(s,"")),t=we(this.weekdaysShort(s,"")),s=we(this.weekdays(s,"")),n.push(a),r.push(t),d.push(s),_.push(a),_.push(t),_.push(s);n.sort(e),r.sort(e),d.sort(e),_.sort(e),this._weekdaysRegex=new RegExp("^("+_.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+d.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+r.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+n.join("|")+")","i")}function ua(){return this.hours()%12||12}function la(e,a){s(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),a)})}function Ma(e,a){return a._meridiemParse}s("H",["HH",2],0,"hour"),s("h",["hh",2],0,ua),s("k",["kk",2],0,function(){return this.hours()||24}),s("hmm",0,0,function(){return""+ua.apply(this)+de(this.minutes(),2)}),s("hmmss",0,0,function(){return""+ua.apply(this)+de(this.minutes(),2)+de(this.seconds(),2)}),s("Hmm",0,0,function(){return""+this.hours()+de(this.minutes(),2)}),s("Hmmss",0,0,function(){return""+this.hours()+de(this.minutes(),2)+de(this.seconds(),2)}),la("a",!0),la("A",!1),h("a",Ma),h("A",Ma),h("H",r,M),h("h",r,u),h("k",r,u),h("HH",r,a),h("hh",r,a),h("kk",r,a),h("hmm",ye),h("hmmss",_),h("Hmm",ye),h("Hmmss",_),k(["H","HH"],D),k(["k","kk"],function(e,a,t){e=f(e);a[D]=24===e?0:e}),k(["a","A"],function(e,a,t){t._isPm=t._locale.isPM(e),t._meridiem=e}),k(["h","hh"],function(e,a,t){a[D]=f(e),Y(t).bigHour=!0}),k("hmm",function(e,a,t){var s=e.length-2;a[D]=f(e.substr(0,s)),a[Pe]=f(e.substr(s)),Y(t).bigHour=!0}),k("hmmss",function(e,a,t){var s=e.length-4,n=e.length-2;a[D]=f(e.substr(0,s)),a[Pe]=f(e.substr(s,2)),a[Oe]=f(e.substr(n)),Y(t).bigHour=!0}),k("Hmm",function(e,a,t){var s=e.length-2;a[D]=f(e.substr(0,s)),a[Pe]=f(e.substr(s))}),k("Hmmss",function(e,a,t){var s=e.length-4,n=e.length-2;a[D]=f(e.substr(0,s)),a[Pe]=f(e.substr(s,2)),a[Oe]=f(e.substr(n))});m=Ne("Hours",!0);var ha,ca={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Ie,monthsShort:Ue,week:{dow:0,doy:6},weekdays:na,weekdaysMin:da,weekdaysShort:ra,meridiemParse:/[ap]\.?m?\.?/i},g={},La={};function Ya(e){return e&&e.toLowerCase().replace("_","-")}function ya(e){for(var a,t,s,n,r=0;r=a&&function(e,a){for(var t=Math.min(e.length,a.length),s=0;s=a-1)break;a--}r++}return ha}function fa(a){var e,t;if(void 0===g[a]&&"undefined"!=typeof module&&module&&module.exports&&(t=a)&&t.match("^[^/\\\\]*$"))try{e=ha._abbr,require("./locale/"+a),ka(e)}catch(e){g[a]=null}return g[a]}function ka(e,a){return e&&((a=L(a)?Da(e):pa(e,a))?ha=a:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),ha._abbr}function pa(e,a){if(null===a)return delete g[e],null;var t,s=ca;if(a.abbr=e,null!=g[e])ae("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=g[e]._config;else if(null!=a.parentLocale)if(null!=g[a.parentLocale])s=g[a.parentLocale]._config;else{if(null==(t=fa(a.parentLocale)))return La[a.parentLocale]||(La[a.parentLocale]=[]),La[a.parentLocale].push({name:e,config:a}),null;s=t._config}return g[e]=new ne(se(s,a)),La[e]&&La[e].forEach(function(e){pa(e.name,e.config)}),ka(e),g[e]}function Da(e){var a;if(!(e=e&&e._locale&&e._locale._abbr?e._locale._abbr:e))return ha;if(!F(e)){if(a=fa(e))return a;e=[e]}return ya(e)}function Ta(e){var a=e._a;return a&&-2===Y(e).overflow&&(a=a[je]<0||11Ce(a[p],a[je])?xe:a[D]<0||24ta(r,i,o)?Y(s)._overflowWeeks=!0:null!=m?Y(s)._overflowWeekday=!0:(u=ea(r,d,_,i,o),s._a[p]=u.year,s._dayOfYear=u.dayOfYear)),null!=e._dayOfYear&&(n=Aa(e._a[p],t[p]),(e._dayOfYear>Fe(n)||0===e._dayOfYear)&&(Y(e)._overflowDayOfYear=!0),m=Qe(n,0,e._dayOfYear),e._a[je]=m.getUTCMonth(),e._a[xe]=m.getUTCDate()),a=0;a<3&&null==e._a[a];++a)e._a[a]=l[a]=t[a];for(;a<7;a++)e._a[a]=l[a]=null==e._a[a]?2===a?1:0:e._a[a];24===e._a[D]&&0===e._a[Pe]&&0===e._a[Oe]&&0===e._a[We]&&(e._nextDay=!0,e._a[D]=0),e._d=(e._useUTC?Qe:$e).apply(null,l),r=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[D]=24),e._w&&void 0!==e._w.d&&e._w.d!==r&&(Y(e).weekdayMismatch=!0)}}function Fa(e){if(e._f===c.ISO_8601)Pa(e);else if(e._f===c.RFC_2822)Wa(e);else{e._a=[],Y(e).empty=!0;for(var a,t,s,n,r,d=""+e._i,_=d.length,i=0,o=le(e._f,e._locale).match(_e)||[],m=o.length,u=0;ue.valueOf():e.valueOf()"}),u.toJSON=function(){return this.isValid()?this.toISOString():null},u.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},u.unix=function(){return Math.floor(this.valueOf()/1e3)},u.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},u.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},u.eraName=function(){for(var e,a=this.localeData().eras(),t=0,s=a.length;tthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},u.isLocal=function(){return!!this.isValid()&&!this._isUTC},u.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},u.isUtc=Za,u.isUTC=Za,u.zoneAbbr=function(){return this._isUTC?"UTC":""},u.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},u.dates=e("dates accessor is deprecated. Use date instead.",i),u.months=e("months accessor is deprecated. Use month instead",Ke),u.years=e("years accessor is deprecated. Use year instead",ze),u.zone=e("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,a){return null!=e?(this.utcOffset(e="string"!=typeof e?-e:e,a),this):-this.utcOffset()}),u.isDSTShifted=e("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){var e,a;return L(this._isDSTShifted)&&(Z(e={},this),(e=za(e))._a?(a=(e._isUTC?U:w)(e._a),this._isDSTShifted=this.isValid()&&0>>0,s=0;sWe(e)?(r=e+1,t-We(e)):(r=e,t);return{year:r,dayOfYear:n}}function Be(e,t,n){var s,i,r=qe(e.year(),t,n),r=Math.floor((e.dayOfYear()-r-1)/7)+1;return r<1?s=r+N(i=e.year()-1,t,n):r>N(e.year(),t,n)?(s=r-N(e.year(),t,n),i=e.year()+1):(i=e.year(),s=r),{week:s,year:i}}function N(e,t,n){var s=qe(e,t,n),t=qe(e+1,t,n);return(We(e)-s+t)/7}s("w",["ww",2],"wo","week"),s("W",["WW",2],"Wo","isoWeek"),h("w",n,u),h("ww",n,t),h("W",n,u),h("WW",n,t),Oe(["w","ww","W","WW"],function(e,t,n,s){t[s.substr(0,1)]=M(e)});function Je(e,t){return e.slice(t,7).concat(e.slice(0,t))}s("d",0,"do","day"),s("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),s("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),s("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),s("e",0,0,"weekday"),s("E",0,0,"isoWeekday"),h("d",n),h("e",n),h("E",n),h("dd",function(e,t){return t.weekdaysMinRegex(e)}),h("ddd",function(e,t){return t.weekdaysShortRegex(e)}),h("dddd",function(e,t){return t.weekdaysRegex(e)}),Oe(["dd","ddd","dddd"],function(e,t,n,s){s=n._locale.weekdaysParse(e,s,n._strict);null!=s?t.d=s:p(n).invalidWeekday=e}),Oe(["d","e","E"],function(e,t,n,s){t[s]=M(e)});var Qe="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Xe="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ke="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),et=i,tt=i,nt=i;function st(){function e(e,t){return t.length-e.length}for(var t,n,s,i=[],r=[],a=[],o=[],u=0;u<7;u++)s=l([2e3,1]).day(u),t=f(this.weekdaysMin(s,"")),n=f(this.weekdaysShort(s,"")),s=f(this.weekdays(s,"")),i.push(t),r.push(n),a.push(s),o.push(t),o.push(n),o.push(s);i.sort(e),r.sort(e),a.sort(e),o.sort(e),this._weekdaysRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+a.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+r.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+i.join("|")+")","i")}function it(){return this.hours()%12||12}function rt(e,t){s(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function at(e,t){return t._meridiemParse}s("H",["HH",2],0,"hour"),s("h",["hh",2],0,it),s("k",["kk",2],0,function(){return this.hours()||24}),s("hmm",0,0,function(){return""+it.apply(this)+r(this.minutes(),2)}),s("hmmss",0,0,function(){return""+it.apply(this)+r(this.minutes(),2)+r(this.seconds(),2)}),s("Hmm",0,0,function(){return""+this.hours()+r(this.minutes(),2)}),s("Hmmss",0,0,function(){return""+this.hours()+r(this.minutes(),2)+r(this.seconds(),2)}),rt("a",!0),rt("A",!1),h("a",at),h("A",at),h("H",n,d),h("h",n,u),h("k",n,u),h("HH",n,t),h("hh",n,t),h("kk",n,t),h("hmm",me),h("hmmss",_e),h("Hmm",me),h("Hmmss",_e),v(["H","HH"],O),v(["k","kk"],function(e,t,n){e=M(e);t[O]=24===e?0:e}),v(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),v(["h","hh"],function(e,t,n){t[O]=M(e),p(n).bigHour=!0}),v("hmm",function(e,t,n){var s=e.length-2;t[O]=M(e.substr(0,s)),t[b]=M(e.substr(s)),p(n).bigHour=!0}),v("hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[O]=M(e.substr(0,s)),t[b]=M(e.substr(s,2)),t[T]=M(e.substr(i)),p(n).bigHour=!0}),v("Hmm",function(e,t,n){var s=e.length-2;t[O]=M(e.substr(0,s)),t[b]=M(e.substr(s))}),v("Hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[O]=M(e.substr(0,s)),t[b]=M(e.substr(s,2)),t[T]=M(e.substr(i))});i=Re("Hours",!0);var ot,ut={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Fe,monthsShort:Le,week:{dow:0,doy:6},weekdays:Qe,weekdaysMin:Ke,weekdaysShort:Xe,meridiemParse:/[ap]\.?m?\.?/i},W={},lt={};function dt(e){return e&&e.toLowerCase().replace("_","-")}function ht(e){for(var t,n,s,i,r=0;r=t&&function(e,t){for(var n=Math.min(e.length,t.length),s=0;s=t-1)break;t--}r++}return ot}function ct(t){var e,n;if(void 0===W[t]&&"undefined"!=typeof module&&module&&module.exports&&(n=t)&&n.match("^[^/\\\\]*$"))try{e=ot._abbr,require("./locale/"+t),ft(e)}catch(e){W[t]=null}return W[t]}function ft(e,t){return e&&((t=g(t)?P(e):mt(e,t))?ot=t:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),ot._abbr}function mt(e,t){if(null===t)return delete W[e],null;var n,s=ut;if(t.abbr=e,null!=W[e])Q("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=W[e]._config;else if(null!=t.parentLocale)if(null!=W[t.parentLocale])s=W[t.parentLocale]._config;else{if(null==(n=ct(t.parentLocale)))return lt[t.parentLocale]||(lt[t.parentLocale]=[]),lt[t.parentLocale].push({name:e,config:t}),null;s=n._config}return W[e]=new K(X(s,t)),lt[e]&<[e].forEach(function(e){mt(e.name,e.config)}),ft(e),W[e]}function P(e){var t;if(!(e=e&&e._locale&&e._locale._abbr?e._locale._abbr:e))return ot;if(!y(e)){if(t=ct(e))return t;e=[e]}return ht(e)}function _t(e){var t=e._a;return t&&-2===p(e).overflow&&(t=t[Y]<0||11He(t[D],t[Y])?S:t[O]<0||24N(r,u,l)?p(s)._overflowWeeks=!0:null!=d?p(s)._overflowWeekday=!0:(h=$e(r,a,o,u,l),s._a[D]=h.year,s._dayOfYear=h.dayOfYear)),null!=e._dayOfYear&&(i=bt(e._a[D],n[D]),(e._dayOfYear>We(i)||0===e._dayOfYear)&&(p(e)._overflowDayOfYear=!0),d=ze(i,0,e._dayOfYear),e._a[Y]=d.getUTCMonth(),e._a[S]=d.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=c[t]=n[t];for(;t<7;t++)e._a[t]=c[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[O]&&0===e._a[b]&&0===e._a[T]&&0===e._a[Te]&&(e._nextDay=!0,e._a[O]=0),e._d=(e._useUTC?ze:Ze).apply(null,c),r=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[O]=24),e._w&&void 0!==e._w.d&&e._w.d!==r&&(p(e).weekdayMismatch=!0)}}function xt(e){if(e._f===_.ISO_8601)Yt(e);else if(e._f===_.RFC_2822)Ot(e);else{e._a=[],p(e).empty=!0;for(var t,n,s,i,r,a=""+e._i,o=a.length,u=0,l=ae(e._f,e._locale).match(te)||[],d=l.length,h=0;he.valueOf():e.valueOf()"}),u.toJSON=function(){return this.isValid()?this.toISOString():null},u.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},u.unix=function(){return Math.floor(this.valueOf()/1e3)},u.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},u.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},u.eraName=function(){for(var e,t=this.localeData().eras(),n=0,s=t.length;nthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},u.isLocal=function(){return!!this.isValid()&&!this._isUTC},u.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},u.isUtc=At,u.isUTC=At,u.zoneAbbr=function(){return this._isUTC?"UTC":""},u.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},u.dates=e("dates accessor is deprecated. Use date instead.",ge),u.months=e("months accessor is deprecated. Use month instead",Ie),u.years=e("years accessor is deprecated. Use year instead",Pe),u.zone=e("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?(this.utcOffset(e="string"!=typeof e?-e:e,t),this):-this.utcOffset()}),u.isDSTShifted=e("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){var e,t;return g(this._isDSTShifted)&&(q(e={},this),(e=Nt(e))._a?(t=(e._isUTC?l:R)(e._a),this._isDSTShifted=this.isValid()&&0 { - "use strict"; +import { main } from "../main.js"; +import { initTOC } from "../layouts/toc.js"; +export function initHBE() { const cryptoObj = window.crypto || window.msCrypto; const storage = window.localStorage; const storageName = "hexo-blog-encrypt:#" + window.location.pathname; - const keySalt = textToArray("hexo-blog-encrypt的作者们都是大帅比!"); - const ivSalt = textToArray("hexo-blog-encrypt是地表最强Hexo加密插件!"); + const keySalt = textToArray("too young too simple"); + const ivSalt = textToArray("sometimes naive!"); // As we can't detect the wrong password with AES-CBC, // so adding an empty div and check it when decrption. @@ -235,24 +236,9 @@ } }); - // support theme-next refresh - window.NexT && - NexT.boot && - typeof NexT.boot.refresh === "function" && - NexT.boot.refresh(); - - // TOC part - var tocDiv = document.getElementById("toc-div"); - if (tocDiv) { - tocDiv.style.display = "inline"; - } - - var tocDivs = document.getElementsByClassName("toc-div-class"); - if (tocDivs && tocDivs.length > 0) { - for (var idx = 0; idx < tocDivs.length; idx++) { - tocDivs[idx].style.display = "inline"; - } - } + // // load Redefine Page components + main.refresh(); + initTOC(); // trigger event var event = new Event("hexo-blog-decrypt"); @@ -344,4 +330,6 @@ } hbeLoader(); -})(); +} + +// initHBE(); diff --git a/js/plugins/typed.js b/js/plugins/typed.js index 7b8a115..3977e93 100644 --- a/js/plugins/typed.js +++ b/js/plugins/typed.js @@ -38,7 +38,11 @@ export default function initTyped(id) { fetch(usrHitokotoAPI) .then((response) => response.json()) .then((data) => { - typing(data.hitokoto); + if (data.from_who && theme.home_banner.subtitle.hitokoto.show_author) { + typing(data.hitokoto + "——" + data.from_who); + } else { + typing(data.hitokoto); + } }) .catch(console.error); } else { diff --git a/js/tools/imageViewer.js b/js/tools/imageViewer.js index f23e91b..095b107 100644 --- a/js/tools/imageViewer.js +++ b/js/tools/imageViewer.js @@ -3,14 +3,27 @@ export default function imageViewer() { let scale = 1; let isMouseDown = false; let dragged = false; - let currentImgIndex = 0; + let currentImgIndex = 0; let lastMouseX = 0; let lastMouseY = 0; let translateX = 0; let translateY = 0; const maskDom = document.querySelector(".image-viewer-container"); + if (!maskDom) { + console.warn( + "Image viewer container not found. Exiting imageViewer function.", + ); + return; + } + const targetImg = maskDom.querySelector("img"); + if (!targetImg) { + console.warn( + "Target image not found in image viewer container. Exiting imageViewer function.", + ); + return; + } const showHandle = (isShow) => { document.body.style.overflow = isShow ? "hidden" : "auto"; @@ -48,7 +61,7 @@ export default function imageViewer() { isMouseDown = true; lastMouseX = event.clientX; lastMouseY = event.clientY; - targetImg.style.cursor = 'grabbing'; + targetImg.style.cursor = "grabbing"; }; let lastTime = 0; @@ -68,7 +81,7 @@ export default function imageViewer() { lastMouseX = event.clientX; lastMouseY = event.clientY; targetImg.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`; - dragged = true; + dragged = true; } }; @@ -77,7 +90,7 @@ export default function imageViewer() { event.stopPropagation(); } isMouseDown = false; - targetImg.style.cursor = 'grab'; + targetImg.style.cursor = "grab"; }; targetImg.addEventListener("wheel", zoomHandle, { passive: false }); @@ -87,7 +100,7 @@ export default function imageViewer() { targetImg.addEventListener("mouseleave", dragEndHandle, { passive: false }); maskDom.addEventListener("click", (event) => { - if (!dragged) { + if (!dragged) { isBigImage = false; showHandle(isBigImage); scale = 1; @@ -95,9 +108,9 @@ export default function imageViewer() { translateY = 0; targetImg.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`; } - dragged = false; + dragged = false; }); - + const imgDoms = document.querySelectorAll( ".markdown-body img, .masonry-item img, #shuoshuo-content img", ); @@ -115,42 +128,43 @@ export default function imageViewer() { } }; - imgDoms.forEach((img, index) => { - img.addEventListener("click", () => { - currentImgIndex = index; - isBigImage = true; - showHandle(isBigImage); - targetImg.src = img.src; - document.addEventListener("keydown", escapeKeyListener); + if (imgDoms.length > 0) { + imgDoms.forEach((img, index) => { + img.addEventListener("click", () => { + currentImgIndex = index; + isBigImage = true; + showHandle(isBigImage); + targetImg.src = img.src; + document.addEventListener("keydown", escapeKeyListener); + }); }); - }); - const handleArrowKeys = (event) => { - if (!isBigImage) return; - - if (event.key === "ArrowUp" || event.key === "ArrowLeft") { - currentImgIndex = (currentImgIndex - 1 + imgDoms.length) % imgDoms.length; - } else if (event.key === "ArrowDown" || event.key === "ArrowRight") { - currentImgIndex = (currentImgIndex + 1) % imgDoms.length; - } else { - return; - } - - const currentImg = imgDoms[currentImgIndex]; - let newSrc = currentImg.src; - - if (currentImg.hasAttribute("lazyload")) { - newSrc = currentImg.getAttribute("data-src"); - currentImg.src = newSrc; - currentImg.removeAttribute("lazyload"); - } + const handleArrowKeys = (event) => { + if (!isBigImage) return; - targetImg.src = newSrc; -}; + if (event.key === "ArrowUp" || event.key === "ArrowLeft") { + currentImgIndex = + (currentImgIndex - 1 + imgDoms.length) % imgDoms.length; + } else if (event.key === "ArrowDown" || event.key === "ArrowRight") { + currentImgIndex = (currentImgIndex + 1) % imgDoms.length; + } else { + return; + } + + const currentImg = imgDoms[currentImgIndex]; + let newSrc = currentImg.src; + + if (currentImg.hasAttribute("lazyload")) { + newSrc = currentImg.getAttribute("data-src"); + currentImg.src = newSrc; + currentImg.removeAttribute("lazyload"); + } - document.addEventListener("keydown", handleArrowKeys); + targetImg.src = newSrc; + }; - if (!imgDoms.length && maskDom) { - maskDom.parentNode.removeChild(maskDom); + document.addEventListener("keydown", handleArrowKeys); + } else { + // console.warn("No images found to attach image viewer functionality."); } } diff --git a/js/utils.js b/js/utils.js index 772ddfb..5c26b03 100644 --- a/js/utils.js +++ b/js/utils.js @@ -83,7 +83,19 @@ export default function initUtils() { }, calculatePercentage(scrollTop, scrollHeight, clientHeight) { - return Math.round((scrollTop / (scrollHeight - clientHeight)) * 100); + let percentageValue = Math.round( + (scrollTop / (scrollHeight - clientHeight)) * 100, + ); + if ( + isNaN(percentageValue) || + percentageValue < 0 || + !isFinite(percentageValue) + ) { + percentageValue = 0; + } else if (percentageValue > 100) { + percentageValue = 100; + } + return percentageValue; }, // register window scroll event diff --git a/lib/hbe.js b/lib/hbe.js deleted file mode 100644 index 2b6bc4a..0000000 --- a/lib/hbe.js +++ /dev/null @@ -1,347 +0,0 @@ -(() => { - "use strict"; - - const cryptoObj = window.crypto || window.msCrypto; - const storage = window.localStorage; - - const storageName = "hexo-blog-encrypt:#" + window.location.pathname; - const keySalt = textToArray("hexo-blog-encrypt的作者们都是大帅比!"); - const ivSalt = textToArray("hexo-blog-encrypt是地表最强Hexo加密插件!"); - - // As we can't detect the wrong password with AES-CBC, - // so adding an empty div and check it when decrption. - const knownPrefix = ""; - - const mainElement = document.getElementById("hexo-blog-encrypt"); - const wrongPassMessage = mainElement.dataset["wpm"]; - const wrongHashMessage = mainElement.dataset["whm"]; - const dataElement = mainElement.getElementsByTagName("script")["hbeData"]; - const encryptedData = dataElement.innerText; - const HmacDigist = dataElement.dataset["hmacdigest"]; - - function hexToArray(s) { - return new Uint8Array( - s.match(/[\da-f]{2}/gi).map((h) => { - return parseInt(h, 16); - }), - ); - } - - function textToArray(s) { - var i = s.length; - var n = 0; - var ba = new Array(); - - for (var j = 0; j < i; ) { - var c = s.codePointAt(j); - if (c < 128) { - ba[n++] = c; - j++; - } else if (c > 127 && c < 2048) { - ba[n++] = (c >> 6) | 192; - ba[n++] = (c & 63) | 128; - j++; - } else if (c > 2047 && c < 65536) { - ba[n++] = (c >> 12) | 224; - ba[n++] = ((c >> 6) & 63) | 128; - ba[n++] = (c & 63) | 128; - j++; - } else { - ba[n++] = (c >> 18) | 240; - ba[n++] = ((c >> 12) & 63) | 128; - ba[n++] = ((c >> 6) & 63) | 128; - ba[n++] = (c & 63) | 128; - j += 2; - } - } - return new Uint8Array(ba); - } - - function arrayBufferToHex(arrayBuffer) { - if ( - typeof arrayBuffer !== "object" || - arrayBuffer === null || - typeof arrayBuffer.byteLength !== "number" - ) { - throw new TypeError("Expected input to be an ArrayBuffer"); - } - - var view = new Uint8Array(arrayBuffer); - var result = ""; - var value; - - for (var i = 0; i < view.length; i++) { - value = view[i].toString(16); - result += value.length === 1 ? "0" + value : value; - } - - return result; - } - - async function getExecutableScript(oldElem) { - let out = document.createElement("script"); - const attList = [ - "type", - "text", - "src", - "crossorigin", - "defer", - "referrerpolicy", - ]; - attList.forEach((att) => { - if (oldElem[att]) out[att] = oldElem[att]; - }); - - return out; - } - - async function convertHTMLToElement(content) { - let out = document.createElement("div"); - out.innerHTML = content; - out.querySelectorAll("script").forEach(async (elem) => { - elem.replaceWith(await getExecutableScript(elem)); - }); - - return out; - } - - function getKeyMaterial(password) { - let encoder = new TextEncoder(); - return cryptoObj.subtle.importKey( - "raw", - encoder.encode(password), - { - name: "PBKDF2", - }, - false, - ["deriveKey", "deriveBits"], - ); - } - - function getHmacKey(keyMaterial) { - return cryptoObj.subtle.deriveKey( - { - name: "PBKDF2", - hash: "SHA-256", - salt: keySalt.buffer, - iterations: 1024, - }, - keyMaterial, - { - name: "HMAC", - hash: "SHA-256", - length: 256, - }, - true, - ["verify"], - ); - } - - function getDecryptKey(keyMaterial) { - return cryptoObj.subtle.deriveKey( - { - name: "PBKDF2", - hash: "SHA-256", - salt: keySalt.buffer, - iterations: 1024, - }, - keyMaterial, - { - name: "AES-CBC", - length: 256, - }, - true, - ["decrypt"], - ); - } - - function getIv(keyMaterial) { - return cryptoObj.subtle.deriveBits( - { - name: "PBKDF2", - hash: "SHA-256", - salt: ivSalt.buffer, - iterations: 512, - }, - keyMaterial, - 16 * 8, - ); - } - - async function verifyContent(key, content) { - const encoder = new TextEncoder(); - const encoded = encoder.encode(content); - - let signature = hexToArray(HmacDigist); - - const result = await cryptoObj.subtle.verify( - { - name: "HMAC", - hash: "SHA-256", - }, - key, - signature, - encoded, - ); - console.log(`Verification result: ${result}`); - if (!result) { - alert(wrongHashMessage); - console.log(`${wrongHashMessage}, got `, signature, ` but proved wrong.`); - } - return result; - } - - async function decrypt(decryptKey, iv, hmacKey) { - let typedArray = hexToArray(encryptedData); - - const result = await cryptoObj.subtle - .decrypt( - { - name: "AES-CBC", - iv: iv, - }, - decryptKey, - typedArray.buffer, - ) - .then(async (result) => { - const decoder = new TextDecoder(); - const decoded = decoder.decode(result); - - // check the prefix, if not then we can sure here is wrong password. - if (!decoded.startsWith(knownPrefix)) { - throw "Decode successfully but not start with KnownPrefix."; - } - - const hideButton = document.createElement("button"); - hideButton.textContent = "Encrypt again"; - hideButton.type = "button"; - hideButton.classList.add("hbe-button"); - hideButton.addEventListener("click", () => { - window.localStorage.removeItem(storageName); - window.location.reload(); - }); - - document.getElementById("hexo-blog-encrypt").style.display = "inline"; - document.getElementById("hexo-blog-encrypt").innerHTML = ""; - document - .getElementById("hexo-blog-encrypt") - .appendChild(await convertHTMLToElement(decoded)); - document.getElementById("hexo-blog-encrypt").appendChild(hideButton); - - // support html5 lazyload functionality. - document.querySelectorAll("img").forEach((elem) => { - if (elem.getAttribute("data-src") && !elem.src) { - elem.src = elem.getAttribute("data-src"); - } - }); - - // support theme-next refresh - window.NexT && - NexT.boot && - typeof NexT.boot.refresh === "function" && - NexT.boot.refresh(); - - // TOC part - var tocDiv = document.getElementById("toc-div"); - if (tocDiv) { - tocDiv.style.display = "inline"; - } - - var tocDivs = document.getElementsByClassName("toc-div-class"); - if (tocDivs && tocDivs.length > 0) { - for (var idx = 0; idx < tocDivs.length; idx++) { - tocDivs[idx].style.display = "inline"; - } - } - - // trigger event - var event = new Event("hexo-blog-decrypt"); - window.dispatchEvent(event); - - return await verifyContent(hmacKey, decoded); - }) - .catch((e) => { - alert(wrongPassMessage); - console.log(e); - return false; - }); - - return result; - } - - function hbeLoader() { - const oldStorageData = JSON.parse(storage.getItem(storageName)); - - if (oldStorageData) { - console.log( - `Password got from localStorage(${storageName}): `, - oldStorageData, - ); - - const sIv = hexToArray(oldStorageData.iv).buffer; - const sDk = oldStorageData.dk; - const sHmk = oldStorageData.hmk; - - cryptoObj.subtle - .importKey( - "jwk", - sDk, - { - name: "AES-CBC", - length: 256, - }, - true, - ["decrypt"], - ) - .then((dkCK) => { - cryptoObj.subtle - .importKey( - "jwk", - sHmk, - { - name: "HMAC", - hash: "SHA-256", - length: 256, - }, - true, - ["verify"], - ) - .then((hmkCK) => { - decrypt(dkCK, sIv, hmkCK).then((result) => { - if (!result) { - storage.removeItem(storageName); - } - }); - }); - }); - } - - mainElement.addEventListener("keydown", async (event) => { - if (event.isComposing || event.key === "Enter") { - const password = document.getElementById("hbePass").value; - const keyMaterial = await getKeyMaterial(password); - const hmacKey = await getHmacKey(keyMaterial); - const decryptKey = await getDecryptKey(keyMaterial); - const iv = await getIv(keyMaterial); - - decrypt(decryptKey, iv, hmacKey).then((result) => { - console.log(`Decrypt result: ${result}`); - if (result) { - cryptoObj.subtle.exportKey("jwk", decryptKey).then((dk) => { - cryptoObj.subtle.exportKey("jwk", hmacKey).then((hmk) => { - const newStorageData = { - dk: dk, - iv: arrayBufferToHex(iv), - hmk: hmk, - }; - storage.setItem(storageName, JSON.stringify(newStorageData)); - }); - }); - } - }); - } - }); - } - - hbeLoader(); -})(); diff --git a/links/index.html b/links/index.html index 0950db4..0a47b14 100644 --- a/links/index.html +++ b/links/index.html @@ -30,17 +30,16 @@ - - + + - + - 友情链接 - + 友情链接 | Paw5zx - Paw5zx @@ -71,7 +70,7 @@ - + @@ -80,7 +79,7 @@ @@ -190,7 +189,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/05/16/linux-centos-boot-time-optimization/index.html b/linux-centos-boot-time-optimization/index.html similarity index 79% rename from 2024/05/16/linux-centos-boot-time-optimization/index.html rename to linux-centos-boot-time-optimization/index.html index 0f3c86d..1a7df6d 100644 --- a/2024/05/16/linux-centos-boot-time-optimization/index.html +++ b/linux-centos-boot-time-optimization/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - - + + - + - Centos8系统启动时间优化 - + Centos8系统启动时间优化 | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/05/16/linux-centos-boot-time-optimization/result.png b/linux-centos-boot-time-optimization/result.png similarity index 100% rename from 2024/05/16/linux-centos-boot-time-optimization/result.png rename to linux-centos-boot-time-optimization/result.png diff --git a/2024/07/29/linux-update-alternatives/confirm.png b/linux-update-alternatives/confirm.png similarity index 100% rename from 2024/07/29/linux-update-alternatives/confirm.png rename to linux-update-alternatives/confirm.png diff --git a/2024/07/29/linux-update-alternatives/gcc_version.png b/linux-update-alternatives/gcc_version.png similarity index 100% rename from 2024/07/29/linux-update-alternatives/gcc_version.png rename to linux-update-alternatives/gcc_version.png diff --git a/2024/07/29/linux-update-alternatives/index.html b/linux-update-alternatives/index.html similarity index 75% rename from 2024/07/29/linux-update-alternatives/index.html rename to linux-update-alternatives/index.html index 993ce97..c417b47 100644 --- a/2024/07/29/linux-update-alternatives/index.html +++ b/linux-update-alternatives/index.html @@ -13,7 +13,7 @@ - + @@ -21,32 +21,31 @@ - + - - - + + + - + - - + + - + - 使用update-alternatives管理GCC版本 - + 使用update-alternatives管理GCC版本 | Paw5zx - Paw5zx @@ -77,7 +76,7 @@ - + @@ -86,7 +85,7 @@ @@ -196,7 +195,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/07/29/linux-update-alternatives/result.png b/linux-update-alternatives/result.png similarity index 100% rename from 2024/07/29/linux-update-alternatives/result.png rename to linux-update-alternatives/result.png diff --git a/images/O7_allmode.png b/logos/O7_allmode.png similarity index 100% rename from images/O7_allmode.png rename to logos/O7_allmode.png diff --git a/images/O7_allmode.svg b/logos/O7_allmode.svg similarity index 100% rename from images/O7_allmode.svg rename to logos/O7_allmode.svg diff --git a/2024/03/04/network-bridging/index.html b/network-bridging/index.html similarity index 76% rename from 2024/03/04/network-bridging/index.html rename to network-bridging/index.html index 3830e59..4e12729 100644 --- a/2024/03/04/network-bridging/index.html +++ b/network-bridging/index.html @@ -13,7 +13,7 @@ - + @@ -21,34 +21,33 @@ - + - - - - - + + + + + - + - - + + - + - CentOS8系统网口桥接 - + CentOS8系统网口桥接 | Paw5zx - Paw5zx @@ -79,7 +78,7 @@ - + @@ -88,7 +87,7 @@ @@ -198,7 +197,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/03/04/network-bridging/net_config.png b/network-bridging/net_config.png similarity index 100% rename from 2024/03/04/network-bridging/net_config.png rename to network-bridging/net_config.png diff --git a/2024/03/04/network-bridging/net_config2.png b/network-bridging/net_config2.png similarity index 100% rename from 2024/03/04/network-bridging/net_config2.png rename to network-bridging/net_config2.png diff --git a/2024/03/04/network-bridging/port_name.png b/network-bridging/port_name.png similarity index 100% rename from 2024/03/04/network-bridging/port_name.png rename to network-bridging/port_name.png diff --git a/2024/03/04/network-bridging/result.png b/network-bridging/result.png similarity index 100% rename from 2024/03/04/network-bridging/result.png rename to network-bridging/result.png diff --git a/2024/03/04/network-bridging/result2.png b/network-bridging/result2.png similarity index 100% rename from 2024/03/04/network-bridging/result2.png rename to network-bridging/result2.png diff --git a/page/2/index.html b/page/2/index.html index c81fb30..fbd2a66 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -28,15 +28,16 @@ - - + + - + - Paw5zx + Paw5zx - Redefine Your Hexo Journey. + @@ -67,7 +68,7 @@ - + @@ -76,7 +77,7 @@ @@ -186,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/page/3/index.html b/page/3/index.html index f9f0a67..33b510c 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -28,15 +28,16 @@ - - + + - + - Paw5zx + Paw5zx - Redefine Your Hexo Journey. + @@ -67,7 +68,7 @@ - + @@ -76,7 +77,7 @@ @@ -186,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/page/4/index.html b/page/4/index.html index 24f3575..ab4e8a6 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -28,15 +28,16 @@ - - + + - + - Paw5zx + Paw5zx - Redefine Your Hexo Journey. + @@ -67,7 +68,7 @@ - + @@ -76,7 +77,7 @@ @@ -186,7 +187,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/2024/04/07/reference-counting/ctr_block.png b/reference-counting/ctr_block.png similarity index 100% rename from 2024/04/07/reference-counting/ctr_block.png rename to reference-counting/ctr_block.png diff --git a/2024/04/07/reference-counting/index.html b/reference-counting/index.html similarity index 88% rename from 2024/04/07/reference-counting/index.html rename to reference-counting/index.html index b705889..5fb340e 100644 --- a/2024/04/07/reference-counting/index.html +++ b/reference-counting/index.html @@ -13,7 +13,7 @@ - + @@ -21,30 +21,29 @@ - + - + - + - - + + - + - C++智能指针学习——小谈引用计数 - + C++智能指针学习——小谈引用计数 | Paw5zx - Paw5zx @@ -75,7 +74,7 @@ - + @@ -84,7 +83,7 @@ @@ -194,7 +193,7 @@

- Paw5zx + Paw5zx's Blog

+ - + + + + + + + + + + + - - -
diff --git a/search.xml b/search.xml index d959f50..000b461 100644 --- a/search.xml +++ b/search.xml @@ -2,7 +2,7 @@ CentOS8系统换源安装(带GUI) - /2023/10/09/Centos8-install/ + /Centos8-install/ 最近在制作系统盘时发现使用ISO镜像文件安装CentOS 8系统时,在选择安装源时总是报错,显示错误的安装源。

后来查了一下资料,了解到CentOS 8操作系统已经结束了生命周期,社区已不再维护该操作系统版本。按照社区规则,CentOS 8的源地址内容已移除,目前第三方的镜像站中均已移除CentOS 8的源。但由于个人业务需要,仍需使用CentOS 8系统,因此我们需要换源在线安装。

系统安装方法

确保网络连接

由于安装过程是在线安装,因此需要确保设备连接了互联网,可使用ping操作验证:

@@ -13,7 +13,7 @@
mirrors.aliyun.com/centos-vault/8.2.2004/BaseOS/x86_64/os/

我安装的是Centos 8.2版本,使用阿里的源,也可以使用其他源。

-
+

我在这里没有勾选Appstream,因为勾选了Appstream后,后面的安装总是报错

@@ -38,14 +38,301 @@ Linux操作 + + GObject学习笔记(一)类和实例 + /GObject-tutorial-beginner-01/ + 前言

最近阅读Aravis 源码,其中大量运用了GObject,于是打算学习一下。

+

此系列笔记仅主要面向初学者,不会很深入探讨源码的细节,专注于介绍GObject的基本用法。

+

此系列笔记参考GObject Tutorial for beginners

+ +
+

套个盾:文中定义的名词只是为了更好地理解GObject,不具备权威性。

+ +
+ + +

类和实例

在GObject中,每个可实例化类类型都与两个结构体相关联:一个是类结构体,一个是实例结构体。

+
    +
  • 类结构体会被注册到类型系统中(具体注册方式在下一节讨论),在g_object_new首次调用时,类型系统会检查相应的类结构体是否已经被初始化为一个类变量,没有则创建并初始化。此后所有该类的实例变量都将共享这个已初始化的类变量。每个类变量只会被创建一次。
  • +
  • 每次调用g_object_new时都会创建实例变量。
  • +
+ +
+

在GObject系统中,类结构体和实例结构体都会被实例化,在内存中占有特定的空间。为了便于描述,我们将分配给类结构体的实例称为“类变量”,而分配给实例结构体的实例称为“实例变量”。

+ +
+ + + +

GObject实例的结构体定义如下

+
//file: gobject.h
typedef struct _GObject GObject;
struct _GObject
{
GTypeInstance g_type_instance;

/*< private >*/
guint ref_count; /* (atomic) */
GData *qdata;
};
+ +

GObject类的结构体定义如下(我们可以先不用了解结构的细节):

+
//file: gobject.h
typedef struct _GObjectClass GObjectClass;
struct _GObjectClass
{
GTypeClass g_type_class;

/*< private >*/
GSList *construct_properties;

/*< public >*/
/* seldom overridden */
GObject* (*constructor) (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties);
/* overridable methods */
void (*set_property) (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
void (*get_property) (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
void (*dispose) (GObject *object);
void (*finalize) (GObject *object);
/* seldom overridden */
void (*dispatch_properties_changed) (GObject *object,
guint n_pspecs,
GParamSpec **pspecs);
/* signals */
void (*notify) (GObject *object,
GParamSpec *pspec);

/* called when done constructing */
void (*constructed) (GObject *object);

/*< private >*/
gsize flags;

gsize n_construct_properties;

gpointer pspecs;
gsize n_pspecs;

/* padding */
gpointer pdummy[3];
};
+ +

下面使用一个简单示例,来演示GObject的类和实例的使用

+
//file: example01.c
#include <glib-object.h>

int main (int argc, char **argv)
{

GObject *instance1, *instance2; //指向实例的指针
GObjectClass *class1, *class2; //指向类的指针

instance1 = g_object_new (G_TYPE_OBJECT, NULL);
instance2 = g_object_new (G_TYPE_OBJECT, NULL);
g_print ("The address of instance1 is %p\n", instance1);
g_print ("The address of instance2 is %p\n", instance2);

class1 = G_OBJECT_GET_CLASS (instance1);
class2 = G_OBJECT_GET_CLASS (instance2);
g_print ("The address of the class of instance1 is %p\n", class1);
g_print ("The address of the class of instance2 is %p\n", class2);

g_object_unref (instance1);
g_object_unref (instance2);

return 0;
}
+

其中:

+
    +
  • g_object_new函数创建实例变量并返回指向它的指针。在实例变量第一次被创建之前,它对应的类变量也会被创建并初始化。
  • +
  • 参数G_TYPE_OBJECT是GObject基类的类型标识符,这是GObject类型系统的核心,所有其他GObject类型都从这个基类型派生。
  • +
  • G_OBJECT_GET_CLASS返回指向参数所属类变量的指针
  • +
  • g_object_unref会销毁实例变量并释放内存。
  • +
+

输出:

+
The address of instance1 is 0x55d3ddc05600
The address of instance2 is 0x55d3ddc05620
The address of the class of instance1 is 0x55d3ddc05370
The address of the class of instance2 is 0x55d3ddc05370
+ +

可以发现,两个实例变量的地址不同,但两个实例变量对应的类变量的地址相同,因为两个实例变量共享一个类变量

+

引用计数

引用计数机制的概念在此不做介绍

+

在GObject中,GObject实例具有引用计数机制:

+
//file: example02.c
#include <glib-object.h>

static void show_ref_count (GObject *instance)
{
if (G_IS_OBJECT (instance))
/* Users should not use ref_count member in their program. */
/* This is only for demonstration. */
g_print ("Reference count is %d.\n", instance->ref_count);
else
g_print ("Instance is not GObject.\n");
}

int main (int argc, char **argv)
{
GObject *instance;

instance = g_object_new (G_TYPE_OBJECT, NULL);
g_print ("Call g_object_new.\n");
show_ref_count (instance);
g_object_ref (instance);
g_print ("Call g_object_ref.\n");
show_ref_count (instance);
g_object_unref (instance);
g_print ("Call g_object_unref.\n");
show_ref_count (instance);
g_object_unref (instance);
g_print ("Call g_object_unref.\n");
g_print ("Now the reference count is zero and the instance is destroyed.\n");
g_print ("The instance memories are possibly returned to the system.\n");
g_print ("Therefore, the access to the same address may cause a segmentation error.\n");

return 0;
}
+ +

其中:

+
    +
  • g_object_new创建一个实例变量,然后将变量的引用计数置为1
  • +
  • g_object_ref将其引用计数加1
  • +
  • g_object_unref将引用计数减1,如果此时引用计数为0,则析构变量。
  • +
+

输出:

+
Call g_object_new.
Reference count is 1.
Call g_object_ref.
Reference count is 2.
Call g_object_unref.
Reference count is 1.
Call g_object_unref.
Now the reference count is zero and the instance is destroyed.
The instance memories are possibly returned to the system.
Therefore, the access to the same address may cause a segmentation error.
+ +

初始化和析构过程

GObject初始化和销毁的实际过程比较复杂。以下是简单的描述,不做详细说明.

+

初始化

1.用类型系统注册GObject类型。这是在调用main函数之前的GLib的初始化过程中完成的。(如果编译器是gcc,则__attribute__ ((constructor))用于限定初始化函数。)
2.为GObjectClass和GObject结构分配内存
3.初始化GObjectClass结构内存。这个内存将是GObject的类变量。
4.初始化GObject结构内存。这个内存将是GObject的实例变量。

+

上述初始化过程在第一次调用g_object_new函数时执行。在第二次及后续调用g_object_new时,它只执行两个过程:①为GObject结构分配内存②初始化内存。

+

析构

1.销毁GObject实例。释放实例的内存

+

GObject变量类型是静态类型。静态类型永远不会破坏它的类。因此,即使被销毁的实例变量是最后一个,类变量仍然存在,直到程序终止。

+

参考文章

1.GObject Tutorial for beginners

+]]>
+ + C + 三方库 + GObject + +
+ + GObject学习笔记(二)类型创建与注册 + /GObject-tutorial-beginner-02/ + 前言

上一节中我们介绍了GObject类型的类和实例变量的创建和使用。GObject是一个基本的可实例化类类型,是所有使用GObject系统的类型的基类,提供了继承、封装、多态等面向对象的核心特性。不过我们一般不直接使用GObject本身,而是通过继承GObject来创建新的类型。

+ +
+

对于GObject官方文档中:

+

可实例化的类类型:object(Instantiatable classed types: objects),本文以及后文中称其为类型。
不可实例化的类类型:interface(Non-instantiatable classed types: interfaces),本文以及后文中称其为接口。

+ +
+ +

本文中我们主要介绍一下GObject类型系统中的命名约定,以及介绍如何创建一个自定义的类型。

+

命名约定

+
+

命名约定贯穿整个GObject类型系统。

+ +
+ +

首先,我们先了解基本的命名约定:一个对象名由命名空间(也可称为moudle)和名称组成。例如,GObject由命名空间“G”和名称“Object”组成。GtkWidget由命名空间“Gtk”和名称“Widget”组成。在本文中,为了更好的演示,我们将定义一个新类型,其命名空间为“Paw”,名称为“Double”,用于表示一个浮点数据。

+

好了,你现在已了解了基本的命名约定,下面我们来看一下更多的命名约定:

+
    +
  • 类型名称必须至少有三个字符长,并以a-z, A-Z或_开头。
  • +
  • 函数名使用object_method模式:要在类型为Double的实例上定义名为add的函数,则函数名为double_save
  • +
  • 使用前缀可以避免与其他项目的名称空间冲突。如我的库(或应用程序)名为Paw,就在所有函数名前加上paw_。例如:paw_double_add。前缀应该是一个词,即在第一个字母之后不应该包含任何大写字母。例如,应该是Exampleprefix而不是ExamplePrefix。
  • +
+

除了上述约定,本文还将介绍更多命名约定,将在文中适时描述。

+

类型创建和注册

类型的创建是指定义一个新的GObject类型,包括其所有的数据和行为。这会涉及到:

+
    +
  • 定义类结构体和实例结构体
  • +
  • 定义类型相关的函数:如类初始化(class_init)、实例初始化(instance_init)等函数。
  • +
+

类型的注册是将创建的新GObject类型在GObject类型系统中注册,使其成为GObject系统可识别和使用的一部分。这会涉及到:

+
    +
  • 调用类型注册函数:g_type_register_staticg_type_register_dynamic,这些函数负责在GObject类型系统中注册新创建的类型
  • +
+

在我们平时的使用中,类型的创建和注册通常可以通过GObject提供的一些便利宏来完成,如G_DECLARE_FINAL_TYPEG_DEFINE_TYPE等。这些便利宏可以让用户不用关心一些类型创建和注册的具体细节。

+

在本文中,为了更好地理解GObject类型系统,会先展示不使用便利宏的类型创建和注册过程,之后再介绍便利宏。

+ +
+

GObject类型系统中有两种类型:静态类型和动态类型。

+

对于静态类型,即使所有实例都被销毁后也不会销毁其类。对于动态类型,在最后一个实例被销毁时销毁其类。GObject的类型是静态的,其派生的类型也是静态的。

+ +
+ + + +

手动

定义类型的类和实例结构体

类和实例结构体命名约定如下:

+
    +
  • 类结构体的命名为:<Moudle><Name>Class,如PawDoubleClass。
  • +
  • 实例结构体的命名为:<Moudle><Name>,如PawDouble。
  • +
+
//类结构体
typedef struct _PawDoubleClass PawDoubleClass;
struct _PawDoubleClass
{
GObjectClass parent_class;
};
+

PawDoubleClass的第一个成员必须是其父类型的类结构体

+
//实例结构体
typedef struct _PawDouble PawDouble;
struct _PawDouble
{
GObject parent;
double value;
};
+

PawDouble的第一个成员必须是其父类型的实例结构体。
PawDouble有自己的成员value,是PawDouble类型代表的浮点数据的值

+

定义初始化函数

类和实例的初始化函数命名约定如下:

+
    +
  • 类初始化函数的命名为:<moudle>_<name>_class_init,如paw_double_class_init。
  • +
  • 实例初始化函数的命名为:<moudle>_<name>_init,如paw_double_init。
  • +
+
//类构造函数
static void paw_double_class_init(PawDoubleClass *class)
{
}

//实例构造函数
static void paw_double_init(PawDouble *self)
{
}
+ +

类型注册

对于静态类型,我们使用g_type_register_static将其注册至GObject的类型系统中

+
//file: gtype.h
GType
g_type_register_static (GType parent_type,
const gchar* type_name,
const GTypeInfo* info,
GTypeFlags flags);
+

其中:

+
    +
  • parent_type:父类类型
  • +
  • type_name:类型名称,如PawDouble
  • +
  • info:向类型系统传递类型初始化和销毁的相关信息。GTypeInfo结构体将在下文中介绍
  • +
  • flags:如果类型是抽象类型或抽象值类型,则设置它们的标志位。否则,将其设为0。
  • +
+

GTyepInfo结构体:

+
typedef struct _GTypeInfo  GTypeInfo;

struct _GTypeInfo
{
/* interface types, classed types, instantiated types */
guint16 class_size;

GBaseInitFunc base_init;
GBaseFinalizeFunc base_finalize;

/* interface types, classed types, instantiated types */
GClassInitFunc class_init;
GClassFinalizeFunc class_finalize;
gconstpointer class_data;

/* instantiated types */
guint16 instance_size;
guint16 n_preallocs;
GInstanceInitFunc instance_init;

/* value handling */
const GTypeValueTable *value_table;
};
+

此结构必须在类型注册前创建,其中:

+
    +
  • class_size: 类的大小。例如,PawDouble类型的类大小为sizeof(PawDoubleClass)
  • +
  • base_init, base_finalize: 这些函数初始化/销毁类的动态成员。在许多情况下,它们不是必需的,被赋值为NULL。详见GObject.BaseInitFunc GObject.ClassInitFunc
  • +
  • class_init: 类的初始化函数。用户需要将定义的类初始化函数赋值给class_init成员。按照命名约定,类初始化函数名称为<moudle>_<name>_class_init,例如paw_double_class_init
  • +
  • class_finalize: 类的销毁函数。因为GObject的子类类型是静态的,所以它没有销毁函数。将class_finalize成员赋值为NULL即可。
  • +
  • class_data: 用户提供数据,传递给类的初始化/销毁函数。通常赋值为 NULL。
  • +
  • instance_size: 实例的大小。例如,PawDouble类型的实例大小为sizeof(PawDouble)
  • +
  • n_preallocs: 用于指定预分配的实例数量。自GLib 2.10以来,该字段被忽略。
  • +
  • instance_init: 实例的初始化函数。用户需要将定义的实例初始化函数赋值给instance_init成员。按照命名约定,实例初始化函数名称为<moudle>_<name>_init,例如 paw_double_init
  • +
  • value_table: 这通常只对基本类型有用。如果类型是GObject的后代,赋值为NULL。
  • +
+

我们将编写一个函数paw_double_get_type,用于向GObject类型系统注册新类型,并返回所注册类型的id

+
GType paw_double_get_type(void) 
{
static GType type = 0;
GTypeInfo info;

if(type == 0)
{
//赋值
info.class_size = sizeof(PawDoubleClass);
info.base_init = NULL;
info.base_finalize = NULL;
info.class_init = (GClassInitFunc) paw_double_class_init;
info.class_finalize = NULL;
info.class_data = NULL;
info.instance_size = sizeof(PawDouble);
info.n_preallocs = 0;
info.instance_init = (GInstanceInitFunc) paw_double_init;
info.value_table = NULL;
//注册类型
type = g_type_register_static(G_TYPE_OBJECT, "PawDouble", &info, 0);
}
return type;
}
+ + + +

汇总

上述的类型创建和注册过程汇总如下:

+
#include <glib-object.h>

#define PAW_TYPE_DOUBLE (paw_double_get_type())

//定义实例结构体
typedef struct _PawDouble PawDouble;
struct _PawDouble
{
GObject parent;
double value;
};

//定义类结构体
typedef struct _PawDoubleClass PawDoubleClass;
struct _PawDoubleClass
{
GObjectClass parent_class;
};

//类构造函数
static void paw_double_class_init(PawDoubleClass *class)
{
}

//实例构造函数
static void paw_double_init(PawDouble *self)
{
}

//首次调用时注册类型
//返回类型
GType paw_double_get_type(void)
{
static GType type = 0;
GTypeInfo info;

if(type == 0)
{
info.class_size = sizeof(PawDoubleClass);
info.base_init = NULL;
info.base_finalize = NULL;
info.class_init = (GClassInitFunc) paw_double_class_init;
info.class_finalize = NULL;
info.class_data = NULL;
info.instance_size = sizeof(PawDouble);
info.n_preallocs = 0;
info.instance_init = (GInstanceInitFunc) paw_double_init;
info.value_table = NULL;
type = g_type_register_static(G_TYPE_OBJECT, "PawDouble", &info, 0);
}
return type;
}

int main(int argc, char **argv)
{
GType dtype;
PawDouble *d;

dtype = paw_double_get_type(); /* or dtype = PAW_TYPE_DOUBLE */
if(dtype)
g_print("Registration was a success. The type is %lx.\n", dtype);
else
g_print("Registration failed.\n");

d = g_object_new(PAW_TYPE_DOUBLE, NULL);
if(d)
g_print("Instantiation was a success. The instance address is %p.\n", d);
else
g_print("Instantiation failed.\n");
g_object_unref(d); /* Releases the object d. */

return 0;
}
+ +
    +
  • 20-28:类初始化函数和实例初始化函数,参数class是指类结构体,参数self是指实例结构体。这两个函数在示例中内容为空,但他们是注册过程必须的。

    +
  • +
  • 30-52:paw_double_get_type函数,返回PawDouble类型的id。这种函数的命名总是遵循<moudle>_<name>_get_type。同时,宏<MOUDLE>_TYPE_<NAME>(所有字符都是大写)是这个函数的别名。paw_double_get_type函数有一个静态变量type来存储对象的类型。在此函数的第一次调用时,type是零。然后函数内调用 g_type_register_static将新类型注册到类型系统中。在第二次和之后的调用中,该函数只是返回type,因为静态变量type已经被g_type_register_static赋予了非零值,并且它保持该值。

    +
  • +
  • 39-49:设置info结构体并调用g_type_register_static注册。

    +
  • +
  • 54-73:主函数。获取PawDouble类型id并显示它。函数g_object_new被用来创建类型实例。GObject API文档中表示g_object_new返回一个指向GObject实例的指针,但实际上它返回的是一个gpointergpointer基本等同于void*,可以被赋值给指向任何类型的指针。因此,语句d = g_object_new(PAW_TYPE_DOUBLE, NULL);是正确的。如果函数g_object_new返回的是GObject*,那么就需要对返回的指针进行类型转换。在创建完成后,我们打印了实例的地址。最后,使用函数g_object_unref释放并销毁实例。

    +
  • +
+

便利宏

注册的过程总是可以使用相同的算法完成,因此可以被定义为宏。

+

GObject提供了一些宏:

+

G_DEFINE_TYPE

#define G_DEFINE_TYPE(TN, t_n, T_P)
+

其中:

+
    +
  • TN:新类型的名称,驼峰形式,如PawDouble
  • +
  • t_n:新类型的名称,全小写,单词之间使用下划线分隔。如paw_double
  • +
  • T_P:父类的类型,GType
  • +
+

G_DEFINE_TYPE内部完成了以下操作:

+
    +
  • 声明一个类初始化函数。其名称为<moudle>_<name>_class_init。例如,如果类型名称是PawDouble,它就是paw_double_class_init。这只是一个声明,不是定义。用户需要定义它。
  • +
  • 声明一个实例初始化函数。其名称为<moudle>_<name>_init。例如,如果类型名称是PawDouble,它就是paw_double_init。这只是一个声明,不是定义。用户需要定义它。
  • +
  • 声明一个指向父类的静态变量。其名称为<moudle>_<name>_parent_class。例如,如果对象名称是PawDouble,它就是paw_double_parent_class
  • +
  • 定义一个<moudle>_<name>_get_type()函数。例如,如果对象名称是PawDouble,它就是paw_double_get_type。在这个函数中完成类型注册,就像前面描述的那样。
  • +
+

要使用此宏完成类型的创建和注册,我们只需要再手动提供

+
    +
  • 类和实例结构体的定义(必须在使用G_DEFINE_TYPE之前完成)
  • +
  • 类和实例初始化函数的定义(通常在使用G_DEFINE_TYPE之后完成)
  • +
+

因此,我们可以将手动创建和注册类型的代码简化如下:

+
#include <glib-object.h>

#define PAW_TYPE_DOUBLE (paw_double_get_type())

typedef struct _PawDouble PawDouble;
struct _PawDouble
{
GObject parent;
double value;
};

typedef struct _PawDoubleClass PawDoubleClass;
struct _PawDoubleClass
{
GObjectClass parent_class;
};

G_DEFINE_TYPE(PawDouble, paw_double, G_TYPE_OBJECT)

static void paw_double_class_init(PawDoubleClass *class)
{
}

static void paw_double_init(PawDouble *self)
{
}

int main(int argc, char **argv)
{
GType dtype;
PawDouble *d;

dtype = paw_double_get_type(); /* or dtype = PAW_TYPE_DOUBLE */
if(dtype)
g_print("Registration was a success. The type is %lx.\n", dtype);
else
g_print("Registration failed.\n");

d = g_object_new(PAW_TYPE_DOUBLE, NULL);
if(d)
g_print("Instantiation was a success. The instance address is %p.\n", d);
else
g_print("Instantiation failed.\n");
g_object_unref(d);

return 0;
}
+

G_DECLARE_FINAL_TYPE

另一个有用的宏是G_DECLARE_FINAL_TYPE。这个宏可以用于声明最派生类型(final type)。如果想声明一个可派生类型,可使用G_DECLARE_DERIVABLE_TYPE(会在后面介绍)。然而,在大多数情况下,我们都是需要创建最派生类型。

+

其声明为:

+
#define G_DECLARE_FINAL_TYPE(ModuleObjName, module_obj_name, MODULE, OBJ_NAME, ParentName)
+

其中:

+
    +
  • ModuleObjName:新类型的名称,驼峰形式(如PawDouble
  • +
  • module_obj_name:新类型名称,全小写,单词之间使用下划线分隔(如paw_double
  • +
  • MODULE:模块的名称,全大写(如PAW
  • +
  • OBJ_NAME:新类型的名称,去除修饰,全大写如(DOUBLE
  • +
  • ParentName:父类型的名称,驼峰形式(如GObject
  • +
+

G_DECLARE_FINAL_TYPE内部完成以下操作:

+
    +
  • 声明返回类型为GType<moudle>_<name>_get_type()函数。这只是声明,用户需要定义它。但其实可以使用G_DEFINE_TYPE,其扩展包括该函数的定义。所以,实际上用户不需要手动编写定义。
  • +
  • 对象的C类型被定义为结构体的typedef。例如,如果类型名称是PawDouble,那么内部有typedef struct _PawDouble PawDouble。但是_PawDouble结构体本身并没有定义,应该在使用G_DEFINE_TYPE()之前定义。
  • +
  • 定义<MOUDLE>_<NAME>宏。例如,如果类型是PawDouble,则宏是PAW_DOUBLE。它会被扩展为一个将参数转换为指向该类型实例的指针的函数。例如,PAW_DOUBLE(obj)obj的类型转换为PawDouble*
  • +
  • 定义<MOUDLE>_IS_<NAME>宏。例如,如果对象是PawDouble,则宏是PAW_IS_DOUBLE。它会被扩展为一个检查参数是否为指向PawDouble类型实例的函数。如果参数指向PawDouble及其后代,则宏返回真。
  • +
  • 定义类结构体。最派生类型不需要在类结构中有自己的成员。
  • +
+

在使用G_DECLARE_FINAL_TYPE之前,我们还要手动定义<MOUDLE>_TYPE_<NAME>,如

+
#define PAW_TYPE_DOUBLE paw_double_get_type
+

知道了G_DECLARE_FINAL_TYPE的使用方法,我们就可以将声明和实现分离了

+

声明和实现分离

现在将上面的示例拆分到PawDouble.cPawDouble.hmain.c

+
//file: PawDouble.h
#ifndef PAW_DOUBLE_H
#define PAW_DOUBLE_H

#include <glib-object.h>
G_BEGIN_DECLS

#define PAW_TYPE_DOUBLE (paw_double_get_type())
G_DECLARE_FINAL_TYPE(PawDouble, paw_double, PAW, DOUBLE, GObject)

gboolean paw_double_get_value(PawDouble *self, double *value);

void paw_double_set_value(PawDouble *self, double value);

PawDouble * paw_double_new(double value);

G_END_DECLS

#endif /* PAW_DOUBLE_H */
+ +
    +
  • 头文件是公开的的,即对任何文件都是开放的。
  • +
  • 2-3:预处理器指令,用于防止头文件的内容被多次包含。
  • +
  • 6,17:GObject库中的宏,用于确保当GObject库的头文件被C++编译器包含时,内部声明的C函数不会被当作C++函数进行名称修饰,从而可以在C++代码中正常调用C函数。
  • +
  • 8-9:PAW_TYPE_DOUBLE是公开的。G_DECLARE_FINAL_TYPE展开为公开定义。
  • +
  • 11-13:公共函数声明。它们是对象值的获取器和设置器,被称为“实例方法”,这是面向对象语言中使用的。
  • +
  • 15:对象实例化函数。
  • +
+
//file: PawDouble.c
#include "PawDouble.h"

struct _PawDouble
{
GObject parent;
double value;
};

G_DEFINE_TYPE(PawDouble, paw_double, G_TYPE_OBJECT)

static void paw_double_class_init(PawDoubleClass *class)
{
}

static void paw_double_init(PawDouble *self)
{
}

gboolean paw_double_get_value(PawDouble *self, double *value)
{
g_return_val_if_fail(PAW_IS_DOUBLE(self), FALSE);

*value = self->value;
return TRUE;
}

void paw_double_set_value(PawDouble *self, double value)
{
g_return_if_fail(PAW_IS_DOUBLE(self));

self->value = value;
}

PawDouble * paw_double_new(double value)
{
PawDouble *d;

d = g_object_new(PAW_TYPE_DOUBLE, NULL);
d->value = value;
return d;
}
+ +
    +
  • 4-8:实例结构的声明。由于G_DECLARE_FINAL_TYPE宏定义了typedef struct _PawDouble PawDouble,因此结构的标签名必须是_PawDouble
  • +
  • 10:G_DEFINE_TYPE 宏。
  • +
  • 12-18:类和实例初始化函数。目前,它们不执行任何操作。
  • +
  • 20-26:获取器。参数值是指向双精度类型变量的指针。将对象值(self->value)赋给该变量。如果成功,则返回TRUE。函数g_return_val_if_fail用于检查参数类型。如果参数self不是PawDouble类型,它会输出错误到日志并立即返回FALSE。在静态类函数中不需要使用g_return_val_if_fail,因为静态函数的作用域局限于定义它们的同一源文件内,且通常由同一文件内的其他函数调用,因此调用者对于需要传递给静态函数的参数类型已经有了充分的了解。在这种情况下,使用g_return_val_if_fail进行参数有效性检查可能是多余的(待验证)。
  • +
  • 28-33:设置器。这个函数不返回任何值。因此,我们使用g_return_if_fail而不是g_return_val_if_fail
  • +
  • 35-42:实例化函数。它的参数值用来设置实例表示的值。
  • +
+
//file: main.c
#include <glib-object.h>
#include "PawDouble.h"

int main(int argc, char **argv)
{
PawDouble *d;
double value;

d = paw_double_new(10.0);
if(paw_double_get_value(d, &value))
g_print("paw_double_get_value succesfully assigned %lf to value.\n", value);
else
g_print("paw_double_get_value failed.\n");

paw_double_set_value(d, -20.0);
g_print("Now, set d(PawDouble object) with %lf.\n", -20.0);
if(paw_double_get_value(d, &value))
g_print("paw_double_get_value succesfully assigned %lf to value.\n", value);
else
g_print("paw_double_get_value failed.\n");
g_object_unref(d);

return 0;
}
+ +
    +
  • 3:包含PawDouble.h。这是获取PawDouble类型的必要步骤
  • +
  • 9:实例化PawDouble类型实例并使用指针d指向对象
  • +
  • 11-14:测试获取器
  • +
  • 16-21:测试设置器
  • +
  • 22:释放d
  • +
+

在实际的使用中,任何一个类型都会有这样一个头文件和对应的源文件。

+

参考文章

1.GObject Tutorial for beginners

+]]>
+ + C + 三方库 + GObject + +
+ + I/O多路复用学习(一)select + /IO-Multiplexing-select/ + 前言

本文主要是简单讨论select的特点并梳理一下select的调用链,不涉及具体的使用方法。
本文中涉及的源码均出自Linux内核5.4.0版本

+

简介

select 是一种 IO 多路复用的技术,它允许单个进程或线程高效地管理多个输入/输出流,从而提高程序的性能和响应速度。

+

调用过程

do_select

select调用链
select调用链

+

select的核心功能都在do_select中,里面的关键操作有:
1、poll_initwait:初始化轮询等待队列结构体 (poll_wqueues) 的所有字段,包括函数指针的初始化,后面用于驱动中回调__pollwait
2、for循环:遍历每个fd并调用vfs_pollvfs_poll针对传入的fd,调用其各自的poll函数(由设备驱动程序实现,比如sock_poll)。之后若满足一定条件则跳出循环。
3、poll_freewait:清理等待队列。

+

后面出一篇文章详细讨论do_select()
I/O多路复用学习(二)do_select分析

+

__pollwait

__pollwait调用链
__pollwait调用链

+

__pollwait的作用是在等待队列上注册一个新的节点(),并初始化poll_table_entry的成员。
1、poll_get_entry:从轮询等待队列结构体 (poll_wqueues) 中获取一个空闲的poll_table_entry结构体实例
2、init_waitqueue_func_entry:初始化poll_table_entry结构体实例,包括函数指针的初始化,后面用于驱动中回调pollwake。
3、add_wait_queue:向等待队列添加一个节点

+

pollwake

当监视的文件描述符上发生了感兴趣的事件时(如可读,可写等),设备驱动将触发回调函数pollwake。pollwake会将进程或线程从睡眠状态唤醒。

+

select缺点

1、select默认支持的描述符有限,为1024(可以通过命令ulimit -n 2048临时修改,也可以修改Linux内核头文件posix_types.h修改__FD_SETSIZE的值,但是要重新编译内核);
2、每次调用需要把fd集合在内核态和用户态间拷贝传递两次,在fdset很大时效率低;
3、select内部监视fd是通过轮询的方式,时间复杂度高,效率低;
4、每次调用后需要重新设置fdset,麻烦。

+

参考文章

1.select 机制 - 访问方式(三)

+]]>
+ + Linux + Linux内核源码 + +
I/O多路复用学习(二)do_select分析 - /2024/03/08/IO-Multiplexing-do-select/ + /IO-Multiplexing-do-select/ 前言

前一篇笔记:I/O多路复用学习(一)select ,梳理了一下select的调用过程,这一篇笔记对其中的do_select函数的细节做一下简单的讨论。
本文中涉及的源码均出自Linux内核5.4.0版本

相关结构体

了解相关的结构体可以帮助我们更好地理解select内部的实现
相关结构体关系示意图:

结构体关系图
结构体关系图

struct poll_wqueues

poll_wqueues结构体(轮询等待队列)用于维护若干特定于文件描述符的设备驱动等待队列。但是它并不直接存储设备驱动等待队列本身;它通过inline_entries[]管理一个或多个poll_table_entry项,每个项与一个特定的文件描述符和其等待事件相关联。

@@ -65,7 +352,7 @@

do_select

do_select流程图
do_select流程图

代码省略了一些,比如超时标志位timed_out的置位操作等。

@@ -101,7 +388,7 @@

__pollwait

pollwait
pollwait

__pollwait用于处理轮询时的等待队列。这个函数通过创建并初始化poll_table_entry实例,将等待进程(或线程)添加到指定设备或文件的等待队列中。

@@ -122,7 +409,7 @@

POLL_TABLE_FULL为true情况的示意图:

POLL_TABLE_FULL为真
POLL_TABLE_FULL为真

init_waitqueue_func_entry

init_waitqueue_func_entry用于初始化wait_queue_entry实例的各个成员。

@@ -136,7 +423,7 @@

pollwake

pollwake
pollwake

回调过程

前面提到pollwake会在设备驱动中被回调,下面简单梳理一下在设备驱动中的调用链,还是以socket中的tcp为例,当有数据包来临时函数的调用链为:
tcp_data_queue->sock_def_readable->wake_up_interruptible_sync_poll->__wake_up_sync_key->__wake_up_common_lock->__wake_up_common

@@ -144,35 +431,6 @@

pollwake调用链

pollwake->__pollwake->default_wake_function->try_to_wake_up。最终调用try_to_wake_up唤醒当前进程。

总结

本文讨论了do_select函数调用链上的一些实现细节,梳理了相关结构体之间的关系。有些地方可能解释的不是很详细,后面持续更新。

参考文章

1.select 机制 - 访问方式(三)

-]]>
- - Linux - Linux内核源码 - -
- - I/O多路复用学习(一)select - /2024/03/05/IO-Multiplexing-select/ - 前言

本文主要是简单讨论select的特点并梳理一下select的调用链,不涉及具体的使用方法。
本文中涉及的源码均出自Linux内核5.4.0版本

-

简介

select 是一种 IO 多路复用的技术,它允许单个进程或线程高效地管理多个输入/输出流,从而提高程序的性能和响应速度。

-

调用过程

do_select

select调用链
select调用链

-

select的核心功能都在do_select中,里面的关键操作有:
1、poll_initwait:初始化轮询等待队列结构体 (poll_wqueues) 的所有字段,包括函数指针的初始化,后面用于驱动中回调__pollwait
2、for循环:遍历每个fd并调用vfs_pollvfs_poll针对传入的fd,调用其各自的poll函数(由设备驱动程序实现,比如sock_poll)。之后若满足一定条件则跳出循环。
3、poll_freewait:清理等待队列。

-

后面出一篇文章详细讨论do_select()
I/O多路复用学习(二)do_select分析

-

__pollwait

__pollwait调用链
__pollwait调用链

-

__pollwait的作用是在等待队列上注册一个新的节点(),并初始化poll_table_entry的成员。
1、poll_get_entry:从轮询等待队列结构体 (poll_wqueues) 中获取一个空闲的poll_table_entry结构体实例
2、init_waitqueue_func_entry:初始化poll_table_entry结构体实例,包括函数指针的初始化,后面用于驱动中回调pollwake。
3、add_wait_queue:向等待队列添加一个节点

-

pollwake

当监视的文件描述符上发生了感兴趣的事件时(如可读,可写等),设备驱动将触发回调函数pollwake。pollwake会将进程或线程从睡眠状态唤醒。

-

select缺点

1、select默认支持的描述符有限,为1024(可以通过命令ulimit -n 2048临时修改,也可以修改Linux内核头文件posix_types.h修改__FD_SETSIZE的值,但是要重新编译内核);
2、每次调用需要把fd集合在内核态和用户态间拷贝传递两次,在fdset很大时效率低;
3、select内部监视fd是通过轮询的方式,时间复杂度高,效率低;
4、每次调用后需要重新设置fdset,麻烦。

-

参考文章

1.select 机制 - 访问方式(三)

]]>
Linux @@ -181,96 +439,96 @@
使用FModel提取《黑神话:悟空》的资产 - /2024/08/21/UE-fmodel-blackmyth-wukong/ + /UE-fmodel-blackmyth-wukong/ 前言

黑神话悟空昨天上线了,解个包looklook。

设置

在FModel的setting中修改以下选项:

在Directory中添加AES:

  • AES Key : 0xA896068444F496956900542A215367688B49B19C2537FCD2743D8585BA1EB128
-

设置好之后重启软件,然后参照《使用FModel提取UE4/5游戏资产》 中的步骤查看或导出所需资产。

+

设置好之后重启软件,然后参照《使用FModel提取UE4/5游戏资产》中的步骤查看或导出所需资产。

效果展示

我主要是简单看一下角色的建模,因此下面的图片展示基本都是角色建模。

先看下咱猴哥的英俊面庞:

然后看下四大天王

持国天王:

多闻天王

广目天王

增长天王

最后再看个小狗:

闲聊

通过解包可以发现,黑神话里面的资源命名都是使用汉语拼音而非英文单词,不知道这是不是国内行业普遍使用的规矩,希望有从事相关行业的大佬能解开我这个疑惑。

至于为啥不使用英文,我猜一是有些中文词汇很难用英语翻译,强行翻译可能会词不达意;二是有些翻译会导致命名长度太长。

但是哥们儿,下面这个首字母简写我个人认为确实有一点点抽象了,能全部猜出来的也算是神人了。

由于一周目才刚开始打,我现在只能猜出来一部分:GYCY(观音禅院),HFM(黑风庙?),HGS(花果山),HYS(火焰山),LSH(流沙河?),LYS(雷音寺),MGD(埋骨地?),PSD(盘丝洞)。

另外,通过解包我们还可以看见项目中有刘备,孙权,太史慈的人物建模,难道是《黑神话2:三国群英传》?😂

项目里甚至还有一个电饭煲的模型hhh。讲道理,我孙悟空用电饭煲封印个比克大魔王,也是很合理的好吧。

不过上述资源的存在让我想到了一张梗图:

可能遇到的问题

没有相应的UE引擎版本选项

问题描述:在设置UE引擎版本时,下拉菜单中可能会没有GAME_BlackMythWukong (UE 5.0)这个选项。
解决方法:在settings的update mode选项中选择QA Testing,然后软件会提示你更新,然后一路确定。待更新完成后重新打开软件,即可在UE Version中看到GAME_BlackMythWukong (UE 5.0)这个选项

映射文件生成失败

由于映射文件生成比较复杂,在此提供现成的映射文件(伴随游戏更新映射文件可能失效,失效请联系我更换):

@@ -282,7 +540,7 @@
使用FModel提取UE4/5游戏资产 - /2024/07/16/UE-fmodel-usage/ + /UE-fmodel-usage/ 前言

这篇文章仅记录我作为初学者使用FModel工具提取某款游戏模型的过程。

FModel简介

FModel是一个开源软件,可以用于查看和提取UE4-5项目中的资产。它支持从.pak.uasset文件中提取内容,如3D模型,纹理,音频等。

FModel安装

首先进入FModel官网 ,下载最新的发布版本。

@@ -290,44 +548,44 @@

FModel还需要依赖.NET,如果你的系统中没有,则会提示你安装:

安装好.NET之后,重新打开FModel.exe,此时软件可以正常打开。

FModel使用

初次使用

①软件初次打开会弹出这个界面

这里可以随便设置,之后进入软件还可以更改。
②点击ok进入软件
③设置填写AES key
这里填写你要解包的游戏对应的AES key

④设置选择UE版本和填写游戏路径

解包
全选(我在使用时是这样,可能会因游戏的不同而不一样)然后load

然后就会自动跳到Folder下,此时我们就可以随便选择一个资产双击进行查看

注意:
如果你要解包的游戏是使用UE5开发的,那么在解包的时候可能会报错:

@@ -337,14 +595,14 @@

比如3D Viewer的模型预览是这样

资产导出

SettingsModels中设置资产的导出格式(比如对于mesh可以设置导出为.glbtexture可以设置导出为.png

然后在你要导出的资产上右键,选择要导出的类型即可:

附录

dumper

对于UE5+的游戏来说,具有unversioned属性的包是意料之中的。然而现在有一些解决方案可以让FModel支持对它们的解析。

@@ -354,7 +612,7 @@

当成功生成了*.usmap文件后,你可以在FModel软件的设置界面将其添加到Mapping File Path中:

下面我将演示通过使用Dumper-7生成*.usmap的过程

@@ -362,7 +620,7 @@

向游戏中注入dll

为了向游戏中注入dll,我们要使用一个工具:DLL Injector
官网链接:DLL Injector官网
使用方法:
①打开DLL Injector

②选择要加载的DLL文件(有两种方法):

@@ -371,7 +629,7 @@
  • 拖拽你的dll文件到DLL injector软件的界面中
  • @@ -381,14 +639,14 @@
  • 如果使用筛选功能最后只筛选出一个进程,则此进程会被自动选中
  • ④点击右上方的注入按钮将DLL注入目标进程,结束后会在指定文件夹生成usmap文件

    ]]>
    @@ -397,9 +655,285 @@ UE
    + + GVCP数据包 + /aravis-GVCP-packets/ + 简述

    设备通过监听GVCP端口(3956)等待GVCP数据包。当客户端(如:PC设备)向设备(如:相机)发送一个GVCP命令数据包时,设备会回复一个确认数据包。每个命令/确认对(command/acknowledge pair)都使用一个16 bit的值来标识(就相当于ID),这样可以检查确认数据包是否与之前发送的命令对应。0是这个标识符的错误值。如果在给定的超时时间后没有收到确认,将再次发送命令数据包,直到达到最大重试次数。

    +

    ArvGvcp API提供了一系列处理GVCP包的函数。

    +

    GVCP数据包的内容由一个64 bit的头部组成,头部后面可能跟着一个数据字节数组(也可能没有,具体取决于GVCP数据包的类型)。多字节值采用大端编码。

    + + + + + + + + + + + + + + + + + + + + + + + + +
    表格1.GVCP packet
    015163132474863
    ArvGvcpPacketTypeArvGvcpCommandData sizePacket id
    Optional data
    ...
    + +
    //version: 0.8.31
    //file: arvgvcpprivate.h
    typedef struct {
    guint8 packet_type;
    guint8 packet_flags;
    guint16 command; //a ArvGvcpCommand identifier
    guint16 size; //data size
    guint16 id; //packet identifier
    } ArvGvcpHeader;

    typedef enum {
    ARV_GVCP_PACKET_TYPE_ACK = 0x00, //acknowledge packet
    ARV_GVCP_PACKET_TYPE_CMD = 0x42, //command packet
    ARV_GVCP_PACKET_TYPE_ERROR = 0x80, //error packet
    ARV_GVCP_PACKET_TYPE_UNKNOWN_ERROR = 0x8f //unknown error
    } ArvGvcpPacketType;

    typedef enum {
    ARV_GVCP_COMMAND_DISCOVERY_CMD = 0x0002, //discovery command
    ARV_GVCP_COMMAND_DISCOVERY_ACK = 0x0003, //discovery acknowledge
    ARV_GVCP_COMMAND_BYE_CMD = 0x0004, //goodbye command, for connection termination
    ARV_GVCP_COMMAND_BYE_ACK = 0x0005, //goodbye acknowledge
    ARV_GVCP_COMMAND_PACKET_RESEND_CMD = 0x0040, //packet resend request
    ARV_GVCP_COMMAND_PACKET_RESEND_ACK = 0x0041, //packet resend acknowledge (not used ?)
    ARV_GVCP_COMMAND_READ_REGISTER_CMD = 0x0080, //read register command
    ARV_GVCP_COMMAND_READ_REGISTER_ACK = 0x0081, //read register acknowledge
    ARV_GVCP_COMMAND_WRITE_REGISTER_CMD = 0x0082, //write register command
    ARV_GVCP_COMMAND_WRITE_REGISTER_ACK = 0x0083, //write register acknowledge
    ARV_GVCP_COMMAND_READ_MEMORY_CMD = 0x0084, //read memory command
    ARV_GVCP_COMMAND_READ_MEMORY_ACK = 0x0085, //read memory acknowledge
    ARV_GVCP_COMMAND_WRITE_MEMORY_CMD = 0x0086, //write memory command
    ARV_GVCP_COMMAND_WRITE_MEMORY_ACK = 0x0087, //write memory acknowledge
    ARV_GVCP_COMMAND_PENDING_ACK = 0x0089 //pending command acknowledge
    } ArvGvcpCommand;
    + + +

    发现设备

    设备发现机制是通过客户端向GVCP端口广播一个发现GVCP数据包来实现的。每个可用的设备都会对这个发现数据包响应一个确认数据包,其中包含了设备的描述(设备名称、型号名称、制造商名称、MAC地址等)。

    +

    设备发现命令的数据包中,data size为0(这里估计是作者写错了,data size是248也就是0xf8),packet id为0xffff。

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    表格2.设备发现确认数据包
    Address0151631
    0x00000x0003
    0x00f80xffff
    0x0000Version majorVersion minor
    0x0004EndiannessCharacter set
    0x0008MAC address high
    0x000cMAC address low
    0x0010Supported IP configuration
    0x0014Current IP configuration
    0x0018
    0x001c
    0x0020
    0x0024Current IP address
    0x0028
    0x002c
    0x0030
    0x0034Current subnet mask
    0x0038
    0x003c
    0x0040
    0x0044Current gateway
    0x0048Manufacturer name
    0x004c
    0x0050
    0x0054
    0x0058
    0x005c
    0x0060
    0x0064
    0x0068Model name
    0x006c
    0x0070
    0x0074
    0x0078
    0x007c
    0x0080
    0x0084
    0x0088Device version
    0x008c
    0x0090
    0x0094
    0x0098
    0x009c
    0x00a0
    0x00a4
    0x00a8Manufacturer informations
    0x00ac
    0x00b0
    0x00b4
    0x00b8
    0x00bc
    0x00c0
    0x00c4
    0x00c8
    0x00cc
    0x00d0
    0x00d4
    0x00d8User defined name
    0x00dc
    0x00e0
    0x00e4
    0x00e8
    0x00ec
    0x00f0
    0x00f4
    + +
    //version: 0.8.31
    //file: arvgvcpprivate.h
    typedef struct {
    ArvGvcpHeader header; //packet header
    unsigned char data[]; //variable size byte array
    } ArvGvcpPacket;
    + + +

    读写寄存器

    这些数据包用于读写32位寄存器,通过32位地址访问。对于读命令,向客户端发送一个地址列表,客户端返回一个32位值的列表。对于写命令,向客户端发送一个地址/值对(address/value pair)的列表,客户端返回一个32位值的列表。

    +

    地址和数据在数据包中以大端值的形式编码。

    +

    读写内存

    写内存数据包的数据区包含一个32位地址,后跟要写入的数据。客户端返回一个带有目标地址的确认包。
    对于读内存命令,发送一个地址/大小对(address/size pair)到设备,设备返回给定内存区域的内容

    +

    参考文章

    1.《GVCP packets》

    +]]>
    + + 工业相机 + Aravis + +
    开源相机管理库Aravis例程学习(五)——camera-api - /2024/04/28/aravis-camera-api/ + /aravis-camera-api/ 简介

    本文针对官方例程 中的:03-camera-api做简单的讲解。并介绍其中调用的arv_camera_get_regionarv_camera_get_pixel_format_as_stringarv_camera_get_pixel_formatARV_PIXEL_FORMAT_BIT_PER_PIXEL

    aravis版本:0.8.31
    操作系统:ubuntu-20.04
    gcc版本:9.4.0

    例程代码

    这段代码使用Aravis的API,获取相机的一些基本设置,如图像的宽度、高度和像素格式,主要操作步骤如下:

    @@ -408,14 +942,14 @@
  • 获取图像宽度,高度,像素格式等信息
  • 释放资源
  • -
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>

    /*
    * Connect to the first available camera, then display the current settings for image width and height, as well as the
    * pixel format, using the ArvCamera API.
    */

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    GError *error = NULL;

    //连接相机
    camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (camera)) {
    int width;
    int height;
    const char *pixel_format;
    int format_number;
    int bit_per_pixel;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
    //获取图像宽度和高度
    if (!error) arv_camera_get_region (camera, NULL, NULL, &width, &height, &error);
    //获取图像像素格式
    if (!error) pixel_format = arv_camera_get_pixel_format_as_string (camera, &error);
    if (!error) format_number = arv_camera_get_pixel_format (camera, &error);
    //获取图像像素位数
    if (!error) bit_per_pixel = ARV_PIXEL_FORMAT_BIT_PER_PIXEL (format_number);


    if (error == NULL) {
    printf ("Width = %d\n", width);
    printf ("Height = %d\n", height);
    printf ("Pixel format = %s\n", pixel_format);
    printf ("Pixel format number = %d\n", format_number);
    printf ("Bit per pixel = %d\n", bit_per_pixel);
    }

    g_clear_object (&camera);
    }

    if (error != NULL) {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    +
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>

    /*
    * Connect to the first available camera, then display the current settings for image width and height, as well as the
    * pixel format, using the ArvCamera API.
    */

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    GError *error = NULL;

    //连接相机
    camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (camera))
    {
    int width;
    int height;
    const char *pixel_format;
    int format_number;
    int bit_per_pixel;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
    //获取图像宽度和高度
    if (!error) arv_camera_get_region (camera, NULL, NULL, &width, &height, &error);
    //获取图像像素格式
    if (!error) pixel_format = arv_camera_get_pixel_format_as_string (camera, &error);
    if (!error) format_number = arv_camera_get_pixel_format (camera, &error);
    //获取图像像素位数
    if (!error) bit_per_pixel = ARV_PIXEL_FORMAT_BIT_PER_PIXEL (format_number);


    if (error == NULL)
    {
    printf ("Width = %d\n", width);
    printf ("Height = %d\n", height);
    printf ("Pixel format = %s\n", pixel_format);
    printf ("Pixel format number = %d\n", format_number);
    printf ("Bit per pixel = %d\n", bit_per_pixel);
    }

    g_clear_object (&camera);
    }

    if (error != NULL)
    {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }

    运行结果:

    函数说明

    arv_camera_get_region

    简介:用于获取相机当前的感兴趣区域(ROI),此函数会将当前相机的ROI的位置坐标(x,y)和尺寸(width,height)通过指针返回,并记录错误信息。

    @@ -440,7 +974,7 @@
    开源相机管理库Aravis例程学习(六)——camera-features - /2024/05/01/aravis-camera-features/ + /aravis-camera-features/ 简介

    本文针对官方例程 中的:04-camera-features做简单的讲解。并介绍其中调用的arv_camera_get_integerarv_camera_get_string

    aravis版本:0.8.31
    操作系统:ubuntu-20.04
    gcc版本:9.4.0

    例程代码

    这段代码使用Aravis的API,获取相机的一些基本设置,如图像的宽度、高度和像素格式,主要操作步骤如下:

    @@ -449,7 +983,7 @@
  • 获取图像宽度,高度,像素格式等信息
  • 释放资源
  • -
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>

    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>

    /*
    * Connect to the first available camera, then display the current settings for image width and height, as well as the
    * pixel format, using the more generic ArvCamera feature API.
    */

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    GError *error = NULL;

    //连接相机
    camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (camera)) {
    int width;
    int height;
    const char *pixel_format;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));

    /* Retrieve generally mandatory features for transmitters */

    if (!error) width = arv_camera_get_integer (camera, "Width", &error);
    if (!error) height = arv_camera_get_integer (camera, "Height", &error);
    if (!error) pixel_format = arv_camera_get_string (camera, "PixelFormat", &error);

    if (error == NULL) {
    printf ("Width = %d\n", width);
    printf ("Height = %d\n", height);
    printf ("Pixel format = %s\n", pixel_format);
    }

    g_clear_object (&camera);
    }

    if (error != NULL) {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    +
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>

    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>

    /*
    * Connect to the first available camera, then display the current settings for image width and height, as well as the
    * pixel format, using the more generic ArvCamera feature API.
    */

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    GError *error = NULL;

    //连接相机
    camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (camera))
    {
    int width;
    int height;
    const char *pixel_format;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));

    /* Retrieve generally mandatory features for transmitters */

    if (!error) width = arv_camera_get_integer (camera, "Width", &error);
    if (!error) height = arv_camera_get_integer (camera, "Height", &error);
    if (!error) pixel_format = arv_camera_get_string (camera, "PixelFormat", &error);

    if (error == NULL)
    {
    printf ("Width = %d\n", width);
    printf ("Height = %d\n", height);
    printf ("Pixel format = %s\n", pixel_format);
    }

    g_clear_object (&camera);
    }

    if (error != NULL)
    {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }

    这个例程与03-camera-api 实现的功能相似,但是不同的是本文的代码使用的是更为通用的API(arv_camera_get_integerarv_camera_get_string)来获取的相机的参数。

    我们查看03-camera-api中的arv_camera_get_regionarv_camera_get_pixel_format_as_string的函数定义可以发现,他们的底层其实就是通过调用arv_camera_get_integerarv_camera_get_string来实现的相关功能:

    @@ -459,7 +993,7 @@

    运行结果:

    函数说明

    arv_camera_get_integer

    简介:获取已连接相机的一个整数型特性的值

    @@ -478,7 +1012,7 @@
    开源相机管理库Aravis例程学习(七)——chunk-parser - /2024/05/10/aravis-chunk-parser/ + /aravis-chunk-parser/ 简介

    本文针对官方例程 中的:05-chunk-parser做简单的讲解。并介绍其中调用的arv_camera_create_chunk_parserarv_camera_set_chunksarv_chunk_parser_get_integer_value函数。

    aravis版本:0.8.31
    操作系统:ubuntu-20.04
    gcc版本:9.4.0

    例程代码

    这段代码使用Aravis的API,操作相机捕获图像并获取流数据中附加的块信息(例程中启用的块数据为图像的长和宽),主要操作步骤如下:

    @@ -489,7 +1023,7 @@
  • 打印相关数据
  • 释放资源
  • -
    /* SPDX-License-Identifier:Unlicense */
    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdio.h>

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    ArvChunkParser *parser;
    GError *error =NULL;
    //连接相机
    camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (camera))
    {
    ArvBuffer *buffer = NULL;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));

    //创建chunk parser对象
    parser = arv_camera_create_chunk_parser (camera);

    //设置启用的块数据
    arv_camera_set_chunks (camera, "Width,Height", &error);

    //获取单帧图像
    if (error == NULL)
    buffer = arv_camera_acquisition (camera, 1000000, &error);

    if (buffer != NULL) {
    printf ("ChunkWidth = %d\n", (int) arv_chunk_parser_get_integer_value (parser,
    buffer, "ChunkWidth", NULL));
    printf ("ChunkHeight = %d\n", (int) arv_chunk_parser_get_integer_value (parser,
    buffer, "ChunkHeight", NULL));
    } else {
    printf ("Failed to acquire a single buffer\n");
    }
    //释放资源
    g_clear_object (&buffer);
    g_clear_object (&parser);
    g_clear_object (&camera);
    }

    if (error != NULL) {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    g_clear_error (&error);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    +
    /* SPDX-License-Identifier:Unlicense */
    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdio.h>

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    ArvChunkParser *parser;
    GError *error =NULL;
    //连接相机
    camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (camera))
    {
    ArvBuffer *buffer = NULL;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));

    //创建chunk parser对象
    parser = arv_camera_create_chunk_parser (camera);

    //设置启用的块数据
    arv_camera_set_chunks (camera, "Width,Height", &error);

    //获取单帧图像
    if (error == NULL)
    buffer = arv_camera_acquisition (camera, 1000000, &error);

    if (buffer != NULL)
    {
    printf ("ChunkWidth = %d\n", (int) arv_chunk_parser_get_integer_value (parser,
    buffer, "ChunkWidth", NULL));
    printf ("ChunkHeight = %d\n", (int) arv_chunk_parser_get_integer_value (parser,
    buffer, "ChunkHeight", NULL));
    }
    else
    {
    printf ("Failed to acquire a single buffer\n");
    }
    //释放资源
    g_clear_object (&buffer);
    g_clear_object (&parser);
    g_clear_object (&camera);
    }

    if (error != NULL)
    {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    g_clear_error (&error);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }

    运行结果:
    开源相机管理库Aravis学习——安装 - /2024/03/30/aravis-install/ + /aravis-install/ 前言

    最近在做采集软件的开发,由于我自己使用过Huaray和Basler两个品牌的相机,所以在设计软件时尝试设计统一的接口去控制不同品牌和型号相机的相同或类似的行为。当然,我的设计思路都是建立在调用各品牌SDK的基础上。
    后来我去外网搜索,发现了一个开源项目Aravis,它通过提供一个通用的API,让我们能够不受相机的品牌或型号限制,自由地进行图像采集和相机控制,支持从简单的图像捕获到复杂的相机设置调整的一系列操作。

    项目地址:https://github.com/AravisProject/aravis

    Aravis简介

    Aravis是一个基于glib/gobject的库,允许开发者对遵循GenICam标准的网络相机进行通信和控制。它目前实现了工业相机使用的GigE和USB3协议。它还提供了一个简单的以太网相机模拟器和视频查看器。

    @@ -541,7 +1075,7 @@

    在github上找到所需的aravis的发行版本,并下载:https://github.com/AravisProject/aravis/releases
    我选择的是0.8.31版本:

    下载压缩包后解压即可

    @@ -553,13 +1087,13 @@

    视频查看器

    找到Aravis双击打开,即可查看已连接的相机设备

    安装过程中遇到的问题

    meson版本过低

    我安装的aravis版本是0.8.31,这个版本aravis的编译依赖0.57.0及以上版本的meson,而我通过apt包管理器下载的meson版本为0.53.2,不满足需求。因此要对meson进行升级操作:

    ①首先安装或升级pip

    @@ -577,13 +1111,13 @@

    我的安装结果:

    CMake版本过低

    在构建项目的时候,提示了以下错误信息:

    说明我系统中的CMake版本过低,需要升级。

    @@ -604,7 +1138,7 @@

    缺少GStreamer组件

    直接使用包管理器安装即可

    @@ -619,7 +1153,7 @@
    开源相机管理库Aravis例程学习(三)——注册回调multiple-acquisition-callback - /2024/04/15/aravis-multiple-acquisition-callback/ + /aravis-multiple-acquisition-callback/ 简介

    本文针对官方例程 中的:02-multiple-acquisition-callback做简单的讲解。

    aravis版本:0.8.31
    操作系统:ubuntu-20.04
    gcc版本:9.4.0

    例程代码

    这段代码使用Aravis的API,控制相机连续采集,并异步地在回调函数中获取10个有效图像,主要操作步骤如下:

    @@ -632,19 +1166,19 @@
  • 释放资源
  • 连续采集multiple-acquisition-main-thread 不同的是,本例中图像获取过程以及停止采集条件的改变都是异步进行的(在回调函数中)。

    -
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include "LogManager.h"

    //用于回调函数中传递和储存流的状态和计数器
    typedef struct {
    ArvStream *stream;
    int counter;
    gboolean done;
    } ArvStreamCallbackData;

    //回调函数
    //根据不同的回调类型处理视频流事件
    static void stream_callback (void *user_data, ArvStreamCallbackType type, ArvBuffer *buffer)
    {
    ArvStreamCallbackData *callback_data = (ArvStreamCallbackData *) user_data;

    /* 回调函数内尽量不做非必要的耗时操作 */
    switch (type) {
    case ARV_STREAM_CALLBACK_TYPE_INIT:
    PAW_INFO("ARV_STREAM_CALLBACK_TYPE_INIT");
    break;
    case ARV_STREAM_CALLBACK_TYPE_START_BUFFER:
    PAW_INFO("ARV_STREAM_CALLBACK_TYPE_START_BUFFER");
    break;
    case ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE:
    PAW_INFO("ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE");
    //从buffer池中取出buffer
    g_assert (buffer == arv_stream_pop_buffer(callback_data->stream));
    g_assert (buffer != NULL);

    //检索10个有效buffer
    if (callback_data->counter < 10) {
    if (arv_buffer_get_status(buffer) == ARV_BUFFER_STATUS_SUCCESS)
    PAW_INFO("Acquired"<<arv_buffer_get_image_width(buffer)<<"x"<<arv_buffer_get_image_height(buffer)<< " buffer");
    arv_stream_push_buffer(callback_data->stream, buffer);
    callback_data->counter++;
    } else {
    callback_data->done = TRUE;
    }

    break;
    case ARV_STREAM_CALLBACK_TYPE_EXIT:
    PAW_INFO("ARV_STREAM_CALLBACK_TYPE_EXIT");
    /* Stream thread ended */
    break;
    }
    }

    /*
    * Connect to the first available camera, then acquire 10 buffers.
    */
    int main (int argc, char **argv)
    {
    CLogManager& p_log_instance = CLogManager::GetInstance();

    ArvCamera *camera;
    GError *error = NULL;

    //连接相机
    camera = arv_camera_new ("192.168.6.63", &error);

    if (ARV_IS_CAMERA (camera)) {
    ArvStreamCallbackData callback_data;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
    //设置相机采集模式为连续采集
    arv_camera_set_acquisition_mode (camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);

    //初始化回调数据
    callback_data.counter = 0;
    callback_data.done = FALSE;
    callback_data.stream = NULL;

    if (error == NULL) {
    //创建流对象,注册回调
    PAW_INFO("create stream");
    callback_data.stream = arv_camera_create_stream (camera, stream_callback, &callback_data, &error);
    PAW_INFO("create stream end");
    }

    if (ARV_IS_STREAM (callback_data.stream)) {
    int i;
    size_t payload;

    /* Retrieve the payload size for buffer creation */
    //从相机对象中获取图像负载大小(每个图像的字节大小)
    payload = arv_camera_get_payload (camera, &error);
    PAW_INFO("payload:" << payload);
    if (error == NULL) {
    /* Insert some buffers in the stream buffer pool */
    //双缓冲
    for (i = 0; i < 2; i++)
    arv_stream_push_buffer (callback_data.stream, arv_buffer_new (payload, NULL));
    }

    if (error == NULL)
    /* Start the acquisition */
    arv_camera_start_acquisition (camera, &error);

    if (error == NULL) {
    while (!callback_data.done) {
    usleep (1000);
    }
    }


    if (error == NULL)
    /* Stop the acquisition */
    arv_camera_stop_acquisition (camera, &error);

    /* Destroy the stream object */
    g_clear_object (&callback_data.stream);
    }

    /* Destroy the camera instance */
    PAW_INFO("destroy stream");
    g_clear_object (&camera);
    PAW_INFO("destroy stream end");
    }

    if (error != NULL) {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    +
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include "LogManager.h"

    //用于回调函数中传递和储存流的状态和计数器
    typedef struct
    {
    ArvStream *stream;
    int counter;
    gboolean done;
    } ArvStreamCallbackData;

    //回调函数
    //根据不同的回调类型处理视频流事件
    static void stream_callback (void *user_data, ArvStreamCallbackType type, ArvBuffer *buffer)
    {
    ArvStreamCallbackData *callback_data = (ArvStreamCallbackData *) user_data;

    /* 回调函数内尽量不做非必要的耗时操作 */
    switch (type)
    {
    case ARV_STREAM_CALLBACK_TYPE_INIT:
    PAW_INFO("ARV_STREAM_CALLBACK_TYPE_INIT");
    break;
    case ARV_STREAM_CALLBACK_TYPE_START_BUFFER:
    PAW_INFO("ARV_STREAM_CALLBACK_TYPE_START_BUFFER");
    break;
    case ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE:
    PAW_INFO("ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE");
    //从buffer池中取出buffer
    g_assert (buffer == arv_stream_pop_buffer(callback_data->stream));
    g_assert (buffer != NULL);

    //检索10个有效buffer
    if (callback_data->counter < 10)
    {
    if (arv_buffer_get_status(buffer) == ARV_BUFFER_STATUS_SUCCESS)
    PAW_INFO("Acquired"<<arv_buffer_get_image_width(buffer)<<"x"<<arv_buffer_get_image_height(buffer)<< " buffer");
    arv_stream_push_buffer(callback_data->stream, buffer);
    callback_data->counter++;
    }
    else
    {
    callback_data->done = TRUE;
    }

    break;
    case ARV_STREAM_CALLBACK_TYPE_EXIT:
    PAW_INFO("ARV_STREAM_CALLBACK_TYPE_EXIT");
    /* Stream thread ended */
    break;
    }
    }

    /*
    * Connect to the first available camera, then acquire 10 buffers.
    */
    int main (int argc, char **argv)
    {
    CLogManager& p_log_instance = CLogManager::GetInstance();

    ArvCamera *camera;
    GError *error = NULL;

    //连接相机
    camera = arv_camera_new ("192.168.6.63", &error);

    if (ARV_IS_CAMERA (camera))
    {
    ArvStreamCallbackData callback_data;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
    //设置相机采集模式为连续采集
    arv_camera_set_acquisition_mode (camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);

    //初始化回调数据
    callback_data.counter = 0;
    callback_data.done = FALSE;
    callback_data.stream = NULL;

    if (error == NULL)
    {
    //创建流对象,注册回调
    PAW_INFO("create stream");
    callback_data.stream = arv_camera_create_stream (camera, stream_callback, &callback_data, &error);
    PAW_INFO("create stream end");
    }

    if (ARV_IS_STREAM (callback_data.stream))
    {
    int i;
    size_t payload;

    /* Retrieve the payload size for buffer creation */
    //从相机对象中获取图像负载大小(每个图像的字节大小)
    payload = arv_camera_get_payload (camera, &error);
    PAW_INFO("payload:" << payload);
    if (error == NULL)
    {
    /* Insert some buffers in the stream buffer pool */
    //双缓冲
    for (i = 0; i < 2; i++)
    arv_stream_push_buffer (callback_data.stream, arv_buffer_new (payload, NULL));
    }

    if (error == NULL)
    /* Start the acquisition */
    arv_camera_start_acquisition (camera, &error);

    if (error == NULL)
    {
    while (!callback_data.done)
    {
    usleep (1000);
    }
    }


    if (error == NULL)
    /* Stop the acquisition */
    arv_camera_stop_acquisition (camera, &error);

    /* Destroy the stream object */
    g_clear_object (&callback_data.stream);
    }

    /* Destroy the camera instance */
    PAW_INFO("destroy stream");
    g_clear_object (&camera);
    PAW_INFO("destroy stream end");
    }

    if (error != NULL)
    {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }

    注:PAW_INFO是我自定义的用于打印日志的宏

    运行结果:

    其中<>之间的是线程号。

    arv_camera_create_stream

    连续采集multiple-acquisition-main-thread 中我们简单介绍了arv_camera_create_stream函数,在那个例子中callbackuser_data都被设置为NULL,表示不注册回调。而在本例中callback注册了一个我们自定义的函数stream_callback。至于stream_callback中为什么为switch结构我们在后面的讨论中会给出回答。

    static void stream_callback (void *user_data, ArvStreamCallbackType type, ArvBuffer *buffer)
    {
    ArvStreamCallbackData *callback_data = (ArvStreamCallbackData *) user_data;

    switch (type) {
    case ARV_STREAM_CALLBACK_TYPE_INIT:
    ...
    break;
    case ARV_STREAM_CALLBACK_TYPE_START_BUFFER:
    ...
    break;
    case ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE:
    ...
    break;
    case ARV_STREAM_CALLBACK_TYPE_EXIT:
    ...
    break;
    }
    }

    ArvStreamCallbackType

    简介:一个枚举类,描述了流回调函数被调用的时间点。

    -
    typedef enum {
    ARV_STREAM_CALLBACK_TYPE_INIT,
    ARV_STREAM_CALLBACK_TYPE_EXIT,
    ARV_STREAM_CALLBACK_TYPE_START_BUFFER,
    ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE
    } ArvStreamCallbackType;
    +
    typedef enum
    {
    ARV_STREAM_CALLBACK_TYPE_INIT,
    ARV_STREAM_CALLBACK_TYPE_EXIT,
    ARV_STREAM_CALLBACK_TYPE_START_BUFFER,
    ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE
    } ArvStreamCallbackType;

    ArvStreamCallback

    简介:ArvStreamCallback是一个函数指针类型,用于在实例化流对象时注册回调函数。

    typedef void(* ArvStreamCallback) (
    void* user_data,
    ArvStreamCallbackType type,
    ArvBuffer* buffer
    )

    它在四种情况下会被调用:
    ①流接收线程的初始化时(只会被调用一次,对应type为ARV_STREAM_CALLBACK_TYPE_INIT
    ②流接收线程的终止时(只会被调用一次,对应type为ARV_STREAM_CALLBACK_TYPE_EXIT
    ③每一个buffer从缓冲队列被开始取出时(对应type为ARV_STREAM_CALLBACK_TYPE_START_BUFFER
    ④每一个buffer从缓冲队列中取出完毕时(无论成功与否,对应type为ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE

    @@ -661,7 +1195,7 @@
    开源相机管理库Aravis例程学习(二)——连续采集multiple-acquisition-main-thread - /2024/04/15/aravis-multiple-acquisition-main-thread/ + /aravis-multiple-acquisition-main-thread/ 简介

    本文针对官方例程 中的:02-multiple-acquisition-main-thread做简单的讲解,并简单介绍其中调用的arv_camera_set_acquisition_mode arv_camera_create_streamarv_camera_get_payloadarv_buffer_new arv_stream_push_bufferarv_camera_start_acquisitionarv_stream_pop_bufferarv_camera_stop_acquisition函数。

    aravis版本:0.8.31
    操作系统:ubuntu-20.04
    gcc版本:9.4.0

    例程代码

    这段代码使用Aravis的API,控制相机连续采集,并在主线程中从缓冲区获取前10帧图像(假设不丢帧),主要操作步骤如下:

    @@ -674,12 +1208,12 @@
  • 停止采集
  • 释放资源
  • -
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>

    /*
    * Connect to the first available camera, then acquire 10 buffers.
    */
    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    GError *error = NULL;

    //连接相机
    camera = arv_camera_new ("192.168.6.63", &error);

    if (ARV_IS_CAMERA (camera)) {
    ArvStream *stream = NULL;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
    //设置相机采集模式为连续采集
    arv_camera_set_acquisition_mode (camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);

    if (error == NULL)
    //创建流对象
    stream = arv_camera_create_stream (camera, NULL, NULL, &error);

    if (ARV_IS_STREAM (stream)) {
    int i;
    size_t payload;

    //从相机对象中获取图像负载大小(每个图像的字节大小)
    payload = arv_camera_get_payload (camera, &error);
    if (error == NULL) {
    for (i = 0; i < 2; i++)
    //在流对象buffer池中插入两个buffer
    arv_stream_push_buffer (stream, arv_buffer_new (payload, NULL));
    }

    if (error == NULL)
    //开始采集
    arv_camera_start_acquisition (camera, &error);

    if (error == NULL) {
    for (i = 0; i < 10; i++) {
    ArvBuffer *buffer;
    //从流对象中获取buffer,此时buffer中已经包含了图像数据
    buffer = arv_stream_pop_buffer (stream);
    if (ARV_IS_BUFFER (buffer)) {
    printf ("Acquired %d×%d buffer\n",
    arv_buffer_get_image_width (buffer),
    arv_buffer_get_image_height (buffer));
    //将buffer放回流对象的buffer池中,而不是销毁
    arv_stream_push_buffer (stream, buffer);
    }
    }
    }

    if (error == NULL)
    //停止采集
    arv_camera_stop_acquisition (camera, &error);

    g_clear_object (&stream);
    }

    g_clear_object (&camera);
    }

    if (error != NULL) {
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    +
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>

    /*
    * Connect to the first available camera, then acquire 10 buffers.
    */
    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    GError *error = NULL;

    //连接相机
    camera = arv_camera_new ("192.168.6.63", &error);

    if (ARV_IS_CAMERA (camera))
    {
    ArvStream *stream = NULL;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
    //设置相机采集模式为连续采集
    arv_camera_set_acquisition_mode (camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);

    if (error == NULL)
    //创建流对象
    stream = arv_camera_create_stream (camera, NULL, NULL, &error);

    if (ARV_IS_STREAM (stream))
    {
    int i;
    size_t payload;

    //从相机对象中获取图像负载大小(每个图像的字节大小)
    payload = arv_camera_get_payload (camera, &error);
    if (error == NULL)
    {
    for (i = 0; i < 2; i++)
    //在流对象buffer池中插入两个buffer
    arv_stream_push_buffer (stream, arv_buffer_new (payload, NULL));
    }

    if (error == NULL)
    //开始采集
    arv_camera_start_acquisition (camera, &error);

    if (error == NULL)
    {
    for (i = 0; i < 10; i++) {
    ArvBuffer *buffer;
    //从流对象中获取buffer,此时buffer中已经包含了图像数据
    buffer = arv_stream_pop_buffer (stream);
    if (ARV_IS_BUFFER (buffer)) {
    printf ("Acquired %d×%d buffer\n",
    arv_buffer_get_image_width (buffer),
    arv_buffer_get_image_height (buffer));
    //将buffer放回流对象的buffer池中,而不是销毁
    arv_stream_push_buffer (stream, buffer);
    }
    }
    }

    if (error == NULL)
    //停止采集
    arv_camera_stop_acquisition (camera, &error);

    g_clear_object (&stream);
    }

    g_clear_object (&camera);
    }

    if (error != NULL)
    {
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }

    此例程较为简单,每一步的细节查看注释即可,此处不过多讲解。

    运行结果:

    函数说明

    arv_camera_set_acquisition_mode

    简介:设置相机的采集模式

    @@ -720,7 +1254,7 @@
    开源相机管理库Aravis例程学习(四)——multiple-acquisition-signal - /2024/04/25/aravis-multiple-acquisition-signal/ + /aravis-multiple-acquisition-signal/ 简介

    本文针对官方例程 中的:02-multiple-acquisition-signal做简单的讲解。并简单介绍其中调用的g_main_loop_newg_main_loop_rung_main_loop_quitg_signal_connectarv_stream_set_emit_signals

    aravis版本:0.8.31
    操作系统:ubuntu-20.04
    gcc版本:9.4.0

    例程代码

    这段代码使用Aravis的API,控制相机连续采集,并通过GLib的事件循环机制和GObject的信号系统异步地获取10个图像,主要操作步骤如下:

    @@ -735,12 +1269,12 @@
  • 关闭流对象信号发射,释放资源
  • 连续采集multiple-acquisition-main-thread 不同的是,本例中使用GMainLoop(GLib的事件循环)来处理异步事件,图像获取过程是异步进行的。

    -
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include "LogManager.h"

    typedef struct {
    GMainLoop *main_loop;
    guint32 counter;
    } AppData;

    void new_buffer_cb (ArvStream *stream, void *user_data)
    {
    ArvBuffer *buffer;
    AppData *app_data = static_cast<AppData*>(user_data);

    buffer = arv_stream_pop_buffer (stream);
    PAW_INFO("Acquired"<<arv_buffer_get_image_width(buffer)<<"x"<<arv_buffer_get_image_height(buffer)<< " buffer");

    arv_stream_push_buffer (stream, buffer);

    app_data->counter++;
    if (app_data->counter == 10)
    g_main_loop_quit (app_data->main_loop);
    }

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    AppData app_data;
    GError *error = NULL;

    app_data.main_loop = g_main_loop_new (NULL, FALSE);
    app_data.counter = 0;

    //连接相机
    camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (camera)) {
    ArvStream *stream = NULL;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
    //设置采集模式
    arv_camera_set_acquisition_mode (camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);
    //创建流对象
    if (error == NULL)
    stream = arv_camera_create_stream (camera, NULL, NULL, &error);

    if (ARV_IS_STREAM (stream)) {
    int i;
    size_t payload;

    //获取有效负载大小
    payload = arv_camera_get_payload (camera, &error);
    if (error == NULL) {
    //设置流对象的缓冲区数量
    for (i = 0; i < 5; i++)
    arv_stream_push_buffer (stream, arv_buffer_new (payload, NULL));
    }

    //设置流对象信号回调函数
    g_signal_connect (stream, "new-buffer", G_CALLBACK (new_buffer_cb), &app_data);
    //设置流对象发射信号
    //当流对象接收到新的缓冲区时,发射new-buffer信号
    arv_stream_set_emit_signals (stream, TRUE);

    //开始采集
    if (error == NULL)
    arv_camera_start_acquisition (camera, &error);

    //启动主循环
    PAW_INFO("start main loop");
    if (error == NULL)
    g_main_loop_run (app_data.main_loop);
    PAW_INFO("start main loop end");

    if (error == NULL)
    //停止采集
    arv_camera_stop_acquisition (camera, &error);

    arv_stream_set_emit_signals (stream, FALSE);
    g_clear_object (&stream);
    }

    g_clear_object (&camera);
    }

    g_main_loop_unref (app_data.main_loop);

    if (error != NULL) {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    +
    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include "LogManager.h"

    typedef struct
    {
    GMainLoop *main_loop;
    guint32 counter;
    } AppData;

    void new_buffer_cb (ArvStream *stream, void *user_data)
    {
    ArvBuffer *buffer;
    AppData *app_data = static_cast<AppData*>(user_data);

    buffer = arv_stream_pop_buffer (stream);
    PAW_INFO("Acquired"<<arv_buffer_get_image_width(buffer)<<"x"<<arv_buffer_get_image_height(buffer)<< " buffer");

    arv_stream_push_buffer (stream, buffer);

    app_data->counter++;
    if (app_data->counter == 10)
    g_main_loop_quit (app_data->main_loop);
    }

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    AppData app_data;
    GError *error = NULL;

    app_data.main_loop = g_main_loop_new (NULL, FALSE);
    app_data.counter = 0;

    //连接相机
    camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (camera))
    {
    ArvStream *stream = NULL;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
    //设置采集模式
    arv_camera_set_acquisition_mode (camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);
    //创建流对象
    if (error == NULL)
    stream = arv_camera_create_stream (camera, NULL, NULL, &error);

    if (ARV_IS_STREAM (stream))
    {
    int i;
    size_t payload;

    //获取有效负载大小
    payload = arv_camera_get_payload (camera, &error);
    if (error == NULL)
    {
    //设置流对象的缓冲区数量
    for (i = 0; i < 5; i++)
    arv_stream_push_buffer (stream, arv_buffer_new (payload, NULL));
    }

    //设置流对象信号回调函数
    g_signal_connect (stream, "new-buffer", G_CALLBACK (new_buffer_cb), &app_data);
    //设置流对象发射信号
    //当流对象接收到新的缓冲区时,发射new-buffer信号
    arv_stream_set_emit_signals (stream, TRUE);

    //开始采集
    if (error == NULL)
    arv_camera_start_acquisition (camera, &error);

    //启动主循环
    PAW_INFO("start main loop");
    if (error == NULL)
    g_main_loop_run (app_data.main_loop);
    PAW_INFO("start main loop end");

    if (error == NULL)
    //停止采集
    arv_camera_stop_acquisition (camera, &error);

    arv_stream_set_emit_signals (stream, FALSE);
    g_clear_object (&stream);
    }

    g_clear_object (&camera);
    }

    g_main_loop_unref (app_data.main_loop);

    if (error != NULL)
    {
    /* En error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }

    注:PAW_INFO是我自定义的用于打印日志的宏

    运行结果:

    其中<>之间的是线程号。

    @@ -762,7 +1296,7 @@

    Q&A

    回调函数的同步调用与异步调用

    观察程序运行时的日志,可以发现new_buffer_cb的运行并不是在主线程中。

    但是按照g_signal_connect的描述,回调函数应该是被同步调用,也就是说new_buffer_cb理论上应该在主线程被调用。
    后来查看文档发现,在GObject的信号系统中,处理器的调用是同步的。当信号发射时,其关联的所有处理器会都会在发射信号的线程中按照它们被连接的顺序依次执行。

    @@ -770,7 +1304,7 @@

    在本例中,预定义的信号new-buffer的处理器new_buffer_cb被绑定在流对象上,这意味着每当流对象有一个新的buffer可用时,这个信号就会被发射,随后new_buffer_cb就被调用。而官方文档钟提到,流对象内部是使用一个单独的线程来监听数据的到达,因此信号是在这个单独的线程被发射的,也就是说回调函数也是在这个单独的线程被调用的,而不是在主线程中。

    帧丢失问题

    官方给出的例程中,先启动的相机采集,然后才开始事件循环。我认为这样的话会存在丢帧的问题,因为在事件循环启动并准备好处理接收到的图像之前,相机可能已经开始发送数据,如果数据流的缓冲不足或处理不及时,新的图像数据可能会覆盖还未处理的旧数据,或者直接被丢弃。

    所以我对代码做了一些改动,改变调用顺序为先开启事件循环,然后再启动相机的采集,代码如下:

    -
    /* SPDX-License-Identifier:Unlicense */
    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include "LogManager.h"

    typedef struct {
    GMainLoop *main_loop;
    guint32 counter;
    ArvCamera *camera;
    } AppData;

    gboolean start_acquisition_cb(gpointer user_data)
    {
    AppData *app_data = static_cast<AppData*>(user_data);
    GError *error = NULL;

    arv_camera_start_acquisition(app_data->camera, &error);

    if (error != NULL) {
    printf("Error: %s\n", error->message);
    g_main_loop_quit(app_data->main_loop);
    }
    //只调用一次
    return FALSE;
    }

    ...

    int main (int argc, char **argv)
    {
    AppData app_data;
    GError *error = NULL;

    app_data.main_loop = g_main_loop_new (NULL, FALSE);
    app_data.counter = 0;

    app_data.camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (app_data.camera)) {
    ArvStream *stream = NULL;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (app_data.camera, NULL));

    arv_camera_set_acquisition_mode (app_data.camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);

    if (error == NULL)
    stream = arv_camera_create_stream (app_data.camera, NULL, NULL, &error);

    if (ARV_IS_STREAM (stream)) {
    int i;
    size_t payload;

    payload = arv_camera_get_payload (app_data.camera, &error);
    if (error == NULL) {
    for (i = 0; i < 5; i++)
    arv_stream_push_buffer (stream, arv_buffer_new (payload, NULL));
    }

    g_signal_connect (stream, "new-buffer", G_CALLBACK (new_buffer_cb), &app_data);

    PAW_INFO("emit signals");
    arv_stream_set_emit_signals (stream, TRUE);
    PAW_INFO("emit signals end");

    /* if (error == NULL)
    arv_camera_start_acquisition (camera, &error); */

    //在主循环开始后尽快执行一次start_acquisition_cb
    g_idle_add(start_acquisition_cb, &app_data);

    PAW_INFO("start main loop");
    if (error == NULL)
    g_main_loop_run (app_data.main_loop);
    PAW_INFO("start main loop end");
    if (error == NULL)
    arv_camera_stop_acquisition (app_data.camera, &error);

    arv_stream_set_emit_signals (stream, FALSE);

    g_clear_object (&stream);
    }

    g_clear_object (&app_data.camera);
    }

    g_main_loop_unref (app_data.main_loop);

    if (error != NULL) {
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    ]]>
    +
    /* SPDX-License-Identifier:Unlicense */
    /* Aravis header */
    #include <arv.h>
    /* Standard headers */
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include "LogManager.h"

    typedef struct
    {
    GMainLoop *main_loop;
    guint32 counter;
    ArvCamera *camera;
    } AppData;

    gboolean start_acquisition_cb(gpointer user_data)
    {
    AppData *app_data = static_cast<AppData*>(user_data);
    GError *error = NULL;

    arv_camera_start_acquisition(app_data->camera, &error);

    if (error != NULL)
    {
    printf("Error: %s\n", error->message);
    g_main_loop_quit(app_data->main_loop);
    }
    //只调用一次
    return FALSE;
    }

    ...

    int main (int argc, char **argv)
    {
    AppData app_data;
    GError *error = NULL;

    app_data.main_loop = g_main_loop_new (NULL, FALSE);
    app_data.counter = 0;

    app_data.camera = arv_camera_new (NULL, &error);

    if (ARV_IS_CAMERA (app_data.camera))
    {
    ArvStream *stream = NULL;

    printf ("Found camera '%s'\n", arv_camera_get_model_name (app_data.camera, NULL));

    arv_camera_set_acquisition_mode (app_data.camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);

    if (error == NULL)
    stream = arv_camera_create_stream (app_data.camera, NULL, NULL, &error);

    if (ARV_IS_STREAM (stream))
    {
    int i;
    size_t payload;

    payload = arv_camera_get_payload (app_data.camera, &error);
    if (error == NULL)
    {
    for (i = 0; i < 5; i++)
    arv_stream_push_buffer (stream, arv_buffer_new (payload, NULL));
    }

    g_signal_connect (stream, "new-buffer", G_CALLBACK (new_buffer_cb), &app_data);

    PAW_INFO("emit signals");
    arv_stream_set_emit_signals (stream, TRUE);
    PAW_INFO("emit signals end");

    /* if (error == NULL)
    arv_camera_start_acquisition (camera, &error); */

    //在主循环开始后尽快执行一次start_acquisition_cb
    g_idle_add(start_acquisition_cb, &app_data);

    PAW_INFO("start main loop");
    if (error == NULL)
    g_main_loop_run (app_data.main_loop);
    PAW_INFO("start main loop end");
    if (error == NULL)
    arv_camera_stop_acquisition (app_data.camera, &error);

    arv_stream_set_emit_signals (stream, FALSE);

    g_clear_object (&stream);
    }

    g_clear_object (&app_data.camera);
    }

    g_main_loop_unref (app_data.main_loop);

    if (error != NULL)
    {
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    ]]> 工业相机 Aravis @@ -778,7 +1312,7 @@
    开源相机管理库Aravis学习——PixelFormat编码规则 - /2024/04/28/aravis-pixelformat/ + /aravis-pixelformat/ 前言

    在学习Aravis官方例程 的时候,有这么一个函数:arv_camera_get_pixel_format,它的返回类型是ArvPixelFormat(本质是个32位无符号整数)。这意味着对于每个图像数据格式,都有自己对应的唯一的编码。我比较好奇Aravis是通过什么规则对各种图像数据格式进行的编码,于是就查看了源码。

    本文主要讨论Aravis中对不同图像数据格式的编码规则。

    前置知识

    PixelFormat

    PixelFormat指的是图像中每个像素的数据格式,它定义了图像中像素的组成方式、颜色信息的存储方法和每个像素所占的位数等。这一格式对于图像的处理和显示是非常关键的,因为它直接影响到图像的质量和处理的效率。

    @@ -813,14 +1347,14 @@
    开源相机管理库Aravis例程学习(一)——单帧采集single-acquisition - /2024/04/10/aravis-single-acquisition/ + /aravis-single-acquisition/ 简介

    本文针对官方例程 中的第一个例程:single-acquisition做简单的讲解,并简单分析其中调用的arv_camera_new arv_camera_acquisitionarv_camera_get_model_name arv_buffer_get_image_width arv_buffer_get_image_height 函数。

    aravis版本:0.8.31
    操作系统:ubuntu-20.04
    gcc版本:9.4.0

    -

    源码

    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */

    #include <arv.h>

    /* Standard headers */

    #include <stdlib.h>
    #include <stdio.h>

    /*
    * Connect to the first available camera, then acquire a single buffer.
    */

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    ArvBuffer *buffer;
    GError *error = NULL;

    /* Connect to the first available camera */
    camera = arv_camera_new (NULL, &error);
    //camera = arv_camera_new ("192.168.6.23", &error);

    if (ARV_IS_CAMERA (camera)) {
    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));

    /* Acquire a single buffer */
    buffer = arv_camera_acquisition (camera, 0, &error);

    if (ARV_IS_BUFFER (buffer)) {
    /* Display some informations about the retrieved buffer */
    printf ("Acquired %d×%d buffer\n",
    arv_buffer_get_image_width (buffer),
    arv_buffer_get_image_height (buffer));
    /* Destroy the buffer */
    g_clear_object (&buffer);
    }

    /* Destroy the camera instance */
    g_clear_object (&camera);
    }

    if (error != NULL) {
    /* An error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }
    +

    源码

    /* SPDX-License-Identifier:Unlicense */

    /* Aravis header */

    #include <arv.h>

    /* Standard headers */

    #include <stdlib.h>
    #include <stdio.h>

    /*
    * Connect to the first available camera, then acquire a single buffer.
    */

    int main (int argc, char **argv)
    {
    ArvCamera *camera;
    ArvBuffer *buffer;
    GError *error = NULL;

    /* Connect to the first available camera */
    camera = arv_camera_new (NULL, &error);
    //camera = arv_camera_new ("192.168.6.23", &error);

    if (ARV_IS_CAMERA (camera))
    {
    printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));

    /* Acquire a single buffer */
    buffer = arv_camera_acquisition (camera, 0, &error);

    if (ARV_IS_BUFFER (buffer))
    {
    /* Display some informations about the retrieved buffer */
    printf ("Acquired %d×%d buffer\n",
    arv_buffer_get_image_width (buffer),
    arv_buffer_get_image_height (buffer));
    /* Destroy the buffer */
    g_clear_object (&buffer);
    }

    /* Destroy the camera instance */
    g_clear_object (&camera);
    }

    if (error != NULL)
    {
    /* An error happened, display the correspdonding message */
    printf ("Error: %s\n", error->message);
    return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
    }

    此例程较为简单,每一步的细节查看注释即可,此处不过多讲解。
    运行结果:

    函数说明

    arv_camera_new

    简介:创建一个ArvCamera对象,如果name是NULL,则连接第一个可用的相机。

    @@ -863,7 +1397,7 @@
    C++自用小轮子——单例模板 - /2024/04/03/cpp-development-components-singleton-CRTP/ + /cpp-development-components-singleton-CRTP/ 简介

    记录开发时自用的小轮子:单例模板。

    单例模板

    提供了一个基于模板的单例模式的实现,代码如下:

    #ifndef SINGLETON_H
    #define SINGLETON_H

    template <typename T>
    class CSingleton
    {
    public:
    static T& GetInstance()
    {
    static T instance;
    return instance;
    }
    protected:
    CSingleton() {}

    ~CSingleton() {}
    CSingleton(const CSingleton&) = delete;
    CSingleton& operator=(const CSingleton&) = delete;
    };

    #endif // SINGLETON_H
    @@ -877,7 +1411,7 @@
    C++自用小轮子——线程安全队列 - /2024/04/03/cpp-development-components-threadsafe-queue/ + /cpp-development-components-threadsafe-queue/ 简介

    记录开发时自用的小轮子:线程安全队列

    线程安全队列

    #ifndef THREADSAFEQUEUE_H
    #define THREADSAFEQUEUE_H

    #include <iostream>
    #include <queue>
    #include <mutex>
    #include <condition_variable>
    #include <memory>

    template<typename T>
    class ThreadSafeQueue
    {
    public:
    ThreadSafeQueue();
    ThreadSafeQueue(const ThreadSafeQueue& other);
    ThreadSafeQueue& operator=(const ThreadSafeQueue& other);
    ~ThreadSafeQueue();
    public:
    void push(T new_value);

    //对于pop方法,std::queue中的pop只负责弹出元素,不返回元素
    //这里为了接口简化,设计为在pop的同时返回弹出的元素
    //timeout为超时时间,单位为毫秒
    //默认阻塞pop
    bool wait_and_pop(T& value, std::chrono::milliseconds timeout_millisecond = std::chrono::milliseconds::max());
    std::shared_ptr<T> wait_and_pop(std::chrono::milliseconds timeout_millisecond = std::chrono::milliseconds::max());

    bool empty() const;
    size_t size() const;

    T& front();
    const T& front() const;
    std::shared_ptr<T> front_ptr();

    private:
    mutable std::mutex mtx_;
    std::queue<T> data_queue_;
    std::condition_variable cv_data_;
    };

    template<typename T>
    ThreadSafeQueue<T>::ThreadSafeQueue()
    {
    }

    template<typename T>
    ThreadSafeQueue<T>::~ThreadSafeQueue()
    {
    }

    template<typename T>
    ThreadSafeQueue<T>::ThreadSafeQueue(const ThreadSafeQueue& other)
    {
    std::lock_guard<std::mutex> lock(other.mtx_);
    data_queue_ = other.data_queue_;
    }

    template<typename T>
    ThreadSafeQueue<T>& ThreadSafeQueue<T>::operator=(const ThreadSafeQueue& other)
    {
    if (this == &other)
    {
    return *this;
    }
    //同时锁定两个互斥量,防止死锁
    std::lock(mtx_, other.mtx_);
    //领养锁,因为已经锁定了
    std::lock_guard<std::mutex> self_lock(mtx_, std::adopt_lock);
    std::lock_guard<std::mutex> other_lock(other.mtx_, std::adopt_lock);
    data_queue_ = other.data_queue_;
    return *this;
    }

    template<typename T>
    void ThreadSafeQueue<T>::push(T new_value)
    {
    std::lock_guard<std::mutex> lock(mtx_);
    data_queue_.push(std::move(new_value));
    cv_data_.notify_one();
    }

    template<typename T>
    bool ThreadSafeQueue<T>::wait_and_pop(T& value, std::chrono::milliseconds timeout_millisecond)
    {
    std::unique_lock<std::mutex> lock(mtx_);
    if (data_queue_.empty())
    {
    if (timeout_millisecond == std::chrono::milliseconds::max())
    {
    cv_data_.wait(lock, [this] {return !data_queue_.empty();});
    }
    else
    {
    if (!cv_data_.wait_for(lock, timeout_millisecond, [this] {return !data_queue_.empty();}))
    return false;
    }
    }
    value = std::move(data_queue_.front());
    data_queue_.pop();
    return true;
    }

    template<typename T>
    std::shared_ptr<T> ThreadSafeQueue<T>::wait_and_pop(std::chrono::milliseconds timeout_millisecond)
    {
    std::unique_lock<std::mutex> lock(mtx_);
    if (data_queue_.empty())
    {
    if (timeout_millisecond == std::chrono::milliseconds::max())
    {
    cv_data_.wait(lock, [this] {return !data_queue_.empty();});
    }
    else
    {
    if (!(cv_data_.wait_for(lock, timeout_millisecond, [this] {return !data_queue_.empty();})))
    return std::shared_ptr<T>();
    }
    }
    std::shared_ptr<T> res(std::make_shared<T>(std::move(data_queue_.front())));
    data_queue_.pop();
    return res;
    }

    template<typename T>
    bool ThreadSafeQueue<T>::empty() const
    {
    std::lock_guard<std::mutex> lock(mtx_);
    return data_queue_.empty();
    }

    template<typename T>
    size_t ThreadSafeQueue<T>::size() const
    {
    std::lock_guard<std::mutex> lock(mtx_);
    return data_queue_.size();
    }

    template<typename T>
    T& ThreadSafeQueue<T>::front()
    {
    std::lock_guard<std::mutex> lock(mtx_);
    if(data_queue_.empty())
    throw std::runtime_error("queue is empty");
    return data_queue_.front();
    }

    template<typename T>
    const T& ThreadSafeQueue<T>::front() const
    {
    std::lock_guard<std::mutex> lock(mtx_);
    if(data_queue_.empty())
    throw std::runtime_error("queue is empty");
    return data_queue_.front();
    }

    template<typename T>
    std::shared_ptr<T> ThreadSafeQueue<T>::front_ptr()
    {
    std::lock_guard<std::mutex> lock(mtx_);
    if(data_queue_.empty())
    return std::shared_ptr<T>();
    return std::make_shared<T>(data_queue_.front());
    }

    #endif // THREADSAFEQUEUE_H
    ]]>
    @@ -888,7 +1422,7 @@
    编译期链接时共享库路径搜索优先级实验 - /2024/07/29/cpp-shared-lib-search-priority-test-linking/ + /cpp-shared-lib-search-priority-test-linking/ 前言

    《共享库链接和加载时的路径搜索优先级》 中提到,使用g++时,共享库在编译期链接时的库路径搜索优先级为:-L指定的路径>LIBRARY_PATH记录的路径>默认路径

    本实验分三步验证上述结论
    ①单独测试每种方法指定的路径的可行性
    ②对比测试三种方法间的优先级
    ③使用DEBUG模式,查看链接器输出的详细信息,二次验证上述结论

    值得注意的是,我看网上都说LIBRARY_PATH指定的路径优先级要大于默认路径的优先级,但是就我的测试结果来看,结论是相反的(可能是我使用了g++而不是直接使用底层的ld?)。

    @@ -913,7 +1447,7 @@

    输出:

    可以看到由于我们没有配置任何额外的搜索路径,并且没有在默认搜索路径下放置libhello.so文件,链接器就找不到相应的共享库文件,就会链接失败。

    @@ -925,14 +1459,14 @@

    输出:

    没有报错。

    然后使用readelf -d查看可执行文件的动态段信息,可见链接成功,共享库的soname已经被写入到可执行文件的动态段信息中了。

    LIBRARY_PATH

    创建路径/opt/hellolib,将libhello.so.1.1.0拷贝至/opt/hellolib,并在/opt/hellolib下创建一个软链接(libhello.so)指向它。然后将/opt/hellolib添加至LIBRARY_PATH并进行main.ohello的共享库文件的链接操作,查看是否可以链接成功。

    @@ -942,14 +1476,14 @@

    输出:

    没有报错。

    然后使用readelf -d查看可执行文件的动态段信息,可见链接成功,共享库的soname已经被写入到可执行文件的动态段信息中了。

    -L

    创建路径/opt/hellolib,将libhello.so.1.1.0拷贝至/opt/hellolib,并在/opt/hellolib下创建一个软链接(libhello.so)指向它,然后添加链接选项-L/opt/hellolib并进行链接操作,查看是否可以将main.ohello的共享库文件链接成功。

    @@ -959,14 +1493,14 @@

    输出:

    没有报错。

    然后使用readelf -d查看可执行文件的动态段信息,可见链接成功,共享库的soname已经被写入到可执行文件的动态段信息中了。

    优先级测试

    默认路径和LIBRARY_PATH

      @@ -980,13 +1514,13 @@

      输出:

      然后使用readelf -d查看可执行文件的动态段信息,可见链接成功,并且链接的是默认路径下的共享库文件libhello.so.2.1.0(其soname为libhello.so.2)。因此可以得出结论:默认路径搜索优先级要高于LIBRARY_PATH指定的路径的搜索优先级。

      对于上述结论,将会在后文的DEBUG模式中给出更详细的验证。

      @@ -1001,14 +1535,14 @@

      输出:

      然后使用readelf -d查看可执行文件的动态段信息,可见链接成功,并且链接的是-L指定路径下的共享库文件libhello.so.2.1.0(其soname为libhello.so.2)。因此可以得出结论:-L指定路径搜索优先级要高于默认搜索路径的搜索优先级。

      对于上述结论,将会在后文的DEBUG模式中给出更详细的验证。

      @@ -1026,7 +1560,7 @@

      图片中的文字内容如下:

      @@ -1041,7 +1575,7 @@

      图片中的文字内容如下(省略了一部分不需要关注的):

      @@ -1054,7 +1588,7 @@

      链接器详细信息

      然后我们再看链接器输出的详细信息:

      图片中的文字内容如下:

      @@ -1076,7 +1610,7 @@

      验证

      最后我们可以通过链接器在链接特定库(比如我们的libhello)时的搜索过程验证上述结论:

      可见链接器先是搜索我们使用-L指定的路径/opt/hellolib_L,然后搜索编译器配置的路径/usr/lib/gcc/x86_64-linux-gnu/11/../../../../lib/(其本质就是默认路径/usr/lib/),最后搜索LIBRARY_PATH指定的路径/opt/hellolib。证明了编译过程中链接时库搜索路径的优先级为

      @@ -1100,7 +1634,7 @@ 运行期加载时共享库路径搜索优先级实验 - /2024/08/01/cpp-shared-lib-search-priority-test-loading/ + /cpp-shared-lib-search-priority-test-loading/ 前言

      《共享库链接和加载时的路径搜索优先级》 中提到,共享库在运行期加载时的路径搜索优先级为:
      RPATH>LD_LIBRARY_PATH>RUNPATH>/etc/ld.so.conf/etc/ld.so.conf.d/*>默认库路径

      本实验分两步验证上述结论
      ①单独测试每种方法指定的路径的可行性
      ②查看链接器输出的详细信息,验证上述优先级顺序

      实验环境

      操作系统:Ubuntu 20.04
      编译器:g++-11.4.0
      make:GNU Make 4.2.1

      @@ -1192,7 +1726,7 @@
      共享库链接和加载时的路径搜索优先级 - /2024/07/15/cpp-shared-lib-search-priority/ + /cpp-shared-lib-search-priority/ 前言

      在开发一个新项目时遇到了共享库冲突的问题,因此在这里记录一下共享库的链接和加载过程中库路径的搜索优先级的相关知识。

      共享库的链接

      现在有一个main.o可重定位目标文件,其中需要用到开源库log4cpp。在链接的时候,我们可以这样链接:

      g++ main.o -o a.out -L/path/to/libs -llog4cpp
      @@ -1218,7 +1752,7 @@
      共享库soname机制 - /2024/07/16/cpp-shared-lib-soname/ + /cpp-shared-lib-soname/ 前言

      在使用第三方库时,我们会发现第三方库会提供一组文件,他们的后缀一般是.so(如libname.so),.so.x.so.x.y.z。本文讨论他们之间的关系。

      共享库版本号

      共享库一般会由于修复bug或增加接口等原因不断更新,有些更新是向下兼容的,有些则不是。一旦不向下兼容,那么当共享库更新后,依赖该库的程序将无法运行,需要重新编译。

      为了避免上述情况,就要对共享库进行版本控制。根据更新内容的不同可以划分不同的版本号:

      @@ -1253,7 +1787,7 @@
    • 对于一个共享库文件,我们可以通过readelf -d命令查看其soname
    @@ -1275,13 +1809,13 @@
    设计模式学习(二)工厂模式——抽象工厂模式+注册表 - /2024/07/09/design-pattern-2-abstract-factory-reflect/ + /design-pattern-2-abstract-factory-reflect/ 前言

    上一篇文章中 我们提到了抽象工厂模式初版代码的一些缺点:①客户端违反开闭原则②提供方违反开闭原则。本文将针对这两点进行讨论

    使用简单工厂改进

    对于缺点①,我们可以使用简单工厂的思路来改进抽象工厂的初版代码。对于上一篇文章中的例子,我们去除CameraFactoryBaslerCameraFactorySickCameraFactory,取而代之的是SimpleFactory类。

    类图如下:

    代码如下:

    @@ -1303,12 +1837,12 @@
    设计模式学习(二)工厂模式——抽象工厂模式 - /2024/07/05/design-pattern-2-abstract-factory/ + /design-pattern-2-abstract-factory/ 背景

    现在我需要开发一个相机操作模块,它可能在Windows下运行,也可能在Linux下运行。由于在厂家提供的SDK中,Windows下的SDK和Linux下的SDK是有区别的,因此对于一个品牌的相机,我们要创建两个类去封装这两个不同平台下的API。

    我们先使用工厂方法模式去设计(以Basler相机为例),类图如下:

    对应的代码(就不用智能指针了,要不然类图不好画):

    @@ -1326,7 +1860,7 @@

    AbstractProductAAbstractProductB是两个抽象产品,之所以为抽象,是因为他们可能有多种不同的实现,就刚才的例子来说,抽象产品就是BaslerCameraSickCameraProductA1ProductA2ProductB1ProductB2就是对两个抽象产品的具体分类的实现,对应例子中的LinuxBaslerCameraWindowsBaslerCameraLinuxSickCameraWindowsSickCamera

    @@ -1356,11 +1890,11 @@
    设计模式学习(二)工厂模式——工厂方法模式+注册表 - /2024/06/03/design-pattern-2-factory-method-reflect/ + /design-pattern-2-factory-method-reflect/ 工厂方法模式的瑕疵

    前一篇笔记 中我们介绍了工厂方法模式,示例的类图如下:

    前文中提到

    @@ -1385,7 +1919,7 @@
    设计模式学习(二)工厂模式——工厂方法模式 - /2024/05/17/design-pattern-2-factory-method/ + /design-pattern-2-factory-method/ 前言

    前一篇文章 介绍了简单工厂模式,提到了简单工厂模式的缺点(违反开闭原则,扩展困难),本文要介绍的工厂方法模式在一定程度上弥补了简单工厂模式的缺点。

    工厂方法模式

    简介

    工厂方法模式是创建型设计模式之一,它在抽象工厂类中声明创建对象的接口,在具体工厂类中实现具体的实例化过程。这个模式的核心思想是将对象的实例化延迟到子类中进行。

    这样的话,当要添加一个具体产品时,我们不会修改原有的工厂类(对修改封闭),而是新创建一个关联于具体产品的具体工厂类(对扩展开放)。

    @@ -1394,7 +1928,7 @@

    UML类图如下:

    代码如下:

    @@ -1422,7 +1956,7 @@
    设计模式学习(二)工厂模式——简单工厂模式 - /2024/05/14/design-pattern-2-simple-factory/ + /design-pattern-2-simple-factory/ 前言

    工厂模式是一种常用的设计模式,属于创建型模式之一。它的主要目的是为了解耦组件之间的依赖关系。通过使用工厂模式,系统中的具体类的实例化过程可以被抽象出来,从而使得系统更加模块化,增强了系统的可维护性和可扩展性。

    工厂模式可以分为三种类型:简单工厂模式,工厂方法模式和抽象工厂模式。本文先讨论简单工厂模式。

    背景

    在工业相机领域,多个品牌如Basler、Sick、Huaray等,各自提供了控制相机的API。本文中我们按照提供方和使用方两个角色来进行分析,以便更好地理解工厂模式的优点:

    @@ -1443,7 +1977,7 @@

    UML类图如下:

    代码如下:

    @@ -1470,31 +2004,9 @@ C++设计模式
    - - C++多态学习(二)菱形继承 - /2023/12/06/diamond-inherit/ - 简介

    在前一篇笔记C++多态学习(一)单继承与多重继承 中讨论了单继承和多重继承,本文将针对菱形继承进行讨论

    -

    菱形继承

    class Base
    {
    public:
    Base()
    {
    printf("Base的this指针是:%p!\n", this);
    }
    virtual void func() { cout << "Base::func" << endl; }
    virtual void func1() { cout << "Base::func1" << endl; }
    virtual void func2() { cout << "Base::func2" << endl; }

    int b; //4字节
    };

    class Base1 : public Base
    {
    public:
    Base1()
    {
    printf("Base1的this指针是:%p!\n", this);
    }
    //虚表指针8字节
    void func() override { cout << "Base1::func" << endl; }
    void func1() override { cout << "Base1::func1" << endl; }
    virtual void func3() { cout << "Base1::func3" << endl; }

    int b1; //4字节
    };

    class Base2 : public Base
    {
    public:
    Base2()
    {
    printf("Base2的this指针是:%p!\n", this);
    }
    void func() override { cout << "Base2::func" << endl; }
    void func2() override { cout << "Base2::func2" << endl; }
    virtual void func4() { cout << "Base2::func4" << endl; }

    int b2;
    };

    class Derived : public Base1, public Base2
    {
    public:
    Derived()
    {
    printf("Derive的this指针是:%p!\n", this);
    }
    void func() override { cout << "Derived::func" << endl; }
    void func4() override { cout << "Derived::func4" << endl; }
    void func3() override { cout << "Derived::func3" << endl; }
    virtual void func5() { cout << "Derived::func5" << endl; }

    int d;
    };
    -

    内存布局

    -

    基类冗余

    我们知道Derived继承自Base1Base2,而Base1Base2又继承自Base。这意味着Derived的内存布局中会有两份Base的拷贝。这会引起数据的不一致性和资源的浪费。

    -

    二义性

    Derived obj;
    obj.b = 1; //Derived::b不明确
    Base* p = &obj; //基类Base不明确
    -

    对于obj.b,编译器无法确定在通过Dervide访问Base的成员b时应该选择哪条路径。
    对于Base* p = &obj,编译器无法确定p应该指向通过Derived1继承的Base还是通过Derived2继承的Base

    -

    小结

    本文简单讨论了菱形继承的内存布局以及其可能导致的问题。针对上述问题,可以采用虚继承解决,虚继承将在下一篇笔记中讨论。

    -

    参考文章

    1.VTable Notes on Multiple Inheritance in GCC C++ Compiler v4.0.1

    -]]>
    - - C++ - C++语法 - -
    Git学习——迁移单一仓库至其他代码托管平台 - /2024/05/10/git-code-migration/ + /git-code-migration/ 简介

    因需迁移单一代码仓库至其他代码托管平台,要迁移的包括仓库内容以及所有历史记录和推送日志。

    本文中的方法同样适用于在同一代码托管平台中克隆仓库。

    流程

    1. 创建新仓库:
    在目的平台的指定位置创建一个新的仓库(目的仓库),用于接收克隆的数据。

    @@ -1515,7 +2027,7 @@
    Centos8系统启动时间优化 - /2024/05/16/linux-centos-boot-time-optimization/ + /linux-centos-boot-time-optimization/ 前言

    因需要,对Centos8操作系统的启动时间进行优化。

    初始化系统

    Centos8使用了systemd作为系统和服务管理器。systemd是现代Linux发行版中普遍采用的初始化系统,它负责在启动时初始化系统环境并管理系统服务。我们在分析操作系统的启动过程时可以使用systemdsystemctl相关的命令。

    启动阶段

    首先查看操作系统启动过程中各阶段的耗时信息:

    @@ -1564,7 +2076,7 @@
  • 分析服务启动时间并禁用非必要的服务:使用systemd-analyze blame查看启动过程中每个服务的耗时,根据具体情况确定哪些服务是非常耗时且非必要的,使用systemctl disable xxxservicenamexxx禁用这些服务以加速启动过程。

  • @@ -1585,7 +2097,7 @@
    使用update-alternatives管理GCC版本 - /2024/07/29/linux-update-alternatives/ + /linux-update-alternatives/ 简介

    当操作系统中存在多个版本的GCC时,可以使用使用update-alternatives管理默认使用的编译器版本。

    本文使用gcc-9gcc-11做演示,操作系统为ubuntu-20.04

    操作过程

    ①使用以下命令确认gcc已正确安装

    @@ -1595,7 +2107,7 @@

    没有配置过应该输出如下:

    ③添加版本到update-alternatives

    @@ -1606,7 +2118,7 @@

    执行此命令后,系统将提供一个选择列表,我们可以选择默认的gcc版本

    我这里优先级最大的gcc-11被自动选为了默认版本,我们直接输入回车选择它就可以(具体的要根据你的实际情况进行选择)

    @@ -1615,7 +2127,7 @@

    ]]>
    @@ -1626,7 +2138,7 @@
    CentOS8系统网口桥接 - /2024/03/04/network-bridging/ + /network-bridging/ 简介

    因需要,对主板两个网口进行桥接。

    操作环境

    主板型号:Gigabyte GA-IMB370TN
    操作系统:CentOS 8.2

    桥接步骤

    清除旧配置

    先备份旧的网络配置文件,然后将其清除。
    网络配置文件的位置如下:

    @@ -1634,14 +2146,14 @@

    网络配置文件:

    网络配置文件
    网络配置文件

    查看网口名称

    nmcli con show

    我的两个网口名称分别为:eno1和enp3s0

    网口名称
    网口名称

    建立网桥

    创建一个新的桥接连接,其名为br0,设置其ipv4地址为:xxx.xxx.xxx.xxx(如192.168.23.23),子网掩码为:255.255.255.0,并设置为自动连接。
    br0将eno1和enp3s0作为从属接口,这允许两个网络接口(eno1和enp3s0)在同一个桥接网络内可以相互通信,同时这个桥接还可以与其他设备或网络通信

    @@ -1649,19 +2161,19 @@

    操作结果:

    桥接操作结果
    桥接操作结果

    此时,网络配置文件有三个:
    网络配置文件2
    网络配置文件2

    查看是否桥接成功

    nmcli con show

    在这里插入图片描述
    在这里插入图片描述

    当然也可以使用另一台设备去连接这两个网口,若使用两个网口都可以连接到设置的ip:xxx.xxx.xxx.xxx。则证明操作成功。

    至此网络桥接已操作完成

    @@ -1673,7 +2185,7 @@
    C++智能指针学习——小谈引用计数 - /2024/04/07/reference-counting/ + /reference-counting/ 前言

    本文结合源码讨论std::shared_ptr和std::weak_ptr的部分底层实现,然后讨论引用计数,弱引用计数的创建和增减。
    文章中尽可能的先阐述原理,然后再贴上代码。如果有不想看代码的,直接略过代码即可。
    本文涉及的源码均出自gcc 9.4.0版本

    控制块简介

    控制块是shared_ptrweak_ptr中的重要组成,主要用于管理资源的引用计数和生命周期。这个机制允许智能指针安全地共享和管理同一个对象,同时自动释放不再需要的资源。

    控制块包含以下部分:

    @@ -1688,7 +2200,7 @@

    示意图大概长这样:

    引用计数与弱引用计数创建过程

    在谈引用计数和弱引用计数的创建时,其实就是讨论控制块的创建。

    @@ -1775,87 +2287,6 @@

    std::shared_ptr对象存在的情况下,所有相关std::weak_ptr对象被销毁后,控制块仍存在,且其中的弱引用计数为1,此时在销毁最后一个std::shared_ptr对象时,除了要减少引用计数为0,释放管理的内存资源,还要把最后一个弱引用计数减少为0,销毁控制块。

    std::weak_ptr对象存在的情况下,所有相关std::shared_ptr对象都被销毁后,①std::shared_ptr管理的内存资源会被释放(因为引用计数为0,_M_dispose()被调用)②弱引用计数不为0,控制块仍然存在(直到最后一个std::weak_ptr对象被销毁,控制块才会被销毁)

    参考文章

    1.C++2.0 shared_ptr和weak_ptr深入刨析
    2.智能指针std::weak_ptr

    -]]>
    - - C++ - C++语法 - -
    - - C++多态学习(一)单继承与多重继承 - /2023/11/28/single-and-multi-inherit/ - 简介

    最近在学习虚函数相关的知识,发现理解C++继承在内存中的表现以及多态性在底层的实现原理还是有点必要的,故在此写个小笔记,记录一些小知识点。
    本文相关测试的机器环境:

    -
    Linux Qcumber 5.4.0-84-generic #94~18.04.1-Ubuntu SMP Thu Aug 26 23:17:46 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
    -

    gcc版本:

    -
    gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
    -

    单一继承

    首先从单一继承开始

    -
    class Base
    {
    public:
    virtual void func1() { cout << "Base::func1" << endl; }
    virtual void func2() { cout << "Base::func2" << endl; }

    int b;
    };

    class Derived : public Base
    {
    public:
    void func1() override { cout << "Derived::func1" << endl; }
    virtual void func3() { cout << "Derived::func3" << endl; }

    int d;
    };
    -

    内存布局

    Derived继承了Base所有成员变量和函数,并且重写了func1()Derived对象内存布局应该是这样的:

    -

    对虚函数的调用,比如像这样:

    -
    Derived* d_ptr = new Derived();
    d_ptr->func1();
    -

    其实是等价于*((d_ptr->vptr)[0])(d_ptr)

    -
      -
    • d_ptr->vptr:获取虚表地址;
    • -
    • (d_ptr->vptr)[0]:获取虚表第一个槽的地址;
    • -
    • *((d_ptr->vptr)[0]):解引用,获取Derived虚表上的第一个元素,里面存着Derived::func1()的地址;
    • -
    • *((d_ptr->vptr)[0])(d_ptr):调用Derived::func1(),并隐式地将this指针传递给Derived::func1()
    • -
    -

    当然,我们无法访问vptr,因此这种等价只是理论上的,有助于理解底层的原理。

    -

    指针向上转型

    在C++多态中,支持父类的指针指向子类的对象:

    -
    Derived d;
    Base* b_ptr = &d;
    -

    这是因为所有派生类对象都可以视作基类的对象(因为派生类继承了基类的函数和变量),但并非所有基类的对象都可以视作派生类的对象。

    -

    如果你有一个Base指针,你可以调用在Base中声明的函数。而如果有一个Derived指针,由于Derived继承了Base的所有函数和变量,因此Derived也能够访问Base的函数和变量。

    -

    当使用基类的指针指向派生类对象时,基类指针可访问的部分如下图红框:

    -

    注意:

    -
      -
    • 虚表第一个槽中函数地址已经被替换为Derived::func1()的地址,因此无论是b_ptr->func1()还是d_ptr->func1()都会调用Derived::func1()
    • -
    -

    多重继承

    当多重继承时,内存模型就变得稍微复杂一点了;

    -
    class Base1 {
    public:
    Base1()
    {
    printf("Base1的this指针是:%p!\n", this);
    }
    //虚表指针8字节
    virtual void func1() { cout << "Base1::func1" << endl; }
    virtual void func2() { cout << "Base1::func2" << endl; }

    int b1; //4字节

    };

    class Base2 {
    public:
    Base2()
    {
    printf("Base2的this指针是:%p!\n", this);
    }
    virtual void func3() { cout << "Base2::func3" << endl; }
    virtual void func4() { cout << "Base2::func4" << endl; }

    int b2;
    };

    class Derived : public Base1, public Base2 {
    public:
    Derived()
    {
    printf("Derive的this指针是:%p!\n", this);
    }
    void func1() override { cout << "Derived::func1" << endl; }
    void func3() override { cout << "Derived::func3" << endl; }
    virtual void func5() { cout << "Derived::func5" << endl; }

    int d;
    };
    -

    多重继承中主要关注两个方面:内存布局和虚表

    -

    内存布局

    Derived对象内存布局如下:

    -

    可以观察到Derived对象的内存布局由上到下依次是:Base1,Base2,Derived。因为在内存布局中,首先是基类按照它们在继承列表中的顺序由上到下排列,然后是派生类。

    -

    尾部填充(tail padding)

    待补充。

    -

    this指针调整

    在C++中,一个对象的 this 指针默认指向该对象的起始地址。this指针可以使成员函数能够知道它们是在为哪个具体的对象实例工作,从而可以访问和修改该对象的成员变量。
    然而在多重继承中会涉及到this指针的偏移:

    -
    Derived d;
    Base1* pb1 = &d;
    Base2* pb2 = &d;
    cout<<"d的地址"<<&d<<endl;
    cout<<"pb1指向的地址"<<pb1<<endl;
    cout<<"pb2指向的地址"<<pb2<<endl;
    -

    输出的结果是:

    可以看到静态类型为Base2*pb2指向的地址与d的地址并不相同。这是因为在指针向上转换时,对于继承列表中非首位的基类,编译器会自动将对象的this指针进行偏移,然后赋值给基类的指针。在上述例子中,this指针的偏移量为16字节(正好等于sizeof(Base1)),然后将偏移后的地址赋予了pb2

    -

    值得注意的是这种指针偏移现象也会出现在调用函数时:

    -
    Derived* d = new Derived();
    d->func4();
    -

    当通过指向Derived对象的指针调用func4()时,传入的this指针也会被调整。

    -

    虚表指针

    多重继承中的虚表指针和虚表也是要特别注意的。
    可以观察到内存布局中有两个虚表指针,数量与Derived的直接基类数量相等。

    -

    为什么上述例子中要有两个虚表指针呢?
    因为与单继承不同,Base1Base2完全独立,他们的虚函数没有顺序关系,即func1()func3()有着相同的对虚表起始位置的偏移量。不可以按序排在一起。而且Base1Base2中的成员变量也是无关的。所以使得Base1Base2Derived中必须要处于两个不相交的区域中,同时需要有两个虚指针分别对它们虚函数进行索引。

    -

    non-virtual thunk

    现在我们关注func3()Derived中重写了Base2func3()。根据内存布局图,在虚表中,Base2部分的func3()并没有被Derived::func3()覆盖,而是产生了一个non-virtual thunk,真正的Derived::func3()地址被放在了虚表中Derived的部分下。这个non-virtual thunk的本质是根据top_offset调整this指针,然后调用真正的函数。

    -

    下面解释一下原因,考虑以下情况:

    -
    Base2* p = new Derived();
    p->func3();
    -

    我们主要关注的就是两点:①调用正确版本的func3()②传入正确的this指针
    若仅是要调用正确的func3(),那我们完全可以不用生成non-virtual thunk,直接把将Base2中的&Base2::func3()覆盖为&Derived::func3()即可,但是由于我们期望传入的是指向Derived起始地址的this指针,因此就还需要对this指针进行调整。

    -

    由上面的this指针讨论结果可知p指向DerivedBase2部分的起始地址。通过反汇编发现,non-virtual thunk正好将this指针向上调整了16B(sizeof(Base1)),使其指向了正确的位置(Derived的起始地址),然后调用了’真正’的func3()

    -

    小结

    本文简单讨论了
    1.单继承和多重继承下类对象的内存布局
    2.多态下指针的行为
    3.non-virtual thunk的实现机制

    -

    参考文章

    1.C++ vtables - Part 2 - Multiple Inheritance
    2.VTable Notes on Multiple Inheritance in GCC C++ Compiler v4.0.1
    3.C++ Inheritance Memory Model

    ]]>
    C++ @@ -1864,7 +2295,7 @@
    设计模式学习(一)单例模式补充——单例模式析构 - /2024/03/19/singleton-destruct/ + /singleton-destruct/ 前言

    《单例模式学习》 中提到了,在单例对象是通过new关键字动态分配在堆上的情况下,当程序退出时,不会通过C++的RAII机制自动调用其析构函数。本文讨论一下这种现象的原因以及解决方法。

    无法调用析构函数的原因

    在DCLP(双检查锁模式)中,CSingleton中的instance是一个静态指针变量,被分配在全局/静态存储区。而instance所指向的CSingleton实例是通过new创建在堆上的,只能手动调用delete来释放相关资源(对于单例模式这是无法实现的,因为析构函数私有),无法通过RAII释放相关资源。
    在程序结束时,instance这个指针变量被销毁了,但它所指向的内存空间中的CSingleton对象并没有被显式销毁,而是由操作系统去回收这一块内存(不会调用其析构函数)。然而依赖操作系统来清理资源并不是一个优雅的结束方式,可能会造成文件句柄未关闭、网络连接未断开等资源泄漏。

    class CSingleton
    {
    public:
    static CSingleton* getInstance();
    static std::mutex mtx;
    private:
    CSingleton(){}
    ~CSingleton(){}
    CSingleton(const CSingleton&) = delete;
    CSingleton& operator=(const CSingleton&) = delete;

    static CSingleton* instance;
    };

    CSingleton* CSingleton::instance;

    CSingleton* CSingleton::getInstance()
    {
    if(nullptr == instance)
    {
    mtx.lock();
    if(nullptr == instance)
    {
    instance = new CSingleton();
    }
    mtx.unlock();
    }
    return instance;
    }
    @@ -1878,7 +2309,7 @@

    运行结果:

    智能指针

    我们还可以利用智能指针引用计数机制,对资源自动管理:

    @@ -1889,7 +2320,7 @@

    测试结果:

    局部静态变量

    局部静态变量形式的单例模式也可以完成资源的释放,详见《单例模式学习》

    @@ -1901,7 +2332,7 @@
    设计模式学习(一)单例模式补充——指令重排 - /2024/03/19/singleton-reorder/ + /singleton-reorder/ 前言

    《单例模式学习》 中曾提到懒汉式DCLP的单例模式实际也不是线程安全的,这是编译器的指令重排导致的,本文就简单讨论一下指令重排对单例模式的影响,以及对应的解决方法。

    指令重排简介

    指令重排(Instruction Reordering)是编译器或处理器为了优化程序执行效率而对程序中的指令序列进行重新排序的过程。这种重排可以发生在编译时也可以发生在运行时,目的是为了减少指令的等待时间和提高执行的并行性。

    @@ -1938,7 +2369,7 @@ 设计模式学习(一)单例模式的几种实现方式 - /2024/03/18/singleton/ + /singleton/ 前言

    单例模式,其核心目标是确保在程序运行的过程中,有且只有存在一个实例才能保证他们的逻辑正确性以及良好的效率。因此单例模式的实现思路就是确保一个类有且只有一个实例,并提供一个该实例的全局访问点。
    单例模式设计要点:

    • 私有构造、析构
    • @@ -1954,7 +2385,7 @@

      测试结果:

      饿汉式的缺点:

      @@ -1967,7 +2398,7 @@

      测试结果:

      但是上述代码有几个缺点:

      @@ -1985,7 +2416,7 @@

      测试结果:

      但是遗憾的是,这种方法其实也不是线程安全的,具体原因可见:补充-指令重排

      @@ -1996,7 +2427,7 @@

      测试结果:

      对于线程安全问题:在C++11及更高版本中,静态局部变量的初始化是线程安全的。即当多个线程同时首次访问局部静态变量,编译器可以保证其初始化代码仅执行一次,防止了任何可能的竞态条件或重复初始化。

      @@ -2007,7 +2438,7 @@

      测试结果:

      这种形式使用了奇异递归模板模式(Curiously Recurring Template Pattern, CRTP)。在使用时要注意,子类需要将自己作为模板参数传递给CSingleton模板进行模板类实例化,用做基类;同时需要将基类声明为友元,这样才能在通过CSingleton<T>::getInstance()方法创建MyClass唯一实例时,调用到MyClass的私有构造函数。

      @@ -2020,7 +2451,7 @@ jsoncpp的安装及使用 - /2024/06/13/thirdlib-jsoncpp/ + /thirdlib-jsoncpp/ 前言

      本文操作均在ubuntu20.04下进行。

      安装

      方法一:apt包管理器

      ①使用包管理器安装
      这种方法比较简单,直接使用apt包管理器安装jsoncpp:

      apt install libjsoncpp-dev
      @@ -2028,19 +2459,19 @@

      ②查看头文件和库文件
      安装完毕后我们可以去找一下jsoncpp的头文件和库文件
      头文件位于/usr/include/jsoncpp/json/

      库文件位于/usr/lib/x86_64-linux-gnu/

      但是我们通过头文件的version.h和动态库文件的realname,可以知道使用apt包管理器安装的jsoncpp的版本号为1.7.4

      那如果我需要安装的是jsoncpp的其他版本,就需要下载源代码并编译安装。

      @@ -2061,7 +2492,7 @@

      使用

      编写示例代码

      写JSON

      #include <json/json.h>
      #include <iostream>

      int main()
      {
      // 创建一个Json::Value对象
      Json::Value root;

      // 向对象中添加数据
      root["name"] = "John Doe";
      root["age"] = 30;
      root["isAlive"] = true;
      root["address"]["city"] = "New York";
      root["address"]["state"] = "NY";

      // 创建一个Json::StreamWriterBuilder
      Json::StreamWriterBuilder writer;

      // 将Json::Value对象转换为字符串
      std::string output = Json::writeString(writer, root);

      // 打印输出
      std::cout << output << std::endl;

      return 0;
      }
      @@ -2071,13 +2502,13 @@

      输出

      写JSON

      读JSON

      ]]>
      @@ -2088,7 +2519,7 @@
      log4cpp的安装及使用 - /2024/07/15/thirdlib-log4cpp/ + /thirdlib-log4cpp/ 前言

      本文的操作均在ubuntu20.04下进行

      安装

      本文仅介绍从源码编译安装log4cpp的过程。

      ①在开始编译前,首先要确保系统中安装了g++makeautoconflibtool

      @@ -2099,12 +2530,12 @@

      ④查看头文件和库文件
      默认配置安装的log4cpp,其头文件位于/usr/local/include/log4cpp/,库文件位于/usr/local/lib/

      使用

      示例代码

      #include <string>
      #include <iomanip>
      #include "log4cpp/PropertyConfigurator.hh"
      #include "log4cpp/Category.hh"

      int main()
      {
      try
      {
      log4cpp::PropertyConfigurator::configure("./cfg/log4cfg");
      }
      catch (log4cpp::ConfigureFailure& f)
      {
      std::cerr << "configure problem " << f.what() << std::endl;

      }
      log4cpp::Category & log = log4cpp::Category::getRoot();

      std::string s = __FILE__;
      s += " : ";
      std::ostringstream line;
      line << std::setw(4) << std::setfill('0') << __LINE__;
      s += line.str();
      s += " : ";
      std::ostringstream buf;
      buf<< "test message"; ;
      s += buf.str();

      log.info(s);
      }
      @@ -2113,7 +2544,7 @@

      输出

      输出结果:

      ]]>
      @@ -2122,4 +2553,29 @@ 三方库
      + + 内存布局分析工具pahole的安装和使用 + /tools-pahole/ + 本文相关测试的机器环境:

      +
      Linux user-GA-IMB410TN 5.15.0-122-generic #132~20.04.1-Ubuntu SMP Fri Aug 30 15:50:07 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
      +

      gcc版本:

      +
      gcc (Ubuntu 11.4.0-2ubuntu1~20.04) 11.4.0
      +

      简介

      pahole可以用来查看C/C++编译后的程序中数据结构的内存布局。这个工具属于dwarves软件包中的一部分,它通过分析DWARF调试信息来显示每个数据结构的大小、对齐、和字段间的填充(padding)。这对于优化数据结构的内存使用和访问性能非常有帮助。

      +

      安装

      方法一:包管理器

      pahole工具是dwarves软件包的一部分,若对版本无特殊需求,直接使用包管理器安装即可:

      +
      apt-get install dwarves
      +

      方法二:源码编译安装

      若需要安装pahole指定版本,请访问官方网站 ,解压后查看README文件进行安装

      +

      使用

      示例代码

      // file: example.cpp
      struct S
      {
      unsigned int a : 5; // 第一个位域,位宽为5
      unsigned int b : 17; // 第二个位域,位宽为17
      unsigned int c : 28; // 第三个位域,位宽为28
      unsigned int d : 31; // 第四个位域,位宽为31
      };

      int main()
      {
      S s;
      return 0;
      }
      +

      使用过程

      ①编译待测试的代码
      编译时使用-g参数生成DWARF调试信息

      +
      g++ -g -o example example.cpp
      +

      ②查看内存布局
      编译完成后,使用pahole查看程序中数据结构的内存布局:

      +
      # 查看所有结构体的内存布局
      pahole example
      # 查看指定结构体(S)的内存布局
      pahole -C S example
      +

      示例代码中S的内存布局如下:

      +
      struct S {
      unsigned int a:5; /* 0: 0 4 */
      unsigned int b:17; /* 0: 5 4 */

      /* XXX 10 bits hole, try to pack */

      /* Force alignment to the next boundary: */
      unsigned int :0;

      unsigned int c:28; /* 4: 0 4 */

      /* XXX 4 bits hole, try to pack */

      /* Force alignment to the next boundary: */
      unsigned int :0;

      unsigned int d:31; /* 8: 0 4 */

      /* size: 12, cachelines: 1, members: 4 */
      /* sum bitfield members: 81 bits, bit holes: 2, sum bit holes: 14 bits */
      /* bit_padding: 1 bits */
      /* last cacheline: 12 bytes */
      };
      + +]]>
      + + C++ + Tools + +
      diff --git a/2024/03/19/singleton-destruct/index.html b/singleton-destruct/index.html similarity index 83% rename from 2024/03/19/singleton-destruct/index.html rename to singleton-destruct/index.html index c879e90..9491169 100644 --- a/2024/03/19/singleton-destruct/index.html +++ b/singleton-destruct/index.html @@ -13,7 +13,7 @@ - + @@ -21,31 +21,30 @@ - + - - + + - + - - + + - + - 设计模式学习(一)单例模式补充——单例模式析构 - + 设计模式学习(一)单例模式补充——单例模式析构 | Paw5zx - Paw5zx @@ -76,7 +75,7 @@ - + @@ -85,7 +84,7 @@ @@ -195,7 +194,7 @@

      - Paw5zx + Paw5zx's Blog

      + - + + + + + + + + + + + - - -
      diff --git a/2024/03/19/singleton-destruct/result_garbo.png b/singleton-destruct/result_garbo.png similarity index 100% rename from 2024/03/19/singleton-destruct/result_garbo.png rename to singleton-destruct/result_garbo.png diff --git a/2024/03/19/singleton-destruct/result_shared_ptr.png b/singleton-destruct/result_shared_ptr.png similarity index 100% rename from 2024/03/19/singleton-destruct/result_shared_ptr.png rename to singleton-destruct/result_shared_ptr.png diff --git a/2024/03/19/singleton-reorder/index.html b/singleton-reorder/index.html similarity index 82% rename from 2024/03/19/singleton-reorder/index.html rename to singleton-reorder/index.html index 8f0f10e..33e6489 100644 --- a/2024/03/19/singleton-reorder/index.html +++ b/singleton-reorder/index.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -32,17 +32,16 @@ - - + + - + - 设计模式学习(一)单例模式补充——指令重排 - + 设计模式学习(一)单例模式补充——指令重排 | Paw5zx - Paw5zx @@ -73,7 +72,7 @@ - + @@ -82,7 +81,7 @@ @@ -192,7 +191,7 @@

      - Paw5zx + Paw5zx's Blog

      + - + + + + + + + + + + + - - -
      diff --git a/2024/03/18/singleton/index.html b/singleton/index.html similarity index 84% rename from 2024/03/18/singleton/index.html rename to singleton/index.html index 256cb71..a8f9f28 100644 --- a/2024/03/18/singleton/index.html +++ b/singleton/index.html @@ -13,7 +13,7 @@ - + @@ -21,34 +21,33 @@ - + - - - - - + + + + + - + - - + + - + - 设计模式学习(一)单例模式的几种实现方式 - + 设计模式学习(一)单例模式的几种实现方式 | Paw5zx - Paw5zx @@ -79,7 +78,7 @@ - + @@ -88,7 +87,7 @@ @@ -198,7 +197,7 @@

      - Paw5zx + Paw5zx's Blog

      + - + + + + + + + + + + + - - -
      diff --git a/2024/03/18/singleton/result_CRTP.png b/singleton/result_CRTP.png similarity index 100% rename from 2024/03/18/singleton/result_CRTP.png rename to singleton/result_CRTP.png diff --git a/2024/03/18/singleton/result_DCLP.png b/singleton/result_DCLP.png similarity index 100% rename from 2024/03/18/singleton/result_DCLP.png rename to singleton/result_DCLP.png diff --git a/2024/03/18/singleton/result_hungry.png b/singleton/result_hungry.png similarity index 100% rename from 2024/03/18/singleton/result_hungry.png rename to singleton/result_hungry.png diff --git a/2024/03/18/singleton/result_lazy.png b/singleton/result_lazy.png similarity index 100% rename from 2024/03/18/singleton/result_lazy.png rename to singleton/result_lazy.png diff --git a/2024/03/18/singleton/result_meyers.png b/singleton/result_meyers.png similarity index 100% rename from 2024/03/18/singleton/result_meyers.png rename to singleton/result_meyers.png diff --git a/tags/index.html b/tags/index.html index b8a9049..7e58ac7 100644 --- a/tags/index.html +++ b/tags/index.html @@ -30,17 +30,16 @@ - - + + - + - 标签 - + 标签 | Paw5zx - Paw5zx @@ -71,7 +70,7 @@ - + @@ -80,7 +79,7 @@ @@ -190,7 +189,7 @@

      - Paw5zx + Paw5zx's Blog

      + - + + + + + + + + + + + - - -
      diff --git a/2024/06/13/thirdlib-jsoncpp/apt.png b/thirdlib-jsoncpp/apt.png similarity index 100% rename from 2024/06/13/thirdlib-jsoncpp/apt.png rename to thirdlib-jsoncpp/apt.png diff --git a/2024/06/13/thirdlib-jsoncpp/index.html b/thirdlib-jsoncpp/index.html similarity index 79% rename from 2024/06/13/thirdlib-jsoncpp/index.html rename to thirdlib-jsoncpp/index.html index 3fb7cb1..fa84e9d 100644 --- a/2024/06/13/thirdlib-jsoncpp/index.html +++ b/thirdlib-jsoncpp/index.html @@ -13,44 +13,43 @@ - + - + - + - + - - - + + + - - - + + + - + - + - - + + - + - jsoncpp的安装及使用 - + jsoncpp的安装及使用 | Paw5zx - Paw5zx @@ -81,7 +80,7 @@ - + @@ -90,7 +89,7 @@ @@ -200,7 +199,7 @@

      - Paw5zx + Paw5zx's Blog

      + - + + + + + + + + + + + - - -
      diff --git a/2024/06/13/thirdlib-jsoncpp/libfile.png b/thirdlib-jsoncpp/libfile.png similarity index 100% rename from 2024/06/13/thirdlib-jsoncpp/libfile.png rename to thirdlib-jsoncpp/libfile.png diff --git a/2024/06/13/thirdlib-jsoncpp/location.png b/thirdlib-jsoncpp/location.png similarity index 100% rename from 2024/06/13/thirdlib-jsoncpp/location.png rename to thirdlib-jsoncpp/location.png diff --git a/2024/06/13/thirdlib-jsoncpp/result_read.png b/thirdlib-jsoncpp/result_read.png similarity index 100% rename from 2024/06/13/thirdlib-jsoncpp/result_read.png rename to thirdlib-jsoncpp/result_read.png diff --git a/2024/06/13/thirdlib-jsoncpp/result_write.png b/thirdlib-jsoncpp/result_write.png similarity index 100% rename from 2024/06/13/thirdlib-jsoncpp/result_write.png rename to thirdlib-jsoncpp/result_write.png diff --git a/2024/06/13/thirdlib-jsoncpp/source_location.png b/thirdlib-jsoncpp/source_location.png similarity index 100% rename from 2024/06/13/thirdlib-jsoncpp/source_location.png rename to thirdlib-jsoncpp/source_location.png diff --git a/2024/06/13/thirdlib-jsoncpp/source_soname.png b/thirdlib-jsoncpp/source_soname.png similarity index 100% rename from 2024/06/13/thirdlib-jsoncpp/source_soname.png rename to thirdlib-jsoncpp/source_soname.png diff --git a/2024/07/15/thirdlib-log4cpp/index.html b/thirdlib-log4cpp/index.html similarity index 78% rename from 2024/07/15/thirdlib-log4cpp/index.html rename to thirdlib-log4cpp/index.html index 45238c8..44159d0 100644 --- a/2024/07/15/thirdlib-log4cpp/index.html +++ b/thirdlib-log4cpp/index.html @@ -13,40 +13,39 @@ - + - + - + - + - - - + + + - + - + - - + + - + - log4cpp的安装及使用 - + log4cpp的安装及使用 | Paw5zx - Paw5zx @@ -77,7 +76,7 @@ - + @@ -86,7 +85,7 @@ @@ -196,7 +195,7 @@

      - Paw5zx + Paw5zx's Blog

      + - + + + + + + + + + + + - - -
      diff --git a/2024/07/15/thirdlib-log4cpp/location.png b/thirdlib-log4cpp/location.png similarity index 100% rename from 2024/07/15/thirdlib-log4cpp/location.png rename to thirdlib-log4cpp/location.png diff --git a/2024/07/15/thirdlib-log4cpp/location2.png b/thirdlib-log4cpp/location2.png similarity index 100% rename from 2024/07/15/thirdlib-log4cpp/location2.png rename to thirdlib-log4cpp/location2.png diff --git a/2024/07/15/thirdlib-log4cpp/result.png b/thirdlib-log4cpp/result.png similarity index 100% rename from 2024/07/15/thirdlib-log4cpp/result.png rename to thirdlib-log4cpp/result.png diff --git a/tools-pahole/index.html b/tools-pahole/index.html new file mode 100644 index 0000000..88ed2a5 --- /dev/null +++ b/tools-pahole/index.html @@ -0,0 +1,1105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 内存布局分析工具pahole的安装和使用 | Paw5zx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + + + + + + + +
      + + + + + +
      +

      + Paw5zx's Blog +

      + +
      + +
      + + + +
      + + +
      + + + +
      + +
      + + + +
      + + +
      +
      + +
      + +
      +

      内存布局分析工具pahole的安装和使用

      +
      + +
      + + +
      +
      + +
      +
      +
      + paw5zx + + Lv4 + +
      +
      + + +
      +
      +
      + + + + + +
      +

      本文相关测试的机器环境:

      +
      1
      Linux user-GA-IMB410TN 5.15.0-122-generic #132~20.04.1-Ubuntu SMP Fri Aug 30 15:50:07 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
      +

      gcc版本:

      +
      1
      gcc (Ubuntu 11.4.0-2ubuntu1~20.04) 11.4.0
      +

      简介

      pahole可以用来查看C/C++编译后的程序中数据结构的内存布局。这个工具属于dwarves软件包中的一部分,它通过分析DWARF调试信息来显示每个数据结构的大小、对齐、和字段间的填充(padding)。这对于优化数据结构的内存使用和访问性能非常有帮助。

      +

      安装

      方法一:包管理器

      pahole工具是dwarves软件包的一部分,若对版本无特殊需求,直接使用包管理器安装即可:

      +
      1
      apt-get install dwarves
      +

      方法二:源码编译安装

      若需要安装pahole指定版本,请访问官方网站 ,解压后查看README文件进行安装

      +

      使用

      示例代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      // file: example.cpp
      struct S
      {
      unsigned int a : 5; // 第一个位域,位宽为5
      unsigned int b : 17; // 第二个位域,位宽为17
      unsigned int c : 28; // 第三个位域,位宽为28
      unsigned int d : 31; // 第四个位域,位宽为31
      };

      int main()
      {
      S s;
      return 0;
      }
      +

      使用过程

      ①编译待测试的代码
      编译时使用-g参数生成DWARF调试信息

      +
      1
      g++ -g -o example example.cpp
      +

      ②查看内存布局
      编译完成后,使用pahole查看程序中数据结构的内存布局:

      +
      1
      2
      3
      4
      # 查看所有结构体的内存布局
      pahole example
      # 查看指定结构体(S)的内存布局
      pahole -C S example
      +

      示例代码中S的内存布局如下:

      +
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      struct S {
      unsigned int a:5; /* 0: 0 4 */
      unsigned int b:17; /* 0: 5 4 */

      /* XXX 10 bits hole, try to pack */

      /* Force alignment to the next boundary: */
      unsigned int :0;

      unsigned int c:28; /* 4: 0 4 */

      /* XXX 4 bits hole, try to pack */

      /* Force alignment to the next boundary: */
      unsigned int :0;

      unsigned int d:31; /* 8: 0 4 */

      /* size: 12, cachelines: 1, members: 4 */
      /* sum bitfield members: 81 bits, bit holes: 2, sum bit holes: 14 bits */
      /* bit_padding: 1 bits */
      /* last cacheline: 12 bytes */
      };
      + + +
      + + +
      +
      +
        +
      • 标题: 内存布局分析工具pahole的安装和使用
      • +
      • 作者: paw5zx
      • +
      • 创建于 + : 2024-10-11 10:18:24
      • + +
      • + 更新于 + : 2024-10-11 11:53:08 +
      • + +
      • + 链接: https://paw5zx.github.io/tools-pahole/ +
      • +
      • + + 版权声明: + + + + + 本文章采用 CC BY-NC-SA 4.0 进行许可。 + +
      • +
      +
      + +
      + + + + + +
      + + +
      + + +
      + +
      + +
      + + +
      + +
      + +
      + + + + +
      +
      +
      +
      + 评论 +
      + + + + +
      + + + + + + +
      + +
      + +
      + + +
      +
      +
      +
      目录
      +
      内存布局分析工具pahole的安装和使用
      + + +
      +
      +
      + +
      + + + + + +
      + + + +
      + + +
      + + +
      +
      +
        + + +
      • + +
      • + + + + +
      • + +
      • + +
      +
      + +
      + + +
      +
      +
        +
      • + +
      • + +
      • + +
      • + +
      • + +
      • + + + + + + +
      • + +
      • +
      + +
        +
      • + +
      • + +
      • + + +
      • + + +
      +
      + +
      + +
      + +
      + + + +
      + +
      + + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +