From: Arkadiy Illarionov Date: Sun, 19 May 2024 18:58:54 +0000 (+0300) Subject: Merge pan_item_tri_border() into pan_item_tri_new() X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?p=geeqie.git;a=commitdiff_plain;h=HEAD;hp=31a812337ef48d6c43d9e8961b15a00e843838ac Merge pan_item_tri_border() into pan_item_tri_new() --- diff --git a/.clang-tidy b/.clang-tidy index 88cf9943..c12cbaed 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -29,24 +29,32 @@ Checks: > readability-*, -bugprone-assignment-in-if-condition, -bugprone-branch-clone, + -bugprone-casting-through-void, -bugprone-easily-swappable-parameters, -bugprone-implicit-widening-of-multiplication-result, -bugprone-incorrect-roundings, + -bugprone-multi-level-implicit-pointer-conversion, -bugprone-narrowing-conversions, + -bugprone-non-zero-enum-to-bool-conversion, -bugprone-reserved-identifier, -bugprone-sizeof-expression, - -bugprone-suspicious-missing-comma, -llvm-header-guard, -llvm-namespace-comment, -llvm-qualified-auto, -misc-const-correctness, + -misc-header-include-cycle, + -misc-include-cleaner, -misc-no-recursion, -misc-non-private-member-variables-in-classes, -misc-use-anonymous-namespace, -modernize-avoid-c-arrays, -modernize-raw-string-literal, + -modernize-type-traits, -modernize-use-trailing-return-type, + -performance-enum-size, -performance-no-int-to-ptr, + -readability-avoid-nested-conditional-operator, + -readability-avoid-unconditional-preprocessor-if, -readability-braces-around-statements, -readability-function-cognitive-complexity, -readability-identifier-length, diff --git a/.github/workflows/appimage-aarch64.yml b/.github/workflows/appimage-aarch64.yml index 1d7b65bf..5dca3352 100644 --- a/.github/workflows/appimage-aarch64.yml +++ b/.github/workflows/appimage-aarch64.yml @@ -12,7 +12,7 @@ jobs: cpu: cortex-a53 base_image: raspios_lite_arm64:latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: git fetch --tags --force - run: git fetch --depth=1000000 - uses: pguyot/arm-runner-action@v2 @@ -52,7 +52,7 @@ jobs: yes | sudo apt-get install yelp-tools mkdir -p $GITHUB_WORKSPACE/AppDir mkdir -p $GITHUB_WORKSPACE/AppDir/usr - meson setup -Ddevel=enabled -Ddoxygen=disabled -Dyelp-build=disabled -Dprefix=$GITHUB_WORKSPACE/AppDir/usr build + meson setup -Ddoxygen=disabled -Dyelp-build=disabled -Dprefix=$GITHUB_WORKSPACE/AppDir/usr build ninja -C build install tar -czvf geeqie.gz $GITHUB_WORKSPACE/ @@ -71,7 +71,7 @@ jobs: prerelease: true artifacts: "*.AppImage" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() with: name: logs-all-build-appimage diff --git a/.github/workflows/appimage-minimal-aarch64.yml b/.github/workflows/appimage-minimal-aarch64.yml index 08036b43..96f0d327 100644 --- a/.github/workflows/appimage-minimal-aarch64.yml +++ b/.github/workflows/appimage-minimal-aarch64.yml @@ -12,7 +12,7 @@ jobs: cpu: cortex-a53 base_image: raspios_lite_arm64:latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: git fetch --tags --force - run: git fetch --depth=1000000 - uses: pguyot/arm-runner-action@v2 @@ -36,7 +36,7 @@ jobs: yes | sudo apt-get install yelp-tools mkdir -p $GITHUB_WORKSPACE/AppDir mkdir -p $GITHUB_WORKSPACE/AppDir/usr - meson setup -Darchive=disabled -Dcms=disabled -Ddevel=disabled -Ddoxygen=disabled -Ddjvu=disabled -Devince=disabled -Dexecinfo=disabled -Dexiv2=disabled -Dgps-map=disabled -Dheif=disabled -Dj2k=disabled -Djpeg=disabled -Djpegxl=disabled -Dlibraw=disabled -Dlua=disabled -Dpdf=disabled -Dspell=disabled -Dtiff=disabled -Dvideothumbnailer=disabled -Dwebp=disabled -Dprefix=$GITHUB_WORKSPACE/AppDir/usr build + meson setup -Darchive=disabled -Dcms=disabled -Ddoxygen=disabled -Ddjvu=disabled -Devince=disabled -Dexecinfo=disabled -Dexiv2=disabled -Dgps-map=disabled -Dheif=disabled -Dj2k=disabled -Djpeg=disabled -Djpegxl=disabled -Dlibraw=disabled -Dlua=disabled -Dpdf=disabled -Dspell=disabled -Dtiff=disabled -Dvideothumbnailer=disabled -Dwebp=disabled -Dprefix=$GITHUB_WORKSPACE/AppDir/usr build ninja -C build install tar -czvf geeqie.gz $GITHUB_WORKSPACE/ @@ -55,7 +55,7 @@ jobs: prerelease: true artifacts: "*.AppImage" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: always() with: name: logs-all-build-appimage diff --git a/.github/workflows/appimage-minimal-x86_64.yml b/.github/workflows/appimage-minimal-x86_64.yml index c8332907..4d0746c8 100644 --- a/.github/workflows/appimage-minimal-x86_64.yml +++ b/.github/workflows/appimage-minimal-x86_64.yml @@ -11,10 +11,12 @@ jobs: - run: sudo apt-get install pandoc - run: sudo apt-get install yelp-tools - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: git fetch --tags --force - run: git fetch --depth=1000000 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' - uses: BSFishy/meson-build@v1.0.3 with: action: build @@ -22,7 +24,6 @@ jobs: setup-options: > -Darchive=disabled -Dcms=disabled - -Ddevel=disabled -Ddjvu=disabled -Ddoxygen=disabled -Devince=disabled @@ -64,7 +65,7 @@ jobs: artifacts: "Geeqie-minimal-latest-x86_64.AppImage" - name: Upload logs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: logs-all-build-appimage diff --git a/.github/workflows/appimage-x86_64.yml b/.github/workflows/appimage-x86_64.yml index dd5f32d4..f8159bd5 100644 --- a/.github/workflows/appimage-x86_64.yml +++ b/.github/workflows/appimage-x86_64.yml @@ -26,15 +26,16 @@ jobs: - run: sudo apt-get install pandoc - run: sudo apt-get install yelp-tools - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: git fetch --tags --force - run: git fetch --depth=1000000 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' - uses: BSFishy/meson-build@v1.0.3 with: action: build directory: build - setup-options: -Ddevel=enabled options: --verbose meson-version: 1.0.1 @@ -55,7 +56,7 @@ jobs: artifacts: "Geeqie-latest-x86_64.AppImage" - name: Upload logs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: logs-all-build-appimage diff --git a/.github/workflows/check-build-actions.yml b/.github/workflows/check-build-actions.yml index b1d541ec..3388c32c 100644 --- a/.github/workflows/check-build-actions.yml +++ b/.github/workflows/check-build-actions.yml @@ -5,16 +5,16 @@ jobs: Check-Markdown: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run Markdown Lint uses: actionshub/markdownlint@main Check-Shellcheck: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run Shellcheck Lint - uses: ludeeus/action-shellcheck@2.0.0 + uses: ludeeus/action-shellcheck@master with: ignore_names: downsize @@ -30,8 +30,10 @@ jobs: - run: sudo apt-get install libgtk-3-bin - run: sudo apt-get install libxml2-utils - run: sudo apt-get install shellcheck - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' - run: sudo apt-get install xvfb - uses: BSFishy/meson-build@v1.0.3 with: @@ -40,12 +42,12 @@ jobs: setup-options: > -Darchive=disabled -Dcms=disabled - -Ddevel=disabled -Ddjvu=disabled -Ddoxygen=disabled -Devince=disabled -Dexecinfo=disabled -Dexiv2=disabled + -Dextended_stacktrace=disabled -Dgit=disabled -Dgps-map=disabled -Dgtk4=disabled @@ -59,13 +61,14 @@ jobs: -Dpdf=disabled -Dspell=disabled -Dtiff=disabled + -Dunit_tests=disabled -Dvideothumbnailer=disabled -Dwebp=disabled -Dyelp-build=disabled options: --verbose meson-version: 1.0.0 - name: Upload logs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: logs-all-no-options @@ -103,20 +106,23 @@ jobs: #~ - run: sudo apt-get install libffmpegthumbnailer-dev #~ - run: sudo apt-get install libjxl-dev #~ - run: sudo apt-get install yelp-tools - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: '0' - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' - run: sudo apt-get install xvfb - uses: BSFishy/meson-build@v1.0.3 with: action: test directory: build - setup-options: -Ddevel=enabled + setup-options: > + -Dunit_tests=enabled options: --verbose meson-version: 1.0.0 - name: Upload logs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: logs-all-most-options diff --git a/.github/workflows/check-compile-freebsd.yml b/.github/workflows/check-compile-freebsd.yml index 3a94b3c3..0e1d3ad8 100644 --- a/.github/workflows/check-compile-freebsd.yml +++ b/.github/workflows/check-compile-freebsd.yml @@ -24,7 +24,7 @@ jobs: meson setup build meson compile -C build --verbose > ./build/meson-logs/meson-log-compile.txt - name: Upload logs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: logs-compile-freebsd diff --git a/.gitignore b/.gitignore index eab6477d..d526063b 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,10 @@ Makefile.in /src/view_file/.deps /src/view_file/.dirstamp +# /subprojects +/subprojects/packagecache +/subprojects/googletest-release-* + /build /build-stamp /debian/geeqie* diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 00000000..0674b19f --- /dev/null +++ b/TESTING.md @@ -0,0 +1,147 @@ +# Geeqie testing and validation patterns + +Geeqie incorporates a number of forms of validation, including functional tests, +unit tests, and static analysis. These tests are defined towards the end of the +root `meson.build` file (search the file for `test(`). + +You can run all enabled suites using: + +```text +meson test -C build +``` + +Three test suites exist: `functional`, `unit`, and `analysis`. You can pick out +particular suites to execute with commands like: + +```text +meson test -C build --suite functional +meson test -C build --suite analysis --suite unit +``` + +See the Unit tests section for how to enable unit tests. + +## Unit tests + +Unit tests live under `src/tests`. Because they include a lot of extra code in +the Geeqie binary, they must be manually enabled with a command like: + +```text +meson setup -D unit_tests=enabled build +``` + +After that point, they can be executed with: + +```text +meson test -C build -v --suite unit +``` + +Or you can run them by hand by starting geeqie with the `--run-unit-tests` +argument: + +```text +$ ninja -C build +... + +$ ./build/src/geeqie --run-unit-tests +[==========] Running N tests from 1 test suite. +... +[==========] N tests from 1 test suite ran. (0 ms total) +[ PASSED ] N tests. +``` + +### Adding or modifying unit tests + +Geeqie uses the Googletest framework, which is well-documented: \ + + +To add a new testcase in an existing test file, just add it to the test file. +That testcase will be automatically picked up and executed. + +To create a new test file, create the file under `src/tests/` with a name that +matches the file being tested. **Then make sure to add the file to +`src/tests/meson.build` or it won't be seen or executed.** + +## Functional tests + +The Geeqie functional tests rely on `xvfb` in order to be able to start the app +in a standard way without requiring access to a real X server on the test +machine. If `xvfb` is not present, these tests will not run. + +### Basic test + +This just ensures that Geeqie will start. It uses the `--version` flag to keep +Geeqie from staying running. + +### Image tests + +The image tests are only enabled in unit_test mode. You can set that with: + +```text +meson setup -C build -D unit_test=enabled +``` + +This tests that Geeqie can successfully open and provide metadata info about a +library of images of different types. + +See `scripts/image-test.sh` for more details. + +### Lua tests + +Verifies that Geeqie can successfully run lua scripts by opening a stock test +image and running a variety of lua operations on it. + +See `scripts/lua-test.sh` for more details. + +## Static Analysis + +### Code correctness + +Runs `clang-tidy` code correctness checks for every source file in the project. +Note that this will only execute when running from a clone of the Geeqie git +project. + +See `.clang-tidy` and +for more details. + +### Single value enum checks + +Checks for single-value enums. + +See `scripts/enum-check.sh` for more details. + +### Debug statement checks + +Checks for `DEBUG_0`, `DEBUG_BT`, or `DEBUG_FD` statements in the source tree. + +See `scripts/debug-check.sh` for more details. + +### Temporary comment checks + +Checks for comments starting with `//~` in the source tree. + +See `scripts/temporary-comments-check.sh` for more details. + +### GTK4 migration regression checks + +Checks that gtk functions for which there is a Geeqie GTK4 compatibility +function have a `gq_` prefix. + +See `scripts/gtk4-migration-regression-check.sh` for more details. + +### Untranslated text checks + +Checks for strings that haven't been marked for translation (starting with `_(`) +in the source tree. + +See `scripts/untranslated-text.sh` for more details. + +### Ancillary files checks + +Performs validation of non-source files within the project. This includes +linting of `appdata` files, `desktop` files, Markdown files, GTK UI builder +files, and shell scripts, as well as ensuring that all relevant build options +are covered in the functional test configuration. + +These checks also require `xvfb` for the GTK UI builder validator to run. + +See `scripts/test-ancillary-files.sh` for more details. diff --git a/config.h.in b/config.h.in index 48638558..d33db167 100644 --- a/config.h.in +++ b/config.h.in @@ -226,4 +226,9 @@ /* Do not use */ #mesondefine HAVE_GTK4 +/* Whether to enable a mode of Geeqie that executes unit tests instead of + running the actual app. Actually executing the unit tests _also_ requires + a command-line argument to be supplied. */ +#mesondefine ENABLE_UNIT_TESTS + #endif diff --git a/doc/meson.build b/doc/meson.build index 11e7fa35..0a797e2a 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -32,8 +32,6 @@ else summary({'help' : ['disabled - Help files created:', false]}, section : 'Documentation', bool_yn : true) endif -install_subdir(destdir, install_dir : helpdir, exclude_directories : 'lua-api/latex') - if running_from_git option = get_option('doxygen') if not option.disabled() diff --git a/meson.build b/meson.build index 9d0e1187..e9d06431 100644 --- a/meson.build +++ b/meson.build @@ -64,14 +64,6 @@ i18n = import('i18n') fs = import('fs') configuration_inc = include_directories('.') -# Extended stack trace using backward-app -option = get_option('devel') -if option.enabled() - if cc.has_link_argument('-ldwarf') - add_project_link_arguments('-ldwarf', language: 'cpp') - endif -endif - # External programs glib_compile_resources = find_program('glib-compile-resources', required : true) glib_genmarshal = find_program('glib-genmarshal', required : true) @@ -164,14 +156,19 @@ glib_dep = dependency('glib-2.0', version : '>=2.52', required: true) conf_data.set('HAVE_DEVELOPER', 0) libdw_dep = [] libunwind_dep = [] -option = get_option('devel') -if option.enabled() - libdw_dep = dependency('libdw', required : true) +option = get_option('extended_stacktrace') +if not option.disabled() + libdw_dep = dependency('libdw', required : false) if libdw_dep.found() - libunwind_dep = dependency('libunwind', required : true) + libunwind_dep = dependency('libunwind', required : false) if libunwind_dep.found() - conf_data.set('HAVE_DEVELOPER', 1) - summary({'developer mode' : ['extended stacktrace:', true]}, section : 'Debugging', bool_yn : true) + if cc.has_link_argument('-ldwarf') + add_project_link_arguments('-ldwarf', language: 'cpp') + conf_data.set('HAVE_DEVELOPER', 1) + summary({'developer mode' : ['extended stacktrace:', true]}, section : 'Debugging', bool_yn : true) + else + summary({'developer mode' : ['link argument -ldwarf not found. extended stacktrace:', false]}, section : 'Debugging', bool_yn : true) + endif else summary({'developer mode' : ['libunwind not found. extended stacktrace:', false]}, section : 'Debugging', bool_yn : true) endif @@ -200,6 +197,13 @@ else summary({'execinfo' : ['stacktrace supported:', false]}, section : 'Debugging', bool_yn : true) endif +conf_data.set('ENABLE_UNIT_TESTS', 0) +option = get_option('unit_tests') +if not option.disabled() + conf_data.set('ENABLE_UNIT_TESTS', 1) + # Summary is handled below, where the test() itself is defined. +endif + conf_data.set('HAVE_ARCHIVE', 0) libarchive_dep = [] req_version = '>=3.4.0' @@ -611,6 +615,21 @@ ui_sources = [] subdir('po') subdir('plugins') +conditional_unit_test_deps = [] +if conf_data.get('ENABLE_UNIT_TESTS', 0) == 1 + system_gtest_dep = dependency('gtest', main : false, required : false) + system_gmock_dep = dependency('gmock', required : false) + if system_gtest_dep.found() and system_gmock_dep.found() + conditional_unit_test_deps += system_gtest_dep + conditional_unit_test_deps += system_gmock_dep + else + # Use the subproject gtest as a fallback. + gtest_subproj = subproject('gtest') + conditional_unit_test_deps += gtest_subproj.get_variable('gtest_dep') + conditional_unit_test_deps += gtest_subproj.get_variable('gmock_dep') + endif +endif + # Generate the executable subdir('src') @@ -658,22 +677,24 @@ i18n.merge_file( configure_file(input: 'geeqie.spec.in', output: 'geeqie.spec', configuration: conf_data) +isolate_test_sh = find_program('isolate-test.sh', dirs : scriptsdir, required : true) + # Basic test of the executable -# is_parallel false is to avoid problems with images tests xvfb = find_program('xvfb-run', required : false) if xvfb.found() - test('Basic test', xvfb, args: ['--auto-servernum', geeqie_exe, '--version'], is_parallel : false, timeout: 100) + test_cmd = [xvfb.full_path(), '--auto-servernum', geeqie_exe.full_path(), '--version'] + test('Basic test', isolate_test_sh, args: test_cmd, timeout: 100, suite: 'functional') summary({'xvfb' : ['Test runs:', true]}, section : 'Testing', bool_yn : true) else summary({'xvfb' : ['Test runs:', false]}, section : 'Testing', bool_yn : true) endif # The tests are run on GitHub with all options disabled, and then -# Image tests use option devel as a flag so that normal users do not +# Image tests use option unit_tests as a flag so that normal users do not # download the test image database. # Image checks -option = get_option('devel') +option = get_option('unit_tests') if option.enabled() if xvfb.found() get_test_images_sh = find_program('get-test-images.sh', dirs : scriptsdir, required : true) @@ -687,15 +708,12 @@ if option.enabled() sources = sources_list.stdout().strip().split('\n') foreach image : sources - image_path = '@0@'.format(image) - path_array = image_path.split('/') + path_array = image.split('/') image_name = path_array[path_array.length() - 1] - if image_name.startswith('fail') - test('Image_ ' + image_name, image_test_sh, args: [geeqie_exe, image], is_parallel : false, should_fail : true, timeout: 100) - else - test('Image_ ' + image_name, image_test_sh, args: [geeqie_exe, image], is_parallel : false, timeout: 100) - endif + should_fail = image_name.startswith('fail') + test_cmd = [image_test_sh.full_path(), geeqie_exe.full_path(), image] + test('Image_ ' + image_name, isolate_test_sh, args: test_cmd, should_fail : should_fail, timeout: 100, suite: ['functional', 'image']) endforeach summary({'Image tests' : ['Test runs:', true]}, section : 'Testing', bool_yn : true) else @@ -716,7 +734,7 @@ if running_from_git source_file_name = fs.name(source_file) config_file = join_paths(meson.project_source_root(), '.clang-tidy') - test('Code Correctness_ ' + source_file_name, clang_tidy_exe, args : ['-p', './build', '-quiet', '--config-file', config_file, source_file], timeout : 100) + test('Code Correctness_ ' + source_file_name, clang_tidy_exe, args : ['-p', './build', '-quiet', '--config-file', config_file, source_file], timeout : 100, suite : 'analysis') endif endforeach @@ -733,7 +751,7 @@ enum_check_sh = find_program('enum-check.sh', dirs : scriptsdir, required : true if enum_check_sh.found() foreach source_file : main_sources + pan_view_sources + view_file_sources source_file_name = fs.name(source_file) - test('Single Value enum_ ' + source_file_name, enum_check_sh, args : [source_file], timeout : 100) + test('Single Value enum_ ' + source_file_name, enum_check_sh, args : [source_file], timeout : 100, suite : 'analysis') endforeach summary({'Single Value enum' : ['Test runs:', true]}, section : 'Testing', bool_yn : true) @@ -747,7 +765,7 @@ if debug_check_sh.found() foreach source_file : main_sources + pan_view_sources + view_file_sources source_file_name = fs.name(source_file) if (source_file_name != 'debug.h') - test('Debug Statements_ ' + source_file_name, debug_check_sh, args : [source_file], timeout : 100) + test('Debug Statements_ ' + source_file_name, debug_check_sh, args : [source_file], timeout : 100, suite : 'analysis') endif endforeach @@ -762,7 +780,7 @@ if tmp_comments_check_sh.found() foreach source_file : main_sources + pan_view_sources + view_file_sources source_file_name = fs.name(source_file) if (source_file_name != 'debug.h') - test('Temporary Comments_ ' + source_file_name, tmp_comments_check_sh, args : [source_file], timeout : 100) + test('Temporary Comments_ ' + source_file_name, tmp_comments_check_sh, args : [source_file], timeout : 100, suite : 'analysis') endif endforeach @@ -771,13 +789,45 @@ else summary({'Temporary Comments' : ['Test runs:', false]}, section : 'Testing', bool_yn : true) endif +# GTK4 migration regression checks +gtk4_migration_check_sh = find_program('gtk4-migration-regression-check.sh', dirs : scriptsdir, required : true) +if gtk4_migration_check_sh.found() + compat_cc = join_paths(meson.project_source_root(), 'src', 'compat.cc') + compat_h = join_paths(meson.project_source_root(), 'src', 'compat.h') + foreach source_file : main_sources + pan_view_sources + view_file_sources + source_file_name = fs.name(source_file) + if (source_file_name != 'debug.h') + test('GTK4 migration_ ' + source_file_name, gtk4_migration_check_sh, args : [source_file, compat_cc, compat_h], timeout : 100, suite : 'analysis') + endif + endforeach + + summary({'GTK4 migration' : ['Test runs:', true]}, section : 'Testing', bool_yn : true) +else + summary({'GTK4 migration' : ['Test runs:', false]}, section : 'Testing', bool_yn : true) +endif + +# Untranslated text checks +untranslated_text_sh = find_program('untranslated-text.sh', dirs : scriptsdir, required : true) +if untranslated_text_sh.found() + foreach source_file : main_sources + pan_view_sources + view_file_sources + if fs.name(source_file).endswith('.cc') + source_file_name = fs.name(source_file) + test('Untranslated Text_ ' + source_file_name, untranslated_text_sh, args : [source_file], timeout : 200, suite : 'analysis') + endif + endforeach + + summary({'Untranslated Text' : ['Test runs:', true]}, section : 'Testing', bool_yn : true) +else + summary({'Untranslated Text' : ['Test runs:', false]}, section : 'Testing', bool_yn : true) +endif + # Lua test option = get_option('lua') if not option.disabled() if lua_dep.found() if xvfb.found() lua_test_sh = find_program('lua-test.sh', dirs : scriptsdir, required : true) - test('Lua test', lua_test_sh, args: [geeqie_exe], is_parallel : false, timeout: 100) + test('Lua test', isolate_test_sh, args: [lua_test_sh.full_path(), geeqie_exe.full_path()], timeout: 100, suite : 'analysis') summary({'lua' : ['Test runs:', true]}, section : 'Testing', bool_yn : true) else @@ -792,6 +842,14 @@ endif # Ancillary files test test_ancillary_files_sh = find_program('test-ancillary-files.sh', dirs : scriptsdir, required : true) -test('Ancillary files', test_ancillary_files_sh, args: [meson.current_source_dir()], timeout: 100) +test('Ancillary files', test_ancillary_files_sh, args: [meson.current_source_dir()], timeout: 100, suite : 'analysis') summary({'Ancillary files' : ['Test runs:', true]}, section : 'Testing', bool_yn : true) + +# Unit tests +if conf_data.get('ENABLE_UNIT_TESTS', 0) == 1 + test('Unit tests', isolate_test_sh, args: [geeqie_exe.full_path(), '--run-unit-tests'], suite : 'unit') + summary({'unit_tests' : ['Tests run:', true]}, section : 'Testing', bool_yn : true) +else + summary({'unit_tests' : ['Tests run:', false]}, section : 'Testing', bool_yn : true) +endif diff --git a/meson_options.txt b/meson_options.txt index 9bc8508a..eadbd628 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -25,12 +25,12 @@ option('gq_localedir', type : 'string', value : '', description : 'Location wher option('archive', type : 'feature', value : 'auto', description : 'archive files e.g. zip, gz') option('cms', type : 'feature', value : 'auto', description : 'color management system') -option('devel', type : 'feature', value : 'disabled', description : 'developer mode') option('doxygen', type : 'feature', value : 'auto', description : 'lua api help file') option('djvu', type : 'feature', value : 'auto', description : 'djvu') option('evince', type : 'feature', value : 'auto', description : 'print preview') option('execinfo', type : 'feature', value : 'auto', description : 'execinfo.h') option('exiv2', type : 'feature', value : 'auto', description : 'exiv2') +option('extended_stacktrace', type : 'feature', value : 'auto', description : 'extended stacktrace') option('git', type : 'feature', value : 'auto', description : 'lua-api and changelog.html') option('gps-map', type : 'feature', value : 'auto', description : 'gps map') option('gtk4', type : 'feature', value : 'disabled', description : 'gtk4 - do not use') @@ -44,6 +44,7 @@ option('pandoc', type : 'feature', value : 'auto', description : 'README.html') option('pdf', type : 'feature', value : 'auto', description : 'pdf') option('spell', type : 'feature', value : 'auto', description : 'spelling checks') option('tiff', type : 'feature', value : 'auto', description : 'tiff') +option('unit_tests', type : 'feature', value : 'disabled', description : 'unit tests') option('videothumbnailer', type : 'feature', value : 'auto', description : 'video thumbnailer') option('webp', type : 'feature', value : 'auto', description : 'webp') option('yelp-build', type : 'feature', value : 'auto', description : 'help files') diff --git a/plugins/export-jpeg/geeqie-export-jpeg b/plugins/export-jpeg/geeqie-export-jpeg index cf83ca54..628aee48 100755 --- a/plugins/export-jpeg/geeqie-export-jpeg +++ b/plugins/export-jpeg/geeqie-export-jpeg @@ -229,5 +229,5 @@ then fi fi - geeqie --remote view:"$tmpdir/" + geeqie --remote --view="$tmpdir/" fi diff --git a/plugins/image-crop/geeqie-image-crop b/plugins/image-crop/geeqie-image-crop index 23711ddb..33aa6cf8 100755 --- a/plugins/image-crop/geeqie-image-crop +++ b/plugins/image-crop/geeqie-image-crop @@ -28,7 +28,7 @@ process_raw () rm "$tmpdir/$src_filename" - geeqie --remote view:"$tmpdir/$filename-crop.$extension" + geeqie --remote --view="$tmpdir/$filename-crop.$extension" res=0 else res=1 @@ -49,7 +49,7 @@ process_plain () then zenity --error --title="$title" --text="Cannot process this file format" --width="$width" --window-icon="$window_icon" else - geeqie --remote view:"$tmpdir/$filename-crop.$extension" + geeqie --remote --view="$tmpdir/$filename-crop.$extension" fi } diff --git a/plugins/random-image/geeqie-random-image b/plugins/random-image/geeqie-random-image index 8f221f29..e802c43e 100755 --- a/plugins/random-image/geeqie-random-image +++ b/plugins/random-image/geeqie-random-image @@ -13,7 +13,7 @@ collection_list=$(geeqie --remote --get-collection-list) for collection_name in $collection_list do - collection_file_list=$(geeqie --remote --get-collection:"$collection_name") + collection_file_list=$(geeqie --remote --get-collection="$collection_name") for collection_file in $collection_file_list do list="${list:+${list}}\n${collection_file}" @@ -21,7 +21,7 @@ do done # get list of images in current folder -file_list=$(geeqie --remote --get-filelist:) +file_list=$(geeqie --remote --get-filelist=) for file_name in $file_list do @@ -61,4 +61,4 @@ then display_image=$(printf '%b' "$files_no_spaces" | sort --uniq | shuf -n 1) fi -geeqie --remote file:"$display_image" +geeqie --remote file="$display_image" diff --git a/plugins/rotate/geeqie-rotate b/plugins/rotate/geeqie-rotate index 0430130a..703ba91c 100755 --- a/plugins/rotate/geeqie-rotate +++ b/plugins/rotate/geeqie-rotate @@ -10,7 +10,7 @@ GQ_METADATA_DIR="$HOME/.local/share/geeqie/metadata" gq_exiftran() { - if ! [ -x "$(command -v exiftranx)" ] + if ! [ -x "$(command -v exiftran)" ] then zenity --title="Geeqie rotate" --info --width=200 --text="Exiftran is not installed" --window-icon=/usr/local/share/pixmaps/geeqie.png 2> /dev/null exit 0 @@ -21,7 +21,7 @@ gq_exiftran() gq_exiv2() { - if ! [ -x "$(command -v exiv2x)" ] + if ! [ -x "$(command -v exiv2)" ] then zenity --title="Geeqie rotate" --info --width=200 --text="Exiv2 is not installed" --window-icon=/usr/local/share/pixmaps/geeqie.png 2> /dev/null exit 0 @@ -32,7 +32,7 @@ gq_exiv2() gq_mogrify() { - if ! [ -x "$(command -v mogrifyx)" ] + if ! [ -x "$(command -v mogrify)" ] then zenity --title="Geeqie rotate" --info --width=200 --text="ImageMagick is not installed" --window-icon=/usr/local/share/pixmaps/geeqie.png 2> /dev/null exit 0 @@ -216,7 +216,7 @@ do then # we got only one file for each group, typically the main one # get the sidecars: - geeqie -r --get-sidecars:"$file" | while read -r sidecar + geeqie --remote --get-sidecars="$file" | while read -r sidecar do # the main file is included in the sidecar file list, no special handling is required [ ! -w "$sidecar" ] && exit 5 diff --git a/po/meson.build b/po/meson.build index f6801e42..edbe339a 100644 --- a/po/meson.build +++ b/po/meson.build @@ -57,16 +57,11 @@ po_sources = files([ 'zh_TW.po' ]) -po_source_list = '' -foreach name : po_sources - po_source_list = po_source_list + meson.project_source_root() + '/' + '@0@'.format(name) + '\n' -endforeach - translators_sh = join_paths(scriptsdir, 'translators.sh') translator_resources = custom_target('translator_resources', input : ['locales.txt', 'translators.gresource.xml'], output : ['translators.h', 'translators.c'], - command : [translators_sh, '@PRIVATE_DIR@', po_source_list, meson.current_build_dir() , '@INPUT0@', '@INPUT1@']) + command : [translators_sh, '@PRIVATE_DIR@', meson.current_source_dir(), meson.current_build_dir() , '@INPUT0@', '@INPUT1@', po_sources]) project_sources += translator_resources diff --git a/scripts/clang-tidy-check.sh b/scripts/clang-tidy-check.sh index 04129765..474a1a71 100755 --- a/scripts/clang-tidy-check.sh +++ b/scripts/clang-tidy-check.sh @@ -98,6 +98,11 @@ done if [ ! -d "build" ] then meson setup build +else + if [ ! -d "build/test-images.p" ] + then + printf 'Warning: Probably all options are not enabled\n\n' + fi fi ninja -C build diff --git a/scripts/gtk4-migration-regression-check.sh b/scripts/gtk4-migration-regression-check.sh new file mode 100755 index 00000000..6546d6d1 --- /dev/null +++ b/scripts/gtk4-migration-regression-check.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +#********************************************************************** +# Copyright (C) 2024 - The Geeqie Team +# +# Author: Colin Clark +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +#********************************************************************** + +## @file +## @brief Look for function calls that do not conform to GTK4 migration format +## +## The files compat.cc and compat.h contain functions that should be used instead +## of the standard GTK calls. The compatibility calls are all prefixed by gq_ +## +## Create a list of function names to be looked for by searching +## compat.cc and compat.h for identifiers prefixed by gq_gtk_ +## +## Search the input file for any of the above gtk_ function names that +## are not prefixed by gq_ +## +## $1 full path to file to process +## $2 full path to compat.cc +## $3 full path to compat.h +## + +exit_status=0 + +if [ ! "${1#*compat.cc}" = "$1" ] +then + exit "$exit_status" +fi + +if [ ! "${1#*compat.h}" = "$1" ] +then + exit "$exit_status" +fi + +compat_functions=$(grep --only-matching --no-filename 'gq_gtk_\(\(\([[:alnum:]]*\)\_*\)*\)' "$2" "$3" | sort | uniq | cut --characters 4-) + +while read -r line +do + if grep --line-number --perl-regexp '(?/dev/null 2>&1 then - rm "$config_home/geeqie/.command" exit 1 fi -result=$(xvfb-run --auto-servernum "$1" --remote --get-file-info) -xvfb-run --auto-servernum "$1" --remote --quit +result=$(xvfb-run --auto-servernum "$geeqie_exe" --remote --get-file-info) + +## Teardown: various increasingly-forceful attempts to kill the running geeqie process. +xvfb-run --auto-servernum "$geeqie_exe" --remote --quit + +sleep 1 + +if ps "$xvfb_pid" >/dev/null 2>&1 +then + echo "Quit command for xvfb geeqie failed for pid ${xvfb_pid}; sending sigterm" >&2 + kill -TERM "$xvfb_pid" + + sleep 1 + if ps "$xvfb_pid" >/dev/null 2>&1 + then + echo "kill -TERM failed to stop pid ${xvfb_pid}; sending sigkill" >&2 + kill -KILL "$xvfb_pid" + fi +fi if echo "$result" | grep -q "Class: Unknown" then @@ -60,4 +83,3 @@ then else exit 0 fi - diff --git a/scripts/isolate-test.sh b/scripts/isolate-test.sh new file mode 100755 index 00000000..c034a52a --- /dev/null +++ b/scripts/isolate-test.sh @@ -0,0 +1,64 @@ +#!/bin/sh +#********************************************************************** +# Copyright (C) 2024 - The Geeqie Team +# +# Author: Omari Stephens +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +#********************************************************************** + +## @file +## @brief Isolates the test from the rest of the environment. The goal is to +## make the test more reliable, and to avoid interrupting other processes +## that might be running on the host. Passes all args through and passes +## the return code back. +## +## $1 Test executable +## +## + +set -e + +TEST_HOME=$(mktemp -d) + +if [ -z "$TEST_HOME" ]; then + echo "Failed to create temporary home directory." >&2 + exit 1 +fi + +if [ "$TEST_HOME" = "$HOME" ]; then + # This both breaks isolation, and makes automatic cleanup extremely dangerous. + echo "Temporary homedir ($TEST_HOME) is the same as the actual homedir ($HOME)" >&2 + exit 1 +fi + +# Automatically clean up the temporary home directory on exit. +teardown() { + # echo "Cleaning up temporary homedir $TEST_HOME" >&2 + rm -rf "$TEST_HOME" +} +trap teardown EXIT + +export HOME="$TEST_HOME" +export XDG_CONFIG_HOME="${HOME}/.config" + +# Change to temporary homedir and ensure that XDG_CONFIG_HOME exists. +cd +mkdir -p "$XDG_CONFIG_HOME" + +# This will automatically pass the command name and args in the expected order. +# And `set -e` (above) means that we'll automatically exit with the same return +# code as our sub-command. +env -i HOME="$HOME" XDG_CONFIG_HOME="$XDG_CONFIG_HOME" "$@" diff --git a/scripts/lua-test.sh b/scripts/lua-test.sh index 37d94f4e..5b953e80 100755 --- a/scripts/lua-test.sh +++ b/scripts/lua-test.sh @@ -27,6 +27,8 @@ ## Create a basic image and run all lua built-in functions on it. ## The image file and the Lua test file are created within this script. +geeqie_exe="$1" + if [ -z "$XDG_CONFIG_HOME" ] then config_home="$HOME/.config" @@ -58,7 +60,7 @@ return ret " printf "%s" "$lua_test" > "$lua_test_file" -xvfb-run --auto-servernum "$1" & +xvfb-run --auto-servernum "$geeqie_exe" & # Wait for remote to initialize while [ ! -e "$config_home/geeqie/.command" ] ; @@ -69,8 +71,8 @@ done sleep 2 base_lua=$(basename "$lua_test_file") -result=$(xvfb-run --auto-servernum "$1" --remote --lua="$lua_test_image","$base_lua") -xvfb-run --auto-servernum "$1" --remote --quit +result=$(xvfb-run --auto-servernum "$geeqie_exe" --remote --lua="$lua_test_image","$base_lua") +xvfb-run --auto-servernum "$geeqie_exe" --remote --quit ## @FIXME Running on GitHub gives additional dbind-WARNINGs. The data required is the last n lines. result_tail=$(printf "%s" "$result" | tail --lines=7) diff --git a/scripts/test-all.sh b/scripts/test-all.sh index 4d87a021..a7c6b851 100755 --- a/scripts/test-all.sh +++ b/scripts/test-all.sh @@ -40,17 +40,18 @@ export XDG_CACHE_HOME export XDG_DATA_HOME rm --recursive --force build +tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/geeqie.XXXXXXXXXX") # Check with all options disabled meson setup \ -Darchive=disabled \ -Dcms=disabled \ --Ddevel=disabled \ -Ddoxygen=disabled \ -Ddjvu=disabled \ -Devince=disabled \ -Dexecinfo=disabled \ -Dexiv2=disabled \ +-Dextended_stacktrace=disabled \ -Dgit=disabled \ -Dgps-map=disabled \ -Dgtk4=disabled \ @@ -64,6 +65,7 @@ meson setup \ -Dpdf=disabled \ -Dspell=disabled \ -Dtiff=disabled \ +-Dunit_tests=disabled \ -Dvideothumbnailer=disabled \ -Dwebp=disabled \ -Dyelp-build=disabled \ @@ -71,17 +73,20 @@ build meson test -C build -tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/geeqie.XXXXXXXXXX") -cp ./build/meson-logs/testlog.txt "$tmpdir/testlog-options-disabled.txt" +cp ./build/meson-logs/meson-log.txt "$tmpdir/testlog-options-disabled.txt" +cat ./build/meson-logs/testlog.txt >> "$tmpdir/testlog-options-disabled.txt" rm --recursive --force build - -meson setup -Ddevel=enabled build - +meson setup -Dunit_tests=enabled build meson test -C build -cp ./build/meson-logs/testlog.txt "$tmpdir/testlog-options-enabled.txt" +cp ./build/meson-logs/meson-log.txt "$tmpdir/testlog-options-enabled.txt" +cat ./build/meson-logs/testlog.txt >> "$tmpdir/testlog-options-enabled.txt" rm -r "$XDG_CONFIG_HOME" rm -r "$XDG_CACHE_HOME" rm -r "$XDG_DATA_HOME" + +printf "\n%s" "$tmpdir/testlog-options-disabled.txt" +printf "\n%s\n" "$tmpdir/testlog-options-enabled.txt" + diff --git a/scripts/test-ancillary-files.sh b/scripts/test-ancillary-files.sh index c15cf3f9..1650e382 100755 --- a/scripts/test-ancillary-files.sh +++ b/scripts/test-ancillary-files.sh @@ -42,11 +42,28 @@ fi exit_status=0 +# All script files must be POSIX +# downsize is a third-party file and is excluded +while read -r file +do + result=$(file "$file" | grep "shell script") + + if [ -n "$result" ] + then + if [ "${result#*"POSIX"}" = "$result" ] + then + printf "ERROR; Executable script is not POSIX: %s\n" "$file" + exit_status=1 + fi + fi +done << EOF +$(find "$1/plugins" "$1/src" "$1/scripts" -type f -not -name downsize -executable) +EOF + # Script files must have the file extension .sh or # be symlinked as so - for doxygen while read -r file do - #~ check_sh result=$(file "$file" | grep "POSIX shell script") if [ -n "$result" ] @@ -123,7 +140,7 @@ then fi fi done << EOF -$(find . -not -path "*/.*" -name "*.md" -exec mdl --no-verbose --config .mdlrc {} \;) +$(find . -not -path "*/.*" -not -path "*/subprojects/*" -name "*.md" -exec mdl --no-verbose --config .mdlrc {} \;) EOF fi fi @@ -149,7 +166,7 @@ then fi fi done << EOF -$(find . -name "*.sh") +$(find . -name "*.sh" -not -path "./subprojects/*") EOF fi fi diff --git a/scripts/translators.sh b/scripts/translators.sh index 35fb43fb..8ea6cedb 100755 --- a/scripts/translators.sh +++ b/scripts/translators.sh @@ -25,10 +25,11 @@ ## The lists will be displayed in the About - Credits dialog. ## ## $1 Meson PRIVATE_DIR \n -## $2 po source list \n +## $2 Meson current_source_dir \n ## $3 Meson current_build_dir \n ## $4 locales.txt \n ## $5 gresource.xml \n +## $6...$n po source list - space separated list \n ## ## It is expected that the .po files have a list of translators in the form: \n ## \# Translators: \n @@ -37,14 +38,25 @@ ## \# mkdir -p "$1" +private_dir="$1" +shift +source_dir="$1" +shift +build_dir="$1" +shift +locales="$1" +shift +resource_xml="$1" +shift -printf %s "$2" | while read -r file +while [ -n "$1" ] do - base=$(basename "$file") + base=$(basename "$1") + full_file_path="$source_dir/$1" locale=${base%.po} printf "\n" - awk '$1 == "'"$locale"'" {print $0}' "$4" + awk '$1 == "'"$locale"'" {print $0}' "$locales" awk '$0 ~/Translators:/ { while (1) { getline $0 @@ -56,10 +68,11 @@ do } } print $0 - }' "$file" + }' "$full_file_path" -done > "$1"/translators -printf "\n\0" >> "$1"/translators +shift +done > "$private_dir"/translators +printf "\n\0" >> "$private_dir"/translators -glib-compile-resources --generate-header --sourcedir="$1" --target="$3"/translators.h "$5" -glib-compile-resources --generate-source --sourcedir="$1" --target="$3"/translators.c "$5" +glib-compile-resources --generate-header --sourcedir="$private_dir" --target="$build_dir"/translators.h "$resource_xml" +glib-compile-resources --generate-source --sourcedir="$private_dir" --target="$build_dir"/translators.c "$resource_xml" diff --git a/scripts/untranslated-text.sh b/scripts/untranslated-text.sh index a1587c78..ef6ef93e 100755 --- a/scripts/untranslated-text.sh +++ b/scripts/untranslated-text.sh @@ -1,18 +1,253 @@ #!/bin/sh +#********************************************************************** +# Copyright (C) 2024 - The Geeqie Team +# +# Author: Colin Clark +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +#********************************************************************** + ## @file ## @brief Locate strings not marked for translation ## -## Checks all .c files under ./src +## The check is not comprehensive - the exclusions make this +## of limited value. +## +## @FIXME Strings starting with a space, or a lower-case alpha +## or if there is more than one string per line, are not +## checked for. +## +## The regex search is for a character sequence: \n +## double quotes \n +## upper-case alpha character \n +## alpha character or space \n +## printable character \n +## previous character type repeated one or more times \n +## double quotes +## +## The above sequence preceded by "_(" will not be a hit. ## -## The check is not comprehensive - some errors are not detected -## and there are some false hits. +## $1 file to process ## -for file in src/*.cc src/view-file/*.cc +omit_text_array=" + msg +#define +#include +< +@brief +@param +COPYRIGHT +ColorSpace +DEBUG +Damien +ERR +EXIF +Error +Exif\. +FIXME +ImageLoaderType +LUA_ +MonoSpace +N_( +NikonTag +Pause +PixbufRenderer +PluginsMenu +READ_ +Separator +WRITE_ +Wrap +\"Desktop\" +\"Layout\" +\"OK\" +\"Xmp\. +\.html +\/\* +\/\/ +\{\" +_attribute +action_group +courier +exif_get_item +filter_add_if_missing +font_name +g_ascii_strcasecmp +g_build_filename +g_critical +g_key_file_get_ +g_message +g_object +g_signal +g_str_has_suffix +g_strstr_len +g_themed_icon_new +g_warning +getenv +gtk_action_group_get_action +gtk_container_child_get +gtk_widget_add_accelerator +layout_actions +layout_toolbar_add +luaL_ +lua_ +memcmp +mouse_button_ +options-> +osd_template_insert +pango_attr +path_to_utf8 +primaries_name +print_term +printf +return g_strdup +runcmd +setenv +signal_ +signals_ +strcmp +strncmp +trc_name +website-label +write_char_option + +##cellrendericon.cc +\"Background color as a GdkRGBA\"\, +\"Background color\"\, +\"Background set\"\, +\"Draw focus indicator\"\, +\"Fixed height\"\, +\"Fixed width\"\, +\"Focus\"\, +\"Foreground color as a GdkRGBA\"\, +\"Foreground color\"\, +\"Foreground set\"\, +\"GQvCellRendererIcon\"\, +\"Height of icon excluding text\"\, +\"Marks bit array\"\, +\"Marks\"\, +\"Number of marks\"\, +\"Pixbuf Object\"\, +\"Show marks\"\, +\"Show text\"\, +\"Text to render\"\, +\"Text\"\, +\"The pixbuf to render\"\, +\"Toggled mark\"\, +\"Whether the marks are displayed\"\, +\"Whether the text is displayed\"\, +\"Whether this tag affects the background color\"\, +\"Whether this tag affects the foreground color\"\, +\"Width of cell\"\, + +##pixbuf-renderer.cc +\"Delay image update\"\, +\"Display cache size MiB\"\, +\"Expand image in autozoom.\"\, +\"Fit window to image size\"\, +\"Image actively loading\"\, +\"Image rendering complete\"\, +\"Limit size of image when autofitting\"\, +\"Limit size of parent window\"\, +\"New image scroll reset\"\, +\"Number of tiles to retain in memory at any one time.\"\, +\"Size increase limit of image when autofitting\"\, +\"Size limit of image when autofitting\"\, +\"Size limit of parent window\"\, +\"Tile cache count\"\, +\"Zoom maximum\"\, +\"Zoom minimum\"\, +\"Zoom quality\"\, + +##print.cc +G_CALLBACK(print_set_font_cb)\, const_cast(\"Image text font\")); +G_CALLBACK(print_set_font_cb)\, const_cast(\"Page text font\")); + +##remote.cc +render_intent = g_strdup(\"Absolute Colorimetric\"); +render_intent = g_strdup(\"Absolute Colorimetric\"); +render_intent = g_strdup(\"Perceptual\"); +render_intent = g_strdup(\"Relative Colorimetric\"); +render_intent = g_strdup(\"Saturation\"); +" + +exclude_files_array=" +exif.cc +format-canon.cc +format-fuji.cc +format-nikon.cc +format-olympus.cc +keymap-template.cc +" + +filename_printed="no" + +omit="FILE_OK" +while read -r omit_file do - for search_text in "label" "menu_item_add" "tooltip" "_button" "_text" + if [ -n "$omit_file" ] + then + if echo "$1" | grep --quiet "$omit_file" + then + omit="omit" + fi + fi +done << EOF +$exclude_files_array +EOF + +if [ "$omit" = "FILE_OK" ] +then + while read -r infile_line do - cat -n "$file" | grep --extended-regexp --ignore-case "$search_text.*\(\"" | grep --invert-match "_(" | grep --invert-match "(\"\")" && printf '%s\n\n' "$file" - done -done + if [ -n "$infile_line" ] + then + omit="LINE_NOT_OK" + while read -r omit_text + do + if [ -n "$omit_text" ] + then + if echo "$infile_line" | grep --quiet "$omit_text" + then + omit="omit" + fi + fi + done << EOF +$omit_text_array +EOF + if [ "$omit" = "LINE_NOT_OK" ] + then + if [ "$filename_printed" = "no" ] + then + printf "\nfile: %s\n" "$1" + filename_printed="yes" + fi + + no_tabs=$(echo "$infile_line" | tr -s '\t') + printf "line: %s\n" "$no_tabs" + fi + fi + done << EOF +$(cat --number "$1" | grep --perl-regexp '(?(list->data)) == 0) return TRUE; - list = list->next; - } - - return FALSE; + return g_list_find_custom(history_list_get_by_key("exif_extras"), name, reinterpret_cast(strcmp)) ? TRUE : FALSE; } static void advanced_exif_update(ExifWin *ew) @@ -407,6 +398,8 @@ static gboolean advanced_exif_keypress(GtkWidget *, GdkEventKey *event, gpointer advanced_exif_close(ew); stop_signal = TRUE; break; + default: + break; } } // if (event->state & GDK_CONTROL... if (!stop_signal && is_help_key(event)) diff --git a/src/bar-gps.cc b/src/bar-gps.cc index bce37f2c..5e09c4dc 100644 --- a/src/bar-gps.cc +++ b/src/bar-gps.cc @@ -979,7 +979,7 @@ GtkWidget *bar_pane_gps_new(const gchar *id, const gchar *title, const gchar *ma view = gtk_champlain_embed_get_view(GTK_CHAMPLAIN_EMBED(gpswidget)); gq_gtk_box_pack_start(GTK_BOX(vbox), gpswidget, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(frame), vbox); + gq_gtk_container_add(GTK_WIDGET(frame), vbox); status = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0); #if HAVE_GTK4 diff --git a/src/bar-keywords.cc b/src/bar-keywords.cc index 5cc9315f..2225ddbe 100644 --- a/src/bar-keywords.cc +++ b/src/bar-keywords.cc @@ -420,6 +420,8 @@ void bar_pane_keywords_filter_modify(GtkTreeModel *model, GtkTreeIter *iter, GVa case FILTER_KEYWORD_COLUMN_IS_KEYWORD: gtk_tree_model_get_value(keyword_tree, &child_iter, KEYWORD_COLUMN_IS_KEYWORD, value); break; + default: + break; } } diff --git a/src/cache-maint.cc b/src/cache-maint.cc index 3d28d731..7cfcc8d4 100644 --- a/src/cache-maint.cc +++ b/src/cache-maint.cc @@ -1527,7 +1527,7 @@ static void cache_manager_sim_start_cb(GenericDialog *, gpointer data) g_list_free(list_total); cd->count_done = 0; - while (cache_manager_sim_file(static_cast(cd))); + while (cache_manager_sim_file(cd)); } g_free(path); diff --git a/src/collect-io.cc b/src/collect-io.cc index 656cce0d..994ac447 100644 --- a/src/collect-io.cc +++ b/src/collect-io.cc @@ -693,22 +693,14 @@ static void collect_manager_entry_reset(CollectManagerEntry *entry) static CollectManagerEntry *collect_manager_get_entry(const gchar *path) { - GList *work; + const auto collect_manager_entry_compare_path = [](gconstpointer data, gconstpointer user_data) + { + return strcmp(static_cast(data)->path, static_cast(user_data)); + }; - work = collection_manager_entry_list; - while (work) - { - CollectManagerEntry *entry; - - entry = static_cast(work->data); - work = work->next; - if (strcmp(entry->path, path) == 0) - { - return entry; - } - } - return nullptr; + GList *work = g_list_find_custom(collection_manager_entry_list, path, collect_manager_entry_compare_path); + return work ? static_cast(work->data) : nullptr; } static void collect_manager_entry_add_action(CollectManagerEntry *entry, CollectManagerAction *action) @@ -1104,14 +1096,6 @@ void collect_manager_notify_cb(FileData *fd, NotifyType type, gpointer) } } -static gint collection_manager_sort_cb(gconstpointer a, gconstpointer b) -{ - auto char_a = static_cast(a); - auto char_b = static_cast(b); - - return g_strcmp0(char_a, char_b); -} - /** * @brief Creates sorted list of collections * @param[out] names_exc sorted list of collections names excluding extension @@ -1150,19 +1134,19 @@ void collect_manager_list(GList **names_exc, GList **names_inc, GList **paths) if (names_exc != nullptr) { *names_exc = g_list_insert_sorted(*names_exc, g_strdup(name), - collection_manager_sort_cb); + reinterpret_cast(g_strcmp0)); *names_exc = g_list_first(*names_exc); } if (names_inc != nullptr) { *names_inc = g_list_insert_sorted(*names_inc,filename, - collection_manager_sort_cb); + reinterpret_cast(g_strcmp0)); *names_inc = g_list_first(*names_inc); } if (paths != nullptr) { *paths = g_list_insert_sorted(*paths, g_strdup(fd->path), - collection_manager_sort_cb); + reinterpret_cast(g_strcmp0)); *paths = g_list_first(*paths); } g_free(name); diff --git a/src/collect-table.cc b/src/collect-table.cc index ee39fb90..41d2c1bb 100644 --- a/src/collect-table.cc +++ b/src/collect-table.cc @@ -2259,7 +2259,7 @@ static GtkWidget *collection_table_drop_menu(CollectTable *ct) g_signal_connect(G_OBJECT(menu), "destroy", G_CALLBACK(collection_table_popup_destroy_cb), ct); - menu_item_add_stock(menu, _("Dropped list includes folders."), GQ_ICON_DND, nullptr, nullptr); + menu_item_add_icon(menu, _("Dropped list includes folders."), GQ_ICON_DIRECTORY, nullptr, nullptr); menu_item_add_divider(menu); menu_item_add_icon(menu, _("_Add contents"), GQ_ICON_OK, G_CALLBACK(confirm_dir_list_add), ct); diff --git a/src/collect.cc b/src/collect.cc index 5b9a62fd..ae2141a1 100644 --- a/src/collect.cc +++ b/src/collect.cc @@ -321,19 +321,15 @@ CollectWindow *collection_window_find(CollectionData *cd) CollectWindow *collection_window_find_by_path(const gchar *path) { - GList *work; - if (!path) return nullptr; - work = collection_window_list; - while (work) - { - auto cw = static_cast(work->data); - if (cw->cd->path && strcmp(cw->cd->path, path) == 0) return cw; - work = work->next; - } + const auto collect_window_compare_data_path = [](gconstpointer data, gconstpointer user_data) + { + return g_strcmp0(static_cast(data)->cd->path, static_cast(user_data)); + }; - return nullptr; + GList *work = g_list_find_custom(collection_window_list, path, collect_window_compare_data_path); + return work ? static_cast(work->data) : nullptr; } /** diff --git a/src/compat.h b/src/compat.h index 11471337..477c1e41 100644 --- a/src/compat.h +++ b/src/compat.h @@ -21,6 +21,7 @@ #ifndef COMPAT_H #define COMPAT_H +#include #include #include @@ -44,8 +45,6 @@ #define gq_gtk_window_move(window, x, y) ; #define gq_gtk_window_set_keep_above(window, setting) ; #define gq_gtk_window_set_position(window, position) ; - - void gq_gtk_container_add(GtkWidget *container, GtkWidget *widget); #else #define gq_gtk_box_pack_end(box, child, expand, fill, padding) gtk_box_pack_end(box, child, expand, fill, padding) #define gq_gtk_box_pack_start(box, child, expand, fill, padding) gtk_box_pack_start(box, child, expand, fill, padding) @@ -58,9 +57,49 @@ #define gq_gtk_window_move(window, x, y) gtk_window_move(window, x, y) #define gq_gtk_window_set_keep_above(window, setting) gtk_window_set_keep_above(window, setting) #define gq_gtk_window_set_position(window, position) gtk_window_set_position(window, position) - - void gq_gtk_container_add(GtkWidget *container, GtkWidget *widget); #endif +void gq_gtk_container_add(GtkWidget *container, GtkWidget *widget); + +// Hide GtkAction deprecation warnings +// @todo Remove after porting to GAction/GMenu +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +inline gboolean GQ_GTK_IS_RADIO_ACTION(GtkAction *action) { return GTK_IS_RADIO_ACTION(action); } +inline gboolean GQ_GTK_IS_TOGGLE_ACTION(GtkAction *action) { return GTK_IS_TOGGLE_ACTION(action); } +const auto gq_gtk_action_activate = gtk_action_activate; +const auto gq_gtk_action_create_icon = gtk_action_create_icon; +const auto gq_gtk_action_get_accel_path = gtk_action_get_accel_path; +const auto gq_gtk_action_get_icon_name = gtk_action_get_icon_name; +const auto gq_gtk_action_get_name = gtk_action_get_name; +const auto gq_gtk_action_get_stock_id = gtk_action_get_stock_id; +const auto gq_gtk_action_get_tooltip = gtk_action_get_tooltip; +const auto gq_gtk_action_set_sensitive = gtk_action_set_sensitive; +const auto gq_gtk_action_set_visible = gtk_action_set_visible; +const auto gq_gtk_action_group_add_actions = gtk_action_group_add_actions; +const auto gq_gtk_action_group_add_radio_actions = gtk_action_group_add_radio_actions; +const auto gq_gtk_action_group_add_toggle_actions = gtk_action_group_add_toggle_actions; +const auto gq_gtk_action_group_get_action = gtk_action_group_get_action; +const auto gq_gtk_action_group_list_actions = gtk_action_group_list_actions; +const auto gq_gtk_action_group_new = gtk_action_group_new; +const auto gq_gtk_action_group_set_translate_func = gtk_action_group_set_translate_func; +const auto gq_gtk_radio_action_get_current_value = gtk_radio_action_get_current_value; +const auto gq_gtk_radio_action_set_current_value = gtk_radio_action_set_current_value; +const auto gq_gtk_toggle_action_get_active = gtk_toggle_action_get_active; +const auto gq_gtk_toggle_action_set_active = gtk_toggle_action_set_active; +const auto gq_gtk_ui_manager_add_ui = gtk_ui_manager_add_ui; +const auto gq_gtk_ui_manager_add_ui_from_resource = gtk_ui_manager_add_ui_from_resource; +const auto gq_gtk_ui_manager_add_ui_from_string = gtk_ui_manager_add_ui_from_string; +const auto gq_gtk_ui_manager_ensure_update = gtk_ui_manager_ensure_update; +const auto gq_gtk_ui_manager_get_accel_group = gtk_ui_manager_get_accel_group; +const auto gq_gtk_ui_manager_get_action_groups = gtk_ui_manager_get_action_groups; +const auto gq_gtk_ui_manager_get_widget = gtk_ui_manager_get_widget; +const auto gq_gtk_ui_manager_insert_action_group = gtk_ui_manager_insert_action_group; +const auto gq_gtk_ui_manager_new = gtk_ui_manager_new; +const auto gq_gtk_ui_manager_new_merge_id = gtk_ui_manager_new_merge_id; +const auto gq_gtk_ui_manager_remove_action_group = gtk_ui_manager_remove_action_group; +const auto gq_gtk_ui_manager_remove_ui = gtk_ui_manager_remove_ui; +const auto gq_gtk_ui_manager_set_add_tearoffs = gtk_ui_manager_set_add_tearoffs; +G_GNUC_END_IGNORE_DEPRECATIONS + #endif /* COMPAT_H */ /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/src/dupe.cc b/src/dupe.cc index 68e553f6..a918f460 100644 --- a/src/dupe.cc +++ b/src/dupe.cc @@ -4529,6 +4529,8 @@ static gint column_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, case DUPE_COLUMN_PATH: ret = utf8_compare(di_a->fd->path, di_b->fd->path, TRUE); break; + default: + break; } } else if (group_a < group_b) @@ -4737,7 +4739,7 @@ DupeWindow *dupe_window_new() dw->controls_box = controls_box; dw->button_thumbs = gtk_check_button_new_with_label(_("Thumbnails")); - gtk_widget_set_tooltip_text(GTK_WIDGET(dw->button_thumbs), "Ctrl-T"); + gtk_widget_set_tooltip_text(GTK_WIDGET(dw->button_thumbs), _("Ctrl-T")); dw->show_thumbs = options->duplicates_thumbnails; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dw->button_thumbs), dw->show_thumbs); g_signal_connect(G_OBJECT(dw->button_thumbs), "toggled", @@ -4757,7 +4759,7 @@ DupeWindow *dupe_window_new() gq_gtk_box_pack_start(GTK_BOX(controls_box), label, FALSE, FALSE, PREF_PAD_SPACE); gtk_widget_show(label); dw->custom_threshold = gtk_spin_button_new_with_range(1, 100, 1); - gtk_widget_set_tooltip_text(GTK_WIDGET(dw->custom_threshold), "Custom similarity threshold\n(Use tab key to set value)"); + gtk_widget_set_tooltip_text(GTK_WIDGET(dw->custom_threshold), _("Custom similarity threshold\n(Use tab key to set value)")); gtk_spin_button_set_value(GTK_SPIN_BUTTON(dw->custom_threshold), options->duplicates_similarity_threshold); g_signal_connect(G_OBJECT(dw->custom_threshold), "value_changed", G_CALLBACK(dupe_window_custom_threshold_cb), dw); gq_gtk_box_pack_start(GTK_BOX(controls_box), dw->custom_threshold, FALSE, FALSE, PREF_PAD_SPACE); @@ -4807,7 +4809,7 @@ DupeWindow *dupe_window_new() gtk_widget_show(button); button = pref_button_new(nullptr, GQ_ICON_CLOSE, _("Close"), G_CALLBACK(dupe_window_close_cb), dw); - gtk_widget_set_tooltip_text(GTK_WIDGET(button), "Ctrl-W"); + gtk_widget_set_tooltip_text(GTK_WIDGET(button), _("Ctrl-W")); gq_gtk_container_add(GTK_WIDGET(hbox), button); gtk_widget_set_can_default(button, TRUE); gtk_widget_grab_default(button); @@ -4920,7 +4922,7 @@ static GtkWidget *dupe_confirm_dir_list(DupeWindow *dw, GList *list) g_signal_connect(G_OBJECT(menu), "destroy", G_CALLBACK(confirm_dir_list_destroy), d); - menu_item_add_stock(menu, _("Dropped list includes folders."), GQ_ICON_DND, nullptr, nullptr); + menu_item_add_icon(menu, _("Dropped list includes folders."), GQ_ICON_DIRECTORY, nullptr, nullptr); menu_item_add_divider(menu); menu_item_add_icon(menu, _("_Add contents"), GQ_ICON_OK, G_CALLBACK(confirm_dir_list_add), d); menu_item_add_icon(menu, _("Add contents _recursive"), GQ_ICON_ADD, G_CALLBACK(confirm_dir_list_recurse), d); diff --git a/src/editors.cc b/src/editors.cc index 43bba680..27f6d463 100644 --- a/src/editors.cc +++ b/src/editors.cc @@ -197,8 +197,6 @@ gboolean editor_read_desktop_file(const gchar *path) gchar *try_exec; GtkTreeIter iter; gboolean category_geeqie = FALSE; - GList *work; - gboolean disabled; if (g_hash_table_lookup(editors, key)) return FALSE; /* the file found earlier wins */ @@ -367,20 +365,7 @@ gboolean editor_read_desktop_file(const gchar *path) if (editor->ignored) return TRUE; - work = options->disabled_plugins; - - disabled = FALSE; - while (work) - { - if (g_strcmp0(path, static_cast(work->data)) == 0) - { - disabled = TRUE; - break; - } - work = work->next; - } - - editor->disabled = disabled; + editor->disabled = g_list_find_custom(options->disabled_plugins, path, reinterpret_cast(g_strcmp0)) ? TRUE : FALSE; gtk_list_store_append(desktop_file_list, &iter); gtk_list_store_set(desktop_file_list, &iter, @@ -733,9 +718,13 @@ static gchar *editor_command_path_parse(const FileData *fd, gboolean consider_si p = fd->path; else { + const auto file_data_compare_ext = [](gconstpointer data, gconstpointer user_data) + { + return g_ascii_strcasecmp(static_cast(data)->extension, static_cast(user_data)); + }; + while (work) { - GList *work2; auto ext = static_cast(work->data); work = work->next; @@ -746,20 +735,19 @@ static gchar *editor_command_path_parse(const FileData *fd, gboolean consider_si break; } - work2 = consider_sidecars ? fd->sidecar_files : nullptr; - while (work2) + if (consider_sidecars) { - auto sfd = static_cast(work2->data); - work2 = work2->next; - - if (g_ascii_strcasecmp(ext, sfd->extension) == 0) + GList *work2 = g_list_find_custom(fd->sidecar_files, ext, file_data_compare_ext); + if (work2) { + auto sfd = static_cast(work2->data); p = sfd->path; - break; } } + if (p) break; } + if (!p) return nullptr; } } @@ -1253,6 +1241,8 @@ static EditorFlags editor_command_next_finish(EditorData *ed, gint status) return static_cast(editor_errors(ed->flags)); case EDITOR_CB_SKIP: return editor_command_done(ed); + default: + break; } return editor_command_next_start(ed); diff --git a/src/exif-common.cc b/src/exif-common.cc index 4dcdc4b9..c220f7d7 100644 --- a/src/exif-common.cc +++ b/src/exif-common.cc @@ -446,6 +446,8 @@ static gchar *exif_build_formatted_Flash(ExifData *exif) case 3: string = g_string_append(string, _("auto")); break; + default: + break; } /* return light (bits 1, 2) */ @@ -836,7 +838,7 @@ static gchar *exif_build_formatted_localtime(ExifData *exif) /** * @brief Gets timezone from GPS lat/long * @param[in] exif - * @returns Timezone string in the form "Europe/London" + * @returns Timezone string in the form Europe/London * * */ diff --git a/src/exif.cc b/src/exif.cc index 1f84d5be..fd4a2e05 100644 --- a/src/exif.cc +++ b/src/exif.cc @@ -1275,20 +1275,15 @@ ExifData *exif_read(gchar *path, gchar *, GHashTable *) ExifItem *exif_get_item(ExifData *exif, const gchar *key) { - GList *work; - if (!key) return nullptr; - work = exif->items; - while (work) - { - ExifItem *item; + const auto exif_item_compare_marker_key = [](gconstpointer data, gconstpointer user_data) + { + return g_strcmp0(static_cast(data)->marker->key, static_cast(user_data)); + }; - item = static_cast(work->data); - work = work->next; - if (item->marker->key && strcmp(key, item->marker->key) == 0) return item; - } - return nullptr; + GList *work = g_list_find_custom(exif->items, key, exif_item_compare_marker_key); + return work ? static_cast(work->data) : nullptr; } #define EXIF_DATA_AS_TEXT_MAX_COUNT 16 diff --git a/src/filedata.cc b/src/filedata.cc index 3589331d..9bc66137 100644 --- a/src/filedata.cc +++ b/src/filedata.cc @@ -1921,6 +1921,34 @@ GList *file_data_filter_marks_list(GList *list, guint filter) return list; } +gboolean file_data_mark_to_selection(FileData *fd, gint mark, MarkToSelectionMode mode, gboolean selected) +{ + gint n = mark - 1; + gboolean mark_val = file_data_get_mark(fd, n); + + switch (mode) + { + case MTS_MODE_MINUS: return !mark_val && selected; + case MTS_MODE_SET: return mark_val; + case MTS_MODE_OR: return mark_val || selected; + case MTS_MODE_AND: return mark_val && selected; + } + + return selected; // arbitrary value, we shouldn't get here +} + +void file_data_selection_to_mark(FileData *fd, gint mark, SelectionToMarkMode mode) +{ + gint n = mark - 1; + + switch (mode) + { + case STM_MODE_RESET: file_data_set_mark(fd, n, FALSE); break; + case STM_MODE_SET: file_data_set_mark(fd, n, TRUE); break; + case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n)); break; + } +} + gboolean file_data_filter_file_filter(FileData *fd, GRegex *filter) { return g_regex_match(filter, fd->name, static_cast(0), nullptr); diff --git a/src/filedata.h b/src/filedata.h index d3af8ed7..547a9fbc 100644 --- a/src/filedata.h +++ b/src/filedata.h @@ -210,6 +210,9 @@ void file_data_set_mark(FileData *fd, gint n, gboolean value); gboolean file_data_filter_marks(FileData *fd, guint filter); GList *file_data_filter_marks_list(GList *list, guint filter); +gboolean file_data_mark_to_selection(FileData *fd, gint mark, MarkToSelectionMode mode, gboolean selected); +void file_data_selection_to_mark(FileData *fd, gint mark, SelectionToMarkMode mode); + gboolean file_data_filter_file_filter(FileData *fd, GRegex *filter); GList *file_data_filter_file_filter_list(GList *list, GRegex *filter); diff --git a/src/filefilter.cc b/src/filefilter.cc index 650abb78..b4770a53 100644 --- a/src/filefilter.cc +++ b/src/filefilter.cc @@ -93,20 +93,15 @@ void filter_remove_entry(FilterEntry *fe) static FilterEntry *filter_get_by_key(const gchar *key) { - GList *work; - if (!key) return nullptr; - work = filter_list; - while (work) - { - auto fe = static_cast(work->data); - work = work->next; - - if (strcmp(fe->key, key) == 0) return fe; - } + const auto filter_entry_compare_key = [](gconstpointer data, gconstpointer user_data) + { + return g_strcmp0(static_cast(data)->key, static_cast(user_data)); + }; - return nullptr; + GList *work = g_list_find_custom(filter_list, key, filter_entry_compare_key); + return work ? static_cast(work->data) : nullptr; } static gboolean filter_key_exists(const gchar *key) @@ -140,27 +135,20 @@ void filter_add_unique(const gchar *description, const gchar *extensions, FileFo static void filter_add_if_missing(const gchar *key, const gchar *description, const gchar *extensions, FileFormatClass file_class, gboolean writable, gboolean allow_sidecar, gboolean enabled) { - GList *work; - if (!key) return; - work = filter_list; - while (work) + FilterEntry *fe = filter_get_by_key(key); + if (fe) { - auto fe = static_cast(work->data); - work = work->next; - if (fe->key && strcmp(fe->key, key) == 0) - { - if (fe->file_class == FORMAT_CLASS_UNKNOWN) - fe->file_class = file_class; /* for compatibility */ + if (fe->file_class == FORMAT_CLASS_UNKNOWN) + fe->file_class = file_class; /* for compatibility */ - if (fe->writable && fe->allow_sidecar) - { - fe->writable = writable; - fe->allow_sidecar = allow_sidecar; - } - return; + if (fe->writable && fe->allow_sidecar) + { + fe->writable = writable; + fe->allow_sidecar = allow_sidecar; } + return; } filter_add(key, description, extensions, file_class, writable, allow_sidecar, enabled); diff --git a/src/histogram.cc b/src/histogram.cc index 5823acf2..5104ae8f 100644 --- a/src/histogram.cc +++ b/src/histogram.cc @@ -132,6 +132,8 @@ const gchar *histogram_label(Histogram *histogram) case HCHAN_B: t1 = _("Log Histogram on Blue"); break; case HCHAN_RGB: t1 = _("Log Histogram on RGB"); break; case HCHAN_MAX: t1 = _("Log Histogram on value"); break; + default: + break; } else switch (histogram->histogram_channel) @@ -141,6 +143,8 @@ const gchar *histogram_label(Histogram *histogram) case HCHAN_B: t1 = _("Linear Histogram on Blue"); break; case HCHAN_RGB: t1 = _("Linear Histogram on RGB"); break; case HCHAN_MAX: t1 = _("Linear Histogram on value"); break; + default: + break; } return t1; } @@ -361,6 +365,8 @@ gboolean histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf case HCHAN_R: rplus = r = 255; break; case HCHAN_G: gplus = g = 255; break; case HCHAN_B: bplus = b = 255; break; + default: + break; } switch (histogram->histogram_channel) @@ -375,6 +381,8 @@ gboolean histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf case HCHAN_G: r = 0; b = 0; break; case HCHAN_B: r = 0; g = 0; break; case HCHAN_MAX: r = 0; b = 0; g = 0; break; + default: + break; } if (v[chanmax] == 0) diff --git a/src/image-load-dds.cc b/src/image-load-dds.cc index 9247b952..b2bb0cff 100644 --- a/src/image-load-dds.cc +++ b/src/image-load-dds.cc @@ -243,6 +243,8 @@ uint ddsGetDXTColor(uint c0, uint c1, uint a, uint t) { case 1: return ddsGetDXTColor1(c1, a); case 2: return (c0 > c1) ? ddsGetDXTColor2_1(c0, c1, a) : ddsGetDXTColor1_1(c0, c1, a); case 3: return (c0 > c1) ? ddsGetDXTColor2_1(c1, c0, a) : 0; + default: + break; } return 0; } @@ -330,6 +332,8 @@ int ddsGetDXT5Alpha(uint a0, uint a1, uint t) { case 5: return (3 * a0 + 4 * a1) / 7; case 6: return (2 * a0 + 5 * a1) / 7; case 7: return (a0 + 6 * a1) / 7; + default: + break; } else switch (t) { case 0: return a0; @@ -340,6 +344,8 @@ int ddsGetDXT5Alpha(uint a0, uint a1, uint t) { case 5: return (a0 + 4 * a1) / 5; case 6: return 0; case 7: return 255; + default: + break; } return 0; } @@ -569,6 +575,8 @@ gboolean ImageLoaderDDS::write(const guchar *buf, gsize &chunk_size, gsize count case X8B8G8R8: pixels = ddsReadX8B8G8R8(width, height, buf); break; case A8R8G8B8: pixels = ddsReadA8R8G8B8(width, height, buf); break; case X8R8G8B8: pixels = ddsReadX8R8G8B8(width, height, buf); break; + default: + break; } pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, width, height, rowstride, free_buffer, nullptr); area_updated_cb(nullptr, 0, 0, width, height, data); diff --git a/src/img-view.cc b/src/img-view.cc index e78cbeb8..d193c2ee 100644 --- a/src/img-view.cc +++ b/src/img-view.cc @@ -1606,7 +1606,7 @@ static GtkWidget *view_confirm_dir_list(ViewWindow *vw, GList *list) g_signal_connect(G_OBJECT(menu), "destroy", G_CALLBACK(view_dir_list_destroy), d); - menu_item_add_stock(menu, _("Dropped list includes folders."), GQ_ICON_DND, nullptr, nullptr); + menu_item_add_icon(menu, _("Dropped list includes folders."), GQ_ICON_DIRECTORY, nullptr, nullptr); menu_item_add_divider(menu); menu_item_add_icon(menu, _("_Add contents"), GQ_ICON_OK, G_CALLBACK(view_dir_list_add), d); menu_item_add_icon(menu, _("Add contents _recursive"), GQ_ICON_ADD, G_CALLBACK(view_dir_list_recurse), d); diff --git a/src/layout-config.cc b/src/layout-config.cc index ab98a549..f021e46c 100644 --- a/src/layout-config.cc +++ b/src/layout-config.cc @@ -262,6 +262,8 @@ gchar num_to_text_char(gint n) case 2: return '3'; break; + default: + break; } return '1'; } diff --git a/src/layout-image.cc b/src/layout-image.cc index 3b413bf8..79a74df8 100644 --- a/src/layout-image.cc +++ b/src/layout-image.cc @@ -33,6 +33,7 @@ #include "archives.h" #include "collect.h" +#include "compat.h" #include "debug.h" #include "dnd.h" #include "editors.h" @@ -504,8 +505,8 @@ void layout_image_animate_toggle(LayoutWindow *lw) lw->options.animate = !lw->options.animate; - action = gtk_action_group_get_action(lw->action_group, "Animate"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.animate); + action = gq_gtk_action_group_get_action(lw->action_group, "Animate"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.animate); layout_image_animate_new_file(lw); } diff --git a/src/layout-util.cc b/src/layout-util.cc index c845c31c..25aa9dbf 100644 --- a/src/layout-util.cc +++ b/src/layout-util.cc @@ -561,16 +561,16 @@ static void layout_menu_alter_desaturate_cb(GtkToggleAction *action, gpointer da { auto lw = static_cast(data); - layout_image_set_desaturate(lw, gtk_toggle_action_get_active(action)); + layout_image_set_desaturate(lw, gq_gtk_toggle_action_get_active(action)); } static void layout_menu_alter_ignore_alpha_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (lw->options.ignore_alpha == gtk_toggle_action_get_active(action)) return; + if (lw->options.ignore_alpha == gq_gtk_toggle_action_get_active(action)) return; - layout_image_set_ignore_alpha(lw, gtk_toggle_action_get_active(action)); + layout_image_set_ignore_alpha(lw, gq_gtk_toggle_action_get_active(action)); } static void layout_menu_alter_none_cb(GtkAction *, gpointer data) @@ -584,27 +584,27 @@ static void layout_menu_exif_rotate_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - options->image.exif_rotate_enable = gtk_toggle_action_get_active(action); + options->image.exif_rotate_enable = gq_gtk_toggle_action_get_active(action); layout_image_reset_orientation(lw); } static void layout_menu_select_rectangle_cb(GtkToggleAction *action, gpointer) { - options->draw_rectangle = gtk_toggle_action_get_active(action); + options->draw_rectangle = gq_gtk_toggle_action_get_active(action); } static void layout_menu_split_pane_sync_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - lw->options.split_pane_sync = gtk_toggle_action_get_active(action); + lw->options.split_pane_sync = gq_gtk_toggle_action_get_active(action); } static void layout_menu_select_overunderexposed_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - layout_image_set_overunderexposed(lw, gtk_toggle_action_get_active(action)); + layout_image_set_overunderexposed(lw, gq_gtk_toggle_action_get_active(action)); } static void layout_menu_write_rotate(GtkToggleAction *, gpointer data, gboolean keep_date) @@ -918,7 +918,7 @@ static void layout_menu_split_cb(GtkRadioAction *action, GtkRadioAction *, gpoin ImageSplitMode mode; layout_exit_fullscreen(lw); - mode = static_cast(gtk_radio_action_get_current_value(action)); + mode = static_cast(gq_gtk_radio_action_get_current_value(action)); layout_split_change(lw, mode); } @@ -927,7 +927,7 @@ static void layout_menu_thumb_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - layout_thumb_set(lw, gtk_toggle_action_get_active(action)); + layout_thumb_set(lw, gq_gtk_toggle_action_get_active(action)); } @@ -936,7 +936,7 @@ static void layout_menu_list_cb(GtkRadioAction *action, GtkRadioAction *, gpoint auto lw = static_cast(data); layout_exit_fullscreen(lw); - layout_views_set(lw, lw->options.dir_view_type, static_cast(gtk_radio_action_get_current_value(action))); + layout_views_set(lw, lw->options.dir_view_type, static_cast(gq_gtk_radio_action_get_current_value(action))); } static void layout_menu_view_dir_as_cb(GtkToggleAction *action, gpointer data) @@ -945,7 +945,7 @@ static void layout_menu_view_dir_as_cb(GtkToggleAction *action, gpointer data) layout_exit_fullscreen(lw); - if (gtk_toggle_action_get_active(action)) + if (gq_gtk_toggle_action_get_active(action)) { layout_views_set(lw, DIRVIEW_TREE, lw->options.file_view_type); } @@ -989,7 +989,7 @@ void open_with_response_cb(GtkDialog *, gint response_id, gpointer data) g_object_unref(open_with_data->application); g_object_unref(g_list_first(open_with_data->g_file_list)->data); g_list_free(open_with_data->g_file_list); - gtk_widget_destroy(GTK_WIDGET(open_with_data->app_chooser_dialog)); + gq_gtk_widget_destroy(GTK_WIDGET(open_with_data->app_chooser_dialog)); g_free(open_with_data); } @@ -1018,7 +1018,7 @@ static void open_with_application_activated_cb(GtkAppChooserWidget *, GAppInfo * g_object_unref(open_with_data->application); g_object_unref(g_list_first(open_with_data->g_file_list)->data); g_list_free(open_with_data->g_file_list); - gtk_widget_destroy(GTK_WIDGET(open_with_data->app_chooser_dialog)); + gq_gtk_widget_destroy(GTK_WIDGET(open_with_data->app_chooser_dialog)); g_free(open_with_data); } @@ -1105,7 +1105,7 @@ static void layout_menu_overlay_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (gtk_toggle_action_get_active(action)) + if (gq_gtk_toggle_action_get_active(action)) { OsdShowFlags flags = image_osd_get(lw->image); @@ -1114,10 +1114,10 @@ static void layout_menu_overlay_cb(GtkToggleAction *action, gpointer data) } else { - GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(lw->action_group, "ImageHistogram")); + GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gq_gtk_action_group_get_action(lw->action_group, "ImageHistogram")); image_osd_set(lw->image, OSD_SHOW_NOTHING); - gtk_toggle_action_set_active(histogram_action, FALSE); /* this calls layout_menu_histogram_cb */ + gq_gtk_toggle_action_set_active(histogram_action, FALSE); /* this calls layout_menu_histogram_cb */ } } @@ -1125,7 +1125,7 @@ static void layout_menu_histogram_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (gtk_toggle_action_get_active(action)) + if (gq_gtk_toggle_action_get_active(action)) { image_osd_set(lw->image, static_cast(OSD_SHOW_INFO | OSD_SHOW_STATUS | OSD_SHOW_HISTOGRAM)); layout_util_sync_views(lw); /* show the overlay state, default channel and mode in the menu */ @@ -1142,13 +1142,13 @@ static void layout_menu_animate_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (lw->options.animate == gtk_toggle_action_get_active(action)) return; + if (lw->options.animate == gq_gtk_toggle_action_get_active(action)) return; layout_image_animate_toggle(lw); } static void layout_menu_rectangular_selection_cb(GtkToggleAction *action, gpointer) { - options->collections.rectangular_selection = gtk_toggle_action_get_active(action); + options->collections.rectangular_selection = gq_gtk_toggle_action_get_active(action); } static void layout_menu_histogram_toggle_channel_cb(GtkAction *, gpointer data) @@ -1170,24 +1170,24 @@ static void layout_menu_histogram_toggle_mode_cb(GtkAction *, gpointer data) static void layout_menu_histogram_channel_cb(GtkRadioAction *action, GtkRadioAction *, gpointer data) { auto lw = static_cast(data); - gint channel = gtk_radio_action_get_current_value(action); - GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(lw->action_group, "ImageHistogram")); + gint channel = gq_gtk_radio_action_get_current_value(action); + GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gq_gtk_action_group_get_action(lw->action_group, "ImageHistogram")); if (channel < 0 || channel >= HCHAN_COUNT) return; - gtk_toggle_action_set_active(histogram_action, TRUE); /* this calls layout_menu_histogram_cb */ + gq_gtk_toggle_action_set_active(histogram_action, TRUE); /* this calls layout_menu_histogram_cb */ image_osd_histogram_set_channel(lw->image, channel); } static void layout_menu_histogram_mode_cb(GtkRadioAction *action, GtkRadioAction *, gpointer data) { auto lw = static_cast(data); - gint mode = gtk_radio_action_get_current_value(action); - GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(lw->action_group, "ImageHistogram")); + gint mode = gq_gtk_radio_action_get_current_value(action); + GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gq_gtk_action_group_get_action(lw->action_group, "ImageHistogram")); if (mode < 0 || mode > 1) return; - gtk_toggle_action_set_active(histogram_action, TRUE); /* this calls layout_menu_histogram_cb */ + gq_gtk_toggle_action_set_active(histogram_action, TRUE); /* this calls layout_menu_histogram_cb */ image_osd_histogram_set_mode(lw->image, mode); } @@ -1219,7 +1219,7 @@ static void layout_menu_float_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (lw->options.tools_float == gtk_toggle_action_get_active(action)) return; + if (lw->options.tools_float == gq_gtk_toggle_action_get_active(action)) return; layout_exit_fullscreen(lw); layout_tools_float_toggle(lw); @@ -1237,7 +1237,7 @@ static void layout_menu_selectable_toolbars_cb(GtkToggleAction *action, gpointer { auto lw = static_cast(data); - if (lw->options.selectable_toolbars_hidden == gtk_toggle_action_get_active(action)) return; + if (lw->options.selectable_toolbars_hidden == gq_gtk_toggle_action_get_active(action)) return; layout_exit_fullscreen(lw); layout_selectable_toolbars_toggle(lw); @@ -1247,7 +1247,7 @@ static void layout_menu_info_pixel_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (lw->options.show_info_pixel == gtk_toggle_action_get_active(action)) return; + if (lw->options.show_info_pixel == gq_gtk_toggle_action_get_active(action)) return; layout_exit_fullscreen(lw); layout_info_pixel_set(lw, !lw->options.show_info_pixel); @@ -1258,7 +1258,7 @@ static void layout_menu_bar_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (layout_bar_enabled(lw) == gtk_toggle_action_get_active(action)) return; + if (layout_bar_enabled(lw) == gq_gtk_toggle_action_get_active(action)) return; layout_exit_fullscreen(lw); layout_bar_toggle(lw); @@ -1268,7 +1268,7 @@ static void layout_menu_bar_sort_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (layout_bar_sort_enabled(lw) == gtk_toggle_action_get_active(action)) return; + if (layout_bar_sort_enabled(lw) == gq_gtk_toggle_action_get_active(action)) return; layout_exit_fullscreen(lw); layout_bar_sort_toggle(lw); @@ -1278,7 +1278,7 @@ static void layout_menu_hide_bars_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (lw->options.bars_state.hidden == gtk_toggle_action_get_active(action)) + if (lw->options.bars_state.hidden == gq_gtk_toggle_action_get_active(action)) { return; } @@ -1289,7 +1289,7 @@ static void layout_menu_slideshow_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (layout_image_slideshow_active(lw) == gtk_toggle_action_get_active(action)) return; + if (layout_image_slideshow_active(lw) == gq_gtk_toggle_action_get_active(action)) return; layout_image_slideshow_toggle(lw); } @@ -1323,8 +1323,8 @@ static void layout_menu_stereo_mode_next_cb(GtkAction *, gpointer data) /* 0->1, 1->2, 2->3, 3->1 - disable auto, then cycle */ mode = mode % 3 + 1; - GtkAction *radio = gtk_action_group_get_action(lw->action_group, "StereoAuto"); - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(radio), mode); + GtkAction *radio = gq_gtk_action_group_get_action(lw->action_group, "StereoAuto"); + gq_gtk_radio_action_set_current_value(GTK_RADIO_ACTION(radio), mode); /* this is called via fallback in layout_menu_stereo_mode_cb @@ -1336,7 +1336,7 @@ static void layout_menu_stereo_mode_next_cb(GtkAction *, gpointer data) static void layout_menu_stereo_mode_cb(GtkRadioAction *action, GtkRadioAction *, gpointer data) { auto lw = static_cast(data); - gint mode = gtk_radio_action_get_current_value(action); + gint mode = gq_gtk_radio_action_get_current_value(action); layout_image_stereo_pixbuf_set(lw, mode); } @@ -1593,14 +1593,14 @@ static void layout_menu_file_filter_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - layout_file_filter_set(lw, gtk_toggle_action_get_active(action)); + layout_file_filter_set(lw, gq_gtk_toggle_action_get_active(action)); } static void layout_menu_marks_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - layout_marks_set(lw, gtk_toggle_action_get_active(action)); + layout_marks_set(lw, gq_gtk_toggle_action_get_active(action)); } @@ -1935,7 +1935,7 @@ static void layout_menu_up_cb(GtkAction *, gpointer data) static void layout_menu_edit_cb(GtkAction *action, gpointer data) { auto lw = static_cast(data); - const gchar *key = gtk_action_get_name(action); + const gchar *key = gq_gtk_action_get_name(action); if (!editor_window_flag_set(key)) layout_exit_fullscreen(lw); @@ -1979,9 +1979,9 @@ static void layout_color_menu_enable_cb(GtkToggleAction *action, gpointer data) { auto lw = static_cast(data); - if (layout_image_color_profile_get_use(lw) == gtk_toggle_action_get_active(action)) return; + if (layout_image_color_profile_get_use(lw) == gq_gtk_toggle_action_get_active(action)) return; - layout_image_color_profile_set_use(lw, gtk_toggle_action_get_active(action)); + layout_image_color_profile_set_use(lw, gq_gtk_toggle_action_get_active(action)); layout_util_sync_color(lw); layout_image_refresh(lw); } @@ -1993,8 +1993,8 @@ static void layout_color_menu_use_image_cb(GtkToggleAction *action, gpointer dat gboolean use_image; if (!layout_image_color_profile_get(lw, &input, &use_image)) return; - if (use_image == gtk_toggle_action_get_active(action)) return; - layout_image_color_profile_set(lw, input, gtk_toggle_action_get_active(action)); + if (use_image == gq_gtk_toggle_action_get_active(action)) return; + layout_image_color_profile_set(lw, input, gq_gtk_toggle_action_get_active(action)); layout_util_sync_color(lw); layout_image_refresh(lw); } @@ -2006,7 +2006,7 @@ static void layout_color_menu_input_cb(GtkRadioAction *action, GtkRadioAction *, gint input; gboolean use_image; - type = gtk_radio_action_get_current_value(action); + type = gq_gtk_radio_action_get_current_value(action); if (type < 0 || type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS) return; if (!layout_image_color_profile_get(lw, &input, &use_image)) return; @@ -2096,7 +2096,7 @@ static void layout_menu_collection_recent_update(LayoutWindow *lw) menu_item_add(menu, _("Empty"), nullptr, nullptr); } - recent = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/FileMenu/OpenRecent" : "/MainMenu/FileMenu/OpenRecent"); + recent = gq_gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/FileMenu/OpenRecent" : "/MainMenu/FileMenu/OpenRecent"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), menu); gtk_widget_set_sensitive(recent, (n != 0)); } @@ -2152,7 +2152,7 @@ static void layout_menu_collection_open_update(LayoutWindow *lw) menu_item_add(menu, _("Empty"), nullptr, nullptr); } - recent = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/FileMenu/OpenCollection" : "/MainMenu/FileMenu/OpenCollection"); + recent = gq_gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/FileMenu/OpenCollection" : "/MainMenu/FileMenu/OpenCollection"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), menu); gtk_widget_set_sensitive(recent, (n != 0)); } @@ -2221,9 +2221,7 @@ static gint layout_window_menu_list_sort_cb(gconstpointer a, gconstpointer b) static GList *layout_window_menu_list(GList *listin) { - GList *list; WindowNames *wn; - gboolean dupe; DIR *dp; struct dirent *dir; gchar *pathl; @@ -2243,30 +2241,16 @@ static GList *layout_window_menu_list(GList *listin) if (g_str_has_suffix(name_file, ".xml")) { - LayoutWindow *lw_tmp ; gchar *name_utf8 = path_to_utf8(name_file); gchar *name_base = g_strndup(name_utf8, strlen(name_utf8) - 4); - list = layout_window_list; - dupe = FALSE; - while (list) - { - lw_tmp = static_cast(list->data); - if (g_strcmp0(lw_tmp->options.id, name_base) == 0) - { - dupe = TRUE; - } - list = list->next; - } - gchar *dpath = g_build_filename(pathl, name_utf8, NULL); + wn = g_new0(WindowNames, 1); - wn->displayed = dupe; - wn->name = g_strdup(name_base); - wn->path = g_strdup(dpath); + wn->displayed = g_list_find_custom(layout_window_list, name_base, reinterpret_cast(layout_compare_options_id)) ? TRUE : FALSE; + wn->name = name_base; + wn->path = g_build_filename(pathl, name_utf8, NULL); listin = g_list_append(listin, wn); - g_free(dpath); g_free(name_utf8); - g_free(name_base); } } closedir(dp); @@ -2312,7 +2296,7 @@ static void layout_menu_new_window_update(LayoutWindow *lw) list = layout_window_menu_list(list); - menu = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/WindowsMenu/NewWindow" : "/MainMenu/WindowsMenu/NewWindow"); + menu = gq_gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/WindowsMenu/NewWindow" : "/MainMenu/WindowsMenu/NewWindow"); sub_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu)); children = gtk_container_get_children(GTK_CONTAINER(sub_menu)); @@ -2353,30 +2337,24 @@ static void window_rename_ok(GenericDialog *, gpointer data) { auto rw = static_cast(data); gchar *path; - gboolean window_layout_name_exists = FALSE; - GList *list = nullptr; gchar *xml_name; gchar *new_id; new_id = g_strdup(gq_gtk_entry_get_text(GTK_ENTRY(rw->window_name_entry))); - list = layout_window_menu_list(list); - while (list) + const auto window_names_compare_name = [](gconstpointer data, gconstpointer user_data) + { + return g_strcmp0(static_cast(data)->name, static_cast(user_data)); + }; + + if (g_list_find_custom(layout_window_menu_list(nullptr), new_id, window_names_compare_name)) { - auto ln = static_cast(list->data); - if (g_strcmp0(ln->name, new_id) == 0) - { - gchar *buf; - buf = g_strdup_printf(_("Window layout name \"%s\" already exists."), new_id); - warning_dialog(_("Rename window"), buf, GQ_ICON_DIALOG_WARNING, rw->gd->dialog); - g_free(buf); - window_layout_name_exists = TRUE; - break; - } - list = list->next; + gchar *buf; + buf = g_strdup_printf(_("Window layout name \"%s\" already exists."), new_id); + warning_dialog(_("Rename window"), buf, GQ_ICON_DIALOG_WARNING, rw->gd->dialog); + g_free(buf); } - - if (!window_layout_name_exists) + else { xml_name = g_strdup_printf("%s.xml", rw->lw->options.id); path = g_build_filename(get_window_layouts_dir(), xml_name, NULL); @@ -2458,7 +2436,7 @@ static void layout_menu_windows_menu_cb(GtkWidget *, gpointer data) GList *iter; gint i; - menu = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/WindowsMenu/" : "/MainMenu/WindowsMenu/"); + menu = gq_gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/WindowsMenu/" : "/MainMenu/WindowsMenu/"); sub_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu)); @@ -2491,7 +2469,7 @@ static void layout_menu_view_menu_cb(GtkWidget *, gpointer data) gint i; FileData *fd; - menu = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/ViewMenu/" : "/MainMenu/ViewMenu/"); + menu = gq_gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/ViewMenu/" : "/MainMenu/ViewMenu/"); sub_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu)); fd = layout_image_get_fd(lw); @@ -2750,7 +2728,7 @@ static GtkActionEntry menu_entries[] = { { "Maintenance", PIXBUF_INLINE_ICON_MAINTENANCE, N_("_Cache maintenance..."), nullptr, N_("Cache maintenance..."), CB(layout_menu_remove_thumb_cb) }, { "Mirror", GQ_ICON_FLIP_HORIZONTAL, N_("_Mirror"), "M", N_("Image Mirror"), CB(layout_menu_alter_mirror_cb) }, { "Move", PIXBUF_INLINE_ICON_MOVE, N_("_Move..."), "M", N_("Move..."), CB(layout_menu_move_cb) }, - { "NewCollection", GQ_ICON_COLLECTION, N_("_New collection"), "C", N_("New collection"), CB(layout_menu_new_cb) }, + { "NewCollection", PIXBUF_INLINE_COLLECTION, N_("_New collection"), "C", N_("New collection"), CB(layout_menu_new_cb) }, { "NewFolder", GQ_ICON_DIRECTORY, N_("N_ew folder..."), "F", N_("New folder..."), CB(layout_menu_dir_cb) }, { "NewWindowDefault", nullptr, N_("default"), "N", N_("New window (default)"), CB(layout_menu_window_default_cb) }, { "NewWindowFromCurrent", nullptr, N_("from current"), nullptr, N_("from current"), CB(layout_menu_window_from_current_cb) }, @@ -2936,8 +2914,8 @@ static void layout_actions_setup_mark(LayoutWindow *lw, gint mark, const gchar * else entry.tooltip = nullptr; - gtk_action_group_add_actions(lw->action_group, &entry, 1, lw); - action = gtk_action_group_get_action(lw->action_group, name); + gq_gtk_action_group_add_actions(lw->action_group, &entry, 1, lw); + action = gq_gtk_action_group_get_action(lw->action_group, name); g_object_set_data(G_OBJECT(action), "mark_num", GINT_TO_POINTER(mark > 0 ? mark : 10)); } @@ -3007,7 +2985,7 @@ static void layout_actions_setup_marks(LayoutWindow *lw) g_string_append(desc, "" ); error = nullptr; - if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error)) + if (!gq_gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error)) { g_message("building menus failed: %s", error->message); g_error_free(error); @@ -3110,16 +3088,16 @@ static void layout_actions_setup_editors(LayoutWindow *lw) if (lw->ui_editors_id) { - gtk_ui_manager_remove_ui(lw->ui_manager, lw->ui_editors_id); + gq_gtk_ui_manager_remove_ui(lw->ui_manager, lw->ui_editors_id); } if (lw->action_group_editors) { - gtk_ui_manager_remove_action_group(lw->ui_manager, lw->action_group_editors); + gq_gtk_ui_manager_remove_action_group(lw->ui_manager, lw->action_group_editors); g_object_unref(lw->action_group_editors); } - lw->action_group_editors = gtk_action_group_new("MenuActionsExternal"); - gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group_editors, 1); + lw->action_group_editors = gq_gtk_action_group_new("MenuActionsExternal"); + gq_gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group_editors, 1); /* lw->action_group_editors contains translated entries, no translate func is required */ desc = g_string_new( @@ -3150,7 +3128,7 @@ static void layout_actions_setup_editors(LayoutWindow *lw) { entry.stock_id = editor->key; } - gtk_action_group_add_actions(lw->action_group_editors, &entry, 1, lw); + gq_gtk_action_group_add_actions(lw->action_group_editors, &entry, 1, lw); path = layout_actions_editor_menu_path(editor); layout_actions_editor_add(desc, path, old_path); @@ -3173,7 +3151,7 @@ static void layout_actions_setup_editors(LayoutWindow *lw) error = nullptr; - lw->ui_editors_id = gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error); + lw->ui_editors_id = gq_gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error); if (!lw->ui_editors_id) { g_message("building menus failed: %s", error->message); @@ -3203,44 +3181,44 @@ void layout_actions_setup(LayoutWindow *lw) DEBUG_1("%s layout_actions_setup: start", get_exec_time()); if (lw->ui_manager) return; - lw->action_group = gtk_action_group_new("MenuActions"); - gtk_action_group_set_translate_func(lw->action_group, menu_translate, nullptr, nullptr); + lw->action_group = gq_gtk_action_group_new("MenuActions"); + gq_gtk_action_group_set_translate_func(lw->action_group, menu_translate, nullptr, nullptr); - gtk_action_group_add_actions(lw->action_group, + gq_gtk_action_group_add_actions(lw->action_group, menu_entries, G_N_ELEMENTS(menu_entries), lw); - gtk_action_group_add_toggle_actions(lw->action_group, + gq_gtk_action_group_add_toggle_actions(lw->action_group, menu_toggle_entries, G_N_ELEMENTS(menu_toggle_entries), lw); - gtk_action_group_add_radio_actions(lw->action_group, + gq_gtk_action_group_add_radio_actions(lw->action_group, menu_radio_entries, G_N_ELEMENTS(menu_radio_entries), 0, G_CALLBACK(layout_menu_list_cb), lw); - gtk_action_group_add_radio_actions(lw->action_group, + gq_gtk_action_group_add_radio_actions(lw->action_group, menu_split_radio_entries, G_N_ELEMENTS(menu_split_radio_entries), 0, G_CALLBACK(layout_menu_split_cb), lw); - gtk_action_group_add_toggle_actions(lw->action_group, + gq_gtk_action_group_add_toggle_actions(lw->action_group, menu_view_dir_toggle_entries, G_N_ELEMENTS(menu_view_dir_toggle_entries), lw); - gtk_action_group_add_radio_actions(lw->action_group, + gq_gtk_action_group_add_radio_actions(lw->action_group, menu_color_radio_entries, COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS, 0, G_CALLBACK(layout_color_menu_input_cb), lw); - gtk_action_group_add_radio_actions(lw->action_group, + gq_gtk_action_group_add_radio_actions(lw->action_group, menu_histogram_channel, G_N_ELEMENTS(menu_histogram_channel), 0, G_CALLBACK(layout_menu_histogram_channel_cb), lw); - gtk_action_group_add_radio_actions(lw->action_group, + gq_gtk_action_group_add_radio_actions(lw->action_group, menu_histogram_mode, G_N_ELEMENTS(menu_histogram_mode), 0, G_CALLBACK(layout_menu_histogram_mode_cb), lw); - gtk_action_group_add_radio_actions(lw->action_group, + gq_gtk_action_group_add_radio_actions(lw->action_group, menu_stereo_mode_entries, G_N_ELEMENTS(menu_stereo_mode_entries), 0, G_CALLBACK(layout_menu_stereo_mode_cb), lw); - lw->ui_manager = gtk_ui_manager_new(); - gtk_ui_manager_set_add_tearoffs(lw->ui_manager, TRUE); - gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group, 0); + lw->ui_manager = gq_gtk_ui_manager_new(); + gq_gtk_ui_manager_set_add_tearoffs(lw->ui_manager, TRUE); + gq_gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group, 0); DEBUG_1("%s layout_actions_setup: add menu", get_exec_time()); error = nullptr; - if (!gtk_ui_manager_add_ui_from_resource(lw->ui_manager, options->hamburger_menu ? GQ_RESOURCE_PATH_UI "/menu-hamburger.ui" : GQ_RESOURCE_PATH_UI "/menu-classic.ui" , &error)) + if (!gq_gtk_ui_manager_add_ui_from_resource(lw->ui_manager, options->hamburger_menu ? GQ_RESOURCE_PATH_UI "/menu-hamburger.ui" : GQ_RESOURCE_PATH_UI "/menu-classic.ui" , &error)) { g_message("building menus failed: %s", error->message); g_error_free(error); @@ -3337,14 +3315,14 @@ void layout_actions_add_window(LayoutWindow *lw, GtkWidget *window) if (!lw->ui_manager) return; - group = gtk_ui_manager_get_accel_group(lw->ui_manager); + group = gq_gtk_ui_manager_get_accel_group(lw->ui_manager); gtk_window_add_accel_group(GTK_WINDOW(window), group); } GtkWidget *layout_actions_menu_bar(LayoutWindow *lw) { if (lw->menu_bar) return lw->menu_bar; - lw->menu_bar = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu"); + lw->menu_bar = gq_gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu"); g_object_ref(lw->menu_bar); return lw->menu_bar; } @@ -3396,20 +3374,20 @@ void toolbar_clear_cb(GtkWidget *widget, gpointer) g_signal_handler_disconnect(action, GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "id"))); } } - gtk_widget_destroy(widget); + gq_gtk_widget_destroy(widget); } void layout_toolbar_clear(LayoutWindow *lw, ToolbarType type) { if (lw->toolbar_merge_id[type]) { - gtk_ui_manager_remove_ui(lw->ui_manager, lw->toolbar_merge_id[type]); - gtk_ui_manager_ensure_update(lw->ui_manager); + gq_gtk_ui_manager_remove_ui(lw->ui_manager, lw->toolbar_merge_id[type]); + gq_gtk_ui_manager_ensure_update(lw->ui_manager); } g_list_free_full(lw->toolbar_actions[type], g_free); lw->toolbar_actions[type] = nullptr; - lw->toolbar_merge_id[type] = gtk_ui_manager_new_merge_id(lw->ui_manager); + lw->toolbar_merge_id[type] = gq_gtk_ui_manager_new_merge_id(lw->ui_manager); if (lw->toolbar[type]) { @@ -3435,15 +3413,15 @@ void action_toggle_activate_cb(GtkAction* self, gpointer data) { auto button = static_cast(data); - if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(self)) != gtk_toggle_button_get_active(button)) + if (gq_gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(self)) != gtk_toggle_button_get_active(button)) { - gtk_toggle_button_set_active(button, gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(self))); + gtk_toggle_button_set_active(button, gq_gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(self))); } } gboolean toolbar_button_press_event_cb(GtkWidget *, GdkEvent *, gpointer data) { - gtk_action_activate(GTK_ACTION(data)); + gq_gtk_action_activate(GTK_ACTION(data)); return TRUE; } @@ -3482,10 +3460,10 @@ void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action_ create a dummy action for now */ if (!lw->action_group_editors) { - lw->action_group_editors = gtk_action_group_new("MenuActionsExternal"); - gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group_editors, 1); + lw->action_group_editors = gq_gtk_action_group_new("MenuActionsExternal"); + gq_gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group_editors, 1); } - if (!gtk_action_group_get_action(lw->action_group_editors, action_name)) + if (!gq_gtk_action_group_get_action(lw->action_group_editors, action_name)) { GtkActionEntry entry = { action_name, GQ_ICON_MISSING_IMAGE, @@ -3495,7 +3473,7 @@ void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action_ nullptr }; DEBUG_1("Creating temporary action %s", action_name); - gtk_action_group_add_actions(lw->action_group_editors, &entry, 1, lw); + gq_gtk_action_group_add_actions(lw->action_group_editors, &entry, 1, lw); } } @@ -3505,27 +3483,23 @@ void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action_ } else { - action = gtk_action_group_get_action(lw->action_group, action_name); + action = gq_gtk_action_group_get_action(lw->action_group, action_name); - action_icon = gtk_action_create_icon(action, GTK_ICON_SIZE_SMALL_TOOLBAR); - tooltip_text = gtk_action_get_tooltip(action); + action_icon = gq_gtk_action_create_icon(action, GTK_ICON_SIZE_SMALL_TOOLBAR); + tooltip_text = gq_gtk_action_get_tooltip(action); - gtk_ui_manager_add_ui(lw->ui_manager, lw->toolbar_merge_id[type], path, action_name, action_name, GTK_UI_MANAGER_TOOLITEM, FALSE); + gq_gtk_ui_manager_add_ui(lw->ui_manager, lw->toolbar_merge_id[type], path, action_name, action_name, GTK_UI_MANAGER_TOOLITEM, FALSE); - if (GTK_IS_RADIO_ACTION(action) || GTK_IS_TOGGLE_ACTION(action)) + if (GQ_GTK_IS_RADIO_ACTION(action) || GQ_GTK_IS_TOGGLE_ACTION(action)) { button = gtk_toggle_button_new(); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), gq_gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))); } else { button = gtk_button_new(); } - if (GTK_IS_TOGGLE_ACTION(action) || GTK_IS_RADIO_ACTION(action)) - { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))); - } - if (action_icon) { gtk_button_set_image(GTK_BUTTON(button), action_icon); @@ -3538,12 +3512,12 @@ void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action_ gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); gtk_widget_set_tooltip_text(button, tooltip_text); - if (GTK_IS_RADIO_ACTION(action)) + if (GQ_GTK_IS_RADIO_ACTION(action)) { id = g_signal_connect(G_OBJECT(action), "changed", G_CALLBACK(action_radio_changed_cb), button); g_object_set_data(G_OBJECT(button), "id", GUINT_TO_POINTER(id)); } - else if (GTK_IS_TOGGLE_ACTION(action)) + else if (GQ_GTK_IS_TOGGLE_ACTION(action)) { id = g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(action_toggle_activate_cb), button); g_object_set_data(G_OBJECT(button), "id", GUINT_TO_POINTER(id)); @@ -3709,8 +3683,8 @@ void layout_util_status_update_write(LayoutWindow *lw) { GtkAction *action; gint n = metadata_queue_length(); - action = gtk_action_group_get_action(lw->action_group, "SaveMetadata"); - gtk_action_set_sensitive(action, n > 0); + action = gq_gtk_action_group_get_action(lw->action_group, "SaveMetadata"); + gq_gtk_action_set_sensitive(action, n > 0); if (n > 0) { gchar *buf = g_strdup_printf(_("Number of files with unsaved metadata: %d"), n); @@ -3761,9 +3735,9 @@ void layout_util_sync_color(LayoutWindow *lw) use_color = layout_image_color_profile_get_use(lw); - action = gtk_action_group_get_action(lw->action_group, "UseColorProfiles"); + action = gq_gtk_action_group_get_action(lw->action_group, "UseColorProfiles"); #if HAVE_LCMS - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_color); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_color); if (layout_image_color_profile_get_status(lw, &image_profile, &screen_profile)) { gchar *buf; @@ -3778,19 +3752,19 @@ void layout_util_sync_color(LayoutWindow *lw) g_object_set(G_OBJECT(action), "tooltip", _("Click to enable color management"), NULL); } #else - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), FALSE); - gtk_action_set_sensitive(action, FALSE); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), FALSE); + gq_gtk_action_set_sensitive(action, FALSE); g_object_set(G_OBJECT(action), "tooltip", _("Color profiles not supported"), NULL); #endif - action = gtk_action_group_get_action(lw->action_group, "UseImageProfile"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_image); - gtk_action_set_sensitive(action, use_color); + action = gq_gtk_action_group_get_action(lw->action_group, "UseImageProfile"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_image); + gq_gtk_action_set_sensitive(action, use_color); for (i = 0; i < COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS; i++) { sprintf(action_name, "ColorProfile%d", i); - action = gtk_action_group_get_action(lw->action_group, action_name); + action = gq_gtk_action_group_get_action(lw->action_group, action_name); if (i >= COLOR_PROFILE_FILE) { @@ -3808,15 +3782,15 @@ void layout_util_sync_color(LayoutWindow *lw) g_object_set(G_OBJECT(action), "label", buf, NULL); g_free(buf); - gtk_action_set_visible(action, file && file[0]); + gq_gtk_action_set_visible(action, file && file[0]); } - gtk_action_set_sensitive(action, !use_image); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), (i == input)); + gq_gtk_action_set_sensitive(action, !use_image); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), (i == input)); } - action = gtk_action_group_get_action(lw->action_group, "Grayscale"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_image_get_desaturate(lw)); + action = gq_gtk_action_group_get_action(lw->action_group, "Grayscale"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_image_get_desaturate(lw)); } void layout_util_sync_file_filter(LayoutWindow *lw) @@ -3825,8 +3799,8 @@ void layout_util_sync_file_filter(LayoutWindow *lw) if (!lw->action_group) return; - action = gtk_action_group_get_action(lw->action_group, "ShowFileFilter"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_file_filter); + action = gq_gtk_action_group_get_action(lw->action_group, "ShowFileFilter"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_file_filter); } void layout_util_sync_marks(LayoutWindow *lw) @@ -3835,8 +3809,8 @@ void layout_util_sync_marks(LayoutWindow *lw) if (!lw->action_group) return; - action = gtk_action_group_get_action(lw->action_group, "ShowMarks"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_marks); + action = gq_gtk_action_group_get_action(lw->action_group, "ShowMarks"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_marks); } static void layout_util_sync_views(LayoutWindow *lw) @@ -3846,98 +3820,98 @@ static void layout_util_sync_views(LayoutWindow *lw) if (!lw->action_group) return; - action = gtk_action_group_get_action(lw->action_group, "FolderTree"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.dir_view_type); + action = gq_gtk_action_group_get_action(lw->action_group, "FolderTree"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.dir_view_type); - action = gtk_action_group_get_action(lw->action_group, "SplitSingle"); - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), lw->split_mode); + action = gq_gtk_action_group_get_action(lw->action_group, "SplitSingle"); + gq_gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), lw->split_mode); - action = gtk_action_group_get_action(lw->action_group, "SplitNextPane"); - gtk_action_set_sensitive(action, !(lw->split_mode == SPLIT_NONE)); - action = gtk_action_group_get_action(lw->action_group, "SplitPreviousPane"); - gtk_action_set_sensitive(action, !(lw->split_mode == SPLIT_NONE)); - action = gtk_action_group_get_action(lw->action_group, "SplitUpPane"); - gtk_action_set_sensitive(action, !(lw->split_mode == SPLIT_NONE)); - action = gtk_action_group_get_action(lw->action_group, "SplitDownPane"); - gtk_action_set_sensitive(action, !(lw->split_mode == SPLIT_NONE)); + action = gq_gtk_action_group_get_action(lw->action_group, "SplitNextPane"); + gq_gtk_action_set_sensitive(action, !(lw->split_mode == SPLIT_NONE)); + action = gq_gtk_action_group_get_action(lw->action_group, "SplitPreviousPane"); + gq_gtk_action_set_sensitive(action, !(lw->split_mode == SPLIT_NONE)); + action = gq_gtk_action_group_get_action(lw->action_group, "SplitUpPane"); + gq_gtk_action_set_sensitive(action, !(lw->split_mode == SPLIT_NONE)); + action = gq_gtk_action_group_get_action(lw->action_group, "SplitDownPane"); + gq_gtk_action_set_sensitive(action, !(lw->split_mode == SPLIT_NONE)); - action = gtk_action_group_get_action(lw->action_group, "SplitPaneSync"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.split_pane_sync); + action = gq_gtk_action_group_get_action(lw->action_group, "SplitPaneSync"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.split_pane_sync); - action = gtk_action_group_get_action(lw->action_group, "ViewIcons"); - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), lw->options.file_view_type); + action = gq_gtk_action_group_get_action(lw->action_group, "ViewIcons"); + gq_gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), lw->options.file_view_type); - action = gtk_action_group_get_action(lw->action_group, "FloatTools"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.tools_float); + action = gq_gtk_action_group_get_action(lw->action_group, "FloatTools"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.tools_float); - action = gtk_action_group_get_action(lw->action_group, "SBar"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_bar_enabled(lw)); + action = gq_gtk_action_group_get_action(lw->action_group, "SBar"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_bar_enabled(lw)); - action = gtk_action_group_get_action(lw->action_group, "SBarSort"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_bar_sort_enabled(lw)); + action = gq_gtk_action_group_get_action(lw->action_group, "SBarSort"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_bar_sort_enabled(lw)); - action = gtk_action_group_get_action(lw->action_group, "HideSelectableToolbars"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.selectable_toolbars_hidden); + action = gq_gtk_action_group_get_action(lw->action_group, "HideSelectableToolbars"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.selectable_toolbars_hidden); - action = gtk_action_group_get_action(lw->action_group, "ShowInfoPixel"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_info_pixel); + action = gq_gtk_action_group_get_action(lw->action_group, "ShowInfoPixel"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_info_pixel); - action = gtk_action_group_get_action(lw->action_group, "SlideShow"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_image_slideshow_active(lw)); + action = gq_gtk_action_group_get_action(lw->action_group, "SlideShow"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_image_slideshow_active(lw)); - action = gtk_action_group_get_action(lw->action_group, "IgnoreAlpha"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.ignore_alpha); + action = gq_gtk_action_group_get_action(lw->action_group, "IgnoreAlpha"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.ignore_alpha); - action = gtk_action_group_get_action(lw->action_group, "Animate"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.animate); + action = gq_gtk_action_group_get_action(lw->action_group, "Animate"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.animate); - action = gtk_action_group_get_action(lw->action_group, "ImageOverlay"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), osd_flags != OSD_SHOW_NOTHING); + action = gq_gtk_action_group_get_action(lw->action_group, "ImageOverlay"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), osd_flags != OSD_SHOW_NOTHING); - action = gtk_action_group_get_action(lw->action_group, "ImageHistogram"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), osd_flags & OSD_SHOW_HISTOGRAM); + action = gq_gtk_action_group_get_action(lw->action_group, "ImageHistogram"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), osd_flags & OSD_SHOW_HISTOGRAM); - action = gtk_action_group_get_action(lw->action_group, "ExifRotate"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->image.exif_rotate_enable); + action = gq_gtk_action_group_get_action(lw->action_group, "ExifRotate"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->image.exif_rotate_enable); - action = gtk_action_group_get_action(lw->action_group, "OverUnderExposed"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->overunderexposed); + action = gq_gtk_action_group_get_action(lw->action_group, "OverUnderExposed"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->overunderexposed); - action = gtk_action_group_get_action(lw->action_group, "DrawRectangle"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->draw_rectangle); + action = gq_gtk_action_group_get_action(lw->action_group, "DrawRectangle"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->draw_rectangle); - action = gtk_action_group_get_action(lw->action_group, "RectangularSelection"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->collections.rectangular_selection); + action = gq_gtk_action_group_get_action(lw->action_group, "RectangularSelection"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), options->collections.rectangular_selection); - action = gtk_action_group_get_action(lw->action_group, "ShowFileFilter"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_file_filter); + action = gq_gtk_action_group_get_action(lw->action_group, "ShowFileFilter"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_file_filter); - action = gtk_action_group_get_action(lw->action_group, "HideBars"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), (lw->options.bars_state.hidden)); + action = gq_gtk_action_group_get_action(lw->action_group, "HideBars"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), (lw->options.bars_state.hidden)); if (osd_flags & OSD_SHOW_HISTOGRAM) { - action = gtk_action_group_get_action(lw->action_group, "HistogramChanR"); - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), image_osd_histogram_get_channel(lw->image)); + action = gq_gtk_action_group_get_action(lw->action_group, "HistogramChanR"); + gq_gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), image_osd_histogram_get_channel(lw->image)); - action = gtk_action_group_get_action(lw->action_group, "HistogramModeLin"); - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), image_osd_histogram_get_mode(lw->image)); + action = gq_gtk_action_group_get_action(lw->action_group, "HistogramModeLin"); + gq_gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), image_osd_histogram_get_mode(lw->image)); } - action = gtk_action_group_get_action(lw->action_group, "ConnectZoomMenu"); - gtk_action_set_sensitive(action, lw->split_mode != SPLIT_NONE); + action = gq_gtk_action_group_get_action(lw->action_group, "ConnectZoomMenu"); + gq_gtk_action_set_sensitive(action, lw->split_mode != SPLIT_NONE); // @todo `which` is deprecated, use command -v gboolean is_write_rotation = !runcmd("which exiftran >/dev/null 2>&1") && !runcmd("which mogrify >/dev/null 2>&1") && !options->metadata.write_orientation; - action = gtk_action_group_get_action(lw->action_group, "WriteRotation"); - gtk_action_set_sensitive(action, is_write_rotation); - action = gtk_action_group_get_action(lw->action_group, "WriteRotationKeepDate"); - gtk_action_set_sensitive(action, is_write_rotation); + action = gq_gtk_action_group_get_action(lw->action_group, "WriteRotation"); + gq_gtk_action_set_sensitive(action, is_write_rotation); + action = gq_gtk_action_group_get_action(lw->action_group, "WriteRotationKeepDate"); + gq_gtk_action_set_sensitive(action, is_write_rotation); - action = gtk_action_group_get_action(lw->action_group, "StereoAuto"); - gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), layout_image_stereo_pixbuf_get(lw)); + action = gq_gtk_action_group_get_action(lw->action_group, "StereoAuto"); + gq_gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), layout_image_stereo_pixbuf_get(lw)); layout_util_sync_marks(lw); layout_util_sync_color(lw); @@ -3950,8 +3924,8 @@ void layout_util_sync_thumb(LayoutWindow *lw) if (!lw->action_group) return; - action = gtk_action_group_get_action(lw->action_group, "Thumbnails"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_thumbnails); + action = gq_gtk_action_group_get_action(lw->action_group, "Thumbnails"); + gq_gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_thumbnails); g_object_set(action, "sensitive", (lw->options.file_view_type == FILEVIEW_LIST), NULL); } diff --git a/src/layout.cc b/src/layout.cc index ab57e97d..1d9a6471 100644 --- a/src/layout.cc +++ b/src/layout.cc @@ -167,17 +167,13 @@ LayoutWindow *layout_find_by_layout_id(const gchar *id) return nullptr; } - work = layout_window_list; - while (work) - { - auto lw = static_cast(work->data); - work = work->next; - - if (lw->options.id && strcmp(id, lw->options.id) == 0) - return lw; - } + work = g_list_find_custom(layout_window_list, id, reinterpret_cast(layout_compare_options_id)); + return work ? static_cast(work->data) : nullptr; +} - return nullptr; +gint layout_compare_options_id(const LayoutWindow *lw, const gchar *id) +{ + return g_strcmp0(lw->options.id, id); } gchar *layout_get_unique_id() @@ -418,7 +414,7 @@ static GtkWidget *layout_tool_setup(LayoutWindow *lw) gq_gtk_container_add(GTK_WIDGET(scroll_window), menu_toolbar_box); gq_gtk_box_pack_start(GTK_BOX(box), scroll_window, FALSE, FALSE, 0); - gtk_widget_show_all(scroll_window); + gq_gtk_widget_show_all(scroll_window); } else { diff --git a/src/layout.h b/src/layout.h index 78141e14..a40638cb 100644 --- a/src/layout.h +++ b/src/layout.h @@ -176,7 +176,7 @@ void layout_write_config(LayoutWindow *lw, GString *outstr, gint indent); LayoutWindow *layout_find_by_image(ImageWindow *imd); LayoutWindow *layout_find_by_image_fd(ImageWindow *imd); LayoutWindow *layout_find_by_layout_id(const gchar *id); - +gint layout_compare_options_id(const LayoutWindow *lw, const gchar *id); const gchar *layout_get_path(LayoutWindow *lw); gboolean layout_set_path(LayoutWindow *lw, const gchar *path); diff --git a/src/logwindow.cc b/src/logwindow.cc index 19ae7e23..ef3151d2 100644 --- a/src/logwindow.cc +++ b/src/logwindow.cc @@ -450,7 +450,7 @@ static LogWindow *log_window_create(LayoutWindow *lw) gq_gtk_container_add(GTK_WIDGET(logwin->pause), label) ; gq_gtk_box_pack_start(GTK_BOX(hbox),logwin->pause, FALSE, FALSE, 0) ; g_signal_connect(logwin->pause, "toggled", G_CALLBACK(log_window_pause_cb), logwin); - gtk_widget_show_all(logwin->pause); + gq_gtk_widget_show_all(logwin->pause); logwin->wrap = gtk_toggle_button_new(); label = gtk_label_new("Wrap"); @@ -458,7 +458,7 @@ static LogWindow *log_window_create(LayoutWindow *lw) gq_gtk_container_add(GTK_WIDGET(logwin->wrap), label) ; gq_gtk_box_pack_start(GTK_BOX(hbox),logwin->wrap, FALSE, FALSE, 0) ; g_signal_connect(logwin->wrap, "toggled", G_CALLBACK(log_window_line_wrap_cb), logwin); - gtk_widget_show_all(logwin->wrap); + gq_gtk_widget_show_all(logwin->wrap); logwin->timer_data = gtk_toggle_button_new(); label = gtk_label_new(_("Timer")); @@ -470,7 +470,7 @@ static LogWindow *log_window_create(LayoutWindow *lw) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(logwin->timer_data), TRUE); } g_signal_connect(logwin->timer_data, "toggled", G_CALLBACK(log_window_timer_data_cb), logwin); - gtk_widget_show_all(logwin->timer_data); + gq_gtk_widget_show_all(logwin->timer_data); search_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gq_gtk_container_add(GTK_WIDGET(hbox), search_box); @@ -514,7 +514,7 @@ static LogWindow *log_window_create(LayoutWindow *lw) gtk_widget_set_tooltip_text(GTK_WIDGET(all_button), _("Highlight all")); gq_gtk_box_pack_start(GTK_BOX(search_box), all_button, FALSE, FALSE, 0) ; g_signal_connect(all_button, "toggled", G_CALLBACK(all_keypress_event_cb), logwin); - gtk_widget_show_all(all_button); + gq_gtk_widget_show_all(all_button); g_object_unref(pixbuf); pref_label_new(hbox, _("Filter regexp")); diff --git a/src/main-defines.h b/src/main-defines.h index b9f0f5b5..6c536601 100644 --- a/src/main-defines.h +++ b/src/main-defines.h @@ -162,8 +162,6 @@ #define GQ_ICON_COLOR_MANAGEMENT "preferences-color" // breeze has nicer "color-management" icon, missing in others // not done... plus many more -#define GQ_ICON_COLLECTION GTK_STOCK_INDEX -#define GQ_ICON_DND GTK_STOCK_DND_MULTIPLE // PIXBUF_INLINE_ICON_ZOOMFILLHOR // PIXBUF_INLINE_ICON_ZOOMFILLVERT diff --git a/src/main.cc b/src/main.cc index 08dee254..58c80f2b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -84,6 +84,10 @@ #include "ui-fileops.h" #include "ui-utildlg.h" +#if ENABLE_UNIT_TESTS +# include "gtest/gtest.h" +#endif + gboolean thumb_format_changed = FALSE; static RemoteConnection *remote_connection = nullptr; @@ -633,28 +637,24 @@ static void parse_command_line_for_debug_option(gint argc, gchar *argv[]) { #ifdef DEBUG const gchar *debug_option = "--debug"; - gint len = strlen(debug_option); + const gint len = strlen(debug_option); - if (argc > 1) + for (gint i = 1; i < argc; i++) { - gint i; - - for (i = 1; i < argc; i++) + // TODO(xsdg): Replace this with a regex match. Simpler and less error-prone. + const gchar *cmd_line = argv[i]; + if (strncmp(cmd_line, debug_option, len) == 0) { - const gchar *cmd_line = argv[i]; - if (strncmp(cmd_line, debug_option, len) == 0) - { - gint cmd_line_len = strlen(cmd_line); + const gint cmd_line_len = strlen(cmd_line); - /* we now increment the debug state for verbosity */ - if (cmd_line_len == len) - debug_level_add(1); - else if (cmd_line[len] == '=' && g_ascii_isdigit(cmd_line[len+1])) - { - gint n = atoi(cmd_line + len + 1); - if (n < 0) n = 1; - debug_level_add(n); - } + /* we now increment the debug state for verbosity */ + if (cmd_line_len == len) + debug_level_add(1); + else if (cmd_line[len] == '=' && g_ascii_isdigit(cmd_line[len+1])) + { + gint n = atoi(cmd_line + len + 1); + if (n < 0) n = 1; + debug_level_add(n); } } } @@ -663,47 +663,55 @@ static void parse_command_line_for_debug_option(gint argc, gchar *argv[]) #endif } -#if HAVE_CLUTTER -static gboolean parse_command_line_for_clutter_option(gint argc, gchar *argv[]) +static gboolean search_command_line_for_option(const gint argc, const gchar* const argv[], const gchar* option_name) { - const gchar *clutter_option = "--disable-clutter"; - gint len = strlen(clutter_option); - gboolean ret = FALSE; + const gint name_len = strlen(option_name); - if (argc > 1) + for (gint i = 1; i < argc; i++) { - gint i; - - for (i = 1; i < argc; i++) + const gchar *current_arg = argv[i]; + // TODO(xsdg): This actually only checks prefixes. We should + // probably replace this with strcmp, since strlen already has + // the shortcomings of strcmp (as compared to strncmp). + // + // That said, people may be unknowingly relying on the lenience + // of this parsing strategy, so that's also something to consider. + if (strncmp(current_arg, option_name, name_len) == 0) { - const gchar *cmd_line = argv[i]; - if (strncmp(cmd_line, clutter_option, len) == 0) - { - ret = TRUE; - } + return TRUE; } } - return ret; + return FALSE; +} + +static gboolean search_command_line_for_unit_test_option(gint argc, gchar *argv[]) +{ + return search_command_line_for_option(argc, argv, "--run-unit-tests"); +} + +#if HAVE_CLUTTER +static gboolean search_command_line_for_clutter_option(gint argc, gchar *argv[]) +{ + return search_command_line_for_option(argc, argv, "--disable-clutter"); } #endif static gboolean parse_command_line_for_cache_maintenance_option(gint argc, gchar *argv[]) { const gchar *cache_maintenance_option = "--cache-maintenance="; - gint len = strlen(cache_maintenance_option); - gboolean ret = FALSE; + const gint len = strlen(cache_maintenance_option); if (argc >= 2) { const gchar *cmd_line = argv[1]; if (strncmp(cmd_line, cache_maintenance_option, len) == 0) { - ret = TRUE; + return TRUE; } } - return ret; + return FALSE; } static void process_command_line_for_cache_maintenance_option(gint argc, gchar *argv[]) @@ -1250,6 +1258,19 @@ static void create_application_paths() gint main(gint argc, gchar *argv[]) { + // We handle unit tests here because it takes the place of running the + // rest of the app. + if (search_command_line_for_unit_test_option(argc, argv)) + { +#if ENABLE_UNIT_TESTS + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +#else + fprintf(stderr, "Unit tests are not enabled in this build.\n"); + return 1; +#endif + } + CollectionData *cd = nullptr; CollectionData *first_collection = nullptr; gboolean disable_clutter = FALSE; @@ -1313,7 +1334,7 @@ gint main(gint argc, gchar *argv[]) parse_command_line_for_debug_option(argc, argv); DEBUG_1("%s main: gtk_init", get_exec_time()); #if HAVE_CLUTTER - if (parse_command_line_for_clutter_option(argc, argv)) + if (search_command_line_for_clutter_option(argc, argv)) { disable_clutter = TRUE; gtk_init(&argc, &argv); diff --git a/src/menu.cc b/src/menu.cc index 085e69de..5d9ac017 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -459,8 +459,8 @@ GtkWidget *submenu_add_collections(GtkWidget *menu, GtkWidget **menu_item, submenu = gtk_menu_new(); g_object_set_data(G_OBJECT(submenu), "submenu_data", data); - menu_item_add_stock_sensitive(submenu, _("New collection"), - GQ_ICON_COLLECTION, TRUE, G_CALLBACK(func), GINT_TO_POINTER(-1)); + menu_item_add_icon_sensitive(submenu, _("New collection"), + PIXBUF_INLINE_COLLECTION, TRUE, G_CALLBACK(func), GINT_TO_POINTER(-1)); menu_item_add_divider(submenu); collect_manager_list(&collection_list,nullptr,nullptr); diff --git a/src/meson.build b/src/meson.build index 67330e30..e39330e7 100644 --- a/src/meson.build +++ b/src/meson.build @@ -309,6 +309,10 @@ subdir('third-party') subdir('ui') subdir('view-file') +if conf_data.get('ENABLE_UNIT_TESTS', 0) == 1 + subdir('tests') +endif + gq_marshal = gnome.genmarshal('gq-marshal', prefix : 'gq_marshal', sources : 'gq-marshal.list') project_sources += gq_marshal[1] @@ -360,5 +364,5 @@ lua_dep, poppler_glib_dep, thread_dep, tiff_dep -], +] + conditional_unit_test_deps, include_directories : [configuration_inc], install : true) diff --git a/src/metadata.cc b/src/metadata.cc index 022906ff..4ba1dcd7 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -59,6 +59,11 @@ enum MetadataKey { MK_COMMENT }; +struct MetadataCacheEntry { + gchar *key; + GList *values; +}; + /* If contents change, keep GuideOptionsMetadata.xml up to date */ /** * @brief Tags that will be written to all files in a group - selected by: options->metadata.sync_grouped_files, Preferences/Metadata/Write The Same Description Tags To All Grouped Sidecars @@ -88,6 +93,20 @@ constexpr std::array group_keys{ "Xmp.xmp.Rating", }; +gint metadata_cache_entry_compare_key(const MetadataCacheEntry *entry, const gchar *key) +{ + return strcmp(entry->key, key); +} + +void metadata_cache_entry_free(MetadataCacheEntry *entry) +{ + if (!entry) return; + + g_free(entry->key); + g_list_free_full(entry->values, g_free); + g_free(entry); +} + inline gboolean is_keywords_separator(gchar c) { return c == ',' @@ -111,82 +130,64 @@ static gboolean metadata_file_read(gchar *path, GList **keywords, gchar **commen *------------------------------------------------------------------- */ -/* fd->cached metadata list of lists - each particular list contains key as a first entry, then the values -*/ +/* fd->cached_metadata list of MetadataCacheEntry */ static void metadata_cache_update(FileData *fd, const gchar *key, const GList *values) { GList *work; - work = fd->cached_metadata; - while (work) + work = g_list_find_custom(fd->cached_metadata, key, reinterpret_cast(metadata_cache_entry_compare_key)); + if (work) { - auto entry = static_cast(work->data); - auto entry_key = static_cast(entry->data); + /* key found - just replace values */ + auto *entry = static_cast(work->data); - if (strcmp(entry_key, key) == 0) - { - /* key found - just replace values */ - GList *old_values = entry->next; - entry->next = nullptr; - old_values->prev = nullptr; - g_list_free_full(old_values, g_free); - work->data = g_list_append(entry, string_list_copy(values)); - DEBUG_1("updated %s %s\n", key, fd->path); - return; - } - work = work->next; + g_list_free_full(entry->values, g_free); + entry->values = string_list_copy(values); + DEBUG_1("updated %s %s\n", key, fd->path); + return; } /* key not found - prepend new entry */ - fd->cached_metadata = g_list_prepend(fd->cached_metadata, - g_list_prepend(string_list_copy(values), g_strdup(key))); - DEBUG_1("added %s %s\n", key, fd->path); + auto *entry = g_new0(MetadataCacheEntry, 1); + entry->key = g_strdup(key); + entry->values = string_list_copy(values); + fd->cached_metadata = g_list_prepend(fd->cached_metadata, entry); + DEBUG_1("added %s %s\n", key, fd->path); } static const GList *metadata_cache_get(FileData *fd, const gchar *key) { GList *work; - work = fd->cached_metadata; - while (work) + work = g_list_find_custom(fd->cached_metadata, key, reinterpret_cast(metadata_cache_entry_compare_key)); + if (work) { - auto entry = static_cast(work->data); - auto entry_key = static_cast(entry->data); + /* key found */ + auto *entry = static_cast(work->data); - if (strcmp(entry_key, key) == 0) - { - /* key found */ - DEBUG_1("found %s %s\n", key, fd->path); - return entry; - } - work = work->next; + DEBUG_1("found %s %s\n", key, fd->path); + return entry->values; } - return nullptr; DEBUG_1("not found %s %s\n", key, fd->path); + return nullptr; } static void metadata_cache_remove(FileData *fd, const gchar *key) { GList *work; - work = fd->cached_metadata; - while (work) + work = g_list_find_custom(fd->cached_metadata, key, reinterpret_cast(metadata_cache_entry_compare_key)); + if (work) { - auto entry = static_cast(work->data); - auto entry_key = static_cast(entry->data); + /* key found */ + auto *entry = static_cast(work->data); - if (strcmp(entry_key, key) == 0) - { - /* key found */ - g_list_free_full(entry, g_free); - fd->cached_metadata = g_list_delete_link(fd->cached_metadata, work); - DEBUG_1("removed %s %s\n", key, fd->path); - return; - } - work = work->next; + metadata_cache_entry_free(entry); + fd->cached_metadata = g_list_delete_link(fd->cached_metadata, work); + DEBUG_1("removed %s %s\n", key, fd->path); + return; } DEBUG_1("not removed %s %s\n", key, fd->path); } @@ -195,19 +196,11 @@ void metadata_cache_free(FileData *fd) { if (fd->cached_metadata) DEBUG_1("freed %s\n", fd->path); - g_list_free_full(fd->cached_metadata, [](gpointer data) - { - auto entry = static_cast(data); - g_list_free_full(entry, g_free); - }); + g_list_free_full(fd->cached_metadata, reinterpret_cast(metadata_cache_entry_free)); fd->cached_metadata = nullptr; } - - - - /* *------------------------------------------------------------------- * write queue @@ -689,21 +682,21 @@ GList *metadata_read_list(FileData *fd, const gchar *key, MetadataFormat format) { ExifData *exif; GList *list = nullptr; - const GList *cache_entry; + const GList *cache_values; if (!fd) return nullptr; /* unwritten data override everything */ if (fd->modified_xmp && format == METADATA_PLAIN) { - list = static_cast(g_hash_table_lookup(fd->modified_xmp, key)); + list = static_cast(g_hash_table_lookup(fd->modified_xmp, key)); if (list) return string_list_copy(list); } if (format == METADATA_PLAIN && strcmp(key, KEYWORD_KEY) == 0 - && (cache_entry = metadata_cache_get(fd, key))) + && (cache_values = metadata_cache_get(fd, key))) { - return string_list_copy(cache_entry->next); + return string_list_copy(cache_values); } /* @@ -1395,20 +1388,8 @@ static gboolean keyword_tree_is_set_casefold(GtkTreeModel *keyword_tree, GtkTree if (keyword_get_is_keyword(keyword_tree, &iter)) { - GList *work = casefold_list; - gboolean found = FALSE; gchar *iter_casefold = keyword_get_casefold(keyword_tree, &iter); - while (work) - { - auto casefold = static_cast(work->data); - work = work->next; - - if (strcmp(iter_casefold, casefold) == 0) - { - found = TRUE; - break; - } - } + GList *found = g_list_find_custom(casefold_list, iter_casefold, reinterpret_cast(strcmp)); g_free(iter_casefold); if (!found) return FALSE; } @@ -1442,20 +1423,8 @@ static gboolean keyword_tree_is_set_casefull(GtkTreeModel *keyword_tree, GtkTree if (keyword_get_is_keyword(keyword_tree, &iter)) { - GList *work = kw_list; - gboolean found = FALSE; gchar *iter_name = keyword_get_name(keyword_tree, &iter); - while (work) - { - auto name = static_cast(work->data); - work = work->next; - - if (strcmp(iter_name, name) == 0) - { - found = TRUE; - break; - } - } + GList *found = g_list_find_custom(kw_list, iter_name, reinterpret_cast(strcmp)); g_free(iter_name); if (!found) return FALSE; } diff --git a/src/misc.cc b/src/misc.cc index 632471b8..9c9871a8 100644 --- a/src/misc.cc +++ b/src/misc.cc @@ -335,6 +335,8 @@ gchar *date_get_abbreviated_day_name(gint day) case 7: abday = g_strdup(nl_langinfo(ABDAY_7)); break; + default: + break; } return abday; diff --git a/src/pan-view/pan-calendar.cc b/src/pan-view/pan-calendar.cc index e3faa61f..6c419252 100644 --- a/src/pan-view/pan-calendar.cc +++ b/src/pan-view/pan-calendar.cc @@ -88,8 +88,6 @@ void pan_calendar_update(PanWindow *pw, PanItem *pi_day) gint y3; gint x; gint y; - gint w; - gint h; gint grid; gint column; @@ -187,13 +185,11 @@ void pan_calendar_update(PanWindow *pw, PanItem *pi_day) y2 = pbox->y + MIN(42, pbox->height); x3 = pbox->x + 1; y3 = MAX(pbox->y, y2 - 30); - util_clip_triangle(x1, y1, x2, y2, x3, y3, - x, y, w, h); - pi = pan_item_tri_new(pw, nullptr, x, y, w, h, - x1, y1, x2, y2, x3, y3, - PAN_CAL_POPUP_COLOR); - pan_item_tri_border(pi, PAN_BORDER_1 | PAN_BORDER_3, PAN_CAL_POPUP_BORDER_COLOR); + pi = pan_item_tri_new(pw, + x1, y1, x2, y2, x3, y3, + PAN_CAL_POPUP_COLOR, + PAN_BORDER_1 | PAN_BORDER_3, PAN_CAL_POPUP_BORDER_COLOR); pan_item_set_key(pi, "day_bubble"); pan_item_added(pw, pi); diff --git a/src/pan-view/pan-folder.cc b/src/pan-view/pan-folder.cc index 9e3eff30..84e1ce72 100644 --- a/src/pan-view/pan-folder.cc +++ b/src/pan-view/pan-folder.cc @@ -76,15 +76,13 @@ static void pan_flower_size(PanWindow *pw, gint &width, gint &height) if (pi->type == PAN_ITEM_TRIANGLE && pi->data) { - gint *coord; - - coord = static_cast(pi->data); - coord[0] -= x1; - coord[1] -= y1; - coord[2] -= x1; - coord[3] -= y1; - coord[4] -= x1; - coord[5] -= y1; + auto *coord = static_cast(pi->data); + + for (gint i = 0; i < 3; ++i) + { + coord[i].x -= x1; + coord[i].y -= y1; + } } } @@ -183,10 +181,6 @@ static void pan_flower_build(PanWindow *pw, FlowerGroup *group, FlowerGroup *par gint py; gint gx; gint gy; - gint x1; - gint y1; - gint x2; - gint y2; px = parent->x + parent->width / 2; py = parent->y + parent->height / 2; @@ -194,16 +188,10 @@ static void pan_flower_build(PanWindow *pw, FlowerGroup *group, FlowerGroup *par gx = group->x + group->width / 2; gy = group->y + group->height / 2; - x1 = MIN(px, gx); - y1 = MIN(py, gy); - - x2 = MAX(px, gx + 5); - y2 = MAX(py, gy + 5); - - pi = pan_item_tri_new(pw, nullptr, x1, y1, x2 - x1, y2 - y1, - px, py, gx, gy, gx + 5, gy + 5, - {255, 40, 40, 128}); - pan_item_tri_border(pi, PAN_BORDER_1 | PAN_BORDER_3, {255, 0, 0, 128}); + pi = pan_item_tri_new(pw, + px, py, gx, gy, gx + 5, gy + 5, + {255, 40, 40, 128}, + PAN_BORDER_1 | PAN_BORDER_3, {255, 0, 0, 128}); } pw->list = g_list_concat(group->items, pw->list); diff --git a/src/pan-view/pan-item.cc b/src/pan-view/pan-item.cc index 13b4dec0..dca12e98 100644 --- a/src/pan-view/pan-item.cc +++ b/src/pan-view/pan-item.cc @@ -217,42 +217,42 @@ gint pan_item_box_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRender } if (util_clip_region(x, y, width, height, - pi->x, pi->y, bw, bh, - &rx, &ry, &rw, &rh)) + pi->x, pi->y, bw, bh, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, pi->color.r, pi->color.g, pi->color.b, pi->color.a); } if (util_clip_region(x, y, width, height, - pi->x, pi->y, bw, pi->border, - &rx, &ry, &rw, &rh)) + pi->x, pi->y, bw, pi->border, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, pi->color2.r, pi->color2.g, pi->color2.b, pi->color2.a); } if (util_clip_region(x, y, width, height, - pi->x, pi->y + pi->border, pi->border, bh - pi->border * 2, - &rx, &ry, &rw, &rh)) + pi->x, pi->y + pi->border, pi->border, bh - pi->border * 2, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, pi->color2.r, pi->color2.g, pi->color2.b, pi->color2.a); } if (util_clip_region(x, y, width, height, - pi->x + bw - pi->border, pi->y + pi->border, - pi->border, bh - pi->border * 2, - &rx, &ry, &rw, &rh)) + pi->x + bw - pi->border, pi->y + pi->border, + pi->border, bh - pi->border * 2, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, pi->color2.r, pi->color2.g, pi->color2.b, pi->color2.a); } if (util_clip_region(x, y, width, height, - pi->x, pi->y + bh - pi->border, - bw, pi->border, - &rx, &ry, &rw, &rh)) + pi->x, pi->y + bh - pi->border, + bw, pi->border, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, @@ -269,48 +269,35 @@ gint pan_item_box_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRender *----------------------------------------------------------------------------- */ -PanItem *pan_item_tri_new(PanWindow *pw, FileData *, gint x, gint y, gint width, gint height, +PanItem *pan_item_tri_new(PanWindow *pw, gint x1, gint y1, gint x2, gint y2, gint x3, gint y3, - const PanColor &color) + const PanColor &color, + gint borders, const PanColor &border_color) { PanItem *pi; - gint *coord; pi = g_new0(PanItem, 1); pi->type = PAN_ITEM_TRIANGLE; - pi->x = x; - pi->y = y; - pi->width = width; - pi->height = height; - pi->color = color; - coord = g_new0(gint, 6); - coord[0] = x1; - coord[1] = y1; - coord[2] = x2; - coord[3] = y2; - coord[4] = x3; - coord[5] = y3; + util_clip_triangle(x1, y1, x2, y2, x3, y3, + pi->x, pi->y, pi->width, pi->height); + + auto *coord = g_new0(GdkPoint, 3); + coord[0] = {x1, y1}; + coord[1] = {x2, y2}; + coord[2] = {x3, y3}; pi->data = coord; - pi->border = PAN_BORDER_NONE; + pi->border = borders; + pi->color2 = border_color; pw->list = g_list_prepend(pw->list, pi); return pi; } -void pan_item_tri_border(PanItem *pi, gint borders, const PanColor &color) -{ - if (!pi || pi->type != PAN_ITEM_TRIANGLE) return; - - pi->border = borders; - - pi->color2 = color; -} - gint pan_item_tri_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *, gint x, gint y, gint width, gint height) { gint rx; @@ -319,41 +306,29 @@ gint pan_item_tri_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRender gint rh; if (util_clip_region(x, y, width, height, - pi->x, pi->y, pi->width, pi->height, - &rx, &ry, &rw, &rh) && pi->data) + pi->x, pi->y, pi->width, pi->height, + rx, ry, rw, rh) && pi->data) { - auto coord = static_cast(pi->data); + auto coord = static_cast(pi->data); pixbuf_draw_triangle(pixbuf, - rx - x, ry - y, rw, rh, - coord[0] - x, coord[1] - y, - coord[2] - x, coord[3] - y, - coord[4] - x, coord[5] - y, - pi->color.r, pi->color.g, pi->color.b, pi->color.a); + rx - x, ry - y, rw, rh, + coord[0].x - x, coord[0].y - y, + coord[1].x - x, coord[1].y - y, + coord[2].x - x, coord[2].y - y, + pi->color.r, pi->color.g, pi->color.b, pi->color.a); - if (pi->border & PAN_BORDER_1) - { - pixbuf_draw_line(pixbuf, - rx - x, ry - y, rw, rh, - coord[0] - x, coord[1] - y, - coord[2] - x, coord[3] - y, - pi->color2.r, pi->color2.g, pi->color2.b, pi->color2.a); - } - if (pi->border & PAN_BORDER_2) - { - pixbuf_draw_line(pixbuf, - rx - x, ry - y, rw, rh, - coord[2] - x, coord[3] - y, - coord[4] - x, coord[5] - y, - pi->color2.r, pi->color2.g, pi->color2.b, pi->color2.a); - } - if (pi->border & PAN_BORDER_3) - { + const auto draw_line = [pixbuf, rx, ry, rw, rh, x, y, &color = pi->color2](const GdkPoint &start, const GdkPoint &end) + { pixbuf_draw_line(pixbuf, - rx - x, ry - y, rw, rh, - coord[4] - x, coord[5] - y, - coord[0] - x, coord[1] - y, - pi->color2.r, pi->color2.g, pi->color2.b, pi->color2.a); - } + rx - x, ry - y, rw, rh, + start.x - x, start.y - y, + end.x - x, end.y - y, + color.r, color.g, color.b, color.a); + }; + + if (pi->border & PAN_BORDER_1) draw_line(coord[0], coord[1]); + if (pi->border & PAN_BORDER_2) draw_line(coord[1], coord[2]); + if (pi->border & PAN_BORDER_3) draw_line(coord[2], coord[0]); } return FALSE; @@ -504,8 +479,8 @@ gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRe if (gdk_pixbuf_get_has_alpha(pi->pixbuf)) { if (util_clip_region(x, y, width, height, - tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th, - &rx, &ry, &rw, &rh)) + tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th, + rx, ry, rw, rh)) { pixbuf_draw_shadow(pixbuf, rx - x, ry - y, rw, rh, @@ -517,9 +492,9 @@ gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRe else { if (util_clip_region(x, y, width, height, - tx + tw, ty + PAN_SHADOW_OFFSET, - PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET, - &rx, &ry, &rw, &rh)) + tx + tw, ty + PAN_SHADOW_OFFSET, + PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET, + rx, ry, rw, rh)) { pixbuf_draw_shadow(pixbuf, rx - x, ry - y, rw, rh, @@ -528,8 +503,8 @@ gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRe PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA); } if (util_clip_region(x, y, width, height, - tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET, - &rx, &ry, &rw, &rh)) + tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET, + rx, ry, rw, rh)) { pixbuf_draw_shadow(pixbuf, rx - x, ry - y, rw, rh, @@ -540,8 +515,8 @@ gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRe } if (util_clip_region(x, y, width, height, - tx, ty, tw, th, - &rx, &ry, &rw, &rh)) + tx, ty, tw, th, + rx, ry, rw, rh)) { gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh, static_cast(tx) - x, @@ -551,34 +526,34 @@ gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRe } if (util_clip_region(x, y, width, height, - tx, ty, tw, PAN_OUTLINE_THICKNESS, - &rx, &ry, &rw, &rh)) + tx, ty, tw, PAN_OUTLINE_THICKNESS, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, PAN_OUTLINE_COLOR_1); } if (util_clip_region(x, y, width, height, - tx, ty, PAN_OUTLINE_THICKNESS, th, - &rx, &ry, &rw, &rh)) + tx, ty, PAN_OUTLINE_THICKNESS, th, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, PAN_OUTLINE_COLOR_1); } if (util_clip_region(x, y, width, height, - tx + tw - PAN_OUTLINE_THICKNESS, ty + PAN_OUTLINE_THICKNESS, - PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS, - &rx, &ry, &rw, &rh)) + tx + tw - PAN_OUTLINE_THICKNESS, ty + PAN_OUTLINE_THICKNESS, + PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, PAN_OUTLINE_COLOR_2); } if (util_clip_region(x, y, width, height, - tx + PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS, - tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS, - &rx, &ry, &rw, &rh)) + tx + PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS, + tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS, + rx, ry, rw, rh)) { pixbuf_draw_rect_fill(pixbuf, rx - x, ry - y, rw, rh, @@ -593,8 +568,8 @@ gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRe ty = pi->y + PAN_SHADOW_OFFSET; if (util_clip_region(x, y, width, height, - tx, ty, tw, th, - &rx, &ry, &rw, &rh)) + tx, ty, tw, th, + rx, ry, rw, rh)) { gint d; @@ -677,8 +652,8 @@ gint pan_item_image_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRend gint rh; if (util_clip_region(x, y, width, height, - pi->x, pi->y, pi->width, pi->height, - &rx, &ry, &rw, &rh)) + pi->x, pi->y, pi->width, pi->height, + rx, ry, rw, rh)) { if (pi->pixbuf) { diff --git a/src/pan-view/pan-item.h b/src/pan-view/pan-item.h index ec43470f..bfd88be7 100644 --- a/src/pan-view/pan-item.h +++ b/src/pan-view/pan-item.h @@ -57,10 +57,10 @@ gint pan_item_box_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRend gint x, gint y, gint width, gint height); // Item triangle type -PanItem *pan_item_tri_new(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height, +PanItem *pan_item_tri_new(PanWindow *pw, gint x1, gint y1, gint x2, gint y2, gint x3, gint y3, - const PanColor &color); -void pan_item_tri_border(PanItem *pi, gint borders, const PanColor &color); + const PanColor &color, + gint borders, const PanColor &border_color); gint pan_item_tri_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr, gint x, gint y, gint width, gint height); diff --git a/src/pan-view/pan-view-search.cc b/src/pan-view/pan-view-search.cc index 5247054b..2ff48ae6 100644 --- a/src/pan-view/pan-view-search.cc +++ b/src/pan-view/pan-view-search.cc @@ -70,7 +70,7 @@ PanViewSearchUi *pan_search_ui_new(PanWindow *pw) gtk_button_set_relief(GTK_BUTTON(ui->search_button), GTK_RELIEF_NONE); gtk_widget_set_focus_on_click(ui->search_button, FALSE); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP); - gtk_container_add(GTK_CONTAINER(ui->search_button), hbox); + gq_gtk_container_add(GTK_WIDGET(ui->search_button), hbox); gtk_widget_show(hbox); ui->search_button_arrow = gtk_image_new_from_icon_name(GQ_ICON_PAN_UP, GTK_ICON_SIZE_BUTTON); gq_gtk_box_pack_start(GTK_BOX(hbox), ui->search_button_arrow, FALSE, FALSE, 0); diff --git a/src/pan-view/pan-view.cc b/src/pan-view/pan-view.cc index 1bcc7f34..d3793f6e 100644 --- a/src/pan-view/pan-view.cc +++ b/src/pan-view/pan-view.cc @@ -74,10 +74,7 @@ namespace { struct PanGrid { - gint x; - gint y; - gint w; - gint h; + GdkRectangle rect; GList *list; }; @@ -368,42 +365,35 @@ static gboolean pan_window_request_tile_cb(PixbufRenderer *pr, gint x, gint y, auto pw = static_cast(data); GList *list; GList *work; - gint i; + const GdkRectangle request_rect{x, y, width, height}; + GdkRectangle pan_grid_rect; + GdkRectangle r; pixbuf_set_rect_fill(pixbuf, 0, 0, width, height, PAN_BACKGROUND_COLOR); - for (i = (x / PAN_GRID_SIZE) * PAN_GRID_SIZE; i < x + width; i += PAN_GRID_SIZE) + pan_grid_rect = request_rect; + pan_grid_rect.width = 1; + for (pan_grid_rect.x = (x / PAN_GRID_SIZE) * PAN_GRID_SIZE; pan_grid_rect.x < x + width; pan_grid_rect.x += PAN_GRID_SIZE) { - gint rx; - gint ry; - gint rw; - gint rh; - - if (util_clip_region(x, y, width, height, - i, y, 1, height, - &rx, &ry, &rw, &rh)) + if (gdk_rectangle_intersect(&request_rect, &pan_grid_rect, &r)) { pixbuf_draw_rect_fill(pixbuf, - rx - x, ry - y, rw, rh, - PAN_GRID_COLOR); + r.x - x, r.y - y, r.width, r.height, + PAN_GRID_COLOR); } } - for (i = (y / PAN_GRID_SIZE) * PAN_GRID_SIZE; i < y + height; i += PAN_GRID_SIZE) - { - gint rx; - gint ry; - gint rw; - gint rh; - if (util_clip_region(x, y, width, height, - x, i, width, 1, - &rx, &ry, &rw, &rh)) + pan_grid_rect = request_rect; + pan_grid_rect.height = 1; + for (pan_grid_rect.y = (y / PAN_GRID_SIZE) * PAN_GRID_SIZE; pan_grid_rect.y < y + height; pan_grid_rect.y += PAN_GRID_SIZE) + { + if (gdk_rectangle_intersect(&request_rect, &pan_grid_rect, &r)) { pixbuf_draw_rect_fill(pixbuf, - rx - x, ry - y, rw, rh, - PAN_GRID_COLOR); + r.x - x, r.y - y, r.width, r.height, + PAN_GRID_COLOR); } } @@ -759,7 +749,6 @@ static void pan_grid_clear(PanWindow *pw) static void pan_grid_build(PanWindow *pw, gint width, gint height, gint grid_size) { - GList *work; gint col; gint row; gint cw; @@ -796,54 +785,38 @@ static void pan_grid_build(PanWindow *pw, gint width, gint height, gint grid_siz PanGrid *pg; pg = g_new0(PanGrid, 1); - pg->x = i * cw / 2; - pg->y = j * ch / 2; - pg->w = cw; - pg->h = ch; + pg->rect.x = i * cw / 2; + pg->rect.y = j * ch / 2; + pg->rect.width = cw; + pg->rect.height = ch; pw->list_grid = g_list_prepend(pw->list_grid, pg); - DEBUG_1("grid section: %d,%d (%dx%d)", pg->x, pg->y, pg->w, pg->h); + DEBUG_1("grid section: %d,%d (%dx%d)", pg->rect.x, pg->rect.y, pg->rect.width, pg->rect.height); } } - work = pw->list; - while (work) + for (GList *work = pw->list; work; work = work->next) { - PanItem *pi; - GList *grid; + auto *pi = static_cast(work->data); - pi = static_cast(work->data); - work = work->next; + // @todo use GdkRectangle in PanItem + const GdkRectangle pi_rect{pi->x, pi->y, pi->width, pi->height}; - grid = pw->list_grid; - while (grid) + for (GList *grid = pw->list_grid; grid; grid = grid->next) { - PanGrid *pg; - gint rx; - gint ry; - gint rw; - gint rh; - - pg = static_cast(grid->data); - grid = grid->next; + auto *pg = static_cast(grid->data); - if (util_clip_region(pi->x, pi->y, pi->width, pi->height, - pg->x, pg->y, pg->w, pg->h, - &rx, &ry, &rw, &rh)) + if (gdk_rectangle_intersect(&pi_rect, &pg->rect, nullptr)) { pg->list = g_list_prepend(pg->list, pi); } } } - work = pw->list_grid; - while (work) + for (GList *grid = pw->list_grid; grid; grid = grid->next) { - PanGrid *pg; - - pg = static_cast(work->data); - work = work->next; + auto *pg = static_cast(grid->data); pg->list = g_list_reverse(pg->list); } @@ -969,25 +942,14 @@ static void pan_layout_compute(PanWindow *pw, FileData *dir_fd, } static GList *pan_layout_intersect_l(GList *list, GList *item_list, - gint x, gint y, gint width, gint height) + const GdkRectangle &rect) { - GList *work; - - work = item_list; - while (work) + for (GList *work = item_list; work; work = work->next) { - PanItem *pi; - gint rx; - gint ry; - gint rw; - gint rh; + auto *pi = static_cast(work->data); + const GdkRectangle pi_rect = {pi->x, pi->y, pi->width, pi->height}; - pi = static_cast(work->data); - work = work->next; - - if (util_clip_region(x, y, width, height, - pi->x, pi->y, pi->width, pi->height, - &rx, &ry, &rw, &rh)) + if (gdk_rectangle_intersect(&rect, &pi_rect, nullptr)) { list = g_list_prepend(list, pi); } @@ -999,31 +961,29 @@ static GList *pan_layout_intersect_l(GList *list, GList *item_list, GList *pan_layout_intersect(PanWindow *pw, gint x, gint y, gint width, gint height) { GList *list = nullptr; - GList *grid; - PanGrid *pg = nullptr; + const GdkRectangle rect{x, y, width, height}; - grid = pw->list_grid; - while (grid && !pg) - { - pg = static_cast(grid->data); - grid = grid->next; + const auto pan_grid_contains_rect = [](gconstpointer data, gconstpointer user_data) -> gint + { + const auto *pg = static_cast(data); + const auto *rect = static_cast(user_data); - if (x < pg->x || x + width > pg->x + pg->w || - y < pg->y || y + height > pg->y + pg->h) - { - pg = nullptr; - } - } + GdkRectangle intersection; + if (!gdk_rectangle_intersect(&pg->rect, rect, &intersection)) return 1; + + return gdk_rectangle_equal(rect, &intersection) ? 0 : 1; + }; - list = pan_layout_intersect_l(list, pw->list, x, y, width, height); + list = pan_layout_intersect_l(list, pw->list, rect); - if (pg) + GList *grid = g_list_find_custom(pw->list_grid, &rect, pan_grid_contains_rect); + if (grid) { - list = pan_layout_intersect_l(list, pg->list, x, y, width, height); + list = pan_layout_intersect_l(list, static_cast(grid->data)->list, rect); } else { - list = pan_layout_intersect_l(list, pw->list_static, x, y, width, height); + list = pan_layout_intersect_l(list, pw->list_static, rect); } return list; @@ -1379,6 +1339,8 @@ static gboolean pan_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, g break; stop_signal = FALSE; break; + default: + break; } } } @@ -1439,10 +1401,6 @@ void pan_info_update(PanWindow *pw, PanItem *pi) gint y2; gint x3; gint y3; - gint x; - gint y; - gint w; - gint h; if (pw->click_pi == pi) return; if (pi && !pi->fd) pi = nullptr; @@ -1460,8 +1418,8 @@ void pan_info_update(PanWindow *pw, PanItem *pi) if (pi->type == PAN_ITEM_THUMB && pi->pixbuf) { - w = gdk_pixbuf_get_width(pi->pixbuf); - h = gdk_pixbuf_get_height(pi->pixbuf); + gint w = gdk_pixbuf_get_width(pi->pixbuf); + gint h = gdk_pixbuf_get_height(pi->pixbuf); x1 = pi->x + pi->width - (pi->width - w) / 2 - 8; y1 = pi->y + (pi->height - h) / 2 + 8; @@ -1476,13 +1434,11 @@ void pan_info_update(PanWindow *pw, PanItem *pi) y2 = pbox->y + 36; x3 = pbox->x + 1; y3 = pbox->y + 12; - util_clip_triangle(x1, y1, x2, y2, x3, y3, - x, y, w, h); - p = pan_item_tri_new(pw, nullptr, x, y, w, h, - x1, y1, x2, y2, x3, y3, - PAN_POPUP_COLOR); - pan_item_tri_border(p, PAN_BORDER_1 | PAN_BORDER_3, PAN_POPUP_BORDER_COLOR); + p = pan_item_tri_new(pw, + x1, y1, x2, y2, x3, y3, + PAN_POPUP_COLOR, + PAN_BORDER_1 | PAN_BORDER_3, PAN_POPUP_BORDER_COLOR); pan_item_set_key(p, "info"); pan_item_added(pw, p); @@ -1533,6 +1489,8 @@ void pan_info_update(PanWindow *pw, PanItem *pi) case PAN_IMAGE_SIZE_100: scale = 100; break; + default: + break; } iw = MAX(1, iw * scale / 100); @@ -1898,7 +1856,7 @@ static void pan_window_new_real(FileData *dir_fd) vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); DEBUG_NAME(vbox); - gtk_container_add(GTK_CONTAINER(pw->window), vbox); + gq_gtk_container_add(GTK_WIDGET(pw->window), vbox); gtk_widget_show(vbox); box = pref_box_new(vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE); @@ -1947,19 +1905,19 @@ static void pan_window_new_real(FileData *dir_fd) vbox_imd_widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); hbox_imd_widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_pack_start(GTK_BOX(vbox_imd_widget), pw->imd->widget, true, true, 0); + gq_gtk_box_pack_start(GTK_BOX(vbox_imd_widget), pw->imd->widget, true, true, 0); pw->scrollbar_h = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, nullptr); g_signal_connect(G_OBJECT(pw->scrollbar_h), "value_changed", G_CALLBACK(pan_window_scrollbar_h_value_cb), pw); - gtk_box_pack_start(GTK_BOX(vbox_imd_widget), pw->scrollbar_h, false, false, 0); + gq_gtk_box_pack_start(GTK_BOX(vbox_imd_widget), pw->scrollbar_h, false, false, 0); - gtk_box_pack_start(GTK_BOX(hbox_imd_widget), vbox_imd_widget, true, true, 0); + gq_gtk_box_pack_start(GTK_BOX(hbox_imd_widget), vbox_imd_widget, true, true, 0); pw->scrollbar_v = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, nullptr); g_signal_connect(G_OBJECT(pw->scrollbar_v), "value_changed", G_CALLBACK(pan_window_scrollbar_v_value_cb), pw); - gtk_box_pack_start(GTK_BOX(hbox_imd_widget), pw->scrollbar_v, false, false, 0); + gq_gtk_box_pack_start(GTK_BOX(hbox_imd_widget), pw->scrollbar_v, false, false, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox_imd_widget, true, true, 0); + gq_gtk_box_pack_start(GTK_BOX(vbox), hbox_imd_widget, true, true, 0); gtk_widget_show(GTK_WIDGET(hbox_imd_widget)); gtk_widget_show(GTK_WIDGET(pw->imd->widget)); @@ -1993,7 +1951,7 @@ static void pan_window_new_real(FileData *dir_fd) gtk_widget_show(frame); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE); - gtk_container_add(GTK_CONTAINER(frame), hbox); + gq_gtk_container_add(GTK_WIDGET(frame), hbox); gtk_widget_show(hbox); pref_spacer(hbox, 0); @@ -2007,7 +1965,7 @@ static void pan_window_new_real(FileData *dir_fd) gtk_widget_show(frame); pw->label_zoom = gtk_label_new(""); - gtk_container_add(GTK_CONTAINER(frame), pw->label_zoom); + gq_gtk_container_add(GTK_WIDGET(frame), pw->label_zoom); gtk_widget_show(pw->label_zoom); // Add the "Find" button to the status bar area. diff --git a/src/pixbuf-renderer.cc b/src/pixbuf-renderer.cc index 933eae9f..b95b970c 100644 --- a/src/pixbuf-renderer.cc +++ b/src/pixbuf-renderer.cc @@ -2284,6 +2284,8 @@ static void pr_create_anaglyph_color(GdkPixbuf *pixbuf, GdkPixbuf *right, gint x dp[0] = sp[0]; dp[1] = sp[1]; break; + default: + break; } sp += COLOR_BYTES; dp += COLOR_BYTES; @@ -2338,6 +2340,8 @@ static void pr_create_anaglyph_gray(GdkPixbuf *pixbuf, GdkPixbuf *right, gint x, dp[1] = g2; dp[2] = g1; break; + default: + break; } sp += COLOR_BYTES; dp += COLOR_BYTES; @@ -2383,6 +2387,8 @@ static void pr_create_anaglyph_dubois(GdkPixbuf *pixbuf, GdkPixbuf *right, gint case YB: memcpy(pr_dubois_matrix, pr_dubois_matrix_YB, sizeof pr_dubois_matrix); break; + default: + break; } srs = gdk_pixbuf_get_rowstride(right); diff --git a/src/pixbuf-util.cc b/src/pixbuf-util.cc index 3e2a2572..0735a047 100644 --- a/src/pixbuf-util.cc +++ b/src/pixbuf-util.cc @@ -395,30 +395,23 @@ GdkPixbuf *pixbuf_fallback(FileData *fd, gint requested_width, gint requested_he */ gboolean util_clip_region(gint x, gint y, gint w, gint h, - gint clip_x, gint clip_y, gint clip_w, gint clip_h, - gint *rx, gint *ry, gint *rw, gint *rh) + gint clip_x, gint clip_y, gint clip_w, gint clip_h, + gint &rx, gint &ry, gint &rw, gint &rh) { - // Ensures that clip region and main region have some overlap (they aren't - // completely disjoint). - if (clip_x + clip_w <= x || /* assert(x < clip_right) && */ - clip_x >= x + w || /* assert(clip_x < right) && */ - clip_y + clip_h <= y || /* assert(y < clip_bottom && */ - clip_y >= y + h) /* assert(bottom < clip_y) */ + GdkRectangle main{x, y, w, h}; + GdkRectangle clip{clip_x, clip_y, clip_w, clip_h}; + GdkRectangle r; + + const gboolean rectangles_intersect = gdk_rectangle_intersect(&main, &clip, &r); + if (rectangles_intersect) { - return FALSE; + rx = r.x; + ry = r.y; + rw = r.width; + rh = r.height; } - // We choose the right-most x coordinate. - *rx = MAX(x, clip_x); - // And the narrowest width. - *rw = MIN((x + w), (clip_x + clip_w)) - *rx; - - // We choose the bottom-most y coordinate. - *ry = MAX(y, clip_y); - // And the shortest height. - *rh = MIN((y + h), (clip_y + clip_h)) - *ry; - - return TRUE; + return rectangles_intersect; } /* @@ -1070,8 +1063,8 @@ void pixbuf_draw_triangle(GdkPixbuf *pb, // Intersects the clip region with the pixbuf. r{x,y,w,h} is that // intersecting region. if (!util_clip_region(0, 0, pw, ph, - clip_x, clip_y, clip_w, clip_h, - &rx, &ry, &rw, &rh)) return; + clip_x, clip_y, clip_w, clip_h, + rx, ry, rw, rh)) return; // Determine the bounding box for the triangle. util_clip_triangle(x1, y1, x2, y2, x3, y3, @@ -1079,8 +1072,8 @@ void pixbuf_draw_triangle(GdkPixbuf *pb, // And now clip the triangle bounding box to the pixbuf clipping region. if (!util_clip_region(rx, ry, rw, rh, - tx, ty, tw, th, - &fx1, &fy1, &fw, &fh)) return; + tx, ty, tw, th, + fx1, fy1, fw, fh)) return; fx2 = fx1 + fw; fy2 = fy1 + fh; @@ -1322,8 +1315,8 @@ void pixbuf_draw_line(GdkPixbuf *pb, // Intersects the clip region with the pixbuf. r{x,y,w,h} is that // intersecting region. if (!util_clip_region(0, 0, pw, ph, - clip_x, clip_y, clip_w, clip_h, - &rx, &ry, &rw, &rh)) return; + clip_x, clip_y, clip_w, clip_h, + rx, ry, rw, rh)) return; // TODO(xsdg): These explicit casts are unnecessary and harm readability. // Clips the specified line segment to the intersecting region from above. if (!util_clip_line(static_cast(rx), static_cast(ry), static_cast(rw), static_cast(rh), @@ -1528,8 +1521,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, // Intersects the clip region with the pixbuf. r{x,y,w,h} is that // intersecting region. if (!util_clip_region(0, 0, pw, ph, - clip_x, clip_y, clip_w, clip_h, - &rx, &ry, &rw, &rh)) return; + clip_x, clip_y, clip_w, clip_h, + rx, ry, rw, rh)) return; has_alpha = gdk_pixbuf_get_has_alpha(pb); prs = gdk_pixbuf_get_rowstride(pb); @@ -1539,8 +1532,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, // as contracted by `border` pixels, with a composition fraction that's defined // by the supplied `a` parameter. if (util_clip_region(x + border, y + border, w - border * 2, h - border * 2, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_rect_fill(pb, fx, fy, fw, fh, r, g, b, a); } @@ -1549,8 +1542,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, // Draws linear gradients along each of the 4 edges. if (util_clip_region(x, y + border, border, h - border * 2, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_fade_linear(p_pix, prs, has_alpha, x + border, TRUE, border, @@ -1558,8 +1551,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, r, g, b, a); } if (util_clip_region(x + w - border, y + border, border, h - border * 2, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_fade_linear(p_pix, prs, has_alpha, x + w - border, TRUE, border, @@ -1567,8 +1560,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, r, g, b, a); } if (util_clip_region(x + border, y, w - border * 2, border, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_fade_linear(p_pix, prs, has_alpha, y + border, FALSE, border, @@ -1576,8 +1569,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, r, g, b, a); } if (util_clip_region(x + border, y + h - border, w - border * 2, border, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_fade_linear(p_pix, prs, has_alpha, y + h - border, FALSE, border, @@ -1586,8 +1579,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, } // Draws radial gradients at each of the 4 corners. if (util_clip_region(x, y, border, border, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_fade_radius(p_pix, prs, has_alpha, x + border, y + border, border, @@ -1595,8 +1588,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, r, g, b, a); } if (util_clip_region(x + w - border, y, border, border, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_fade_radius(p_pix, prs, has_alpha, x + w - border, y + border, border, @@ -1604,8 +1597,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, r, g, b, a); } if (util_clip_region(x, y + h - border, border, border, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_fade_radius(p_pix, prs, has_alpha, x + border, y + h - border, border, @@ -1613,8 +1606,8 @@ void pixbuf_draw_shadow(GdkPixbuf *pb, r, g, b, a); } if (util_clip_region(x + w - border, y + h - border, border, border, - rx, ry, rw, rh, - &fx, &fy, &fw, &fh)) + rx, ry, rw, rh, + fx, fy, fw, fh)) { pixbuf_draw_fade_radius(p_pix, prs, has_alpha, x + w - border, y + h - border, border, diff --git a/src/pixbuf-util.h b/src/pixbuf-util.h index 87ff6add..c86026b0 100644 --- a/src/pixbuf-util.h +++ b/src/pixbuf-util.h @@ -233,8 +233,8 @@ void pixbuf_ignore_alpha_rect(GdkPixbuf *pb, * @retval TRUE The intersection operation was performed, and the output params were set. */ gboolean util_clip_region(gint x, gint y, gint w, gint h, - gint clip_x, gint clip_y, gint clip_w, gint clip_h, - gint *rx, gint *ry, gint *rw, gint *rh); + gint clip_x, gint clip_y, gint clip_w, gint clip_h, + gint &rx, gint &ry, gint &rw, gint &rh); // TODO(xsdg): Rename this function to util_triangle_bounding_box. /** diff --git a/src/preferences.cc b/src/preferences.cc index f0ae2de3..03c035b8 100644 --- a/src/preferences.cc +++ b/src/preferences.cc @@ -821,7 +821,6 @@ static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint ro static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data) { - ActionItem *action_item = nullptr; auto option = static_cast(data); gchar *label; GList *list; @@ -830,20 +829,15 @@ static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data) label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo)); list = get_action_items(); - work = list; - - while (work) + work = g_list_find_custom(list, label, reinterpret_cast(action_item_compare_label)); + if (work) { - action_item = static_cast(work->data); - if (g_strcmp0(action_item->label, label) == 0) - { - break; - } - work=work->next; + auto *action_item = static_cast(work->data); + + g_free(*option); + *option = g_strdup(action_item->name); } - g_free(*option); - *option = g_strdup(action_item->name); g_free(label); action_items_free(list); } @@ -1290,6 +1284,8 @@ static void filter_set_func(GtkTreeViewColumn *, GtkCellRenderer *cell, g_object_set(GTK_CELL_RENDERER(cell), "active", fe->allow_sidecar, NULL); break; + default: + break; } } @@ -1654,14 +1650,14 @@ static void accel_store_populate() lw = static_cast(layout_window_list->data); /* get the actions from the first window, it should not matter, they should be the same in all windows */ g_assert(lw && lw->ui_manager); - groups = gtk_ui_manager_get_action_groups(lw->ui_manager); + groups = gq_gtk_ui_manager_get_action_groups(lw->ui_manager); while (groups) { - actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data)); + actions = gq_gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data)); while (actions) { action = GTK_ACTION(actions->data); - accel_path = gtk_action_get_accel_path(action); + accel_path = gq_gtk_action_get_accel_path(action); if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key)) { gchar *label; @@ -1680,7 +1676,7 @@ static void accel_store_populate() } accel = gtk_accelerator_name(key.accel_key, key.accel_mods); - icon_name = gtk_action_get_icon_name(action); + icon_name = gq_gtk_action_get_icon_name(action); if (tooltip) { @@ -2351,7 +2347,7 @@ static void config_tab_image(GtkWidget *notebook) 100, 999, 1, options->image.max_enlargement_size, &c_options->image.max_enlargement_size); pref_checkbox_link_sensitivity(enlargement_button, spin); - gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("Enable this to allow Geeqie to increase the image size for images that are smaller than the current view area when the zoom is set to \"Fit image to window\". This value sets the maximum expansion permitted in percent i.e. 100% is full-size.")); + gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("Enable this to allow Geeqie to increase the image size for images that are smaller than the current view area when the zoom is set to 'Fit image to window'. This value sets the maximum expansion permitted in percent i.e. 100% is full-size.")); hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE); ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (%% of actual window):"), @@ -2360,7 +2356,7 @@ static void config_tab_image(GtkWidget *notebook) 10, 150, 1, options->image.max_autofit_size, &c_options->image.max_autofit_size); pref_checkbox_link_sensitivity(ct_button, spin); - gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("This value will set the virtual size of the window when \"Fit image to window\" is set. Instead of using the actual size of the window, the specified percentage of the window will be used. It allows one to keep a border around the image (values lower than 100%) or to auto zoom the image (values greater than 100%). It affects fullscreen mode too.")); + gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("This value will set the virtual size of the window when 'Fit image to window' is set. Instead of using the actual size of the window, the specified percentage of the window will be used. It allows one to keep a border around the image (values lower than 100%) or to auto zoom the image (values greater than 100%). It affects fullscreen mode too.")); group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL); @@ -2478,7 +2474,7 @@ static void config_tab_windows(GtkWidget *notebook) widget = pref_checkbox_new_int(group, _("Hide window decorations"), options->hide_window_decorations, &c_options->hide_window_decorations); - gtk_widget_set_tooltip_text(widget, "Remove borders and title bar from windows. A restart of Geeqie is required for this feature to take effect on the main layout window"); + gtk_widget_set_tooltip_text(widget, _("Remove borders and title bar from windows. A restart of Geeqie is required for this feature to take effect on the main layout window")); pref_checkbox_new_int(group, _("Show window IDs"), options->show_window_ids, &c_options->show_window_ids); @@ -2993,7 +2989,7 @@ static void config_tab_metadata(GtkWidget *notebook) gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used")); tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive); - gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords")); + gtk_widget_set_tooltip_text(tmp_widget, _("When selected, 'Place' and 'place' are two different keywords")); ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation); gtk_widget_set_tooltip_text(ct_button, _("If checked, the results of orientation commands (Rotate, Mirror and Flip) issued on an image will be written to metadata\nNote: If this option is not checked, the results of orientation commands will be lost when Geeqie closes")); @@ -3031,7 +3027,7 @@ static void config_tab_metadata(GtkWidget *notebook) group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL); ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle); - gtk_widget_set_tooltip_text(ct_button,"On folder change, read DateTimeOriginal, DateTimeDigitized and Star Rating in the idle loop.\nIf this is not selected, initial loading of the folder will be faster but sorting on these items will be slower"); + gtk_widget_set_tooltip_text(ct_button,_("On folder change, read DateTimeOriginal, DateTimeDigitized and Star Rating in the idle loop.\nIf this is not selected, initial loading of the folder will be faster but sorting on these items will be slower")); } /* keywords tab */ @@ -3279,10 +3275,8 @@ static void config_tab_keywords_save() GtkTextIter end; GtkTextBuffer *buffer; GList *kw_list = nullptr; - GList *work; gchar *buffer_text; gchar *kw_split; - gboolean found; buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text)); gtk_text_buffer_get_bounds(buffer, &start, &end); @@ -3292,18 +3286,7 @@ static void config_tab_keywords_save() kw_split = strtok(buffer_text, "\n"); while (kw_split != nullptr) { - work = kw_list; - found = FALSE; - while (work) - { - if (g_strcmp0(static_cast(work->data), kw_split) == 0) - { - found = TRUE; - break; - } - work = work->next; - } - if (!found) + if (!g_list_find_custom(kw_list, kw_split, reinterpret_cast(g_strcmp0))) { kw_list = g_list_append(kw_list, g_strdup(kw_split)); } @@ -3640,9 +3623,9 @@ static void config_tab_behavior(GtkWidget *notebook) options->marks_save, &c_options->marks_save); gtk_widget_set_tooltip_text(marks,_("Note that marks linked to a keyword will be saved irrespective of this setting")); - with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"), + with_rename = pref_checkbox_new_int(group, _("Use 'With Rename' as default for Copy/Move dialogs"), options->with_rename, &c_options->with_rename); - gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs"); + gtk_widget_set_tooltip_text(with_rename,_("Change the default button for Copy/Move dialogs")); collections_on_top = pref_checkbox_new_int(group, _("Permit duplicates in Collections"), options->collections_duplicates, &c_options->collections_duplicates); @@ -3654,11 +3637,11 @@ static void config_tab_behavior(GtkWidget *notebook) hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"), options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen); - gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice"); + gtk_widget_set_tooltip_text(hide_window_in_fullscreen, _("When alt-tabbing, prevent Geeqie window showing twice")); hide_osd_in_fullscreen = pref_checkbox_new_int(group, _("Hide OSD in fullscreen"), options->hide_osd_in_fullscreen, &c_options->hide_osd_in_fullscreen); - gtk_widget_set_tooltip_text(hide_osd_in_fullscreen,"Hide Overlay Screen Display in fullscreen mode"); + gtk_widget_set_tooltip_text(hide_osd_in_fullscreen, _("Hide Overlay Screen Display in fullscreen mode")); pref_spin_new_int(group, _("Recent folder list maximum size"), nullptr, 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize); @@ -3928,11 +3911,6 @@ static void config_tab_toolbar_status(GtkWidget *notebook) } /* advanced tab */ -static gint extension_sort_cb(gconstpointer a, gconstpointer b) -{ - return g_strcmp0(static_cast(a), static_cast(b)); -} - static void config_tab_advanced(GtkWidget *notebook) { gchar **extensions; @@ -3967,7 +3945,7 @@ static void config_tab_advanced(GtkWidget *notebook) i = 0; while (extensions[i]) { - extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb); + extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), reinterpret_cast(g_strcmp0)); i++; } diff --git a/src/remote.cc b/src/remote.cc index b0710946..573b69c8 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -1597,10 +1597,10 @@ static void gr_action(const gchar *text, GIOChannel *, gpointer) } else { - action = gtk_action_group_get_action(lw_id->action_group, text); + action = gq_gtk_action_group_get_action(lw_id->action_group, text); if (action) { - gtk_action_activate(action); + gq_gtk_action_activate(action); } else { diff --git a/src/renderer-tiles.cc b/src/renderer-tiles.cc index 654fbbd4..889e9f2b 100644 --- a/src/renderer-tiles.cc +++ b/src/renderer-tiles.cc @@ -1130,128 +1130,132 @@ static void rt_tile_apply_orientation(RendererTiles *rt, gint orientation, GdkPi } } +/** + * @brief Renders the contents of the specified region of the specified ImageTile, using + * SourceTiles that the RendererTiles knows how to create/access. + * @param rt The RendererTiles object. + * @param it The ImageTile to render. + * @param x,y,w,h The sub-region of the ImageTile to render. + * @retval TRUE We rendered something that needs to be drawn. + * @retval FALSE We didn't render anything that needs to be drawn. + */ static gboolean rt_source_tile_render(RendererTiles *rt, ImageTile *it, gint x, gint y, gint w, gint h, - gboolean, gboolean fast) + gboolean, gboolean) { PixbufRenderer *pr = rt->pr; - GList *list; - GList *work; gboolean draw = FALSE; - if (pr->zoom == 1.0 || pr->scale == 1.0) - { - list = pr_source_tile_compute_region(pr, it->x + x, it->y + y, w, h, TRUE); - work = list; - while (work) - { - SourceTile *st; - gint rx; - gint ry; - gint rw; - gint rh; - - st = static_cast(work->data); - work = work->next; - - if (pr_clip_region(st->x, st->y, pr->source_tile_width, pr->source_tile_height, - it->x + x, it->y + y, w, h, - &rx, &ry, &rw, &rh)) - { - cairo_t *cr; - cr = cairo_create(it->surface); - cairo_rectangle (cr, rx - it->x, ry - it->y, rw, rh); + if (pr->image_width == 0 || pr->image_height == 0) return FALSE; - if (st->blank) - { - cairo_set_source_rgb(cr, 0, 0, 0); - cairo_fill (cr); - } - else /* (pr->zoom == 1.0 || pr->scale == 1.0) */ - { - rt_hidpi_aware_draw(rt, cr, st->pixbuf, -it->x + st->x, -it->y + st->y); - } - cairo_destroy (cr); - } - } - } - else - { - gdouble scale_x; - gdouble scale_y; - gint sx; - gint sy; - gint sw; - gint sh; + // This is the scale due to zooming. So if the user is zoomed in 2x (we're + // rendering twice as large), these numbers will be 2. Note that these values + // can definitely be fractional (becomes important below). + const gdouble scale_x = static_cast(pr->width) / pr->image_width; + const gdouble scale_y = static_cast(pr->height) / pr->image_height; - if (pr->image_width == 0 || pr->image_height == 0) return FALSE; - scale_x = static_cast(pr->width) / pr->image_width; - scale_y = static_cast(pr->height) / pr->image_height; + // And these are the unscaled coordinates where our tile data should originate from. + const gint sx = static_cast(it->x + x) / scale_x; + const gint sy = static_cast(it->y + y) / scale_y; + const gint sw = static_cast(w) / scale_x; + const gint sh = static_cast(h) / scale_y; - sx = static_cast(it->x + x) / scale_x; - sy = static_cast(it->y + y) / scale_y; - sw = static_cast(w) / scale_x; - sh = static_cast(h) / scale_y; - - if (pr->width < PR_MIN_SCALE_SIZE || pr->height < PR_MIN_SCALE_SIZE) fast = TRUE; + /* HACK: The pixbuf scalers get kinda buggy(crash) with extremely + * small sizes for anything but GDK_INTERP_NEAREST + */ + const gboolean force_nearest = pr->width < PR_MIN_SCALE_SIZE || pr->height < PR_MIN_SCALE_SIZE; #if 0 - /* draws red over draw region, to check for leaks (regions not filled) */ - pixbuf_set_rect_fill(it->pixbuf, x, y, w, h, 255, 0, 0, 255); + // Draws red over draw region, to check for leaks (regions not filled) + pixbuf_set_rect_fill(it->pixbuf, x, y, rt->hidpi_scale * w, rt->hidpi_scale * h, 255, 0, 0, 255); #endif - list = pr_source_tile_compute_region(pr, sx, sy, sw, sh, TRUE); - work = list; - while (work) + // Since the RendererTiles ImageTiles and PixbufRenderer SourceTiles are different + // sizes and may not exactly overlap, we now determine which SourceTiles are needed + // to cover the ImageTile that we're being asked to render. + // + // This will render the relevant SourceTiles if needed, or pull from the cache if + // they've already been generated. + GList *list = pr_source_tile_compute_region(pr, sx, sy, sw, sh, TRUE); + GList *work = list; + while (work) + { + const auto st = static_cast(work->data); + work = work->next; + + // The scaled (output) coordinates that are covered by this SourceTile. + // To avoid aliasing line artifacts due to under-drawing, we expand the + // render area to the nearest whole pixel. + const gint stx = floor(st->x * scale_x); + const gint sty = floor(st->y * scale_y); + const gint stw = ceil((st->x + pr->source_tile_width) * scale_x) - stx; + const gint sth = ceil((st->y + pr->source_tile_height) * scale_y) - sty; + + // We find the overlapping region (r{x,y,w,h}) between the ImageTile (output) + // region and the region that's covered by this SourceTile (input). + gint rx, ry, rw, rh; // NOLINT(readability-isolate-declaration) + if (pr_clip_region(stx, sty, stw, sth, + it->x + x, it->y + y, w, h, + &rx, &ry, &rw, &rh)) { - SourceTile *st; - gint rx; - gint ry; - gint rw; - gint rh; - gint stx; - gint sty; - gint stw; - gint sth; - - st = static_cast(work->data); - work = work->next; - - stx = floor(static_cast(st->x) * scale_x); - sty = floor(static_cast(st->y) * scale_y); - stw = ceil(static_cast(st->x + pr->source_tile_width) * scale_x) - stx; - sth = ceil(static_cast(st->y + pr->source_tile_height) * scale_y) - sty; - - if (pr_clip_region(stx, sty, stw, sth, - it->x + x, it->y + y, w, h, - &rx, &ry, &rw, &rh)) - { - if (st->blank) - { - cairo_t *cr; - cr = cairo_create(it->surface); - cairo_rectangle (cr, rx - st->x, ry - st->y, rw, rh); - cairo_set_source_rgb(cr, 0, 0, 0); - cairo_fill (cr); - cairo_destroy (cr); - } - else - { - gdouble offset_x; - gdouble offset_y; - - /* may need to use unfloored stx,sty values here */ - offset_x = static_cast(stx - it->x); - offset_y = static_cast(sty - it->y); - - gdk_pixbuf_scale(st->pixbuf, it->pixbuf, rx - it->x, ry - it->y, rw, rh, - static_cast(0.0) + offset_x, - static_cast(0.0) + offset_y, - scale_x, scale_y, - (fast) ? GDK_INTERP_NEAREST : pr->zoom_quality); - draw = TRUE; - } + if (st->blank) + { + // If this SourceTile has no contents, we just paint a black rect + // of the appropriate size. + cairo_t *cr = cairo_create(it->surface); + cairo_rectangle (cr, rx - st->x, ry - st->y, rt->hidpi_scale * rw, rt->hidpi_scale * rh); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_fill (cr); + cairo_destroy (cr); + // TODO(xsdg): We almost certainly need to set draw = TRUE in this branch. + // This may explain the smearing that we sometimes get when panning the view while drawing. + } + else + { + // Note that the ImageTile it contains its own solitary pixbuf, it->pixbuf. + // This means that the region covered by this function (possibly split across + // multiple SourceTiles) has origin (0, 0). Additionally, the width and height + // of that pixbuf will reflect the value of GDK_SCALE (which is stored by the + // RendererTiles rt). The following is an invariant: + // it->pixbuf->width = rt->hidpi_scale * it->width + // it->pixbuf->height = rt->hidpi_scale * it->height + // + // So for hidpi rendering, we need to multiply the scale factor from the zoom by + // the additional scale factor for hidpi. This combined scale factor is then + // applied to the offset (explained below), width, and height. + + // (May need to use unfloored stx,sty values here) + const gdouble offset_x = rt->hidpi_scale * static_cast(stx - it->x); + const gdouble offset_y = rt->hidpi_scale * static_cast(sty - it->y); + + // TODO(xsdg): Just draw instead of usign scale-draw for the case where + // (pr->zoom == 1.0 || pr->scale == 1.0) + + // The order of operations in this function is scale, offset, clip, copy. + // So we start with the data from st->pixbuf. First we scale that data by + // the scale factors. Then we offset that intermediate image by the offsets. + // Next, we clip that offsetted image to the (x,y,w,h) region specified. And + // lastly, we copy the resulting region into the _region with the same + // coordinates_ in it->pixbuf. + // + // At this point, recall that we may need to render into ImageTile from multiple + // SourceTiles. The region specified by r{x,y,w,h} accounts for this, and thus, + // those are the coordinates _within the current SourceTile_ that need to be + // rendered into the ImageTile. + // + // The offsets translate the region from wherever it may be in the actual image + // to the ImageTile pixbuf coordinate system. Because ImageTile and SourceTile + // coordinates are not necessarily aligned, an offset will be negative if this + // SourceTile starts left of or above the ImageTile, positive if it starts in + // the middle of the ImageTile, or zero if the left or top edges are aligned. + gdk_pixbuf_scale( + st->pixbuf, it->pixbuf, + rx - it->x, ry - it->y, rt->hidpi_scale * rw, rt->hidpi_scale * rh, + offset_x, offset_y, + rt->hidpi_scale * scale_x, rt->hidpi_scale * scale_y, + (force_nearest) ? GDK_INTERP_NEAREST : pr->zoom_quality); + draw = TRUE; } } } @@ -2197,7 +2201,7 @@ static gboolean rt_realize_cb(GtkWidget *widget, gpointer data) rt->surface = gdk_window_create_similar_surface(gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR, gtk_widget_get_allocated_width(widget), gtk_widget_get_allocated_height(widget)); cr = cairo_create(rt->surface); - cairo_set_source_rgb(cr, static_cast(rt->pr->color.red), static_cast(rt->pr->color.green), static_cast(rt->pr->color.blue)); + cairo_set_source_rgb(cr, rt->pr->color.red, rt->pr->color.green, rt->pr->color.blue); cairo_paint(cr); cairo_destroy(cr); } @@ -2218,7 +2222,7 @@ static gboolean rt_size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation cr = cairo_create(rt->surface); - cairo_set_source_rgb(cr, static_cast(options->image.border_color.red), static_cast(options->image.border_color.green), static_cast(options->image.border_color.blue)); + cairo_set_source_rgb(cr, options->image.border_color.red, options->image.border_color.green, options->image.border_color.blue); cairo_paint(cr); cairo_set_source_surface(cr, old_surface, 0, 0); cairo_paint(cr); diff --git a/src/search-and-run.cc b/src/search-and-run.cc index c23da619..b6b82022 100644 --- a/src/search-and-run.cc +++ b/src/search-and-run.cc @@ -104,14 +104,14 @@ static void command_store_populate(SarData* sar) gtk_tree_sortable_set_sort_column_id(sortable, SAR_LABEL, GTK_SORT_ASCENDING); - groups = gtk_ui_manager_get_action_groups(sar->lw->ui_manager); + groups = gq_gtk_ui_manager_get_action_groups(sar->lw->ui_manager); while (groups) { - actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data)); + actions = gq_gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data)); while (actions) { action = GTK_ACTION(actions->data); - accel_path = gtk_action_get_accel_path(action); + accel_path = gq_gtk_action_get_accel_path(action); if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key)) { g_object_get(action, "tooltip", &tooltip, "label", &label, NULL); @@ -199,7 +199,7 @@ static gboolean entry_box_activate_cb(GtkWidget *, gpointer data) if (sar->action) { - gtk_action_activate(sar->action); + gq_gtk_action_activate(sar->action); } search_and_run_destroy(sar); @@ -236,7 +236,7 @@ static gboolean match_selected_cb(GtkEntryCompletion *, GtkTreeModel *model, Gtk if (sar->action) { - gtk_action_activate(sar->action); + gq_gtk_action_activate(sar->action); } g_idle_add(static_cast(search_and_run_destroy), sar); diff --git a/src/search.cc b/src/search.cc index 79625e65..be3a39d0 100644 --- a/src/search.cc +++ b/src/search.cc @@ -2115,24 +2115,16 @@ static gboolean search_file_next(SearchData *sd) if (list) { - GList *needle; - GList *haystack; + GList *needle = sd->search_keyword_list; if (sd->match_keywords == SEARCH_MATCH_ALL) { gboolean found = TRUE; - needle = sd->search_keyword_list; while (needle && found) { - found = FALSE; - haystack = list; - while (haystack && !found) - { - found = (g_ascii_strcasecmp(static_cast(needle->data), - static_cast(haystack->data)) == 0); - haystack = haystack->next; - } + found = (g_list_find_custom(list, needle->data, + reinterpret_cast(g_ascii_strcasecmp)) != nullptr); needle = needle->next; } @@ -2142,16 +2134,10 @@ static gboolean search_file_next(SearchData *sd) { gboolean found = FALSE; - needle = sd->search_keyword_list; while (needle && !found) { - haystack = list; - while (haystack && !found) - { - found = (g_ascii_strcasecmp(static_cast(needle->data), - static_cast(haystack->data)) == 0); - haystack = haystack->next; - } + found = (g_list_find_custom(list, needle->data, + reinterpret_cast(g_ascii_strcasecmp)) != nullptr); needle = needle->next; } @@ -2161,16 +2147,10 @@ static gboolean search_file_next(SearchData *sd) { gboolean found = FALSE; - needle = sd->search_keyword_list; while (needle && !found) { - haystack = list; - while (haystack && !found) - { - found = (g_ascii_strcasecmp(static_cast(needle->data), - static_cast(haystack->data)) == 0); - haystack = haystack->next; - } + found = (g_list_find_custom(list, needle->data, + reinterpret_cast(g_ascii_strcasecmp)) != nullptr); needle = needle->next; } @@ -2736,9 +2716,7 @@ static void search_start_cb(GtkWidget *, gpointer data) sd->search_lat < -90 || sd->search_lat > 90 || sd->search_lon < -180 || sd->search_lon > 180) { - file_util_warning_dialog(_( - "Entry does not contain a valid lat/long value"), - entry_text, GQ_ICON_DIALOG_WARNING, sd->window); + file_util_warning_dialog(_("Entry does not contain a valid lat/long value"), entry_text, GQ_ICON_DIALOG_WARNING, sd->window); return; } g_free(entry_text); @@ -3449,7 +3427,7 @@ void search_new(FileData *dir_fd, FileData *example_file) pref_checkbox_new_int(hbox, _("Match case"), sd->search_name_match_case, &sd->search_name_match_case); pref_checkbox_new_int(hbox, _("Symbolic link"), sd->search_name_symbolic_link, &sd->search_name_symbolic_link); - gtk_widget_set_tooltip_text(GTK_WIDGET(combo), "When set to \"contains\" or \"path contains\", this field uses Perl Compatible Regular Expressions.\ne.g. use \n.*\\.jpg\n and not \n*.jpg\n\nSee the Help file."); + gtk_widget_set_tooltip_text(GTK_WIDGET(combo), _("When set to 'contains' or 'path contains', this field uses Perl Compatible Regular Expressions.\ne.g. use \n.*\\.jpg\n and not \n*.jpg\n\nSee the Help file.")); /* Search for file size */ hbox = menu_choice(sd->box_search, &sd->check_size, &sd->menu_size, @@ -3558,7 +3536,7 @@ void search_new(FileData *dir_fd, FileData *example_file) gtk_widget_show(sd->entry_comment); pref_checkbox_new_int(hbox, _("Match case"), sd->search_comment_match_case, &sd->search_comment_match_case); - gtk_widget_set_tooltip_text(GTK_WIDGET(sd->entry_comment), "This field uses Perl Compatible Regular Expressions.\ne.g. use \nabc.*ghk\n and not \nabc*ghk\n\nSee the Help file."); + gtk_widget_set_tooltip_text(GTK_WIDGET(sd->entry_comment), _("This field uses Perl Compatible Regular Expressions.\ne.g. use \nabc.*ghk\n and not \nabc*ghk\n\nSee the Help file.")); /* Search for image rating */ hbox = menu_choice(sd->box_search, &sd->check_rating, &sd->menu_rating, @@ -3720,7 +3698,7 @@ void search_new(FileData *dir_fd, FileData *example_file) sd->button_thumbs = pref_checkbox_new(hbox, _("Thumbnails"), FALSE, G_CALLBACK(search_thumb_toggle_cb), sd); - gtk_widget_set_tooltip_text(GTK_WIDGET(sd->button_thumbs), "Ctrl-T"); + gtk_widget_set_tooltip_text(GTK_WIDGET(sd->button_thumbs), _("Ctrl-T")); frame = gtk_frame_new(nullptr); DEBUG_NAME(frame); @@ -3752,15 +3730,15 @@ void search_new(FileData *dir_fd, FileData *example_file) pref_spacer(hbox, PREF_PAD_BUTTON_GAP); sd->button_start = pref_button_new(hbox, GQ_ICON_FIND, _("Find"), G_CALLBACK(search_start_cb), sd); - gtk_widget_set_tooltip_text(GTK_WIDGET(sd->button_start), "Ctrl-Return"); + gtk_widget_set_tooltip_text(GTK_WIDGET(sd->button_start), _("Ctrl-Return")); pref_spacer(hbox, PREF_PAD_BUTTON_GAP); sd->button_stop = pref_button_new(hbox, GQ_ICON_STOP, _("Stop"), G_CALLBACK(search_start_cb), sd); - gtk_widget_set_tooltip_text(GTK_WIDGET(sd->button_stop), "Ctrl-Return"); + gtk_widget_set_tooltip_text(GTK_WIDGET(sd->button_stop), _("Ctrl-Return")); gtk_widget_set_sensitive(sd->button_stop, FALSE); pref_spacer(hbox, PREF_PAD_BUTTON_GAP); sd->button_close = pref_button_new(hbox, GQ_ICON_CLOSE, _("Close"), G_CALLBACK(search_window_close_cb), sd); - gtk_widget_set_tooltip_text(GTK_WIDGET(sd->button_close), "Ctrl-W"); + gtk_widget_set_tooltip_text(GTK_WIDGET(sd->button_close), _("Ctrl-W")); gtk_widget_set_sensitive(sd->button_close, TRUE); search_result_thumb_enable(sd, TRUE); diff --git a/src/tests/meson.build b/src/tests/meson.build new file mode 100644 index 00000000..b7a99513 --- /dev/null +++ b/src/tests/meson.build @@ -0,0 +1,24 @@ +# +# Copyright (C) 2024 The Geeqie Team +# +# Author: Omari Stephens +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Build file to configure and run unit tests. + +unit_test_sources = files('pixbuf-util.cc') + +project_sources += unit_test_sources diff --git a/src/tests/pixbuf-util.cc b/src/tests/pixbuf-util.cc new file mode 100644 index 00000000..af300712 --- /dev/null +++ b/src/tests/pixbuf-util.cc @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2024 The Geeqie Team + * + * Author: Omari Stephens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * + * Unit tests for pixbuf-util.cc + * + */ + +#include "gtest/gtest.h" + +#include "pixbuf-util.h" + +namespace { + +class ClipRegionTest : public ::testing::Test +{ + protected: + gint rx{}; + gint ry{}; + gint rw{}; + gint rh{}; +}; + +TEST_F(ClipRegionTest, RegionAContainsRegionB) +{ + ASSERT_TRUE(util_clip_region(0, 0, 1000, 1000, + 50, 50, 100, 100, + rx, ry, rw, rh)); + + ASSERT_EQ(50, rx); + ASSERT_EQ(50, ry); + ASSERT_EQ(100, rw); + ASSERT_EQ(100, rh); +} + +TEST_F(ClipRegionTest, RegionBContainsRegionA) +{ + ASSERT_TRUE(util_clip_region(50, 50, 100, 100, + 0, 0, 1000, 1000, + rx, ry, rw, rh)); + + ASSERT_EQ(50, rx); + ASSERT_EQ(50, ry); + ASSERT_EQ(100, rw); + ASSERT_EQ(100, rh); +} + +TEST_F(ClipRegionTest, PartialOverlapWithBAfterA) +{ + ASSERT_TRUE(util_clip_region(0, 0, 1000, 1000, + 500, 500, 1000, 1000, + rx, ry, rw, rh)); + + ASSERT_EQ(500, rx); + ASSERT_EQ(500, ry); + ASSERT_EQ(500, rw); + ASSERT_EQ(500, rh); +} + +TEST_F(ClipRegionTest, PartialOverlapWithAAfterB) +{ + ASSERT_TRUE(util_clip_region(500, 500, 1000, 1000, + 0, 0, 1000, 1000, + rx, ry, rw, rh)); + + ASSERT_EQ(500, rx); + ASSERT_EQ(500, ry); + ASSERT_EQ(500, rw); + ASSERT_EQ(500, rh); +} + +} // anonymous namespace + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/src/third-party/backward.h b/src/third-party/backward.h index 9f3b31e2..dd57a4aa 100644 --- a/src/third-party/backward.h +++ b/src/third-party/backward.h @@ -4280,6 +4280,12 @@ public: printer.address = true; printer.print(st, stderr); + /** @FIXME This is probably not the correct way to do this */ + FILE *fp; + fp = fopen("/tmp/geeqie-crash.log", "a"); + printer.print(st, fp); + fclose(fp); + #if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700) || \ (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L) psiginfo(info, nullptr); diff --git a/src/toolbar.cc b/src/toolbar.cc index 417cf84c..cc617b75 100644 --- a/src/toolbar.cc +++ b/src/toolbar.cc @@ -43,33 +43,19 @@ * Called from the Preferences/toolbar tab **/ +namespace +{ + struct ToolbarData { - GtkWidget *widget; GtkWidget *vbox; - GtkWidget *add_button; - - LayoutWindow *lw; }; -struct ToolbarButtonData -{ - GtkWidget *button; - GtkWidget *button_label; - GtkWidget *image; +const gchar *action_name_key = "action_name"; - const gchar *name; /* GtkActionEntry terminology */ - const gchar *stock_id; -}; - -static ToolbarData *toolbarlist[2]; +ToolbarData *toolbarlist[2]; -struct UseableToolbarItems -{ - const gchar *name; /* GtkActionEntry terminology */ - const gchar *label; - const gchar *stock_id; -}; +} // namespace /** * @brief @@ -151,16 +137,15 @@ static void toolbar_menu_popup(GtkWidget *widget) static gboolean toolbar_press_cb(GtkGesture *, int, double, double, gpointer data) { - auto button_data = static_cast(data); + auto *button = static_cast(data); - toolbar_menu_popup(button_data->button); + toolbar_menu_popup(button); return TRUE; } static void get_toolbar_item(const gchar *name, gchar **label, gchar **stock_id) { - ActionItem *action_item; GList *list; GList *work; *label = nullptr; @@ -168,32 +153,22 @@ static void get_toolbar_item(const gchar *name, gchar **label, gchar **stock_id) list = get_action_items(); - work = list; - while (work) + const auto action_item_compare_name = [](gconstpointer data, gconstpointer user_data) + { + return g_strcmp0(static_cast(data)->name, static_cast(user_data)); + }; + work = g_list_find_custom(list, name, action_item_compare_name); + if (work) { - action_item = static_cast(work->data); - if (g_strcmp0(action_item->name, name) == 0) - { - *label = g_strdup(action_item->label); - *stock_id = g_strdup(action_item->icon_name); - break; - } + auto *action_item = static_cast(work->data); - work = work->next; + *label = g_strdup(action_item->label); + *stock_id = g_strdup(action_item->icon_name); } action_items_free(list); } -static void toolbar_item_free(ToolbarButtonData *tbbd) -{ - if (!tbbd) return; - - g_free(const_cast(tbbd->name)); - g_free(const_cast(tbbd->stock_id)); - g_free(const_cast(tbbd)); -} - static void toolbar_button_free(GtkWidget *widget) { g_free(g_object_get_data(G_OBJECT(widget), "toolbar_add_name")); @@ -204,41 +179,35 @@ static void toolbar_button_free(GtkWidget *widget) static void toolbarlist_add_button(const gchar *name, const gchar *label, const gchar *stock_id, GtkBox *box) { - ToolbarButtonData *toolbar_entry; GtkWidget *hbox; GtkGesture *gesture; - toolbar_entry = g_new(ToolbarButtonData,1); - toolbar_entry->button = gtk_button_new(); - gtk_button_set_relief(GTK_BUTTON(toolbar_entry->button), GTK_RELIEF_NONE); - gq_gtk_box_pack_start(GTK_BOX(box), toolbar_entry->button, FALSE, FALSE, 0); - gtk_widget_show(toolbar_entry->button); + GtkWidget *button = gtk_button_new(); + gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); + gq_gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0); + gtk_widget_show(button); - g_object_set_data_full(G_OBJECT(toolbar_entry->button), "toolbarbuttondata", - toolbar_entry, reinterpret_cast(toolbar_item_free)); + g_object_set_data_full(G_OBJECT(button), action_name_key, g_strdup(name), g_free); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP); - gq_gtk_container_add(GTK_WIDGET(toolbar_entry->button), hbox); + gq_gtk_container_add(GTK_WIDGET(button), hbox); gtk_widget_show(hbox); - toolbar_entry->button_label = gtk_label_new(label); - toolbar_entry->name = g_strdup(name); - toolbar_entry->stock_id = g_strdup(stock_id); - #if HAVE_GTK4 gesture = gtk_gesture_click_new(); - gtk_widget_add_controller(toolbar_entry->button, GTK_EVENT_CONTROLLER(gesture)); + gtk_widget_add_controller(button, GTK_EVENT_CONTROLLER(gesture)); #else - gesture = gtk_gesture_multi_press_new(toolbar_entry->button); + gesture = gtk_gesture_multi_press_new(button); #endif gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), MOUSE_BUTTON_RIGHT); - g_signal_connect(gesture, "released", G_CALLBACK(toolbar_press_cb), toolbar_entry); + g_signal_connect(gesture, "released", G_CALLBACK(toolbar_press_cb), button); - if (toolbar_entry->stock_id) + GtkWidget *image; + if (stock_id) { GdkPixbuf *pixbuf; gchar *iconl; - iconl = path_from_utf8(toolbar_entry->stock_id); + iconl = path_from_utf8(stock_id); pixbuf = gdk_pixbuf_new_from_file(iconl, nullptr); g_free(iconl); if (pixbuf) @@ -252,26 +221,26 @@ static void toolbarlist_add_button(const gchar *name, const gchar *label, scaled = gdk_pixbuf_scale_simple(pixbuf, w, h, GDK_INTERP_BILINEAR); - toolbar_entry->image = gtk_image_new_from_pixbuf(scaled); + image = gtk_image_new_from_pixbuf(scaled); g_object_unref(scaled); g_object_unref(pixbuf); } else { - toolbar_entry->image = gtk_image_new_from_stock(toolbar_entry->stock_id, - GTK_ICON_SIZE_BUTTON); + image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON); } } else { - toolbar_entry->image = gtk_image_new_from_icon_name(GQ_ICON_GO_JUMP, - GTK_ICON_SIZE_BUTTON); + image = gtk_image_new_from_icon_name(GQ_ICON_GO_JUMP, GTK_ICON_SIZE_BUTTON); } - gq_gtk_box_pack_start(GTK_BOX(hbox), toolbar_entry->image, FALSE, FALSE, 0); - gtk_widget_show(toolbar_entry->image); - gq_gtk_box_pack_start(GTK_BOX(hbox), toolbar_entry->button_label, FALSE, FALSE, 0); - gtk_widget_show(toolbar_entry->button_label); + gq_gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); + gtk_widget_show(image); + + GtkWidget *button_label = gtk_label_new(label); + gq_gtk_box_pack_start(GTK_BOX(hbox), button_label, FALSE, FALSE, 0); + gtk_widget_show(button_label); } static void toolbarlist_add_cb(GtkWidget *widget, gpointer data) @@ -292,26 +261,25 @@ static void get_desktop_data(const gchar *name, gchar **label, gchar **stock_id) *stock_id = nullptr; editors_list = editor_list_get(); - work = editors_list; - while (work) + const auto editor_compare_key = [](gconstpointer data, gconstpointer user_data) + { + return g_strcmp0(static_cast(data)->key, static_cast(user_data)); + }; + work = g_list_find_custom(editors_list, name, editor_compare_key); + if (work) { auto editor = static_cast(work->data); - if (g_strcmp0(name, editor->key) == 0) - { - *label = g_strdup(editor->name); - *stock_id = g_strconcat(editor->icon, ".desktop", NULL); - break; - } - work = work->next; + *label = g_strdup(editor->name); + *stock_id = g_strconcat(editor->icon, ".desktop", NULL); } g_list_free(editors_list); } -static void toolbar_menu_add_popup(GtkWidget *, gpointer data) +// toolbar_menu_add_popup +static gboolean toolbar_menu_add_cb(GtkWidget *, gpointer data) { ActionItem *action_item; - auto toolbarlist = static_cast(data); GList *list; GList *work; GtkWidget *item; @@ -319,7 +287,7 @@ static void toolbar_menu_add_popup(GtkWidget *, gpointer data) menu = popup_menu_short_lived(); - item = menu_item_add_stock(menu, "Separator", "Separator", G_CALLBACK(toolbarlist_add_cb), toolbarlist); + item = menu_item_add_stock(menu, "Separator", "Separator", G_CALLBACK(toolbarlist_add_cb), data); g_object_set_data(G_OBJECT(item), "toolbar_add_name", g_strdup("Separator")); g_object_set_data(G_OBJECT(item), "toolbar_add_label", g_strdup("Separator")); g_object_set_data(G_OBJECT(item), "toolbar_add_stock_id", g_strdup("no-icon")); @@ -332,7 +300,7 @@ static void toolbar_menu_add_popup(GtkWidget *, gpointer data) { action_item = static_cast(work->data); - item = menu_item_add_stock(menu, action_item->label, action_item->icon_name, G_CALLBACK(toolbarlist_add_cb), toolbarlist); + item = menu_item_add_stock(menu, action_item->label, action_item->icon_name, G_CALLBACK(toolbarlist_add_cb), data); g_object_set_data(G_OBJECT(item), "toolbar_add_name", g_strdup(action_item->name)); g_object_set_data(G_OBJECT(item), "toolbar_add_label", g_strdup(action_item->label)); g_object_set_data(G_OBJECT(item), "toolbar_add_stock_id", g_strdup(action_item->icon_name)); @@ -344,13 +312,7 @@ static void toolbar_menu_add_popup(GtkWidget *, gpointer data) action_items_free(list); gtk_menu_popup_at_pointer(GTK_MENU(menu), nullptr); -} - -static gboolean toolbar_menu_add_cb(GtkWidget *widget, gpointer data) -{ - auto toolbarlist = static_cast(data); - toolbar_menu_add_popup(widget, toolbarlist); return TRUE; } @@ -361,33 +323,25 @@ static gboolean toolbar_menu_add_cb(GtkWidget *widget, gpointer data) */ void toolbar_apply(ToolbarType bar) { - LayoutWindow *lw; - GList *work_windows; - GList *work_toolbar; - - work_windows = layout_window_list; - while (work_windows) - { - lw = static_cast(work_windows->data); + const auto layout_toolbar_apply = [](gpointer data, gpointer user_data) + { + auto *lw = static_cast(data); + auto bar = static_cast(GPOINTER_TO_INT(user_data)); layout_toolbar_clear(lw, bar); - work_toolbar = gtk_container_get_children(GTK_CONTAINER(toolbarlist[bar]->vbox)); - while (work_toolbar) + GList *work_toolbar = gtk_container_get_children(GTK_CONTAINER(toolbarlist[bar]->vbox)); + for (GList *work = work_toolbar; work; work = work->next) { - auto button = static_cast(work_toolbar->data); - ToolbarButtonData *tbbd; + auto button = static_cast(work->data); + auto *action_name = static_cast(g_object_get_data(G_OBJECT(button), action_name_key)); - tbbd = static_cast(g_object_get_data(G_OBJECT(button),"toolbarbuttondata")); - layout_toolbar_add(lw, bar, tbbd->name); - - work_toolbar = work_toolbar->next; + layout_toolbar_add(lw, bar, action_name); } g_list_free(work_toolbar); + }; - work_windows = work_windows->next; - } - + g_list_foreach(layout_window_list, layout_toolbar_apply, GINT_TO_POINTER(bar)); } /** @@ -442,16 +396,15 @@ GtkWidget *toolbar_select_new(LayoutWindow *lw, ToolbarType bar) { toolbarlist[bar] = g_new0(ToolbarData, 1); } - toolbarlist[bar]->lw = lw; - toolbarlist[bar]->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP); - gtk_widget_show(toolbarlist[bar]->widget); + GtkWidget *widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP); + gtk_widget_show(widget); scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_NONE); - gq_gtk_box_pack_start(GTK_BOX(toolbarlist[bar]->widget), scrolled, TRUE, TRUE, 0); + gq_gtk_box_pack_start(GTK_BOX(widget), scrolled, TRUE, TRUE, 0); gtk_widget_show(scrolled); toolbarlist[bar]->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); @@ -462,16 +415,17 @@ GtkWidget *toolbar_select_new(LayoutWindow *lw, ToolbarType bar) add_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_show(add_box); - gq_gtk_box_pack_end(GTK_BOX(toolbarlist[bar]->widget), add_box, FALSE, FALSE, 0); + gq_gtk_box_pack_end(GTK_BOX(widget), add_box, FALSE, FALSE, 0); tbar = pref_toolbar_new(add_box); - toolbarlist[bar]->add_button = pref_toolbar_button(tbar, GQ_ICON_ADD, _("Add"), FALSE, - _("Add Toolbar Item"), - G_CALLBACK(toolbar_menu_add_cb), toolbarlist[bar]); - gtk_widget_show(toolbarlist[bar]->add_button); + + GtkWidget *add_button = pref_toolbar_button(tbar, GQ_ICON_ADD, _("Add"), FALSE, + _("Add Toolbar Item"), + G_CALLBACK(toolbar_menu_add_cb), toolbarlist[bar]); + gtk_widget_show(add_button); toolbarlist_populate(lw,GTK_BOX(toolbarlist[bar]->vbox), bar); - return toolbarlist[bar]->widget; + return widget; } /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/src/trash.cc b/src/trash.cc index 7daa6562..44d5cb0f 100644 --- a/src/trash.cc +++ b/src/trash.cc @@ -202,7 +202,7 @@ gboolean file_util_safe_unlink(const gchar *path) if (!g_file_trash(tmp, FALSE, &error) ) { - message = g_strconcat("See the Help file for a possible workaround.\n\n", error->message, NULL); + message = g_strconcat(_("See the Help file for a possible workaround.\n\n"), error->message, NULL); gd = warning_dialog(_("Move to trash failed\n\n"), message, GQ_ICON_DIALOG_ERROR, nullptr); generic_dialog_add_button(gd, GQ_ICON_HELP, _("Help"), move_to_trash_failed_cb, FALSE); diff --git a/src/ui-bookmark.cc b/src/ui-bookmark.cc index 69a8f49c..3fa37154 100644 --- a/src/ui-bookmark.cc +++ b/src/ui-bookmark.cc @@ -457,6 +457,8 @@ static gboolean bookmark_keypress_cb(GtkWidget *button, GdkEventKey *event, gpoi return TRUE; } break; + default: + break; } return FALSE; @@ -770,7 +772,7 @@ static void bookmark_dnd_get_data(GtkWidget *, GdkDragContext *, if (strstr(real_path, get_collections_dir()) && isfile(path)) { - buf = bookmark_string(filename_from_path(path), path, "gq-icon-collection"); + buf = bookmark_string(filename_from_path(path), path, PIXBUF_INLINE_COLLECTION); } else if (isfile(path)) { @@ -916,7 +918,7 @@ void bookmark_list_add(GtkWidget *list, const gchar *name, const gchar *path) if (strstr(real_path, get_collections_dir()) && isfile(path)) { - buf.reset(bookmark_string(name, path, "gq-icon-collection")); + buf.reset(bookmark_string(name, path, PIXBUF_INLINE_COLLECTION)); } else { diff --git a/src/ui-menu.cc b/src/ui-menu.cc index 2fd315e8..9c04a0aa 100644 --- a/src/ui-menu.cc +++ b/src/ui-menu.cc @@ -25,6 +25,7 @@ #include +#include "compat.h" #include "layout.h" /* @@ -89,8 +90,8 @@ static gint actions_sort_cb(gconstpointer a, gconstpointer b) const gchar *accel_path_b; GtkAccelKey key_b; - accel_path_a = gtk_action_get_accel_path(GTK_ACTION(a)); - accel_path_b = gtk_action_get_accel_path(GTK_ACTION(b)); + accel_path_a = gq_gtk_action_get_accel_path(GTK_ACTION(a)); + accel_path_b = gq_gtk_action_get_accel_path(GTK_ACTION(b)); if (accel_path_a && gtk_accel_map_lookup_entry(accel_path_a, &key_a) && accel_path_b && gtk_accel_map_lookup_entry(accel_path_b, &key_b)) { @@ -130,17 +131,17 @@ static void menu_item_add_main_window_accelerator(GtkWidget *menu, GtkAccelGroup lw = static_cast(layout_window_list->data); /* get the actions from the first window, it should not matter, they should be the same in all windows */ g_assert(lw && lw->ui_manager); - groups = gtk_ui_manager_get_action_groups(lw->ui_manager); + groups = gq_gtk_ui_manager_get_action_groups(lw->ui_manager); while (groups) { - actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data)); + actions = gq_gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data)); actions = g_list_sort(actions, actions_sort_cb); while (actions) { action = GTK_ACTION(actions->data); - accel_path = gtk_action_get_accel_path(action); + accel_path = gq_gtk_action_get_accel_path(action); if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key)) { g_object_get(action, "label", &action_label, NULL); diff --git a/src/ui-misc.cc b/src/ui-misc.cc index 47aff9ed..4aaa8951 100644 --- a/src/ui-misc.cc +++ b/src/ui-misc.cc @@ -1445,17 +1445,6 @@ gchar *text_widget_text_pull_selected(GtkWidget *text_widget) } -static gint simple_sort_cb(gconstpointer a, gconstpointer b) -{ - const ActionItem *a_action; - const ActionItem *b_action; - - a_action = static_cast(a); - b_action = static_cast(b); - - return g_strcmp0(a_action->name, b_action->name); -} - void free_action_items_cb(gpointer data) { ActionItem *action_item; @@ -1486,7 +1475,6 @@ GList* get_action_items() { ActionItem *action_item; const gchar *accel_path; - gboolean duplicate; gchar *action_name; gchar *label; gchar *tooltip; @@ -1494,8 +1482,6 @@ GList* get_action_items() GList *groups; GList *list_duplicates = nullptr; GList *list_unique = nullptr; - GList *work1; - GList *work2; GtkAction *action; LayoutWindow *lw = nullptr; @@ -1504,14 +1490,14 @@ GList* get_action_items() return nullptr; } - groups = gtk_ui_manager_get_action_groups(lw->ui_manager); + groups = gq_gtk_ui_manager_get_action_groups(lw->ui_manager); while (groups) { - actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data)); + actions = gq_gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data)); while (actions) { action = GTK_ACTION(actions->data); - accel_path = gtk_action_get_accel_path(action); + accel_path = gq_gtk_action_get_accel_path(action); if (accel_path && gtk_accel_map_lookup_entry(accel_path, nullptr)) { @@ -1544,7 +1530,7 @@ GList* get_action_items() } action_item->name = action_name; - action_item->icon_name = g_strdup(gtk_action_get_stock_id(action)); + action_item->icon_name = g_strdup(gq_gtk_action_get_stock_id(action)); list_duplicates = g_list_prepend(list_duplicates, action_item); } @@ -1556,34 +1542,23 @@ GList* get_action_items() } /* Use the shortest name i.e. ignore -Alt versions. Sort makes the shortest first in the list */ - list_duplicates = g_list_sort(list_duplicates, simple_sort_cb); + const auto action_item_compare_names = [](gconstpointer a, gconstpointer b) + { + return g_strcmp0(static_cast(a)->name, static_cast(b)->name); + }; + list_duplicates = g_list_sort(list_duplicates, action_item_compare_names); /* Ignore duplicate entries */ - work1 = list_duplicates; - while (work1) + for (GList *work = list_duplicates; work; work = work->next) { - duplicate = FALSE; - work2 = list_unique; - /* The first entry must be unique, list_unique is null so control bypasses the while */ - while (work2) - { - if (g_strcmp0(static_cast(work2->data)->label, static_cast(work1->data)->label) == 0) - { - duplicate = TRUE; - break; - } - work2 = work2->next; - } - - if (!duplicate) + if (!g_list_find_custom(list_unique, static_cast(work->data)->label, reinterpret_cast(action_item_compare_label))) { action_item = g_new0(ActionItem, 1); - action_item->name = g_strdup(static_cast(work1->data)->name); - action_item->label = g_strdup(static_cast(work1->data)->label); - action_item->icon_name = g_strdup(static_cast(work1->data)->icon_name); + action_item->name = g_strdup(static_cast(work->data)->name); + action_item->label = g_strdup(static_cast(work->data)->label); + action_item->icon_name = g_strdup(static_cast(work->data)->icon_name); list_unique = g_list_append(list_unique, action_item); } - work1 = work1->next; } g_list_free_full(list_duplicates, free_action_items_cb); @@ -1591,6 +1566,11 @@ GList* get_action_items() return list_unique; } +gint action_item_compare_label(const ActionItem *action_item, const gchar *label) +{ + return g_strcmp0(action_item->label, label); +} + gboolean defined_mouse_buttons(GtkWidget *, GdkEventButton *event, gpointer data) { auto lw = static_cast(data); @@ -1609,10 +1589,10 @@ gboolean defined_mouse_buttons(GtkWidget *, GdkEventButton *event, gpointer data } else { - action = gtk_action_group_get_action(lw->action_group, options->mouse_button_8); + action = gq_gtk_action_group_get_action(lw->action_group, options->mouse_button_8); if (action) { - gtk_action_activate(action); + gq_gtk_action_activate(action); } ret = TRUE; } @@ -1627,11 +1607,11 @@ gboolean defined_mouse_buttons(GtkWidget *, GdkEventButton *event, gpointer data } else { - action = gtk_action_group_get_action(lw->action_group, options->mouse_button_9); + action = gq_gtk_action_group_get_action(lw->action_group, options->mouse_button_9); ret = TRUE; if (action) { - gtk_action_activate(action); + gq_gtk_action_activate(action); } ret = TRUE; } diff --git a/src/ui-misc.h b/src/ui-misc.h index 881585cf..9cfdd1ed 100644 --- a/src/ui-misc.h +++ b/src/ui-misc.h @@ -237,6 +237,7 @@ struct ActionItem }; GList* get_action_items(); +gint action_item_compare_label(const ActionItem *action_item, const gchar *label); void action_items_free(GList *list); gboolean defined_mouse_buttons(GtkWidget *widget, GdkEventButton *event, gpointer data); diff --git a/src/ui-pathsel.cc b/src/ui-pathsel.cc index bc3fc044..31f3ff41 100644 --- a/src/ui-pathsel.cc +++ b/src/ui-pathsel.cc @@ -710,6 +710,8 @@ static gboolean dest_keypress_cb(GtkWidget *view, GdkEventKey *event, gpointer d return TRUE; } break; + default: + break; } return FALSE; @@ -1033,7 +1035,7 @@ GtkWidget *path_selection_new_with_files(GtkWidget *entry, const gchar *path, gtk_widget_show(dd->hidden_button); gq_gtk_box_pack_start(GTK_BOX(table), hbox1, FALSE, FALSE, 0); - gtk_widget_show_all(hbox1); + gq_gtk_widget_show_all(hbox1); hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP); if (filter) diff --git a/src/ui-tree-edit.cc b/src/ui-tree-edit.cc index b2add4ae..953c8057 100644 --- a/src/ui-tree-edit.cc +++ b/src/ui-tree-edit.cc @@ -516,7 +516,7 @@ void shift_color(GdkRGBA *src, gshort val, gint direction) cs = 1.0 / 100 * val; /* up or down ? */ - if (direction < 0 || (direction == 0 &&(static_cast(src->red) + static_cast(src->green) + static_cast(src->blue)) / 3 > 1.0 / 2)) + if (direction < 0 || (direction == 0 &&(src->red + src->green + src->blue) / 3 > 1.0 / 2)) { src->red = MAX(0 , src->red - cs); src->green = MAX(0 , src->green - cs); diff --git a/src/view-dir-tree.cc b/src/view-dir-tree.cc index de7b1338..a0ce693c 100644 --- a/src/view-dir-tree.cc +++ b/src/view-dir-tree.cc @@ -848,6 +848,8 @@ gboolean vdtree_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat } } break; + default: + break; } return FALSE; diff --git a/src/view-dir.cc b/src/view-dir.cc index 0c453aca..d1722b0c 100644 --- a/src/view-dir.cc +++ b/src/view-dir.cc @@ -53,41 +53,33 @@ namespace { -/** @FIXME Emblems should be attached to icons via e.g.: - * GIcon *.... - * icon = g_themed_icon_new("folder"); - * emblem_icon = g_themed_icon_new("emblem_symbolic_link"); - * emblem = g_emblem_new(emblem_icon); - * emblemed = g_emblemed_icon_new(icon, emblem); - * gtk_icon_info_load_icon(icon_info, NULL) - * But there does not seem to be a way to get GtkIconInfo from a GIcon - */ GdkPixbuf *create_folder_icon_with_emblem(GtkIconTheme *icon_theme, const gchar *emblem, const gchar *fallback_icon, gint size) { - if (!gtk_icon_theme_has_icon(icon_theme, emblem)) + GdkPixbuf *pixbuf = nullptr; + GtkIconInfo *info; + + GIcon *icon_folder = g_themed_icon_new(GQ_ICON_DIRECTORY); + GIcon *icon_emblem = g_themed_icon_new(emblem); + GEmblem *emblem_new = g_emblem_new(icon_emblem); + GIcon *emblemed_icon = g_emblemed_icon_new(icon_folder, emblem_new); + + info = gtk_icon_theme_lookup_by_gicon(icon_theme, emblemed_icon, size, GTK_ICON_LOOKUP_USE_BUILTIN); + + if (info) { - return gq_gtk_icon_theme_load_icon_copy(icon_theme, fallback_icon, size, GTK_ICON_LOOKUP_USE_BUILTIN); + pixbuf = gtk_icon_info_load_icon(info, nullptr); } - GError *error = nullptr; - GdkPixbuf *icon = gtk_icon_theme_load_icon(icon_theme, emblem, size, GTK_ICON_LOOKUP_USE_BUILTIN, &error); - GdkPixbuf *pixbuf; - if (error) + if (pixbuf == nullptr) { - log_printf("Error: %s\n", error->message); - g_error_free(error); pixbuf = gq_gtk_icon_theme_load_icon_copy(icon_theme, fallback_icon, size, GTK_ICON_LOOKUP_USE_BUILTIN); } - else - { - GdkPixbuf *directory_pixbuf = gtk_icon_theme_load_icon(icon_theme, GQ_ICON_DIRECTORY, size, GTK_ICON_LOOKUP_USE_BUILTIN, nullptr); - pixbuf = gdk_pixbuf_copy(directory_pixbuf); - g_object_unref(directory_pixbuf); - - gint scale = gdk_pixbuf_get_width(icon) / 2; - gdk_pixbuf_composite(icon, pixbuf, scale, scale, scale, scale, scale, scale, 0.5, 0.5, GDK_INTERP_HYPER, 255); - } - g_object_unref(icon); + + g_object_unref(emblem_new); + g_object_unref(emblemed_icon); + g_object_unref(icon_emblem); + g_object_unref(icon_folder); + g_object_unref(info); return pixbuf; } @@ -179,7 +171,7 @@ ViewDir *vd_new(LayoutWindow *lw) case DIRVIEW_TREE: vd = vdtree_new(vd, lw->dir_fd); break; } - gtk_container_add(GTK_CONTAINER(vd->widget), vd->view); + gq_gtk_container_add(GTK_WIDGET(vd->widget), vd->view); vd_dnd_init(vd); @@ -914,6 +906,8 @@ static void vd_dnd_get(GtkWidget *, GdkDragContext *, uri_selection_data_set_uris_from_filelist(selection_data, list); g_list_free(list); break; + default: + break; } } diff --git a/src/view-file/view-file-icon.cc b/src/view-file/view-file-icon.cc index 1eedd5f4..9bb913d1 100644 --- a/src/view-file/view-file-icon.cc +++ b/src/view-file/view-file-icon.cc @@ -832,65 +832,33 @@ void vficon_select_list(ViewFile *vf, GList *list) void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode) { - GList *work; - gint n = mark - 1; - g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE); - work = vf->list; - while (work) + for (GList *work = vf->list; work; work = work->next) { auto fd = static_cast(work->data); - gboolean mark_val; gboolean selected; g_assert(fd->magick == FD_MAGICK); - mark_val = file_data_get_mark(fd, n); - selected = fd->selected & SELECTION_SELECTED; - - switch (mode) - { - case MTS_MODE_SET: selected = mark_val; - break; - case MTS_MODE_OR: selected = mark_val || selected; - break; - case MTS_MODE_AND: selected = mark_val && selected; - break; - case MTS_MODE_MINUS: selected = !mark_val && selected; - break; - } + selected = file_data_mark_to_selection(fd, mark, mode, fd->selected & SELECTION_SELECTED); vficon_select_util(vf, fd, selected); - - work = work->next; } } void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode) { GList *slist; - GList *work; - gint n = mark -1; g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE); slist = vficon_selection_get_list(vf); - work = slist; - while (work) + for (GList *work = slist; work; work = work->next) { auto fd = static_cast(work->data); - switch (mode) - { - case STM_MODE_SET: file_data_set_mark(fd, n, 1); - break; - case STM_MODE_RESET: file_data_set_mark(fd, n, 0); - break; - case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n)); - break; - } - work = work->next; + file_data_selection_to_mark(fd, mark, mode); } filelist_free(slist); } diff --git a/src/view-file/view-file-list.cc b/src/view-file/view-file-list.cc index 32c2f131..e0e53e13 100644 --- a/src/view-file/view-file-list.cc +++ b/src/view-file/view-file-list.cc @@ -710,28 +710,24 @@ static void vflist_collapse_cb(GtkTreeView *, GtkTreeIter *iter, GtkTreePath *, *----------------------------------------------------------------------------- */ - -static gchar* vflist_get_formatted(ViewFile *vf, const gchar *name, const gchar *sidecars, const gchar *size, const gchar *time, gboolean expanded, gboolean with_stars, const gchar *star_rating) - { +static gchar* vflist_get_formatted(ViewFile *vf, const gchar *name, const gchar *sidecars, const gchar *size, const gchar *time, gboolean expanded, const gchar *star_rating) +{ gboolean multiline = vflist_is_multiline(vf); - gchar *text; + GString *text = g_string_new(nullptr); + + g_string_printf(text, "%s %s", name, expanded ? "" : sidecars); if (multiline) { - if (with_stars) - { - text = g_strdup_printf("%s %s\n%s\n%s\n%s", name, expanded ? "" : sidecars, size, time, star_rating); - } - else + g_string_append_printf(text, "\n%s\n%s", size, time); + + if (star_rating) { - text = g_strdup_printf("%s %s\n%s\n%s", name, expanded ? "" : sidecars, size, time); + g_string_append_printf(text, "\n%s", star_rating); } } - else - { - text = g_strdup_printf("%s %s", name, expanded ? "" : sidecars); - } - return text; + + return g_string_free(text, FALSE); } static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded) @@ -754,8 +750,8 @@ static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expand FILE_COLUMN_STAR_RATING, &star_rating, -1); - formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded, FALSE, nullptr); - formatted_with_stars = vflist_get_formatted(vf, name, sidecars, size, time, expanded, TRUE, star_rating); + formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded, nullptr); + formatted_with_stars = vflist_get_formatted(vf, name, sidecars, size, time, expanded, star_rating); gtk_tree_store_set(store, iter, FILE_COLUMN_FORMATTED, formatted, FILE_COLUMN_EXPANDED, expanded, @@ -804,8 +800,8 @@ static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *it name = g_strdup_printf("%s%s%s", link, fd->name, disabled_grouping); size = text_from_size(fd->size); - formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded, FALSE, nullptr); - formatted_with_stars = vflist_get_formatted(vf, name, sidecars, size, time, expanded, TRUE, star_rating); + formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded, nullptr); + formatted_with_stars = vflist_get_formatted(vf, name, sidecars, size, time, expanded, star_rating); gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd, FILE_COLUMN_VERSION, fd->version, @@ -1158,7 +1154,7 @@ void vflist_set_star_fd(ViewFile *vf, FileData *fd) FILE_COLUMN_EXPANDED, &expanded, -1); - formatted_with_stars = vflist_get_formatted(vf, name, sidecars, size, time, expanded, TRUE, star_rating); + formatted_with_stars = vflist_get_formatted(vf, name, sidecars, size, time, expanded, star_rating); gtk_tree_store_set(store, &iter, FILE_COLUMN_FORMATTED_WITH_STARS, formatted_with_stars, FILE_COLUMN_EXPANDED, expanded, @@ -1596,7 +1592,6 @@ void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode) GtkTreeIter iter; GtkTreeSelection *selection; gboolean valid; - gint n = mark - 1; g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE); @@ -1607,24 +1602,10 @@ void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode) while (valid) { FileData *fd; - gboolean mark_val; gboolean selected; gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1); - mark_val = file_data_get_mark(fd, n); - selected = gtk_tree_selection_iter_is_selected(selection, &iter); - - switch (mode) - { - case MTS_MODE_SET: selected = mark_val; - break; - case MTS_MODE_OR: selected = mark_val || selected; - break; - case MTS_MODE_AND: selected = mark_val && selected; - break; - case MTS_MODE_MINUS: selected = !mark_val && selected; - break; - } + selected = file_data_mark_to_selection(fd, mark, mode, gtk_tree_selection_iter_is_selected(selection, &iter)); if (selected) gtk_tree_selection_select_iter(selection, &iter); @@ -1640,15 +1621,12 @@ void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode) GtkTreeModel *store; GtkTreeSelection *selection; GList *slist; - GList *work; - gint n = mark - 1; g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview)); slist = gtk_tree_selection_get_selected_rows(selection, &store); - work = slist; - while (work) + for (GList *work = slist; work; work = work->next) { auto tpath = static_cast(work->data); FileData *fd; @@ -1661,15 +1639,7 @@ void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode) complete re-read of the directory - try to do only minimal update instead */ file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */ - switch (mode) - { - case STM_MODE_SET: file_data_set_mark(fd, n, 1); - break; - case STM_MODE_RESET: file_data_set_mark(fd, n, 0); - break; - case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n)); - break; - } + file_data_selection_to_mark(fd, mark, mode); if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */ { @@ -1683,10 +1653,7 @@ void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode) vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, nullptr, FALSE); } - file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM); - - work = work->next; } g_list_free_full(slist, reinterpret_cast(gtk_tree_path_free)); } diff --git a/subprojects/gtest.wrap b/subprojects/gtest.wrap new file mode 100644 index 00000000..ca5d699e --- /dev/null +++ b/subprojects/gtest.wrap @@ -0,0 +1,10 @@ +[wrap-file] +directory = googletest-release-1.10.0 + +source_url = https://github.com/google/googletest/archive/release-1.10.0.zip +source_filename = gtest-1.10.0.zip +source_hash = 94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91 + +patch_url = https://wrapdb.mesonbuild.com/v1/projects/gtest/1.10.0/1/get_zip +patch_filename = gtest-1.10.0-1-wrap.zip +patch_hash = 04ff14e8880e4e465f6260221e9dfd56fea6bc7cce4c4aff0dc528e4a2c8f514