pax_global_header00006660000000000000000000000064147622666110014525gustar00rootroot0000000000000052 comment=5ce8bf3755cfaa47ef34d130f0737133860e9947 dtkgui-5.7.12/000077500000000000000000000000001476226661100131105ustar00rootroot00000000000000dtkgui-5.7.12/.github/000077500000000000000000000000001476226661100144505ustar00rootroot00000000000000dtkgui-5.7.12/.github/ISSUE_TEMPLATE/000077500000000000000000000000001476226661100166335ustar00rootroot00000000000000dtkgui-5.7.12/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000023651476226661100206310ustar00rootroot00000000000000blank_issues_enabled: false contact_links: - name: BUG Report | 缺陷报告 url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=bug-report.yml about: Please create bug reports to the issue board in our dtk repo. - name: docs-update | 文档补充 url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=docs-update.yml about: Please create docs-update to the issue board in our dtk repo. - name: unit-test-report | 单元测试报告 url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=unit-test-report.yml about: Please create unit-test-report to the issue board in our dtk repo. - name: Feature Request | 特性请求 url: https://github.com/linuxdeepin/developer-center/discussions/new?category=features-request-ideas-%E7%89%B9%E6%80%A7%E8%AF%B7%E6%B1%82-%E5%A4%B4%E8%84%91%E9%A3%8E%E6%9A%B4 about: Please create feature requests to the discussion board in our developer-center repo. - name: General Discussion & Questions | 常规讨论与问答 url: https://github.com/linuxdeepin/developer-center/discussions/categories/q-a-%E9%97%AE%E7%AD%94%E6%9D%BF%E5%9D%97 about: Please use the discussion board in our developer-center repo. dtkgui-5.7.12/.github/workflows/000077500000000000000000000000001476226661100165055ustar00rootroot00000000000000dtkgui-5.7.12/.github/workflows/backup-to-gitlab.yml000066400000000000000000000005371476226661100223620ustar00rootroot00000000000000name: backup to gitlab on: [push] concurrency: group: ${{ github.workflow }} cancel-in-progress: true jobs: backup-to-gitlabwh: uses: linuxdeepin/.github/.github/workflows/backup-to-gitlabwh.yml@master secrets: inherit backup-to-gitee: uses: linuxdeepin/.github/.github/workflows/backup-to-gitee.yml@master secrets: inherit dtkgui-5.7.12/.github/workflows/call-api-check.yml000066400000000000000000000004351476226661100217670ustar00rootroot00000000000000name: apiCheck on: pull_request_target: types: [opened, synchronize, reopened] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: api-check: uses: linuxdeepin/.github/.github/workflows/api-check.yml@master secrets: inheritdtkgui-5.7.12/.github/workflows/call-auto-tag.yml000066400000000000000000000005171476226661100216650ustar00rootroot00000000000000name: auto tag on: pull_request_target: types: [opened, synchronize, closed] paths: - "debian/changelog" concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: auto_tag: uses: linuxdeepin/.github/.github/workflows/auto-tag.yml@master secrets: inherit dtkgui-5.7.12/.github/workflows/call-build-distribution.yml000066400000000000000000000004321476226661100237540ustar00rootroot00000000000000name: Call build-distribution on: push: paths-ignore: - ".github/workflows/**" pull_request_target: paths-ignore: - ".github/workflows/**" jobs: check_job: uses: linuxdeepin/.github/.github/workflows/build-distribution.yml@master secrets: inherit dtkgui-5.7.12/.github/workflows/call-chatOps.yml000066400000000000000000000002421476226661100215400ustar00rootroot00000000000000name: chatOps on: issue_comment: types: [created] jobs: chatopt: uses: linuxdeepin/.github/.github/workflows/chatOps.yml@master secrets: inherit dtkgui-5.7.12/.github/workflows/call-clacheck.yml000066400000000000000000000005251476226661100217000ustar00rootroot00000000000000name: Call CLA check on: issue_comment: types: [created] pull_request_target: types: [opened, closed, synchronize] concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: clacheck: uses: linuxdeepin/.github/.github/workflows/cla-check.yml@master secrets: inherit dtkgui-5.7.12/.github/workflows/call-commitlint.yml000066400000000000000000000003641476226661100223230ustar00rootroot00000000000000name: Call commitlint on: pull_request_target: concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: check_job: uses: linuxdeepin/.github/.github/workflows/commitlint.yml@master dtkgui-5.7.12/.github/workflows/call-debian-check.yml000066400000000000000000000004461476226661100224420ustar00rootroot00000000000000name: debianCheck on: pull_request_target: types: [opened, synchronize, reopened] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: debian-check: uses: linuxdeepin/.github/.github/workflows/debian-check.yml@master secrets: inheritdtkgui-5.7.12/.github/workflows/call-deploy-dev-doc.yml000066400000000000000000000007401476226661100227550ustar00rootroot00000000000000name: deploy docs on: push: branches: ["master"] workflow_dispatch: inputs: tag: required: true type: string permissions: contents: read pages: write id-token: write # Allow one concurrent deployment concurrency: group: "pages" cancel-in-progress: true jobs: deploydocs: uses: linuxdeepin/.github/.github/workflows/deploy-dev-doc.yml@master with: ref: ${{ inputs.tag }} secrets: inherit dtkgui-5.7.12/.github/workflows/call-doc-check.yml000066400000000000000000000004671476226661100217700ustar00rootroot00000000000000name: doxygen-check on: pull_request_target: paths-ignore: - ".github/workflows/**" concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: check_job: uses: linuxdeepin/.github/.github/workflows/doc-check.yml@master secrets: inherit dtkgui-5.7.12/.github/workflows/call-license-check.yml000066400000000000000000000005521476226661100226400ustar00rootroot00000000000000name: Call License and README Check on: pull_request_target: types: [opened, synchronize, reopened] permissions: pull-requests: write contents: read concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: license-check: uses: linuxdeepin/.github/.github/workflows/license-check.yml@master dtkgui-5.7.12/.github/workflows/call-static-check.yml000066400000000000000000000004461476226661100225070ustar00rootroot00000000000000name: staticCheck on: pull_request_target: types: [opened, synchronize, reopened] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: static-check: uses: linuxdeepin/.github/.github/workflows/static-check.yml@master secrets: inheritdtkgui-5.7.12/.github/workflows/call-synchronize-to-dtk6.yml000066400000000000000000000010301476226661100237740ustar00rootroot00000000000000name: Call synchronize to dtk6 on: pull_request_target: paths-ignore: - "debian/**" - "archlinux/**" - "rpm/**" - ".obs/**" - ".github/**" jobs: call-synchronize: uses: linuxdeepin/dtk/.github/workflows/synchronize-to-dtk6.yml@master secrets: inherit with: dest_repo: linuxdeepin/dtk6gui source_repo: ${{ github.event.pull_request.head.repo.full_name }} source_ref: ${{ github.event.pull_request.head.ref }} pull_number: ${{ github.event.pull_request.number }} dtkgui-5.7.12/.github/workflows/cppcheck.yml000066400000000000000000000012651476226661100210140ustar00rootroot00000000000000name: cppcheck on: pull_request_target: paths-ignore: - ".github/workflows/**" concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: cppchceck: name: cppcheck runs-on: ubuntu-latest steps: - run: export - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - uses: linuxdeepin/action-cppcheck@main with: github_token: ${{ secrets.GITHUB_TOKEN }} repository: ${{ github.repository }} pull_request_id: ${{ github.event.pull_request.number }} allow_approve: false dtkgui-5.7.12/.gitignore000066400000000000000000000012701476226661100151000ustar00rootroot00000000000000# C++ objects and libs *.slo *.lo *.o *.a *.la *.lai *.so *.dll *.dylib # Qt-es object_script.*.Release object_script.*.Debug *_plugin_import.cpp /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.qbs.user *.qbs.user.* *.moc moc_*.cpp moc_*.h qrc_*.cpp ui_*.h *.qmlc *.jsc Makefile* *build-* # Qt unit tests target_wrapper.* # QtCreator *.autosave # QtCreator Qml *.qmlproject.user *.qmlproject.user.* # QtCreator CMake CMakeLists.txt.user* # vscode .vscode # idea .idea #clangformat .clang-format # build compile_commands.json bin DtkGuis dtkgui_config.h qt_lib_dtkgui*.pri build .cache dtkgui.pc DtkGuiConfig.cmake asan.* Testing # Ignore Doxygen theme files docs/doxygen-theme/ dtkgui-5.7.12/.gitlab-ci.yml000066400000000000000000000002271476226661100155450ustar00rootroot00000000000000include: - remote: 'https://gitlab.deepin.io/dev-tools/letmeci/raw/master/gitlab-ci/dde.yml' variables: CPPCHECK: "true" CODESPELL: "true" dtkgui-5.7.12/.obs/000077500000000000000000000000001476226661100137515ustar00rootroot00000000000000dtkgui-5.7.12/.obs/workflows.yml000066400000000000000000000023121476226661100165270ustar00rootroot00000000000000test_build: steps: - link_package: source_project: deepin:Develop:dde source_package: %{SCM_REPOSITORY_NAME} target_project: deepin:CI - configure_repositories: project: deepin:CI repositories: - name: deepin_develop paths: - target_project: deepin:CI target_repository: deepin_develop architectures: - x86_64 - aarch64 - name: debian paths: - target_project: deepin:CI target_repository: debian_sid architectures: - x86_64 - name: archlinux paths: - target_project: deepin:CI target_repository: archlinux architectures: - x86_64 filters: event: pull_request tag_build: steps: - branch_package: source_project: deepin:Develop:dde source_package: %{SCM_REPOSITORY_NAME} target_project: deepin:Unstable:dde filters: event: tag_push commit_build: steps: - trigger_services: project: deepin:Develop:dde package: %{SCM_REPOSITORY_NAME} filters: event: push dtkgui-5.7.12/.packit.yaml000066400000000000000000000007021476226661100153240ustar00rootroot00000000000000# See the documentation for more information: # https://packit.dev/docs/configuration/ specfile_path: rpm/dtkgui.spec # add or remove files that should be synced synced_files: - rpm/dtkgui.spec - .packit.yaml upstream_package_name: dtkgui # downstream (Fedora) RPM package name downstream_package_name: dtkgui actions: fix-spec-file: | bash -c "sed -i -r \"s/Version:(\s*)\S*/Version:\1${PACKIT_PROJECT_VERSION}/\" rpm/dtkgui.spec" dtkgui-5.7.12/.release.json000066400000000000000000000010451476226661100155010ustar00rootroot00000000000000{ "commit": { "quilt": false, "pkgver": "echo $(git tag | sort -V | tail -n1)'+r'$(git log $(git describe --abbrev=0 --tags)..HEAD --oneline|wc -l)'+g'$(git rev-parse --short HEAD);", "dist": "experimental" }, "release": { "quilt": true, "pkgver": "git describe --abbrev=0 --tags %(ref)s", "dist": "unstable" }, "release-candidate": { "quilt": true, "dist": "unstable" } } dtkgui-5.7.12/.reuse/000077500000000000000000000000001476226661100143115ustar00rootroot00000000000000dtkgui-5.7.12/.reuse/dep5000066400000000000000000000024751476226661100151010ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: dtkgui Upstream-Contact: UnionTech Software Technology Co., Ltd. <> Source: https://github.com/linuxdeepin/dtkgui # ci Files: .github/* .gitlab-ci.yml .obs/* Copyright: None License: CC0-1.0 # gitignore Files: .gitignore .syncexclude Copyright: None License: CC0-1.0 # json conf yaml Files: *.json *conf *.yaml Copyright: None License: CC0-1.0 #interface Files: include/DtkGui/D* Copyright: None License: CC0-1.0 # RPM/Arch Packaging Files: archlinux/* rpm/* Copyright: None License: CC0-1.0 # debian Files: debian/* Copyright: None License: LGPL-3.0-or-later # README Files: *README.md *README.zh_CN.md Copyright: None License: CC-BY-4.0 # Documentations Files: docs/* Copyright: 2022-2023 deepin doc doc go SIG License: CC-BY-4.0 # DBus Files: src/dbus/*.xml Copyright: None License: CC0-1.0 # Project file Files: *.pro *.prf *.pri *.qrc *CMakeLists.txt *.cmake *.in Copyright: None License: CC0-1.0 # images: png svg dci webp Files: src/util/icons/actions/* src/util/icons/icons/* src/util/icons/texts/* src/util/icons/dci/* tests/images/* tests/actions/* tests/dcis/* examples/animation-dci/* Copyright: UnionTech Software Technology Co., Ltd. License: LGPL-3.0-or-later Files: toolGenerate/**/* Copyright: None License: CC0-1.0 dtkgui-5.7.12/.syncexclude000066400000000000000000000003651476226661100154430ustar00rootroot00000000000000# Paths that will be exclude from synchronize workflow # Please use relative path which use project directory as root # Notice that # * .git # * debian # * archlinux # * .obs # * .github # are always ignored linglong.yaml conanfile.py dtkgui-5.7.12/CMakeLists.txt000066400000000000000000000010371476226661100156510ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.25) set(DTK_VERSION "5.6.11" CACHE STRING "define project version") project(DtkGui VERSION ${DTK_VERSION} DESCRIPTION "DTK Gui module" HOMEPAGE_URL "https://github.com/linuxdeepin/dtkgui" LANGUAGES CXX C ) if("${PROJECT_VERSION_MAJOR}" STREQUAL "5") set(QT_VERSION_MAJOR "5") elseif("${PROJECT_VERSION_MAJOR}" STREQUAL "6") set(QT_VERSION_MAJOR "6") set(DTK_VERSION_MAJOR "6") else() message(SEND_ERROR "not support Prject Version ${PROJECT_VERSION}.") endif() include(dtkgui.cmake) dtkgui-5.7.12/LICENSE000066400000000000000000001221631476226661100141220ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . dtkgui-5.7.12/LICENSES/000077500000000000000000000000001476226661100143155ustar00rootroot00000000000000dtkgui-5.7.12/LICENSES/CC-BY-4.0.txt000066400000000000000000000411771476226661100161640ustar00rootroot00000000000000Creative Commons Attribution 4.0 International Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Using Creative Commons Public Licenses Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors. Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public. Creative Commons Attribution 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 – Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. d. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. e. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. f. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. g. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. h. Licensor means the individual(s) or entity(ies) granting rights under this Public License. i. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. j. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 – Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: A. reproduce and Share the Licensed Material, in whole or in part; and B. produce, reproduce, and Share Adapted Material. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 5. Downstream recipients. A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. B. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. Section 3 – License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material (including in modified form), You must: A. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. Section 4 – Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 – Disclaimer of Warranties and Limitation of Liability. a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 – Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 – Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 – Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. dtkgui-5.7.12/LICENSES/CC0-1.0.txt000066400000000000000000000156101476226661100157220ustar00rootroot00000000000000Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. dtkgui-5.7.12/LICENSES/LGPL-3.0-or-later.txt000066400000000000000000001221621476226661100176410ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . dtkgui-5.7.12/README.md000066400000000000000000000020531476226661100143670ustar00rootroot00000000000000## Deepin Tool Kit Gui Deepin Tool Kit (DtkGui) is the development graphical user interface of all C++/Qt Developer work on Deepin. You should read the Deepin Application Specification firstly. ## Dependencies ### Build dependencies * Qt >= 5.10 ## Installation ### Build from source code 1. Make sure you have installed all dependencies. 2. Build: ```bash mkdir build cd build cmake .. make ``` 3. Install: ```bash sudo make install ``` ## Getting help Any usage issues can ask for help via * [Telegram group](https://t.me/deepin) * [Matrix](https://matrix.to/#/#deepin-community:matrix.org) * [IRC (libera.chat)](https://web.libera.chat/#deepin-community) * [Forum](https://bbs.deepin.org) * [WiKi](https://wiki.deepin.org/) ## Getting involved We encourage you to report issues and contribute changes * [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en). ## License deepin-tool-kit is licensed under [LGPL-3.0-or-later](LICENSE). dtkgui-5.7.12/README.zh_CN.md000066400000000000000000000017301476226661100153700ustar00rootroot00000000000000## Deepin Tool Kit Gui Deepin Tool Kit Gui(DtkGui) 提供开发图形用户界面应用程序所需的功能. 您应该首先阅读 Deepin应用程序规范. ## 依赖 ### 编译依赖 * Qt >= 5.10 ## 安装 ### 从源代码构建 1. 确保已经安装了所有的编译依赖. 2. 构建: ```bash mkdir build cd build cmake .. make ``` 3. 安装: ```bash sudo make install ``` ## 帮助 任何使用问题都可以通过以下方式寻求帮助: * [Telegram 群组](https://t.me/deepin) * [Matrix](https://matrix.to/#/#deepin-community:matrix.org) * [IRC (libera.chat)](https://web.libera.chat/#deepin-community) * [Forum](https://bbs.deepin.org) * [WiKi](https://wiki.deepin.org/) ## 参与贡献 我们鼓励您报告问题并作出更改 * [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) ## 协议 DTK工具包遵循协议 [LGPL-3.0-or-later](LICENSE). dtkgui-5.7.12/archlinux/000077500000000000000000000000001476226661100151055ustar00rootroot00000000000000dtkgui-5.7.12/archlinux/PKGBUILD000066400000000000000000000022751476226661100162370ustar00rootroot00000000000000# Maintainer: justforlxz pkgname=dtkgui-git pkgver=5.5.22.r8.g6ef1509 pkgrel=1 sourcename=dtkgui sourcetars=("$sourcename"_"$pkgver".tar.xz) sourcedir="$sourcename" pkgdesc='Deepin Toolkit, gui module for DDE look and feel' arch=('x86_64' 'aarch64') url="https://github.com/linuxdeepin/dtkgui" license=('LGPL3') depends=('dtkcore-git' 'dtkcommon-git' 'qt5-svg' 'libqtxdg' 'freeimage' 'librsvg' 'qt5-wayland') # INFO: you can disable freeimage not to support RAW images # Then set DTK_DISABLE_EX_IMAGE_FORMAT=OFF makedepends=('git' 'qt5-tools' 'gtest' 'gmock' 'ninja' 'cmake' 'doxygen' 'extra-cmake-modules') conflicts=('dtkgui') provides=('dtkgui') groups=('deepin-git') source=("${sourcetars[@]}") sha512sums=('SKIP') build() { cd $sourcedir cmake -GNinja \ -DMKSPECS_INSTALL_DIR=lib/qt/mkspecs/modules/ \ -DBUILD_DOCS=ON \ -DQCH_INSTALL_DESTINATION=share/doc/qt \ -DCMAKE_INSTALL_LIBDIR=lib \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_BUILD_TYPE=Release ninja # INFO: Another cmake option is DTK_DISABLE_EX_IMAGE_FORMAT # If you not want to support RAW images, set it to off } package() { cd $sourcedir DESTDIR="$pkgdir" ninja install } dtkgui-5.7.12/cmake/000077500000000000000000000000001476226661100141705ustar00rootroot00000000000000dtkgui-5.7.12/cmake/FindFreeImage.cmake000066400000000000000000000023721476226661100176230ustar00rootroot00000000000000# # Try to find the FreeImage library and include path. # Once done this will define # # FreeImage_FOUND # FreeImage_INCLUDE_PATH # FreeImage_LIBRARY # find_path(FreeImage_INCLUDE_DIR NAMES FreeImage.h PATHS /usr/include /usr/local/include /sw/include /opt/local/include ${CMAKE_INCLUDE_PATH} ${CMAKE_INSTALL_PREFIX}/include) find_library(FreeImage_LIBRARY NAMES FreeImage freeimage PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /sw/lib /opt/local/lib ${CMAKE_LIBRARY_PATH} ${CMAKE_INSTALL_PREFIX}/lib) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(FreeImage FOUND_VAR FreeImage_FOUND REQUIRED_VARS FreeImage_LIBRARY FreeImage_INCLUDE_DIR ) if(FreeImage_FOUND) set(FreeImage_LIBRARIES ${FreeImage_LIBRARY}) set(FreeImage_INCLUDE_DIRS ${FreeImage_INCLUDE_DIR}) endif() if(FreeImage_FOUND AND NOT TARGET FreeImage::FreeImage) add_library(FreeImage::FreeImage UNKNOWN IMPORTED) set_target_properties(FreeImage::FreeImage PROPERTIES IMPORTED_LOCATION "${FreeImage_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${FreeImage_INCLUDE_DIR}" ) endif() mark_as_advanced( FreeImage_INCLUDE_DIR FreeImage_LIBRARY ) dtkgui-5.7.12/debian/000077500000000000000000000000001476226661100143325ustar00rootroot00000000000000dtkgui-5.7.12/debian/changelog000066400000000000000000000277031476226661100162150ustar00rootroot00000000000000dtkgui (5.7.12) unstable; urgency=medium * fix: palette refresh delayed in qt6 * feat: Add files generated by qdbusXML2cpp and DCONG2cpp -- YeShanShan Thu, 06 Mar 2025 17:29:35 +0800 dtkgui (5.7.11) unstable; urgency=medium * Release 5.7.11 -- YeShanShan Thu, 27 Feb 2025 20:47:39 +0800 dtkgui (5.7.10) unstable; urgency=medium * fix: icon is blurry -- YeShanShan Thu, 13 Feb 2025 17:18:19 +0800 dtkgui (5.7.9) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Thu, 23 Jan 2025 09:07:08 +0000 dtkgui (5.7.8) unstable; urgency=medium * fix: missing window decoration for treeland * chore: update default window corner size -- Deepin Packages Builder Tue, 14 Jan 2025 11:17:31 +0000 dtkgui (5.7.7) unstable; urgency=medium * fix: accessing wild pointer in qt6 * chore: correct typos about Dtk::Gui::DDciIcon::IconAttribute Thanks to Felix Yan -- Deepin Packages Builder Thu, 09 Jan 2025 09:28:38 +0000 dtkgui (5.7.6) unstable; urgency=medium * refact: refacting DPlatformHandle to adap treeland * Revert "refact: refacting DPlatformHandle to adap treeland" * refact: refacting DPlatformHandle to adapt treeland * fix: iterator out of bounds for dciicon * fix: set font family invalid -- Deepin Packages Builder Thu, 02 Jan 2025 05:43:53 +0000 dtkgui (5.7.5) unstable; urgency=medium * fix: availableSizes not work on Qt6 -- Deepin Packages Builder Thu, 12 Dec 2024 03:03:53 +0000 dtkgui (5.7.4) unstable; urgency=medium * chore(CI): add debian check workflow Thanks to kuchune * refactor: xcb platform theme interface * refactor: treeland platform theme interface 扩展Treeland的个性化接口 * fix: Possible null pointer dereference and Notitlebar input parameter error * feat: support treeland platform for wmHelper * fix: blur is invalid for treeland * feat: Limit maximum and minimum fonts * fix: app crashed when window destroyed in quick * fix: app crashed when window destroyed in quick * fix: linglong app load qt translations failed -- Deepin Packages Builder Tue, 03 Dec 2024 02:00:46 +0000 dtkgui (5.7.3) unstable; urgency=medium * fix: No judgment on the validity of the protocol(Bug: 286859) -- Deepin Packages Builder Wed, 20 Nov 2024 02:19:06 +0000 dtkgui (5.7.2) unstable; urgency=medium * chore: Correct the name of TreelandProtocols package in cmake * fix: Under treeland, the dialog has not disabled titlebar * fix: Print "load translate" debug log to channels(Bug: 284539) * chore: add IsWaylandPlatform attribute * chore: highlight color is inconsistency -- Deepin Packages Builder Wed, 13 Nov 2024 01:53:26 +0000 dtkgui (5.7.1) unstable; urgency=medium * Revert "feat: add close.dci"(Issue: https://github.com/linuxdeepin/developer-center/issues/10482) * feat: Add notitlebar function on wayland platform * feat: support qt5 and qt6 * fix: cannot move window on wayland * fix: remove treeland personalization protocols useless function * feat: add fixme note * chore: update license info * chore: add build dep * chore: update license * chore: add extra cmake modules * chore: add dtkgui namespace * fix: app crashed in x11 -- Deepin Packages Builder Wed, 16 Oct 2024 03:30:46 +0000 dtkgui (5.6.34) unstable; urgency=medium * feat: add close.dci Thanks to Yixue Wang * chore: animation-dci supports custom icon * fix: wrong judgment conditions * feat: support to change window effects(Bug: 244347) * feat: add window startup effect Type(Issue: https://github.com/linuxdeepin/developer-center/issues/10322) -- Deepin Packages Builder Tue, 20 Aug 2024 05:03:52 +0000 dtkgui (5.6.32) unstable; urgency=medium * Revert "fix: jagged edges on ddciicon"(Issue: https://github.com/linuxdeepin/developer-center/issues/9443) * chore: dci-icon-theme tool tweak -- Deepin Packages Builder Mon, 08 Jul 2024 02:29:21 +0000 dtkgui (5.6.31) unstable; urgency=medium * fix: jagged edges on ddciicon(Issue: https://github.com/linuxdeepin/developer-center/issues/8691) -- Deepin Packages Builder Thu, 27 Jun 2024 09:11:34 +0000 dtkgui (5.6.30) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Thu, 30 May 2024 02:46:31 +0000 dtkgui (5.6.29) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Mon, 13 May 2024 03:02:53 +0000 dtkgui (5.6.28) unstable; urgency=medium * chore: insert to cache when icon is not null * chore: add flag to disable noncache flag * fix: missing initialization for baseFont of fontManager(Issue: https://github.com/linuxdeepin/developer-center/issues/8040) * feat: dci-icon-theme support multiple icon size -- Deepin Packages Builder Mon, 29 Apr 2024 08:23:44 +0000 dtkgui (5.6.27) unstable; urgency=medium * fix: setWindowBlurAreaByWM only work once in qt6 -- Deepin Packages Builder Fri, 19 Apr 2024 08:55:34 +0000 dtkgui (5.6.26) unstable; urgency=medium * fix: wrong availableSizes for DIconProxyEngine * fix: PlaceholderText color tweak(Issue: https://github.com/linuxdeepin/developer-center/issues/7554) * feat: support to get specified palette -- Deepin Packages Builder Tue, 26 Mar 2024 05:47:35 +0000 dtkgui (5.6.25) unstable; urgency=medium * fix: icon doesn't update when iconTheme changed * fix: font can't follow changes in qt6 * fix: app refresh slowly * fix: changed paletteType's config value * fix: search icon can't change with theme change(Issue: #6230) -- Deepin Packages Builder Mon, 11 Mar 2024 01:16:27 +0000 dtkgui (5.6.22) unstable; urgency=medium * fix: menu icon incorrect in dark mode(Issue: https://github.com/linuxdeepin/developer-center/issues/6624) * feat: enable xdgIconLoader under Qt6 * chore: warning for connect -- Deepin Packages Builder Wed, 10 Jan 2024 02:30:59 +0000 dtkgui (5.6.21) unstable; urgency=medium * chore: update cmake version * fix: xdg icon loading failed with qt6(Issue: https://github.com/linuxdeepin/developer-center/issues/6459) * fix: debian build failed * fix: DIconProxyEngine read not ensureEngine * chore: fix ut_dciiconengine failed on dark theme -- Deepin Packages Builder Tue, 09 Jan 2024 01:45:43 +0000 dtkgui (5.6.20) unstable; urgency=medium * chore: add synchronization workflow * fix: indirect inclusion of QSharedPointer * feat: move ddesktopservices to dtkgui(Issue: #134) -- Deepin Packages Builder Tue, 28 Nov 2023 05:40:52 +0000 dtkgui (5.6.19) unstable; urgency=medium [ root ] * UNRELEASED -- Deepin Packages Builder Mon, 23 Oct 2023 07:33:18 +0000 dtkgui (5.6.18) unstable; urgency=medium * fix: Wrong value of DPalette::TextLively * chore: find qhelpgenerator from property * fix: svg with filter attribute rendering exception * fix: when iconName is absolute path * fix: missing link when disable librsvg * fix: Wrong IconName for DIconEngine(Issue: https://github.com/linuxdeepin/developer-center/issues/5760) -- Deepin Packages Builder Wed, 18 Oct 2023 06:01:44 +0000 dtkgui (5.6.17) unstable; urgency=medium * Release 5.6.17 -- Deepin Packages Builder Fri, 08 Sep 2023 15:15:39 +0800 dtkgui (5.6.16) unstable; urgency=medium * chore: ut build without source * fix: Compiling error in qt6.4 * chore: add DtkBuildHelper depends * fix(build): ut failed on Qt6.4 * fix: dci icon cache key miss theme name(Issue: https://github.com/linuxdeepin/developer-center/issues/4517) -- Deepin Packages Builder Tue, 22 Aug 2023 06:13:45 +0000 dtkgui (5.6.15) unstable; urgency=medium * chore: iconengine tweak and uint test * chore: do not show ui in ut * chore: add unit test * chore: Adaptation for Qt5.11 * refator: rewrite hasUserManual function -- Yixue Wang Fri, 11 Aug 2023 13:57:02 +0800 dtkgui (5.6.14) unstable; urgency=medium * chore: ignore doxygen-theme folder Thanks to syn(Task: 99) * chore: change OUTPUT_DIR variable in cmake (#163) Thanks to WangFei * chore: adjust builtiniconengine (#164) Thanks to WangFei * chore: adjust xdgiconproxyengine (#167) Thanks to WangFei * chore: add unit test about builtinengine * refactor!: deprecate some interfaces in dtk6 * chore: add dciiconengine * chore: adjust icontheme * chore: add unit test about dciiconengine * chore: reduce compilation warnings Thanks to SPUER(Issue: #96) * chore: Sync by https://github.com/linuxdeepin/.github/commit/559e91167d4919644f37bbcf123eb0651c1528ea(Influence: none) * chore: add proxyiconengine * refactor: Move dotsPerInch from normal function to slots * chore: remove unused pro files * fix: build failed in qt6 due to proxyengine * feat: DIconTheme::findQIcon add fallback icon * fix(build): DIconTheme ut failed * fix: DFileDragClient::serverDestroyed nerver emit * feat: add helper for high dpi pixmap * fix: dplatformtheme fetchPalette crash * feat: load app and qt Translation files -- Deepin Packages Builder Thu, 27 Jul 2023 06:56:34 +0000 dtkgui (5.6.12) unstable; urgency=medium * chore: Sync by https://github.com/linuxdeepin/.github/commit/2e5e092ba3f86b16d1aabbabcf0bfd2ae65b19c8(Influence: none) * fix: fix build failure due to metasystem change * fix(build): suport build with Qt6 && Qt5 * chore: Adapt Qt6 && Dtk6 compilation * fix: ut failed * chore: update dconfig appid -- Deepin Packages Builder Sun, 25 Jun 2023 14:43:42 +0800 dtkgui (5.6.11) unstable; urgency=medium * Release 5.6.11 * Fix developer-center#4117 * Fix bug-197713(App blocked by hasUserManual in live system) -- Deepin Packages Builder Mon, 08 May 2023 13:16:17 +0800 dtkgui (5.6.10) unstable; urgency=medium * Release 5.6.10 * support XDG_SESSION_DESKTOP set to DDE * add DontSaveApplciationTheme Attribute -- Deepin Packages Builder Mon, 17 Apr 2023 17:11:55 +0800 dtkgui (5.6.9) unstable; urgency=medium * Release 5.6.9 -- Deepin Packages Builder Mon, 03 Apr 2023 10:13:06 +0800 dtkgui (5.6.8) unstable; urgency=medium * Release 5.6.8 -- Deepin Packages Builder Wed, 22 Feb 2023 14:12:16 +0800 dtkgui (5.6.6) unstable; urgency=medium * Release 5.6.6 -- Deepin Packages Builder Tue, 21 Feb 2023 11:46:51 +0800 dtkgui (5.6.5) unstable; urgency=medium * Release 5.6.5 -- Deepin Packages Builder Thu, 02 Feb 2023 14:12:15 +0800 dtkgui (5.6.4) unstable; urgency=medium * Release 5.6.4 -- Deepin Packages Builder Mon, 09 Jan 2023 13:28:09 +0800 dtkgui (5.6.3) unstable; urgency=medium * Release 5.6.3 -- Deepin Packages Builder Mon, 12 Dec 2022 14:44:49 +0800 dtkgui (5.6.2.2) unstable; urgency=medium * Release 5.6.2.2 -- Deepin Packages Builder Wed, 30 Nov 2022 10:32:07 +0800 dtkgui (5.6.1.1) unstable; urgency=medium * snipe release 5.6.1.1 -- Deepin Packages Builder Wed, 22 Jun 2022 14:33:59 +0800 dtkgui (5.6.0.1) unstable; urgency=medium * Release 5.6.0.1 -- Deepin Packages Builder Tue, 14 Jun 2022 10:51:30 +0800 dtkgui (5.0.0) unstable; urgency=medium * Release 5.0.0 -- Deepin Packages Builder Tue, 03 Sep 2019 08:59:03 +0800 dtkgui (1.0.0-1) unstable; urgency=medium * Initial release -- Deepin Packages Builder Mon, 29 Jul 2019 16:58:07 +0800 dtkgui-5.7.12/debian/control000066400000000000000000000032361476226661100157410ustar00rootroot00000000000000Source: dtkgui Section: libdevel Priority: optional Maintainer: Deepin Packages Builder Build-Depends: debhelper-compat (= 12), pkg-config, qtbase5-private-dev, qtbase5-dev-tools, doxygen, graphviz, qttools5-dev, libdtkcore-dev, librsvg2-dev, libfreeimage-dev, libraw-dev, libgtest-dev, libgmock-dev, libqt5xdg-dev, libqt5xdgiconloader-dev, cmake, qt5-image-formats-plugins, libqt5waylandclient5-dev, extra-cmake-modules, qtwayland5-dev-tools, qtwayland5-private-dev, libkf5wayland-dev, treeland-protocols Standards-Version: 3.9.8 Package: libdtkgui5 Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkdata, qt5-image-formats-plugins Multi-Arch: same Description: Deepin Tool Kit Gui library DtkGui is base library of Deepin Qt/C++ applications. . This package contains the shared libraries. Package: libdtkgui5-bin Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkgui5( =${binary:Version}) Description: Deepin Tool Kit Gui Utilities DtkGui is base devel library of Deepin Qt/C++ applications. . This package contains the utilities of DtkGui Package: libdtkgui-dev Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkgui5( =${binary:Version}), libdtkcommon-dev(>=5.6.16) Description: Deepin Tool Kit Gui Devel library DtkGui is base devel library of Deepin Qt/C++ applications. . This package contains the header files and static libraries of DtkGui Package: libdtkgui-doc Build-Profiles: Architecture: any Depends: ${misc:Depends} Description: Deepin Tool Kit Gui (Document) DtkGui is base devel library of Deepin Qt/C++ applications. . This package contains the qt Document of DtkGui dtkgui-5.7.12/debian/copyright000066400000000000000000000017721476226661100162740ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: dtkgui Source: https://github.com/linuxdeepin/dtkgui Files: * Copyright: 2022 Uniontech Software Technology Co., Ltd. License: LGPL-3+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. . This package 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 Lesser General Public License for more details. . You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU Lesser General Public License version 3 can be found in "/usr/share/common-licenses/LGPL-3". dtkgui-5.7.12/debian/libdtkgui-dev.install000066400000000000000000000001411476226661100204500ustar00rootroot00000000000000usr/lib/*/lib*.so usr/include usr/lib/*/pkgconfig/*.pc usr/lib/*/cmake/*/*.cmake usr/lib/*/qt5/* dtkgui-5.7.12/debian/libdtkgui-doc.install000066400000000000000000000000351476226661100204410ustar00rootroot00000000000000usr/share/qt5/doc/dtkgui.qch dtkgui-5.7.12/debian/libdtkgui5-bin.install000066400000000000000000000000231476226661100205260ustar00rootroot00000000000000usr/*/*/DGui/bin/* dtkgui-5.7.12/debian/libdtkgui5.install000066400000000000000000000000471476226661100177660ustar00rootroot00000000000000usr/lib/*/lib*.so.* #usr/share/dsg/*/* dtkgui-5.7.12/debian/rules000077500000000000000000000014151476226661100154130ustar00rootroot00000000000000#!/usr/bin/make -f DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/default.mk export QT_SELECT = qt5 DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) VERSION = $(DEB_VERSION_UPSTREAM) _PACK_VER = $(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$1}') _BUILD_VER = $(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$2}' | sed 's/[^0-9]//g' | awk '{print int($$1)}') ifeq ($(_BUILD_VER),) CONFIG_VERSION = $(_PACK_VER) else CONFIG_VERSION = $(_PACK_VER).$(_BUILD_VER) endif %: dh $@ override_dh_auto_configure: dh_auto_configure -- -DBUILD_TESTING=OFF -DBUILD_DOCS=ON -DDTK_VERSION=$(_PACK_VER) #override_dh_auto_test: # echo "skip auto test" override_dh_makeshlibs: dh_makeshlibs -V "libdtkgui5 (>= $(shell echo $(VERSION) | cut -d '.' -f 1,2))" dtkgui-5.7.12/debian/source/000077500000000000000000000000001476226661100156325ustar00rootroot00000000000000dtkgui-5.7.12/debian/source/format000066400000000000000000000000151476226661100170410ustar00rootroot000000000000003.0 (native) dtkgui-5.7.12/docs/000077500000000000000000000000001476226661100140405ustar00rootroot00000000000000dtkgui-5.7.12/docs/CMakeLists.txt000066400000000000000000000100051476226661100165740ustar00rootroot00000000000000cmake_minimum_required (VERSION 3.10) find_package (Doxygen REQUIRED) set (QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/qt${QT_VERSION_MAJOR}/doc CACHE STRING "QCH install location") set (DOXYGEN_GENERATE_HTML "YES" CACHE STRING "Doxygen HTML output") set (DOXYGEN_GENERATE_XML "YES" CACHE STRING "Doxygen XML output") set (DOXYGEN_GENERATE_QHP "YES" CACHE STRING "Doxygen QHP output") set (DOXYGEN_FILE_PATTERNS *.cpp *.h *.zh_CN.md *.zh_CN.dox CACHE STRING "Doxygen File Patterns") set (DOXYGEN_PROJECT_NUMBER ${CMAKE_PROJECT_VERSION} CACHE STRING "") # Should be the same as this project is using. set (DOXYGEN_EXTRACT_STATIC YES) set (DOXYGEN_OUTPUT_LANGUAGE "Chinese" CACHE STRING "Doxygen Output Language") set (DOXYGEN_IMAGE_PATH ${CMAKE_CURRENT_LIST_DIR}/images/) set (DOXYGEN_QHP_NAMESPACE "org.deepin.dtk.gui") set (DOXYGEN_QCH_FILE "dtkgui.qch") set (DOXYGEN_QHP_VIRTUAL_FOLDER "dtkgui") set (DOXYGEN_HTML_EXTRA_STYLESHEET "" CACHE STRING "Doxygen custom stylesheet for HTML output") set (DOXYGEN_TAGFILES "qtcore.tags=qthelp://org.qt-project.qtcore/qtcore/" CACHE STRING "Doxygen tag files") # find from cmake target property if("${QT_VERSION_MAJOR}" STREQUAL "5") find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Help) else() find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS ToolsTools) endif() get_target_property(_qhelpgenerator_location Qt${QT_VERSION_MAJOR}::qhelpgenerator IMPORTED_LOCATION) if("${_qhelpgenerator_location}" STREQUAL "") set(_qhelpgenerator_location "qhelpgenerator") endif() set (DOXYGEN_QHG_LOCATION ${_qhelpgenerator_location} CACHE STRING "Doxygen QHG path") set (DOXYGEN_PREDEFINED "D_DECL_DEPRECATED_X(x)=" "DCORE_BEGIN_NAMESPACE=namespace Dtk { namespace Core {" "DCORE_END_NAMESPACE=}}" "DCORE_USE_NAMESPACE=using namespace Dtk::Core\;" "DGUI_BEGIN_NAMESPACE=namespace Dtk { namespace Gui {" "DGUI_END_NAMESPACE=}}" "DGUI_USE_NAMESPACE=using namespace Dtk::Gui\;" ) set (BUILD_THEME OFF CACHE BOOL "Build doxgen theme") if(BUILD_THEME) if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/doxygen-theme") message(STATUS "doxygen-theme exists") else() execute_process(COMMAND git clone https://github.com/linuxdeepin/doxygen-theme.git --depth=1 WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} TIMEOUT 60 ) execute_process(COMMAND bash themesetting.sh WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/doxygen-theme/ ) endif() set (DOXYGEN_HTML_EXTRA_STYLESHEET "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome.css" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-sidebar-only.css" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css" ) set (DOXYGEN_HTML_EXTRA_FILES "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-paragraph-link.js" "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-interactive-toc.js" ) set (DOXYGEN_GENERATE_TREEVIEW "YES") set (DOXYGEN_DISABLE_INDEX "NO") set (DOXYGEN_FULL_SIDEBAR "NO") set (DOXYGEN_HTML_HEADER "docs/doxygen-theme/doxygen-awesome-css/header.html") set (DOXYGEN_HTML_FOOTER "docs/doxygen-theme/doxygen-awesome-css/footer.html") endif() set (DOXYGEN_MACRO_EXPANSION "YES") set (DOXYGEN_EXPAND_ONLY_PREDEF "YES") # Exclude private classes. set (DOXYGEN_EXCLUDE_PATTERNS ${PROJECT_SOURCE_DIR}/src/util/private/dimagehandlerlibs_p.h ${PROJECT_SOURCE_DIR}/src/util/dimagehandlerlibs.cpp ) doxygen_add_docs (doxygen ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/docs ALL WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT "Generate documentation via Doxygen" ) install (FILES ${CMAKE_CURRENT_BINARY_DIR}/html/dtkgui.qch DESTINATION ${QCH_INSTALL_DESTINATION}) dtkgui-5.7.12/docs/images/000077500000000000000000000000001476226661100153055ustar00rootroot00000000000000dtkgui-5.7.12/docs/images/ddciicon-example1.jpg000066400000000000000000000251701476226661100213020ustar00rootroot00000000000000PNG  IHDRͿ? pHYs+ IDATxw|뺓t]Vndc[cMo!|7@7tBI 0&`cd[lY8[䫒)~瞙yfyЂ_UQ@!LB ǜQ! 9cFEj_Zet[w3*:&6k[yM*RHe< BPм_UPy"X&7'yQb&kP KuE5 ??F,@  @ $@cMɪ'KHg"kpRoV\U~  !y( YL3 LQNW6@PFj)9Y#S.@_MX*A}/폾hufNu -'>y7Fdaٌa4uC_)(*[>wI)!dk~LKppAXH?߽58hz& нA+tJ \X6SDdAXH ˊ' FYX@7"x< , K#< , K#< , K#< , K# F3uK#BXAGB X, X,jPu:b8c_\BE1 #}||hbt1!DwvvRi<1RP(#:pB:;;ZL&_=uAӴP<󼯯-oljVzVU(RՍ4P(Z^<#|gg\.C&iZ\.GwVzJǢ}56-i@%J>MNL4)Dλ4M8\_.7p !w& ar!!BNa/F{H$̣|vGϺV*D Su"ʮH8Fe~ϿM,z;_W'lj[EQ'G'O]t[DxAve-q4*D|H='HC5z桽[4rٻẉGk яS[ !fq!juidq2?~Z|C ncg;!f1 i0Oj!,;?x¦X!ӹ %e-!=5Rcoռxe"ꁞ8Fڻܴ7_o nmku,ㆰKzw8?f1Pj:rb"4fvߕ_n;T_ ,{~&;+b.C[] r pq^f\ n8tiZnں/\p9`ڹromW,ضٝ_g 6iezf?O{Թx 7Lzc~g-f|WWxH g?]d,3r_=;ZɶyCeW htԻg/_T|kycG*q1<)pnP;.'FÃ)rTx;|yecs+W*(pk|}cޝ?Tm~Q9{OyO<}C .6]߬Qtn8fO^:zv rq;i)}wrW?UYSreӷ_p5LB2g@&|<;* wgo۝z\/yGe`B.%mُs^nh"hG'?6J'G .ZWP[â e`oG駛^Zm'2%&\D1`tK:\{eƂFi\ p̅K\wxݰX* wf\m׏a2ae+%uX%g%ʮ+i5i(- U4L7}x$I>qPLn%k: WKщ#W(=*(V`: (D)/4JW?CEcl9!z̡#e]i,fBzO!mB!tms3v$S`VCOz8r! HHUUWP沲ZQ\Z[tTH_}$Dg7=Z$OHP+\ٚsznqc,6!̼Ta=Up׏n+ A쬄?tpk2P~o_%96Q+DG=Rw| }`ZnS6õVÞߟOꑙ^~}#+4!cx}+X&!6]&$P o)&k2G,^,.ؼoOD63QAaG]u{V[2ɗyByՊ?|G/x]1dwI+ªxۯ]j#_2asNDb4^td2}/_V(?'9` k8]j%Nկq^ܒ Pp4$bpCURb EzT$3Z}%_&m]kSNyq*~y;Nuݗ{~fVK;ᗳ:bo4`ay;Xuuu!AAZMԇU?+[3;6B&0q$f,ȡ}5# 61#h.Cmfi.6M\ G2 "V@yeـ|@ G},TP((L&B!zզp(J.ja߭8vI]kVyKۯ|sX<⁕w?4^z|Wl$M}[z̯_0]]wL4>˖}n4bY,soHK~owr(??O&zz}?? =k&-oIߌyvYeA+0)2ZC@\ɌYfOk݉;^_tőF lL*U^ԛ~|xŏ]ǤcF $k ͵#r^x~o猝7c \sa *Z$^o3 WT }1Y 7#&&cJ8"8Ѱ0k03#Wkl4=Q0ޱs !%:go9?'&g4nz62g1Jv-U9޾/KH[0Ўj=s|#?͓\pF9W{WL{ڽ|CBfYUIu/ud{Ӱ0qQt/Su%+|! :/]ͣKX毆c9yWe˕k>kdtt9 oRINUPXտP) UuW ™o X͜w|"a/'[ 4lε!K;7yXRDlɉz ;nXWa+dg9?'`iթj 9q/a^ 趽]>ڂݻ 9XV5DXS\*JRӒz%Oщ |ShN{I9\n1FM_0sW{y`NJYvTQQSo|;YqLS/k9}c]pS޿CdIV/\D4 ON?t.:)|ȥ3N !iS}wǥ⦒EOY&W^%Z,)P`;4CQZ R9ZYQdlKP]Q#҇Y.9z 6yhSImJxa}fiʰ00{pN+S# w\+l%Y-uwf.G=~_ 4 B|܎|zyȨ(ʅ;v]hcbs#*.#;#;ϴJ&.o<pBꗉdYԤ'fg(ypk5ҧ,~*oy켹QM5 rL`tYs~)${\1i#{6!5ZGvGXǰk1Ka$?6;rJ B[f+4Sa`uUшxmq7"I$z\FO<#;&u=Co [G;TΧ['m-, An٭_afKrܢ7k $4nI[Jax]]JLDC{&YQF}'vt:EQc mƉ=Q$#K8h !cg z6%xT*tADx_.C:mJ 8h۝'BXD4Q0X-r>ȥ4Md2? đ83L[~JR)355R-[U8boMfM%B8iք<(NրUXr 4M jc!绲ckodť2ME4kЕ<#/QhU^X`p"K#< ,P5_nlh fs/cD KB 1!Ji?,08O19[R[ZQO5oS9BnWBN A '˜䝪mhH'[)"4 wL-oljVΕ6Ie h?2EmC۹Һ[<#aitz{iieF\4n+<ؗV>054 MzWnʝ M;s7 ]oL R6JqP9ݣsj`h7K ΀׾V7f MC)*H+p01i^60M[Wm_KEE;Vac;gV/z~ZB=;ˆFH2g1wD1N?ɶmgy IDATqtFҟرL6nҔqzg-}zc/>tGKgoK| ˇ#}<_Q$g[lBʹ=rb#^L A>Tx0TG**ozqlFR$D_K_.\QΞ=ʧvw{JԣrO^mp>-eSH+ΦNM_?h~J[|bz•KG1uFH-o| /w;9~ pxD-h) . G]9^r/5!'!xtNHsrΚizy]2kmp''$G88X֑S.'e0'u.\x/ ͹c39Diß̕"e4'9sgioʔ_9c%ќm+d(w>߿p8_02ծ\۽rDS82=QL I~"Tlԍ,Bbu|jb 1-9/?"SFνtxݸőNM!q[n0pu/v-Uf}iH&XH ֔^TPVZ`7$o#Sv.g;Zژɪkn1>ѧ7konRl>:VX:Ϭzyc!7Ņ|6$7oV kAgy`tU_N@_,x, >kf ,^H2oXjraq&x]$;uĶ?ٰ{ꪗv;HD+^F)$:ZFw.+`W%'NС5zo..h 9?L)X WqꏑXM6,c/X *Qd 4#nKĈ(*>K^ւCrp\XjjG|k0Rs4!+h1̎?Nrpk2H0^n0Qɽߔ/}mT =.l||LM2Z2VԶOOˍ߿eL5gmns_fAde((;TBɃ៎8B)$r/FFJKIЉDQٙ˗z/7͜ lJ+2ՠ`25PZ VOVm7+*xߞ?е̸8_NzعjBlߨ Y_eaC>,y*v x;` KtctkK~2l|GL,F mv4!vWXXЩ²zsc‹OV8U`F)ʹj-J&̘RRTUӖvK%N?cOaN#` Wk;[R[PV Pd b9^owt -Zwie"8_44£3|;6 cLF؞ okN(E W[fOb6F} QF;gPk6vGpG6 !AiqANS_c9BX{y{'dҬи@e9sqb Z,EfdBw/f1`Z%es FFd~ <=iдjF|Ϳ"`hZ&*"C}Urīt|%—B%/>@Q AB3{7N_a["G*dR V|^NTzT(P!@!|ҖaihO?ءB@(DрD!b>Ⱥ|@Sd|kO)BAtj]J2 K&Uo|iJE(ԈWwhJz,tkl|KLKhe2@(@` (9U@ [̜nEw'd(a 5惻KO 2"BSo)۳7`B0k*DA᱙&3-wD֘(P2 rg*p,Ġ:;,-4-bF&xMID|@O!Abb@&hIENDB`dtkgui-5.7.12/docs/kernel/000077500000000000000000000000001476226661100153205ustar00rootroot00000000000000dtkgui-5.7.12/docs/kernel/dpalette.zh_CN.dox000066400000000000000000000110201476226661100206300ustar00rootroot00000000000000/*! @~chinese @file dpalette.h @ingroup palette @brief DPalette提供了调色板相关操作 @sa [qpalette](https://doc.qt.io/qt-6/qpalette.html) @class Dtk::Gui::DPalette @brief DPalette继承并且扩展了 QPalette 类, 提供了dtk特有的特性. @enum Dtk::Gui::DPalette::ColorType DPalette::ColorType 定义了 DPalette 颜色类型 @details | **键** | **值** | **含义** | |:-----------------:|:-----:|:-------------------------------------------------:| | NoType | 0 | 无类型 | | ItemBackground | 1 | 列表项的背景色 | | TextTitle | 2 | 标题型文本的颜色 | | TextTips | 3 | 提示性文本的颜色 | | TextWarning | 4 | 警告类型的文本颜色 | | TextLively | 5 | 活跃式文本颜色(不受活动色影响) | | LightLively | 6 | 活跃式按钮(recommend button)背景色中的亮色(不受活跃色影响) | | DarkLively | 7 | 活跃式按钮(recommend button)背景色中的暗色,会从亮色渐变到暗色(不受活跃色影响) | | FrameBorder | 8 | 控件边框颜色 | | PlaceholderText | 9 | 占位类型的文本颜色,可用于输入框占位内容等提示性文字 | | FrameShadowBorder | 10 | 用于跟阴影叠加的边框颜色 | | ObviousBackground | 11 | 明显的背景色 | | NColorTypes | 12 | 无颜色类型 | @fn Dtk::Gui::DPalette::DPalette() @brief 构造一个 DPalette 对象 @fn Dtk::Gui::DPalette::DPalette(const DPalette &palette) @brief 构造一个 DPalette 对象 @param[in] palette 要复制的 DPalette 对象 @fn Dtk::Gui::DPalette::DPalette(const QPalette &palette) @brief 构造一个 DPalette 对象 @param[in] palette 要复制的 QPalette 对象 @fn const QColor Dtk::Gui::DPalette::clore(ColorGroup cg, ColorType ct) const @brief 获取指定颜色组和颜色类型的颜色 @param[in] cg 颜色组 @param[in] ct 颜色类型 @fn void Dtk::Gui::DPalette::brush(ColorGroup cg, ColorType ct, const QColor &color) @brief 设置指定颜色组和颜色类型的笔刷 @param[in] cg 颜色组 @param[in] ct 颜色类型 @param[in] color 颜色 @fn void Dtk::Gui::DPalette::setColor(ColorGroup cg, ColorType ct, const QColor &color) @brief 设置指定颜色组和颜色类型的颜色 @param[in] cg 颜色组 @param[in] ct 颜色类型 @param[in] color 颜色 @fn void Dtk::Gui::DPalette::setColor(ColorType ct, const QColor &color) @brief 设置指定颜色类型的颜色 @param[in] ct 颜色类型 @param[in] color 颜色 @fn void Dtk::Gui::DPalette::setBrush(ColorType ct, const QBrush &brush) @brief 设置指定颜色类型的笔刷 @param[in] ct 颜色类型 @param[in] brush 笔刷 @fn void Dtk::Gui::DPalette::setBrush(ColorGroup cg, ColorType ct, const QBrush &brush) @brief 设置指定颜色组和颜色类型的笔刷 @param[in] cg 颜色组 @param[in] ct 颜色类型 @param[in] brush 笔刷 @fn const QBrush & Dtk::Gui::DPalette::itemBackground() const @brief 获取列表项的背景色 @fn const QBrush & Dtk::Gui::DPalette::textTitle() const @brief 获取标题型文本的颜色 @fn const QBrush & Dtk::Gui::DPalette::textTips() const @brief 获取提示性文本的颜色 @fn const QBrush & Dtk::Gui::DPalette::textWarning() const @brief 获取警告类型的文本颜色 @fn const QBrush & Dtk::Gui::DPalette::textLively() const @brief 获取活跃式文本颜色(不受活动色影响) @fn const QBrush & Dtk::Gui::DPalette::lightLively() const @brief 获取活跃式按钮(recommend button)背景色中的亮色,会从暗色渐变到亮色(不受活跃色影响) @fn const QBrush & Dtk::Gui::DPalette::darkLively() const @brief 获取活跃式按钮(recommend button)背景色中的暗色,会从暗色渐变到亮色(不受活跃色影响) @fn const QBrush & Dtk::Gui::DPalette::frameBorder() const @brief 获取边框颜色 @fn const QBrush & Dtk::Gui::DPalette::placeholderText() const @brief 获取占位符文本颜色 @fn const QBrush & Dtk::Gui::DPalette::frameShadowBorder() const @brief 获取阴影边框颜色 */ dtkgui-5.7.12/docs/kernel/index.zh_CN.md000066400000000000000000000002101476226661100177420ustar00rootroot00000000000000@page kernel kernel--dtkgui核心组件 # Dtk-Gui kernel TODO:添加组件说明 @defgroup palette @brief 调色板工具 @detailsdtkgui-5.7.12/docs/src/000077500000000000000000000000001476226661100146275ustar00rootroot00000000000000dtkgui-5.7.12/docs/src/dguiapplicationhelper.zh_CN.dox000066400000000000000000000047611476226661100227270ustar00rootroot00000000000000/*! @~chinese @file dguiapplicationhelper.h @class Dtk::Gui::DGuiApplicationHelper @ingroup dtkgui @brief DGuiApplicationHelper类提供了一个gui应用程序的应用帮助类,可提供widget和declarative的 公共gui功能,例如调色板、字体、主题等功能。 @details @enum Dtk::Gui::DGuiApplicationHelper::SizeMode @brief 控件大小模式枚举包含 dtk支持的控件大小模式种类. | **值** | **含义** | |:-----------:|:---------------------:| | NormalMode | 普通模式,为默认模式 | | CompactMode | 紧凑模式 | @fn void DGuiApplicationHelper::newProcessInstance(qint64 pid, const QStringList &arguments) @brief 通知新进程的信息。 @details 单例程序情况下,尝试启动新的程序实例将触发此信号,以便获取所传入的参数列表等信息,来进行进一步处理。 @param pid 进程 ID. @param arguments 启动进程时所传入的参数列表. @fn DGuiApplicationHelper::SizeMode DGuiApplicationHelper::sizeMode() const @brief 当前应用的控件大小模式。 @details - 若应用没有设置控件大小模式,则跟随系统的控件大小模式 - 用户也可以设置环境变量 D_DTK_SIZEMODE 来影响应用的大小模式的支持,`D_DTK_SIZEMODE=1`为指定为普通模式, 当应用没有显示设置控件大小模式,则会采用普通模式。 - 优先级为 `DGuiApplicationHelper::setSizeMode` > `D_DTK_SIZEMODE` > `System's SizeMode`。 @fn void DGuiApplicationHelper::setSizeMode(const DGuiApplicationHelper::SizeMode sizeMode) @brief 设置应用控件大小模式,应用使用的为此模式,不再响应系统的控件大小模式。 @param sizeMode 需要设置的控件大小模式. @fn void DGuiApplicationHelper::resetSizeMode() @brief 重置设置应用控件大小模式,跟随系统的控件大小模式。 @fn static inline bool DGuiApplicationHelper::isCompactMode() @brief 当前控件大小模式是否为紧凑模式。 @fn void DGuiApplicationHelper::applicationPaletteChanged() @brief 通知调色板对象的改变。 @sa windowPalette() @fn void DGuiApplicationHelper::sizeModeChanged(DGuiApplicationHelper::SizeMode sizeMode) @brief 通知控件大小模式发生改变。 @fn static QStringList DGuiApplicationHelper::userManualPaths(const QString &appName) @brief 获取帮助手册已存在目录 @param appName 目标应用名称 @detail 目录深度具体到appName层级,例:一个典型的目录路径为:/usr/share/deepin-manual/manual-assets/application/appName */ dtkgui-5.7.12/docs/src/dimagehandler.zh_CN.dox000066400000000000000000000263621476226661100211400ustar00rootroot00000000000000/*! @~chinese @file dimagehandler.h dimagehandler.h 提供图像处理类 DImageHandler @class Dtk::Gui::DImageHandler @brief DImageHandler 提供图像处理,读取、保存、旋转、滤镜等。 @details ## 概述 提供多种格式图片的读取、保存,允许对部分格式进行旋转。提供多种滤镜、锐化、二值化等图像处理算法。 通过 `DImageHandler::setFileName` 设置当前处理的图片文件路径,通过 `DImageHandler::readImage` 取得图片数据,通过 `DImageHandler::thumbnail` 取得图片缩略图。设置文件路径将不会立即加载图片, 将在需要图片数据时读取,当不需要缓存数据时,可通过 `DImageHandler::clearCache` 清除缓存数据。 @note 拓展的图片格式依赖 FreeImage 和 LibRaw 公共库,DImageHandler 通过动态加载的方式解析公共库接口。 可通过 DImageHandler::supportFormats() 获取当前支持的图片格式类型。 ## 编译 支持拓展的图片格式,编译时会判断环境是否存在依赖包,安装 libfreeimage-dev 及 libraw-dev , 设置编译选项 DTK_DISABLE_EX_IMAGE_FORMAT=OFF 后将开启拓展图片格式支持。 不同包构建环境默认策略不同,在 **debian** 和 **linglong** 构建环境默认依赖 libfreeimage-dev 及 libraw-dev , 支持拓展图片格式,其它环境需手动安装。 ## image-handler 工具示例 可在程序根目录 ./tools/image-handler 中查看 image-handler 工具项目。 image-handler 工具可用于提取图像信息、旋转图像、设置图像滤镜等。 ```shell image-handler [options] [file...] ``` ### image-handler 选项 | **选项** | **描述** | |---|---| | -h, --help | 显示工具帮助信息 | | -r, --rotate | 根据设置角度旋转图片,旋转角度需为 **90度** 的倍数 | | -o, --output | 保存处理后的文件到指定路径 | | -f | 为图片设置滤镜,可选图片滤镜包括 old, warm, cool, gray, anticolor, metal | | -l, --list | 列出所有图片的格式 | | -e | 列出所有图片的详细信息,结合 **-l** 使用 | @fn Dtk::Gui::DImageHandler::DImageHandler(QObject *parent) @brief 构造 DImageHandler 实例,并指定父控件 @param[in] parent 作为实例的父控件 @fn Dtk::Gui::DImageHandler::~DImageHandler() @brief 销毁 DImageHandler 实例 @fn void Dtk::Gui::DImageHandler::setFileName(const QString &fileName) @brief 设置当前处理的图片文件路径 @param[in] fileName 图片文件路径 @fn QString Dtk::Gui::DImageHandler::fileName() const @brief 返回当前处理的图片文件路径 @return 图片文件路径 @fn QImage Dtk::Gui::DImageHandler::readImage() @brief 从设置的图片文件路径中读取图片 @details 从 fileName() 设置的图片文件中读取图片,若读取失败,将返回空图片实例, 错误信息通过 lastError() 获取 @return 图片实例 @fn QImage Dtk::Gui::DImageHandler::thumbnail(const QSize &size, Qt::AspectRatioMode mode) @brief 获取当前处理图片指定大小的缩略图,可调整宽高比适配模式 @param[in] 缩略图大小 @return 缩略图实例 @fn QString Dtk::Gui::DImageHandler::imageFormat() const @brief 返回当前设置图片文件的格式,若未设置文件路径,返回空字符串 @return 图片格式 @fn QSize Dtk::Gui::DImageHandler::imageSize() @brief 返回当前处理的图片尺寸,若未设置图片文件或加载失败,返回空图片尺寸 (-1, -1) @return 图片大小 @fn QHash Dtk::Gui::DImageHandler::findAllMetaData() @brief 查询图片包含的所有元数据,在动态加载 FreeImage 库后有效 @return 图片信息表 @fn void Dtk::Gui::DImageHandler::clearCache() @brief 清空缓存数据,释放缓存的图片和错误信息 @fn bool Dtk::Gui::DImageHandler::saveImage(const QString &fileName, const QString &format = QString()) @brief 保存当前处理的图片至文件,可指定保存的图片格式, 若存在错误,将返回 false ,错误信息通过 lastError() 获取 @param[in] fileName 保存的文件路径 @param[in] format 指定保存图片格式,默认为空,表示保持原格式 @return 是否成功保存图片 @fn bool Dtk::Gui::DImageHandler::saveImage(const QImage &image, const QString &fileName, const QString &format) @brief 保存图片至文件,可指定保存的图片格式, 若存在错误,将返回 false ,错误信息通过 lastError() 获取 @param[in] image 图片实例 @param[in] fileName 保存的文件路径 @param[in] format 指定保存图片格式,默认为空,表示保持原格式 @return 是否成功保存图片 @fn bool Dtk::Gui::DImageHandler::rotateImage(QImage &image, int angle) @brief 顺时针旋转图片,若存在错误,将返回 false ,错误信息通过 lastError() 获取 @param[in,out] image 图片实例 @param[in] angle 图片旋转角度,必须以90度为倍数 @return 是否成功旋转图片 @fn bool Dtk::Gui::DImageHandler::rotateImageFile(const QString &fileName, int angle) @brief 顺时针旋转图片文件中的图片 @details 读取 fileName 图片文件,顺时针旋转图片 angle 度,并将图片数据写回文件, 若存在错误,将返回 false ,错误信息通过 lastError() 获取 @param[in] fileName 图片文件路径 @param[in] angle 图片旋转角度,必须以90度为倍数 @return 是否成功旋转并保存图片文件 @fn bool Dtk::Gui::DImageHandler::isReadable() const @brief 返回当前设置的图片文件是否可读取,判断基于图片格式,fileName() 为空时返回 false @return 是否可读取 @fn bool Dtk::Gui::DImageHandler::isWriteable() const @brief 返回当前设置的图片文件是否可写入,判断基于图片格式,fileName() 为空时返回 false @return 是否可写入 @fn bool Dtk::Gui::DImageHandler::isRotatable() const @brief 返回当前设置的图片文件是否可旋转,判断基于图片格式,fileName() 为空时返回 false @return 是否可旋转 @fn static QStringList Dtk::Gui::DImageHandler::supportFormats() @brief 返回当前环境下 DImageHandler 可支持的图片格式,可动态加载 FreeImage 库以支持更多图片格式 @return 支持的图片格式 @fn static QString Dtk::Gui::DImageHandler::detectImageFormat(const QString &fileName) @brief 根据文件名称及文件内容检测图片格式 @param[in] fileName 图片文件路径 @return 图片格式 @fn QString Dtk::Gui::DImageHandler::lastError() const; @brief 返回最近一次错误的详细信息 @return 错误信息 @fn static QImage Dtk::Gui::DImageHandler::oldColorFilter(const QImage &img) @brief 为图片设置老照片滤镜并返回处理图片实例 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::warmColorFilter(const QImage &img, int intensity = 30) @brief 为图片设置暖色滤镜并返回处理图片实例 @param[in] img 待处理的图片实例 @param[in] intensity 滤镜处理强度,取值范围 -255 ~ 255 ,默认30 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::coolColorFilter(const QImage &img, int intensity = 30) @brief 为图片设置冷色滤镜并返回处理图片实例 @param[in] img 待处理的图片实例 @param[in] intensity 滤镜处理强度,取值范围 -255 ~ 255 ,默认30 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::grayScaleColorFilter(const QImage &img) @brief 为图片设置灰色滤镜并返回处理图片实例 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::antiColorFilter(const QImage &img) @brief 为图片设置反色滤镜并返回处理图片实例 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::metalColorFilter(const QImage &img) @brief 为图片设置金属风格滤镜并返回处理图片实例 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::bilateralFilter(const QImage &img, double spatialDecay, double photometricStandardDeviation) @brief 对图片进行双边滤波处理,可保持边界并去除噪点,可用于磨皮等处理 @param[in] img 待处理的图片实例 @param[in] spatialDecay 空间衰减值,用于双边滤波的空域信息,默认 0.02 @param[in] photometricStandardDeviation 光度标准差值,用于双边滤波的值域信息, 默认 10 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::contourExtraction(const QImage &img) @brief 提取图片轮廓 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::binaryzation(const QImage &img) @brief 对图片进行二值化处理 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::grayScale(const QImage &img) @brief 取得灰阶图片 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::laplaceSharpen(const QImage &img) @brief 拉普拉斯锐化处理 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::sobelEdgeDetector(const QImage &img) @brief sobel边缘检测处理,用于图片锐化 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::changeLightAndContrast(const QImage &img, int light = 100, int contrast = 150) @brief 变更图片的亮度和对比度并返回处理图片实例 @param[in] img 待处理的图片实例 @param[in] light 调整图片亮度,取值范围 0 ~ 300 @param[in] constrase 调整图片对比度,取值范围 0 ~ 300 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::changeBrightness(const QImage &img, int brightness) @brief 调整图片亮度并返回处理图片实例,取值范围 -255 ~ 255 @param[in] img 待处理的图片实例 @param[in] brightness 图片亮度 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::changeTransparency(const QImage &img, int transparency) @brief 调整图片透明度并返回处理图片实例,取值范围 0 ~ 255 @param[in] img 待处理的图片实例 @param[in] transparency 图片透明度 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::changeStauration(const QImage &img, int saturation) @brief 调整图片饱和度并返回处理图片实例,取值范围 -100 ~ 100 @param[in] img 待处理的图片实例 @param[in] saturation 图片饱和度 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::replacePointColor(const QImage &img, QColor oldColor, QColor newColor) @brief 遍历图片所有像素点,替换图片像素点颜色 @param[in] img 待处理的图片实例 @param[in] oldColor 旧像素颜色 @param[in] newColor 新像素颜色 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::flipHorizontal(const QImage &img) @brief 水平翻转图片 @param[in] img 待处理的图片实例 @return 处理完成的图片实例 @fn static QImage Dtk::Gui::DImageHandler::flipVertical(const QImage &img) @brief 垂直翻转图片 @param[in] img 待处理的图片 @return 处理完成的图片实例 */dtkgui-5.7.12/docs/src/dplatformtheme.zh_CN.dox000066400000000000000000000005661476226661100213650ustar00rootroot00000000000000/*! @~chinese @file dplatformtheme.h @class Dtk::Gui::DPlatformTheme @ingroup dtkgui @brief DPlatformTheme类提供了一个应用程序的主题配置管理类,可以在外部控制应用的默认主题行为, 达到个性化主题的设置,所有的设置是实时响应的。 @property DPlatformTheme::sizeMode @brief 从配置中获取当前控件大小模式 */ dtkgui-5.7.12/docs/util/000077500000000000000000000000001476226661100150155ustar00rootroot00000000000000dtkgui-5.7.12/docs/util/ddciicon.zh_CN.dox000066400000000000000000000367441476226661100203230ustar00rootroot00000000000000/*! @~chinese @file include/util/ddciicon.h @ingroup dci @brief DCI图标类 @class Dtk::Gui::DDciIconImage ddciicon.h @details 用于获取 dci 图标某种状态的图片资源(位图数据),同时支持静态图和动态图,接口的设计类似于 QImageReader,一般通过调用 DDciIcon::image 构造此对象。与 DDciIcon 配合使用,其所支持的图片格式与 DDciIcon::pixmap 接口一致,都取决于 Qt 图片插件系统(即 QImageReader)所提供的能力。 @sa DDciIcon::image @fn Dtk::Gui::DDciIconImage::DDciIconImage() @details 构造一个空的对象。 @fn Dtk::Gui::DDciIconImage::DDciIconImage(const DDciIconImage &other) @details 根据 other 对象构造一个新的 DDciIconImage 对象,这个新的对象将与 other 共享 DDciIconImagePrivate 对象。 @fn Dtk::Gui::DDciIconImage::operator=(const DDciIconImage &other) @details 对当前对象进行赋值,这将导致此对象与 other 共享 DDciIconImagePrivate 对象。 @fn Dtk::Gui::DDciIconImage::operator=(DDciIconImage &&other) @details 对当前对象进行赋值,这将导致此对象与 other 两者的 DDciIconImagePrivate 对象被交换。 @sa DDciIconImage::swap @fn Dtk::Gui::DDciIconImage::swap(DDciIconImage &other) @details 交换两个对象的数据,这将导致两者的 DDciIconImagePrivate 对象被交换。 @fn Dtk::Gui::DDciIconImage::operator ==(const DDciIconImage &other) const @details 如果两个对象引用了相同的 DDciIconImagePrivate 数据对象,则返回 true,否则返回 false。 @fn Dtk::Gui::DDciIconImage::operator !=(const DDciIconImage &other) const @details 如果两个对象引用了不同的 DDciIconImagePrivate 数据对象,则返回 true,否则返回 false。 @fn Dtk::Gui::DDciIconImage::isNull() const @details 如果此对象为空,则返回 true,否则返回 false。当对象为空时,调用其它成员函数将获得一个无效的结果。 @fn Dtk::Gui::DDciIconImage::reset() @details 重置数据的状态,将清理所有的内部缓存数据,并且重置所有的状态记录,与重新调用 DDciIcon::image 获取一个新的对象后的状态相同。对于动画图片而言,这会导致 DDciIconImage::atBegin 变成 true,即动画将从第一帧重新开始。 @fn Dtk::Gui::DDciIconImage::toImage(const DDciIconPalette &palette) const @details 对于静态图片,将读取图片数据,并加载为 QImage 对象返回。对于动态图片,将返回当前帧的位图数据,且多次调用时不会重新加载,将返回缓存的 QImage 对象,另外需要注意的时,与 QImageReader::read 的不同,在调用此函数读取当前帧后,并不会自动跳转到下一帧,即在未调用 DDciIconImage::jumpToNextImage 时,多次调用此函数将返回同一帧。 @param[in] palette 如果此图片支持指定调色板,则将根据传入的 DDciIconPalette 中指定的颜色对图片进行加工。详情请参见 DSG 标准中的 DCI 图片格式设计。 @sa DDciIconImage::hasPalette DDciIconImage::paint @fn Dtk::Gui::DDciIconImage::paint(QPainter *painter, const QRectF &rect, Qt::Alignment alignment, const DDciIconPalette &palette) const @details 将图片的位图数据通过传入的画笔进行绘制。 @param[in] painter 指定画笔对象。 @param[in] rect 指定绘制区域,此区域相对于画笔所对应的 QPainter::paintDevice(),如果此区域的宽度比图片的宽度小,则会在绘制时将图片缩小到此区域的大小,反之则保持图片自身大小,而不会知道图片被放大。 @param[in] alignment 指定绘制时图片相对于 rect 所指定区域的位置,即当图片宽度小于 rect 所指定的宽度时,将根据此参数决定图片的显示位置。 @param[in] palette 如果此图片支持指定调色板,则将根据传入的 DDciIconPalette 中指定的颜色对图片进行加工。详情请参见 DSG 标准中的 DCI 图片格式设计。 @sa DDciIconImage::toImage @fn Dtk::Gui::DDciIconImage::hasPalette() const @details 如果此图片支持指定调色板,则返回 true,否则返回 false。 @fn Dtk::Gui::DDciIconImage::supportsAnimation() const @details 如果此图片支持动画,则返回 true,否则返回 false。 @fn Dtk::Gui::DDciIconImage::atBegin() const @details 如果此图片支持动画且动画处于第一帧,则返回 true,否则返回 false。 @fn Dtk::Gui::DDciIconImage::atEnd() const @details 如果此图片支持动画且动画处于最后一帧,则返回 true,否则返回 false。 @fn Dtk::Gui::DDciIconImage::jumpToNextImage() @details 将动画跳转到下一帧,如果此图片支持动画且当前不是最后一帧,则返回 true,否则返回 false。 @fn Dtk::Gui::DDciIconImage::loopCount() const @details 返回动画的轮播次数,如果此图片不支持动画,则返回值无效。如果返回值为 -1,则表明此动画需要无限循环播放。 @fn Dtk::Gui::DDciIconImage::maxImageCount() const @details 返回动画的最大帧数,如果当前图片有多层且每一层都支持动画,则是所有动画帧数的累加,因此多个动画的播放时间会可能会有重叠的帧,所以无法确保播放此图片时一定能显示这么多帧,动画是否结束需要以 DDciIconImage::atEnd 的返回结果为准。如果此图片不支持动画,则返回值无效。 @fn Dtk::Gui::DDciIconImage::currentImageDuration() const @details 返回当前动画帧的持续时间,单位为毫秒。如果此图片不支持动画,则返回值无效。 @fn Dtk::Gui::DDciIconImage::currentImageNumber() const @details 返回动画已经播放到的帧的序号,此值一定小于 DDciIconImage::maxImageCount - 1。如果此图片不支持动画,则返回值无效。 @class Dtk::Gui::DDciIcon ddciicon.h @details 如果需要详细dci相关介绍以及规范文档, 可以参见[dci文件图标规范](https://github.com/linuxdeepin/deepin-specifications/blob/master/unstable/%E5%9B%BE%E6%A0%87%E6%96%87%E4%BB%B6%E8%A7%84%E8%8C%83.md) ## DDciIcon示例 项目目录结构在同一目录下 ## CMakeLists.txt ```cmake cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 project(ddciicon-example VERSION 1.0.0 LANGUAGES CXX) # 指定项目名称, 版本, 语言 cxx就是c++ set(CMAKE_CXX_STANDARD 11) # 指定c++标准 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 set(CMAKE_AUTOMOC ON) # 支持qt moc set(CMAKE_AUTORCC ON) # support qt resource file # 支持qt资源文件 set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 支持 clangd if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 endif() find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5组件Core find_package(Qt5 REQUIRED COMPONENTS Gui) # 寻找Qt5组件Core find_package(Qt5 REQUIRED COMPONENTS Widgets) # 寻找Qt5组件Widgets find_package(DtkCore REQUIRED) # 寻找Dtk组件Core find_package(Dtk REQUIRED COMPONENTS Gui) # 寻找Dtk组件Gui find_package(Dtk REQUIRED COMPONENTS Widget) # 寻找Dtk组件Widget add_executable(${PROJECT_NAME} # 生成可执行文件 main.cpp qml.qrc ) target_link_libraries(${PROJECT_NAME} PRIVATE # 添加需要链接的共享库 Qt5::Core Qt5::Gui Qt5::Widgets Dtk::Core dtkgui dtkwidget ) ``` ## main.cpp ```cpp #include #include #include #include #include #include #include #include #include #include DWIDGET_USE_NAMESPACE int main(int argc, char *argv[]) { DApplication a(argc, argv); DMainWindow win; QWidget w; QFormLayout* layout = new QFormLayout(&w); // fromTheme表示从图标主题中寻找资源。 DDciIcon dci = DDciIcon::fromTheme("select_indicator"); auto icon = dci.matchIcon(0, DDciIcon::Light, DDciIcon::Hover); qDebug() << "DCI图标的实际大小" << dci.actualSize(icon); // 定义一个函数,传入DIconButton,以及提示信息 auto addBtnRow = [&](DIconButton *iconBtn, const QString name){ iconBtn->setIconSize(QSize(32,32)); QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->addWidget(iconBtn); QLabel *btnLabel = new QLabel(name); hlayout->addWidget(btnLabel); return hlayout; }; // 将DDciIcon传入DIconButton DIconButton *iconBtn1 = new DIconButton(dci); layout->addRow(addBtnRow(iconBtn1, "icon button")); DIconButton *iconBtn2 = new DIconButton(dci); iconBtn2->setDisabled(true); layout->addRow(addBtnRow(iconBtn2, "disabled state")); DIconButton *iconBtn3 = new DIconButton(dci); iconBtn3->setDown(true); layout->addRow(addBtnRow(iconBtn3, "pressed state")); win.setCentralWidget(&w); win.resize(200,100); win.show(); Dtk::Widget::moveToCenter(&win); return a.exec(); } ``` ## qml.qrc ```xml select_indicator.dci ``` ## select_indicator.dci 下载dci-demo解压获取,这是个用qml编写的例子,使用DDciIcon更灵活 [dci-demo](https://github.com/linuxdeepin/deepin-specifications/blob/master/unstable/dci-demo.zip) 编译和运行程序 ```bash cmake -B build cmake --build build ./build/ddciicon-example ``` 程序运行效果如下: ![ddciicon-example](/docs/images/ddciicon-example1.jpg) @enum Dtk::Gui::DDciIcon::Mode @brief DCI图标模式 @details | 键 | 值 | |:--------:|:---:| | Normal | 0 | | Disabled | 1 | | Hover | 2 | | Pressed | 3 | @enum Dtk::Gui::DDciIcon::Theme @brief DCI图标主题 @details | 键 | 值 | |:-----:|:---:| | Light | 0 | | Dark | 1 | @enum Dtk::Gui::DDciIcon::IconAttribute @brief DCI图标属性 @details | 键 | 值 | |:-----:|:---:| | HasPalette | 0x001 | 这个属性为了获取dci图标的图层是否包含调色板颜色调整, 比如某一个图层的图片的需要用高亮色的填充就是 HasPalette, 这个高亮色还可以调整亮度饱和度rgba等参数 @enum Dtk::Gui::DDciIcon::IconMatchedFlag @brief DCI图标匹配参数 @var DDciIcon::None @brief 空,无含义 @var DDciIcon::DontFallbackMode @brief 在查找图片资源时,如果指定的 mode 不存在,则禁止回退,直接当作查找不到处理 @var DDciIcon::RegardPaddingsAsSize @brief 将图层中携带的 paddings 属性算作图层大小的一部分,这会影响图片匹配时的大小判断 @fn Dtk::Gui::DDciIcon::DDciIcon() @brief 构造函数 @fn Dtk::Gui::DDciIcon::DDciIcon(const DCORE_NAMESPACE::DDciFile *dciFile) @brief 指定DCI文件的构造函数 @fn Dtk::Gui::DDciIcon(const QString &fileName) @brief 指定DCI文件名的构造函数 @fn Dtk::Gui::DDciIcon::DDciIcon(const QByteArray &data) @brief 指定DCI文件数据的构造函数 @fn Dtk::Gui::DDciIcon::DDciIcon(const DDciIcon &other) @brief 拷贝构造函数,重载赋值运算符 @fn Dtk::Gui::DDciIcon::swap(DDciIcon &other) @brief 交换两个DDciIcon对象 @fn bool Dtk::Gui::DDciIcon::isNull() const @brief 判断DCI图标是否为空 @fn DDciIconMatchResult Dtk::Gui::DDciIcon::matchIcon(int size, Theme theme, Mode mode, IconMatchedFlags flags = None) const @brief 获取DCI图标匹配元信息, 元信息仅能作为传入参数使用 @param[in] size 图标大小 @param[in] theme 图标主题 @param[in] mode 图标模式 @param[in] flags 图标匹配标志 @fn int Dtk::Gui::DDciIcon::actualSize(DDciIconMatchResult result) const @brief 获取DCI图标实际大小 @param[in] result DCI图标匹配结果 @fn int Dtk::Gui::DDciIcon::actualSize(int size, Theme theme, Mode mode =Normal) const @brief 获取DCI图标实际大小 @details 该函数会根据传入的参数获取DCI图标匹配结果,然后调用actualSize(DDciIconMatchResult result)函数获取DCI图标实际大小 @sa DDciIcon::actualSize(DDciIconMatchResult result) @fn QList Dtk::Gui::DDciIcon::availableSizes(Theme theme, Mode mode=Normal) const @brief 获取DCI图标可用大小列表 @param[in] theme 图标主题 @param[in] mode 图标模式,默认为Normal @fn bool Dtk::Gui::DDciIcon::isSupportedAttribute(DDciIconMatchResult result, IconAttribute attr) @brief 判断DCI图标是否支持指定属性 @param[in] result DCI图标匹配结果 @param[in] attr 图标属性 @fn QPixmap Dtk::Gui::DDciIcon::pixmap(qreal devicePixelRatio, int iconSize, Theme theme, Mode mode = Normal,const DDciIconPalette &palette = DDciIconPalette()) const @brief 获取DCI图标的QPixmap @param[in] devicePixelRatio 设备像素比 @param[in] iconSize 图标大小 @param[in] theme 图标主题 @param[in] mode 图标模式, 默认为Normal @param[in] palette 图标调色板,默认为无(空)调色板 @fn QPixmap Dtk::Gui::DDciIcon::pixmap(qreal devicePixelRatio, int iconSize, DDciIconMatchResult result, const DDciIconPalette &palette = DDciIconPalette()) const @brief 获取DCI图标的QPixmap @param[in] devicePixelRatio 设备像素比 @param[in] iconSize 图标大小 @param[in] result DCI图标匹配结果 @param[in] palette 图标调色板, 默认为无(空)调色板 @fn void Dtk::Gui::DDciIcon::paint(QPainter *painter, const QRect &rect, qreal devicePixelRatio, Theme theme, Mode mode = Normal, Qt::Alignment alignment = Qt::AlignCenter, const DDciIconPalette &palette = DDciIconPalette()) const @brief 绘制DCI图标 @param[in] painter QPainter对象 @param[in] rect 绘制区域 @param[in] devicePixelRatio 设备像素比 @param[in] theme 图标主题 @param[in] mode 图标模式, 默认为Normal @param[in] alignment 对齐方式, 默认为Qt::AlignCenter @param[in] palette 图标调色板, 默认为无(空)调色板 @fn void Dtk::Gui::DDciIcon::paint(QPainter *painter, const QRect &rect, qreal devicePixelRatio, DDciIconMatchResult result, Qt::Alignment alignment = Qt::AlignCenter, const DDciIconPalette &palette = DDciIconPalette()) const @brief 绘制DCI图标 @param[in] painter QPainter对象 @param[in] rect 绘制区域 @param[in] devicePixelRatio 设备像素比 @param[in] result DCI图标匹配结果 @param[in] alignment 对齐方式, 默认为Qt::AlignCenter @param[in] palette 图标调色板, 默认为无(空)调色板 @fn Dtk::Gui::DDciIcon::image(DDciIconMatchResult result, int size, qreal devicePixelRatio) const @details 构造一个 DDciIconImage 对象 @param[in] result 匹配到的图片结果,将根据此匹配结果查找对应的图片数据。 @param[in] size 期望获取到的图片大小,将根据此大小寻找最为接近的图片资源,当图片大小与传入的大小不一致时,将优先返回一个稍大的图片。 @param[in] devicePixelRatio 期望获取到的图片的缩放比例,将根据其寻找最为接近的图片资源,当无法找到指定比例的图片时,将优先返回一个稍大比例的图片。 @sa DDciIcon::matchIcon @fn static DDciIcon Dtk::Gui::DDciIcon::fromTheme(const QString &name) @brief 从dci图标主题(包括内置dci图标资源)中获取图标名字为name的图标 @param[in] name DCI图标名称 @fn static DDciIcon Dtk::Gui::DDciIcon::fromTheme (const QString &name, const DDciIcon &fallback) @brief 从dci图标主题(包括内置dci图标资源)中获取图标名字为name的图标 @param[in] name DCI图标名称 @param[in] fallback 当图标名为 name 的图标找不到时, fallback 到 fallback 的这个dci图标 */ dtkgui-5.7.12/docs/util/ddciiconpalette.zh_CN.dox000066400000000000000000000056441476226661100216750ustar00rootroot00000000000000/*! @~chinese @file include/util/ddciiconpalette.h @ingroup dci @brief DCI图标调色板 @class Dtk::Gui::DDciIconPalette ddciiconpalette.h @brief DCI图标调色板 @fn Dtk::Gui::DDciIconPalette::DDciIconPalette (QColor foreground=QColor::Invalid, QColor background=QColor::Invalid, QColor highlight=QColor::Invalid, QColor highlightForeground=QColor::Invalid) @brief 构造函数 @param[in] foreground 前景色, 默认值为无效色 @param[in] background 背景色, 默认值为无效色 @param[in] highlight 高亮色, 默认值为无效色 @param[in] highlightForeground 高亮前景色, 默认值为无效色 @property Dtk::Gui::DDciIconPalette::foreground() @brief foreground()属性 @sa READ方法: QColor Dtk::Gui::DDciIconPalette::foreground() @sa WRITE方法: void Dtk::Gui::DDciIconPalette::setForeground(const QColor &foreground) @fn QColor Dtk::Gui::DDciIconPalette::foreground() const @brief 返回前景色 @sa DDciIconPalette::foreground @fn void Dtk::Gui::DDciIconPalette::setForeground(const QColor &foreground) @brief 设置前景色 @sa DDciIconPalette::foreground @property Dtk::Gui::DDciIconPalette::background @brief background()属性 @sa READ方法: QColor Dtk::Gui::DDciIconPalette::background() @sa WRITE方法: void Dtk::Gui::DDciIconPalette::setBackground(const QColor &background) @fn QColor Dtk::Gui::DDciIconPalette::background() const @brief 返回背景色 @sa DDciIconPalette::background @fn void Dtk::Gui::DDciIconPalette::setBackground(const QColor &background) @brief 设置背景色 @sa DDciIconPalette::background @property Dtk::Gui::DDciIconPalette::highlightForeground @brief highlightForeground()属性 @sa READ方法: QColor Dtk::Gui::DDciIconPalette::highlightForeground() @sa WRITE方法: void Dtk::Gui::DDciIconPalette::setHighlightForeground(const QColor &highlightForeground) @fn QColor Dtk::Gui::DDciIconPalette::highlightForeground() const @brief 返回高亮前景色 @sa DDciIconPalette::highlightForeground @fn void Dtk::Gui::DDciIconPalette::setHighlightForeground(const QColor &highlightForeground) @brief 设置高亮前景色 @sa DDciIconPalette::highlightForeground @property Dtk::Gui::DDciIconPalette::highlight @brief highlight()属性 @sa READ方法: QColor Dtk::Gui::DDciIconPalette::highlight() @sa WRITE方法: void Dtk::Gui::DDciIconPalette::setHighlight() @fn QColor Dtk::Gui::DDciIconPalette::highlight() const @brief 返回高亮色 @sa DDciIconPalette::highlight @fn void Dtk::Gui::DDciIconPalette::setHighlight() @brief 设置高亮色 @sa DDciIconPalette::highlight @fn static QString Dtk::Gui::DDciIconPalette::convertToString(const DDciIconPalette &palette) @brief 将DDciIconPalette转换为字符串 @fn static DDciIconPalette Dtk::Gui::DDciIconPalette::convertFromString(const QString &data) @brief 将字符串转换为DDciIconPalette @fn static DDciIconPalette Dtk::Gui::DDciIconPalette::fromQPalette(const QPalette &pa) @brief 将QPalette转换为DDciIconPalette @sa QPalette */ dtkgui-5.7.12/docs/util/ddciiconplayer.zh_CN.dox000066400000000000000000000274321476226661100215320ustar00rootroot00000000000000/*! @~chinese @file include/util/ddciiconplayer.h @ingroup dci @brief DCI 图标播放工具 @class Dtk::Gui::DDciIconImagePlayer ddciiconplayer.h @details 用于 DDciIconImage 的动画播放,功能设计类似于 QMovie。支持无缝顺序播放播放多个图片、倒序播放等高级功能。 @enum Dtk::Gui::DDciIconImagePlayer::State @brief 播放状态 @var DDciIconImagePlayer::NotRunning @brief 未播放动画 @var DDciIconImagePlayer::WaitingRead @brief 正在播放动画,且等待读取当前帧 @var DDciIconImagePlayer::Running @brief 正在播放动画,此时处于等待下一帧到来的状态 @enum Dtk::Gui::DDciIconImagePlayer::Flag @brief 播放参数 @details 缓存的帧被判断为无效时将会被自动清理,如调用 DDciIconImagePlayer::setImage 改变了要播放的图片资源。 @var DDciIconImagePlayer::Continue @brief 接着上一次动画停止时的状态继续播放,一般会配合 InvertedOrder 同时使用 @var DDciIconImagePlayer::CacheAll @brief 缓存本次播放中的所有动画帧 @var DDciIconImagePlayer::InvertedOrder @brief 倒序播放 @var DDciIconImagePlayer::IgnoreLastImageLoop @brief 忽略最后一个图片的动画循环次数,即无论 DDciIconImage::loopCount 的值是什么,动画都只播放一次 @var DDciIconImagePlayer::AllowNonLastImageLoop @brief 允许非最后一个图片循环播放,默认时不允许,以确保所有图片都有机会被播放,避免动画在前面的图片中无限循环进行播放 @var DDciIconImagePlayer::ClearCacheOnStop @brief 在动画停止时清理缓存的帧,无论动画是播放完成时的自动停止还是被动停止 @fn Dtk::Gui::DDciIconImagePlayer::DDciIconImagePlayer(QObject *parent) @details 构造此对象。 @param[in] parent 指定此 QObject 对象的父对象 @fn Dtk::Gui::DDciIconImagePlayer::setImages(const QVector &images) @details 指定待播放的图片序列,如果当前的状态不是 NotRunning,并且与上一次指定的图片序列不同,则停止动画。 @param[in] images 图片序列,当为多个时,将无缝顺序播放所有图片。 @fn Dtk::Gui::DDciIconImagePlayer::images() const @details 返回当前已指定的图片序列。 @fn Dtk::Gui::DDciIconImagePlayer::currentImage() const @details 返回当前正在播放的图片对象,如果当前的状态是 NotRunning,则会返回一个空的 DDciIconImage。 @fn Dtk::Gui::DDciIconImagePlayer::currentLoopForever() const @details 如果当前正在播放的图片陷入了无限循环,则返回 true,否则返回 false。 @sa DDciIconImagePlayer::Flag::IgnoreLastImageLoop DDciIconImagePlayer::Flag::AllowNonLastImageLoop @fn Dtk::Gui::DDciIconImagePlayer::setPalette(const DDciIconPalette &palette) @details 指定读取动画帧时所使用的调色板,如果图片支持此功能,则能控制获取到的图片的某些颜色。如果设置成功,并且当前的状态是 NotRunning,则会立即清理缓存帧,否则会在动画停止时清理缓存帧。 @param[out] 如果新的 DDciIconPalette 与当前的 DDciIconPalette 相同,则返回 false,否则返回 true。 @sa DDciIconImagePlayer::palette @fn Dtk::Gui::DDciIconImagePlayer::palette() const @details 返回当前已指定的调色板,如果未设置过调色板,则返回一个空的 DDciIconPalette。 @sa DDciIconImagePlayer::setPalette @fn Dtk::Gui::DDciIconImagePlayer::setLoopCount(int count) @details 指定动画的循环次数,当从调用 DDciIconImagePlayer::start 到收到 DDciIconImagePlayer::finished 信号为一次循环,除非调用 DDciIconImagePlayer::stop,否则不会终止此循环。另外,需要注意的是,此循环与 DDciIconImage::loopCount 无关,他们相互独立,且会叠加生效。 @sa DDciIconImagePlayer::loopCount @fn Dtk::Gui::DDciIconImagePlayer::loopCount() const @details 返回动画循环次数。 @sa DDciIconImagePlayer::setLoopCount @fn Dtk::Gui::DDciIconImagePlayer::abortLoop() const @details 终止本次播放中的所有动画循环,即后续的动画都仅播放一遍,这会导致忽略 DDciIconImage::loopCount 和 DDciIconImagePlayer::loopCount。 @fn Dtk::Gui::DDciIconImagePlayer::readImage() @details 读取当前动画帧,这是一个“生产者-消费者”模型,只有当状态为 WaitingRead 时才能读取,且每一帧只能读取一次。 @sa DDciIconImagePlayer::updated @fn Dtk::Gui::DDciIconImagePlayer::state() const @details 返回当前的状态。 @sa DDciIconImagePlayer::stateChanged @fn Dtk::Gui::DDciIconImagePlayer::clearCache() @details 立即清理所有的缓存帧。 @fn Dtk::Gui::DDciIconImagePlayer::start(float speed, DDciIconImagePlayer::Flags flags) @details 立即启动动画,应当在此之前调用 DDciIconImagePlayer::setImages。如果启动成功,将发送 started 信号。在启动后,会根据每一帧的间隔自动触发 updated 信号,以通知使用方在合适的时候显示新的帧。在动画播放完成后,将发送 finished 信号,在动画未播放结束前调用了 stop 主动结束动画则不会发送信号。 @param[in] speed 本次动画的播放速度,其表示的是倍速,值越大动画播放的越快。设置为 0 时与设置为 1.0 等价。 @param[in] flags 控制本次动画播放时的一些行为。 @param[out] 如果动画启动成功则返回 true,否则返回 false。动画启动失败的原因一般是因为此时已经在播放动画、没有设置任何图片或所有图片都不支持动画。 @sa DDciIconImagePlayer::started DDciIconImagePlayer::updated DDciIconImagePlayer::readImage DDciIconImagePlayer::finished DDciIconImagePlayer::stateChanged @fn Dtk::Gui::DDciIconImagePlayer::stop() @details 立即停止当前动画的播放。这不会发送 finished 信号。 @fn Dtk::Gui::DDciIconImagePlayer::started() @details 通知动画已开始播放。 @fn Dtk::Gui::DDciIconImagePlayer::updated() @details 通知动画的当前帧已经发生变化,在收到此信号后需要立即调用 readImage,否则动画会被暂停,不会自动到下一帧。 @sa DDciIconImagePlayer::readImage @fn Dtk::Gui::DDciIconImagePlayer::finished() @details 在本次动画播放结束时发送信号通知。因为调用 DDciIconImagePlayer::stop 导致的动画停止不会触发此信号。 @sa DDciIconImagePlayer::start @fn Dtk::Gui::DDciIconImagePlayer::stateChanged() @details 在状态改变时发送信号通知。 @sa DDciIconImagePlayer::state @class Dtk::Gui::DDciIconPlayer ddciiconplayer.h @details 实现根据 DDciIcon::Mode 的变化,自动化计算要显示的图标内容,支持动态图标,在 DDciIcon::Mode 被设置时通过 updated 信号通知控件绘制新的内容。对于动态图标的动画播放先后顺序、播放速度等规则遵守 DSG 规范中所提出的 DCI 图标文件标准。有几条特性: 1. 支持动画的倒序播放,如从 Hover 状态变为 Normal 时,可以倒序播放 Hover 状态所对应的 DDciIconImage。此功能依赖于 DDciIconImagePlayer 的实现。 2. 支持动画无缝衔接播放,如从 Normal 状态变化为 Hover 时,在播放 Hover 动画的途中又变为 Pressed 状态,则不会立即将 Hover 的动画打断,将把 Pressed 动画在当前动画播放接受后自动播放。 3. 支持动画记忆播放,如从 Normal 状态变化为 Hover 时,在播放 Hover 动画的途中变回了 Normal 状态,则会从当前已经播放到的这一帧开始倒序播放 Hover 动画。 @enum Dtk::Gui::DDciIconPlayer::State @brief 工作状态 @var DDciIconPlayer::Idle @brief 处于空闲状态,一般表示此时未播放动画 @var DDciIconPlayer::Busy @brief 处于忙碌状态,此时可能正在播放动画 @fn Dtk::Gui::DDciIconPlayer::DDciIconPlayer @details 构造此对象。 @param[in] parent 指定此 QObject 对象的父对象 @fn Dtk::Gui::DDciIconPlayer::state() const @details 返回当前的状态。 @sa DDciIconPlayer::State @fn Dtk::Gui::DDciIconPlayer::setIcon(const DDciIcon &icon) @details 设置要处理的图标对象,这会导致当前动画停止播放,并且释放上一个 icon 相关的所有资源。会触发 updated 信号。 @fn Dtk::Gui::DDciIconPlayer::icon() const @details 返回已设置的图标对象。 @fn Dtk::Gui::DDciIconPlayer::setTheme(DDciIcon::Theme theme) @details 为图标指定要使用的主题,如果值发生变化,会导致当前动画停止播放,并且释放图标相关的所有资源。会触发 updated 信号。 @fn Dtk::Gui::DDciIconPlayer::theme() const @details 返回已设置的图标主题。 @fn Dtk::Gui::DDciIconPlayer::setMode(DDciIcon::Mode mode) @details 指定图标当前要使用的模式,如果值发生变化,会根据新旧模式的过渡规则计算接下来是否需要播放动画,以及当动画不存在或动画停止后所停留的内容。动画播放规则遵守 DSG 中 DCI 图标格式规范中的定义。 @sa DDciIconPlayer::modeChanged DDciIconPlayer::updated @fn Dtk::Gui::DDciIconPlayer::mode() const @details 返回已设置的图标模式。 @fn Dtk::Gui::DDciIconPlayer::setIconSize(int size) @details 为图标指定要渲染的大小,如果值发生变化,会导致当前动画停止播放,并且释放图标相关的所有资源。会触发 updated 信号。 @fn Dtk::Gui::DDciIconPlayer::iconSize() const @details 返回已设置的图标大小。 @fn Dtk::Gui::DDciIconPlayer::setDevicePixelRatio(qreal devicePixelRatio) @details 为图标指定渲染时的缩放比例,如果值发生变化,会导致当前动画停止播放,并且释放图标相关的所有资源。会触发 updated 信号。 @fn Dtk::Gui::DDciIconPlayer::devicePixelRatio() const @details 返回已设置的图标缩放比例。 @fn Dtk::Gui::DDciIconPlayer::setPalette(const DDciIconPalette &palette) @details 为图标指定渲染时所使用的调色板,如果值发生变化,并且当前模式所对应的图片支持指定调色板,在 Busy 状态下,会导致接下来新的动画帧的颜色发生变化,在 Idle 状态下,则会重新为当前模式计算应该显示的内容,这可能会触发 updated 信号。 @sa DDciIconImage::hasPalette DDciIconImage::toImage DDciIconImage::paint @fn Dtk::Gui::DDciIconPlayer::currentImage() const @details 返回当前图标在当前时刻应该显示的位图数据。当此数据变化时会发送 updated 信号。 @sa DDciIconPlayer::setIcon DDciIconPlayer::updated @fn Dtk::Gui::DDciIconPlayer::play(DDciIcon::Mode mode) @details 为指定的图标模式计算要显示的内容,这可能会导致 currentImage 发生变化。这是个一次性行为,不会影响下一次调用 setMode 后的结果。 @param[in] mode 指定要播放的图标模式,如果此模式支持动画,会触发此模式自身的动画播放(与 setMode 导致的动画不同的是,此动画不涉及两种模式变化时的过渡规则),否则将修改 currentImage 为此模式对应的静态图片资源。 @fn Dtk::Gui::DDciIconPlayer::stop() @details 如果当前正在播放动画,则停止当前动画的播放,但不会影响队列中下一个动画的播放。可能会导致 DDciIconPlayer::state 发生变化。 @sa DDciIconPlayer::abort @fn Dtk::Gui::DDciIconPlayer::abort() @details 如果当前正在播放动画,则停止当前动画的播放,并取消队列中所有计划播放的动画。可能会导致 DDciIconPlayer::state 发生变化。 @sa DDciIconPlayer::stop @fn Dtk::Gui::DDciIconPlayer::stateChanged() @details 通知状态发生变化。 @sa DDciIconPlayer::state @fn Dtk::Gui::DDciIconPlayer::updated() @details 通知 DDciIconPlayer::currentImage 发生变化。 @sa DDciIconPlayer::currentImage @fn Dtk::Gui::DDciIconPlayer::modeChanged(DDciIcon::Mode oldMode, DDciIcon::Mode newMode) @details 通知图标的模式发生变化。 @param[in] oldMode 变化之前的 mode @param[in] newMode 变化之后的 mode @sa DDciIconPlayer::setMode DDciIconPlayer::setMode */ dtkgui-5.7.12/docs/util/ddesktopservices.h.zh_CN.dox000066400000000000000000000201041476226661100223350ustar00rootroot00000000000000/*! @~chinese @file include/util/ddesktopservices.h @ingroup DesktopServices @brief Dtk 提供常见桌面服务的方法工具类 @namespace Dtk::Gui::DDesktopServices ddesktopservices.h @details 用于提供一些接口,包括在文件管理器中显示目录,显示文件,显示文件属性,移入回收站,播放系统音效等。 @enum Dtk::Gui::DDesktopServices::SystemSoundEffect @brief 系统音效的枚举 @var Dtk::Gui::DDesktopServices::SSE_Notifications @brief 显示通知的音效 @var Dtk::Gui::DDesktopServices::SEE_Screenshot @brief 截屏的音效 @var Dtk::Gui::DDesktopServices::SSE_EmptyTrash @brief 清空回收站的音效 @var Dtk::Gui::DDesktopServices::SSE_SendFileComplete @brief 完成发送文件(到桌面)的音效 @var Dtk::Gui::DDesktopServices::SSE_BootUp @brief 开机的音效 @var Dtk::Gui::DDesktopServices::SSE_Shutdown @brief 关机的音效 @var Dtk::Gui::DDesktopServices::SSE_Logout @brief 注销的音效 @var Dtk::Gui::DDesktopServices::SSE_WakeUp @brief 唤醒的音效 @var Dtk::Gui::DDesktopServices::SSE_VolumeChange @brief 音量调节的音效 @var Dtk::Gui::DDesktopServices::SSE_LowBattery @brief 低电量的音效 @var Dtk::Gui::DDesktopServices::SSE_PlugIn @brief 电源接入的音效 @var Dtk::Gui::DDesktopServices::SSE_PlugOut @brief 电源移除的音效 @var Dtk::Gui::DDesktopServices::SSE_DeviceAdded @brief 移动设备接入的音效 @var Dtk::Gui::DDesktopServices::SSE_DeviceRemoved @brief 移动设备移除的音效 @var Dtk::Gui::DDesktopServices::SSE_Error @brief 错误提示的音效 @fn Dtk::Gui::DDesktopServices::showFolder(const QString &localFilePath, const QString &startupId = QString()) @details 通过文件管理器显示目录 @param[in] localFilePath 要显示的目录路径 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFolders(const QList &localFilePaths, const QString &startupId = QString()) @details 通过文件管理器显示多个目录 @param[in] localFilePaths 要显示的目录路径列表 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFolder(const QUrl &url, const QString &startupId = QString()) @details 通过文件管理器显示目录 @param[in] url 要显示的目录 QUrl 形式路径 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFolders(const QList &urls, const QString &startupId = QString()) @details 通过文件管理器显示多个目录 @param[in] urls 要显示的目录路径 url 列表 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFileItemProperty(const QString &localFilePath, const QString &startupId = QString()) @details 通过文件管理器显示文件的属性 @param[in] localFilePath 要显示的文件路径 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFileItemProperties(const QList &localFilePaths, const QString &startupId = QString()) @details 通过文件管理器显示多个文件的属性 @param[in] localFilePaths 要显示的文件路径列表 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFileItemProperty(const QUrl &url, const QString &startupId = QString()) @details 通过文件管理器显示文件的属性 @param[in] url 要显示的文件 QUrl 形式路径 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFileItemProperties(const QList &urls, const QString &startupId = QString()) @details 通过文件管理器显示多个文件的属性 @param[in] urls 要显示的目录路径 url 列表 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFileItem(const QString &localFilePath, const QString &startupId = QString()) @details 通过文件管理器在父目录中显示并选中文件(目录) @param[in] localFilePath 要显示(选中)的文件(目录)路径 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFileItems(const QList &localFilePaths, const QString &startupId = QString()) @details 通过文件管理器父目录中显示并选中多个文件(目录) @param[in] localFilePaths 要显示(选中)的文件(目录)路径列表 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFileItem(const QUrl &url, const QString &startupId = QString()) @details 通过文件管理器在父目录中显示并选中文件(目录) @param[in] url 要显示(选中)的文件(目录)QUrl 形式路径 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::showFileItems(const QList &urls, const QString &startupId = QString()) @details 通过文件管理器父目录中显示并选中多个文件(目录) @param[in] urls 要显示选中)的文件(目录)路径 url 列表 @param[in] startupId 本次启动的id, 默认为空 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::trash(const QString &localFilePath) @details 通过文件管理器将文件移入回收站 @param[in] localFilePath 要移入回收站的文件路径 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::trash(const QList &localFilePaths) @details 通过文件管理器将多个文件移入回收站 @param[in] localFilePaths 要移入回收站的文件路径列表 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::trash(const QUrl &url) @details 通过文件管理器将文件移入回收站 @param[in] url 要移入回收站的文件 url 路径 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::trash(const QList &urls) @details 通过文件管理器将多个文件移入回收站 @param[in] urls 要移入回收站的文件路径 url 列表 @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::playSystemSoundEffect(const SystemSoundEffect &effect) @details 播放系统音效。如果系统音效被禁用或者要播放音效被禁用将播放失败 @param[in] effect 要播放的音效,见枚举 Dtk::Gui::DDesktopServices::SystemSoundEffect @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::playSystemSoundEffect(const QString &name) @details 根据音效名播放系统音效。如果系统音效被禁用或者要播放音效被禁用将播放失败 @param[in] name 要播放的音效名称,见 Dtk::Gui::DDesktopServices::getNameByEffectType @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::previewSystemSoundEffect(const SystemSoundEffect &effect) @details 系统音效预览。 @param[in] effect 要播放的音效,见枚举 Dtk::Gui::DDesktopServices::SystemSoundEffect @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::previewSystemSoundEffect(const QString &name) @details 根据音效名预览系统音效。 @param[in] name 要播放的音效名称,见 Dtk::Gui::DDesktopServices::getNameByEffectType @return 调用成功返回 true, 否则返回 false @fn Dtk::Gui::DDesktopServices::getNameByEffectType(const SystemSoundEffect &effect) @details 根据音效名预览系统音效。 @param[in] effect 要获取名称的音效,见枚举 Dtk::Gui::DDesktopServices::SystemSoundEffect @return QString effect 对应的音效名称 @fn Dtk::Gui::DDesktopServices::errorMessage() @details 文件管理器相关调用出错时可以通过此接口获取错误信息 @return 错误信息 */ dtkgui-5.7.12/docs/util/dicontheme.zh_CN.dox000066400000000000000000000124241476226661100206530ustar00rootroot00000000000000/*! @~chinese @file include/util/dicontheme.h @ingroup dci @brief Dtk 图标主题工具类 @namespace Dtk::Gui::DIconTheme dicontheme.h @details 用于提供一些接口,包括查找图标(包括 QIcon 和 DCI 图标 ),图标搜索路径等。 @enum Dtk::Gui::DIconTheme::Option @brief 查找图标时的选项 @var Dtk::Gui::DIconTheme::DontFallbackToQIconFromTheme @brief 是否**不使用** QIcon::fromTheme 的方式去查找图标,当设置此 flag 时查找图标失败时直接返回空图标对象,否则回退到通过 QIcon::fromTheme 查找图标 @var Dtk::Gui::DIconTheme::IgnoreBuiltinIcons @brief 是否忽略通过内置图标引擎方式查找图标资源,当设置此 flag 时查找图标会跳过内置图标引擎的方式查找图标资源,否则优先尝试内置图标引擎查找资源。 @class Dtk::Gui::DIconTheme::Cached @details 图标查找缓存类,提供的查找图标接口,如果找到会加入缓存,下次查找会更快。 @fn Dtk::Gui::DIconTheme::Cached::Cached() @details 图标缓存构造函数 @fn Dtk::Gui::DIconTheme::Cached::~Cached() @details 图标缓存析构函数 @fn Dtk::Gui::DIconTheme::Cached::maxCost() const @details 返回允许的最大缓存数量 @fn Dtk::Gui::DIconTheme::Cached::setMaxCost(int cost) @details 将最大允许的缓存数量设置为 cost 。如果当前的缓存数量大于 cost ,则某些缓存对象会立即删除。 @fn Dtk::Gui::DIconTheme::Cached::clear() @details 清理所有缓存 @fn Dtk::Gui::DIconTheme::Cached::findQIcon(const QString &iconName, Options options, const QIcon &fallback) @details 通过 iconName 查找 QIcon 的接口,找到时会加入缓存 @param[in] iconName 要查找的图标名称 @param[in] options 要查找的选项 @param[in] fallback 图标查找失败时可以返回用户指定的 fallback 对象,默认为空 @sa DIconTheme::findQIcon @fn Dtk::Gui::DIconTheme::Cached::findDciIconFile(const QString &iconName, const QString &themeName, const QString &fallback) @details 通过指定图标名 iconName 和主题名 themeName 查找 DCI 图标文件路径的接口,找到时会加入缓存 @param[in] iconName 要查找的图标名称 @param[in] options 指定 DCI 图标主题 @param[in] fallback 图标查找失败时可以返回用户指定的 fallback ,默认为空 @fn Dtk::Gui::DIconTheme::cached() @details 获取(首次次调用时构造)缓存对象。 @fn Dtk::Gui::DIconTheme::findQIcon(const QString &iconName, Options options) @details 返回 DIconTheme::createIconEngine 接口创建的图标引擎构造 QIcon,当没有设置 DontFallbackToQIconFromTheme 和 createIconEngine 失败时回退到 QIcon::fromTheme @param[in] iconName 要查找的图标名称 @param[in] options 要查找的选项, 选项默认为空 @sa DIconTheme::Cached::findQIcon @sa DIconTheme::createIconEngine @fn Dtk::Gui::DIconTheme::findQIcon(const QString &iconName, const QIcon &fallback, Options options) @details 重载 DIconTheme::findQIcon, 当查找图标失败时返回调用者中提供的 fallback 图标 @param[in] iconName 要查找的图标名称 @param[in] options 要查找的选项, 选项默认为空 @param[in] fallback 如果 iconName 无法找到, 返回此图标 @sa DIconTheme::Cached::findQIcon @sa DIconTheme::createIconEngine @fn Dtk::Gui::DIconTheme::createIconEngine(const QString &iconName, Options options) @details 通过图标名构造图标引擎, 如果未设置 IgnoreBuiltinIcons 标志则优先尝试 qrc:/icons/deepin/builtin 目录查找图标来构造内置图标引擎,否则构造 XDG 图标引擎。 @param[in] iconName 图标名称 @param[in] options 选项, 选项默认为 DIconTheme::DontFallbackToQIconFromTheme @return QIconEngine 对象指针,注意图标查找失败时返回 nullptr。 @fn Dtk::Gui::DIconTheme::findDciIconFile(const QString &iconName, const QString &themeName) @details 通过指定图标名 iconName 和主题名 themeName 查找 DCI 图标文件路径的接口 @param[in] iconName 要查找的图标名称 @param[in] options 指定 DCI 图标主题 @return 返回找到的 DCI 图标文件路径 @sa DDciIcon::fromTheme @sa DIconTheme::dciThemeSearchPaths() @fn Dtk::Gui::DIconTheme::dciThemeSearchPaths() @details 返回 DCI 图标的搜索路径。默认会从这些路径查找 /usr/share/dsg/icons/$theme_name, qrc:/dsg/icons/$theme_name, qrc:/dsg/built-in-icons @sa DIconTheme::findDciIconFile @fn Dtk::Gui::DIconTheme::setDciThemeSearchPaths(const QStringList &path) @details 设置查找 DCI 图标的搜索路径 @sa DIconTheme::dciThemeSearchPaths @fn Dtk::Gui::DIconTheme::isBuiltinIcon(const QIcon &icon) @details 返回 QIcon 是否为内置图标,`内置图标` 是 DTK 中规定的一类集成在二进制内部的图标资源,其一般放置于 qrc:/icons/deepin/builtin 的路径下,在使用 findQIcon 或 createIconEngine 时,如找到此路径下对应的图标文件,则会为其使用一个自定义的 QIconEngine 进行渲染。此方法即通过判断 icon 所使用的 QIconEngine 确认其是否为内置图标。 @fn Dtk::Gui::DIconTheme::isXdgIcon(const QIcon &icon) @details 返回 QIcon 是否为 XDG 图标, XDG 图标一般放置于系统图标主题目录(如:/usr/share/icons)。和 isBuiltinIcon 类似,此方法是通过判断 icon 所使用的 QIconEngine 确认其是否为 XDG 图标。 */ dtkgui-5.7.12/docs/util/index.zh_CN.md000066400000000000000000000002241476226661100174440ustar00rootroot00000000000000@page util util--dtkgui工具组件 # Dtk-Gui util:dtk工具组件 TODO:添加组件说明 @defgroup dci @brief dci图标操作类 @details dtkgui-5.7.12/dtkgui.cmake000066400000000000000000000121541476226661100154040ustar00rootroot00000000000000message(STATUS "Current Qt Version: ${QT_VERSION_MAJOR}") set(LIB_NAME dtk${DTK_VERSION_MAJOR}gui) # Set install path if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX /usr) endif () include(GNUInstallDirs) include(CMakePackageConfigHelpers) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Set build option option(DTK_DISABLE_LIBXDG "Disable libxdg" OFF) find_package(Qt${QT_VERSION_MAJOR}XdgIconLoader) if (NOT Qt${QT_VERSION_MAJOR}XdgIconLoader_FOUND) message(WARNING " XdgIconLoader Not Found, DISABLE LIBXDG !") set (DTK_DISABLE_LIBXDG ON) endif() option(DTK_DISABLE_LIBRSVG "Disable librsvg" OFF) option(DTK_DISABLE_EX_IMAGE_FORMAT "Disable libraw and freeimage" OFF) set(CMAKE_CXX_STANDARD 17) if("${QT_VERSION_MAJOR}" STREQUAL "5") set (BUILD_DOCS ON CACHE BOOL "Generate doxygen-based documentation") else() # dtk6 not build doc set (BUILD_DOCS OFF CACHE BOOL "Generate doxygen-based documentation") endif() set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/dtk${PROJECT_VERSION_MAJOR}/DGui") set(TOOL_INSTALL_DIR "${CMAKE_INSTALL_LIBEXECDIR}/dtk${PROJECT_VERSION_MAJOR}/DGui/bin") set(LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") set(MKSPECS_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/qt${QT_VERSION_MAJOR}/mkspecs/modules" CACHE STRING "Install dir for qt pri module files") set(CONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Gui") set(PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wextra -fopenmp") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(BUILD_TESTING ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -fno-omit-frame-pointer") else () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Ofast") endif () set(CONFIGNAME include/global/dtkgui_config.h) file(WRITE ${CONFIGNAME} "// This is an auto-generated header, please don't modify it.\n" ) file(GLOB CONFIGSOURCE include/DtkGui/*) foreach(FILENAME ${CONFIGSOURCE}) get_filename_component(thefile ${FILENAME} NAME) file(APPEND ${CONFIGNAME} "#define DTKGUI_CLASS_${thefile}\n") endforeach() # Generate cmake config file configure_package_config_file(misc/DtkGuiConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/Dtk${DTK_VERSION_MAJOR}GuiConfig.cmake INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}" PATH_VARS TOOL_INSTALL_DIR ) # Generate cmake version file write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/Dtk${DTK_VERSION_MAJOR}GuiConfigVersion.cmake" VERSION ${DTK_VERSION} COMPATIBILITY SameMajorVersion ) # Install cmake config file and version file to CONFIG_INSTALL_DIR install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Dtk${DTK_VERSION_MAJOR}GuiConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/Dtk${DTK_VERSION_MAJOR}GuiConfigVersion.cmake DESTINATION "${CONFIG_INSTALL_DIR}" ) # Install pkgconfig file configure_file(misc/dtkgui.pc.in dtk${DTK_VERSION_MAJOR}gui.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dtk${DTK_VERSION_MAJOR}gui.pc DESTINATION "${PKGCONFIG_INSTALL_DIR}") # Install pri module configure_file(misc/qt_lib_dtkgui.pri.in qt_lib_dtkgui.pri @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qt_lib_dtkgui.pri DESTINATION "${MKSPECS_INSTALL_DIR}") set(GUISGNAME DtkGuis) file(WRITE ${GUISGNAME} "// This is an auto-generated header, please don't modify it.\n" "#ifndef DTK_GUI_MODULE_H\n" "#define DTK_GUI_MODULE_H\n" ) file(GLOB FILEGRAGTOWRITSOURCE include/filedrag/*) foreach(FILENAME ${FILEGRAGTOWRITSOURCE}) get_filename_component(thefile ${FILENAME} NAME) file(APPEND ${GUISGNAME} "#include \"${thefile}\"\n") endforeach() file(GLOB KERNELTOWRITESOURCE include/kernel/*) foreach(FILENAME ${KERNELTOWRITESOURCE}) get_filename_component(thefile ${FILENAME} NAME) file(APPEND ${GUISGNAME} "#include \"${thefile}\"\n") endforeach() file(GLOB UTILTOWRITESOURCE include/util/*) foreach(FILENAME ${UTILTOWRITESOURCE}) get_filename_component(thefile ${FILENAME} NAME) file(APPEND ${GUISGNAME} "#include \"${thefile}\"\n") endforeach() file(APPEND ${GUISGNAME} "#endif") install(FILES DtkGuis DESTINATION "${INCLUDE_INSTALL_DIR}") # Find common dependencies find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui DBus Network) find_package(PkgConfig REQUIRED) find_package(Dtk${DTK_VERSION_MAJOR} REQUIRED Core) find_package(DtkBuildHelper REQUIRED) pkg_check_modules(librsvg REQUIRED IMPORTED_TARGET librsvg-2.0) # Check optional image handler dependencies. find_package(FreeImage) pkg_check_modules(libraw IMPORTED_TARGET libraw) if(FreeImage_FOUND AND libraw_FOUND) set(EX_IMAGE_FORMAT_LIBS_FOUND ON) endif() set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) add_subdirectory(src ${OUTPUT_DIR}/src) if(BUILD_TESTING) enable_testing() add_subdirectory(tests ${OUTPUT_DIR}/tests) endif() add_subdirectory(tools ${OUTPUT_DIR}/tools) add_subdirectory(examples ${OUTPUT_DIR}/examples) if (BUILD_DOCS) add_subdirectory(docs ${OUTPUT_DIR}/docs) endif () dtkgui-5.7.12/examples/000077500000000000000000000000001476226661100147265ustar00rootroot00000000000000dtkgui-5.7.12/examples/CMakeLists.txt000066400000000000000000000002361476226661100174670ustar00rootroot00000000000000add_subdirectory(dnd-example) #add_subdirectory(test-taskbar) # Don't build #add_subdirectory(frameless-window) # Don't build add_subdirectory(animation-dci) dtkgui-5.7.12/examples/animation-dci/000077500000000000000000000000001476226661100174425ustar00rootroot00000000000000dtkgui-5.7.12/examples/animation-dci/3depict.dci000066400000000000000000001262241476226661100214650ustar00rootroot00000000000000DCI256Dnormal.dark3b1.webp/256/normal.light/3/1.webpnormal.light 3ª1.webpzRIFFrWEBPVP8X ALPH1mHg> Ն~uc J HG] 6HXg# RRL3ٓeR:UvKRR.j,+ w _zu4;]iHסPK8`o>o9WL-}ˤɏ 7GsO5˓_Xn@t A.u5V>tㅍ 56[b౷.|^tڹ5DFj?#ݟ,ݥk}(4O?#·w="B5hj_}#lT:q 0Mo~@?<[6FbK-@5xٯ|߽tPA3_x t·vc0ҏ.ܥ&qAq _>TXeeA]7W~<rB),7pS'mK }퍺:rlHfd%N|d]dV +8, +qd.YY0gN8J H%:$e__[]tD o~Two5[8Wq˦>m?{#`ȷ\X{݋WX>X䆭 8WN:#u ;zBn?^=8Qˈ4 x:{ji m~'O2&(qmtfr( ^xLuusBmz#m;OZuLO[xG"p}2.c14 DF3-ЂD[NA hFy`Oovvp4_mAZx~/F)Ѧ;=-Nja펧XFUoұOɶ|1R~QO,1( .JDT ^AKTXpͪ)"ݹ0{ŭqAx@֌ިB(4ʑ^5l\[^|5t f)Z)m!qȫ b8h, prK[!exnO) !,FWŮ^ƥPUaSy}7fXg`۶vf 7hz5 tTsia BW+MjW!hKM$Q[ Et#:.5BH;H\[Mt~XȨsv.ڹRe&0n8bRylE͚phܼ7{0}܃PMlMj2 NkȇљY[iSY̹9F =i 06k~ ў8?s ew#C3͛&oB(C*}a`~2 owSPTmh爟m(9܄rZ^\׸s暱?]+OqfBJI/C(B6QUa0R-heD|P=WtF7?+ 3m[F89/ fDKAĆ #Rv|QhFnX0`xFfjYjaņHچ L6FMjz^f/W~ :J!-p1_Ksَt.UdinZʵJW랴Ȳ-2 À\v~BѾ|O*N2R;٪ҾvLHPKlޅ \vt|P_O' W*no\ݜulQ0/]ܢv19X5ctD}eɀLQHOk p ySGŗ<+/3߇s4~=Ky~%:e d9bG>{wp04#AQ eMO}H 'HD hkl?!kg|ěx:^ ͈o] =~T kǗ~rcG!}A_qs?{Tf:WMaﭣ'61}]5Hv:z#YPߠ 9dW}qМټ= vUt:NQqMf͆5Bp=^/\ȋBB4ͺUw[=P"ZJ5HpѢCPw3a{v@]$r,hɽ{T)Ӓ{;ft&X(2aӹ&5@PYLRnWy -iMt} ;[,5'Z3ŊBa]N 9QfjdZ4 Kz'9S#+ۤR(uk5P)lك2wo;r]½?&UX #N#\ U/lYdJtc +K[,+z;7l2_R5쒻oT hW,o ]A_C%C~Ľ0Ze& 86`pXeGRS9  tp lGWz<`mt -0/LG_xL0X𹘂=p=@dxNhjsʻd=_tAxכ F(3Gל{UrqoI*G%dIx+(;A PZh^ׯjl,N6듦w 0 /v!PbȕyzT=(u<.]i_l+ӳ@B_.]N]$oFNidw3&V*sd0z_P..4!ݪ!Y6*H~{uaRŋ#.{ fXj}nt>ɨ"XfrX^Cva8J!z:WaԌ܂: qvP14xT6b!ؐ^=l1+98pZ6E<2L]c1BNF>Vﷸ!b]_9X8UEY{FgHeR1v0ޫSX0)jlC‘N{`Pm,atwukrz':,!TǸ!Uڞ}ׇ$z_ .Xm3c3eqMt^+-nquɱQ'EewPA,M]Xlr_P1mR^{-rH)ԧNL4~/DDp{2P5; u{*FW @\ wg~{|cI6$T̨雂u^)/ }xR'9`TȞI 7jjdmV*^#ZojRtק:u j,}z"u׭TUl=)ՌfS9?-W yʻpXuO̩tLsh MJqX2mtkI(߃KZ}y8+0`};TZG-4TT*A.)t `*hi\!T9P)OÈA B,8pALF@MpVV: ͺw.}5a MBקth%0SNiva(>6 i uZޜ2U7yľgҪreO@*J  ֭&IBbd5g],Gة.Boŏz͚3;hNZP&$% v%OΫe!o'TeM]!ږq w(05o5uEjY$w hW*hcVN{~a(2 t۹h㜧̜JJ&%L{GC͸8bQ1g>),uWZL$Yk9ҝUB7c8:fDqҢO|N'$|`aPCU Mu# HEmI]9y#vYrZ4s eBViuL$r?u"it&tl0amq@B\apĵT Ef4EuM6 aW2.io [x8Ǻ"9!5ʂWO@ͪ9Ʊ} 2bO-#)FT}ӗv&Wvn(GN?gMtL]-*mF-؋~ rZxW>m\4ĸ~bVc Ms*[Ln>r-Tv66Q:ؚNkmX9́7bI~AӤS'c6M(Ei@(QZ Yu1  ӎdhڹʉFyv̟_:e~/ҩ~xghD#>ptE>=idIMh\xp\n:όof kJ)%SHmP0uhǺmT=(ҪX`ñ%_{Q?M¾(׮uSA{2'O^+﬍MJ(:~#X gx/G6&Kv/<7}`;GF@:QBslcr}P,rKԧ M)~#1AH v)&m\NEw$,HXo?Et+#" zE+Ai4q7bGvtFPV|gz#83tޒ$YƖJۙ|FĮ]+65{> 2:)&֬H-)ݹ!'%{Z, ƣ2:85+p)-/G##j Ē|)-T2 oHx~IĨ὆A$BnXEZ$ĩ}x_EI`؞Z)e CX`,@toKG=Ŏ&]HXrǣИGk^w6s"mĎL #@fvR yL`7dAV.ߞ.gӱ(|a@-)#p߼LDFx(M?}ק&/2)(78'ޗOLgnߚA200OŒTYylkɆhn~{DŹ;o^&(\qpM4cqnDZ llʽ.mdӀ23:BRA& Vf._6]H>Ks?y+o9wy%40η# cQKm޾~pG>J<l4jŅrs(,\B @1dq%) Ypm6';r]BG.N$4&0NMK`^ͫUbiwemU,5M_n<$%aaK/DWEfÍ'Rd<OŒ-SjFrm6< TH~r  F$&9d]R{lFSAA` XCLdmWC-ͺ?0ЌTG"'<$ 1[Pj_ 40ð-JO(b&MaDE\NC͏6]Ih184'.2-l>JR$4ZhHF[! рc#"x#=@`dD[ \r2DS z Af? qpyB6!3㙲2}oC~_ z 1eikY:^χ 6OТ( 2O_X9 '"rPCR&'H'CoxP4\)*DW~E!90 bpޢ}B81vkUSh`1|,0KAg/L6M38\g B׏# 99a.L⤙MaL+ʴ1|S}x3 72&L:t$|FܼEŝ'-W 8}‡=.0Ĺn/: gBw,oB7^) _ 2“PpWh0Jca]Clb8ҩB#X6:DU|XDshhf!'0$L2]K%,b17/X= l)Db0 tAM3q6."I> {H'0E h[0 wD "HBЬgxe:CW ! b s<\'IIHCJ<}l]TXBx~@K< B4ڋl6ΐI?YtQFg͇3-8_7ʱCclcw_w44BjGHvWyF.4@*B&\[mua,A( a fC |6Si >c;Z ~>f) KhTKV Α"b% #XfH! lk #ՏuBZA<d;bu׊4SzuqB!`!i&n%R36/k|Pbj4<f6وmUr/`u-(aPbݵXQ8|PE/t!5)\=d`F*:/VBcժe92P"&w"VxsSaw!*odk:lW|ԗ@y8 GحjGua zPmsZg*@FnFsf56 /Bw6=y HFnvog4V  -qgۭw_Ec"7Xn]Ǻ\ހKHv^Ҭjgvm)YWx6Bc]+_ߺل|1шIʬ?xK~"fn[ϻj{.<)lV^<>YhNDl1GҡL{ý[miflփɜr0`idIlBb?L}>sj74kOHզ) I >%yv?TtౣC}aSrP8Ғd$à^lɓF{O+sc'GWCh}s:$D-מC݅Oj07>;=sf Ŏ@ki A %`"9ttx`W6ć*{ٕrBKct$Rp#ߑk-xbQ֊;˻;X:d92x. >R2V1$g8 Z$_Kr\G&ӑ$2d24@5V6JRyoZګ4 "A2AG/Sc#C7b g/-`ᾠqv&Z^/X̒R9>֎@)aB$gJr@$0&6X0);KCAb$%ڌYOD(xx) zGd/t)S/)# =\VZ$Ohmz.1?䙜kEFx1e?H܏$1?)Rr̪dI҈dz3,q>gjֺ0r$S懚Hi[5Fg `0`I9_VInpXfuC/)-̪#|Xm" k2܈K\} %E\BtIkΉyIXhAZSb˲-M LFMècEߺt--(4PChZlѤu>{SH8?qlVP8 HyP*>B0 ,ۗ+헗^կ??qawߺ`;=OSwG?~H?O%w__?u}l}7_OW??ȿ}~sϾw7.k>Yg}eu+W/̛?X? _?e~?[cC?{?!=~(n1P7S%p1P7S%p1P7S%p1P7S%p1P7S%p1P7S$ý[{InAKz y_9IS%p1%)He\vKBH59x"ߥ "g?_4؜u8ٽߞ6I-U*bn/L0)*IV]et,2@{\]_h,ǾqV|%$RDLalJvsU~_!ZU4s2:-(mlKRZ1o0}P09j:VELpF髌Q}XyQ'g^ 7n~'(Dn5}Lvʘo;cٺѢTb 'Wm3;.AL밹RQ=a&VgG@S2OULEBb~S%pg)5z^%QˌQM`É^u I_4A{wȡ`MעG]찼IЦmvIӂD6®Gmlv9in[V'O4C};gV3.}69|c;C^ʧ4,wu4C)ӼԸWst }B'|_J&+Ƅn/J7c=k'쳜l B6,:PC.>91.?GM!Wg{HLj|HҦϸKwx=MS J֭9ﱷH{mqeÎ$ @ [U;{>8tD7s^9uhv}s5!7g0'wW70QaIL.~:ǽX °8{t+NI%;qAc~Hx[XT/|9УL#p0cOCki^{$jYn$.9QZF%Ձ٢.4AW^zt"JI;ѰQ7|Q_Nx+:H @8v[dr{`e*ic@&m8MNG3ٞMRxxK8.]R% >yl )B" Zx7<j.j/ha֖ث_?0nKS'0Dm%/oh(F`Moq KOVr(:rE (SrE f #n+B aVS'd?[z_V=ÇW2.A+EG=W}D4kUԛ='Nǜ% h## sփnǚLpp~un؟*U)O'@3AuIp]\$I,MAjiR kʨ$0cG_p: ©?g=kow۠Kh@G*RGvzxn=y%-zg'hRqB?l,`D7ft֜S_f<ּLV^1TBFgCy ޫm#ȮbBhLvqq6i3=2½k Slx 6 }FxHv޼@)d#3ҩ\"~>[rXFw^bLS6Ubyfz7a{+pD3u1`J:}.g<׉p=˗]i9Gzꯛx:kNO0S觘bl?o>uk^U5B/+M^M =3:Rk5a&nn>!ygزٛX)D3!IRHCVhsᾅp1JX>4؄K $@s)a?md^hzqkQlط,.L]<aRnzИ)C>`!z& ئE\Jtd,oPXF%Ez=Z5 o^~@Ƴ$ʅ׏2 A 6|qKEqO30}}5x}3k[ hw W5R^NϑLʅ(^j&2d۰BxH`k*;:}a5C#L?e:O"^pC!NCF}ۚ*3Y`tnn֮_yL ֣tw܅.S*6JɃ|{'({aЕMJD@ʼnV9 W_!ltIDEM$RP6c%^nQ`s8A0[4sc" [7!M v{[H,;[*Tᷮ}kQL-hrCOV(lJ+.<Kb)g~ۺ_Zgc]o*^(P<DdO1{&pNPvE%xfPH\qo/zÐW5޹Ԫhى(0Ư_ >%c?G^YVF`Ā/*osn eGvhCM>$kGrV%ZomQ;CgZQ'獛).~9A?UPsMw葲yCw\ֲ*n_\k[:D~dyyw'QW?pCJuD$HFbqgY'9;=Wz^48@k\|Y0d=$gmzZF36v5ۏh[;ѭ黺x >v?7〜W?>¸f8pw@+'$}5V} Őb]m G8}vtݑhVUyNjŘ:;@AOG"P2$'R5G$v1̙EyE/o}NGhڲulϿWB)Þ!h/2DJT> S:^vuA REͲ s܃5TK7ٴZ 3=Nƥcjzȅp.oiI 6TX ϘI,uHBz1/["R85TL& SU9Lx3._) Ӊ[5~J}@mĄ__nzgQ^BQE%D8\ ѕ3|WX'ی:p^B`"B_Y f@ܒ1P7$H+NWKOb14Ra[y /1qؓuOSgK+?lp͘#oK! N&"eL_ öTQ.f[)3;Fo0"zK~c m/uG/4CM1P7SapM_쳀.AM^:GTo{e%d+Hue @;keL_ 2\/?|&OF_ak$rc>}H/eL_ öT :m3ͮm&g9a y,(mlv 5mI=Pt 1P7S%p1P7S%p1P7S%p1P7S%pРk.L|'V¶8|\=fO0|Q]mT4f@$ sfF on4y@/'wZ]B_Via[V?82dgwnsvTB^9"/( B7?DsduؽO={ |ztl,pznIf*+2k}HF0JRl;Jayeyizrȿ[OlѼL`m5BxSMxH><Ҷ|VC)WgJ xQRްq*9ߕd :6i<Ұ#mUD@kW*AX* &`̅C43˓@s0k [0|@'`;.n -.?Ȅ4qZ"eMn%//P 'ܸNWa` x޲)SS;Imo-F_;9K ]jV'N q R_ax$O -xBӯQ Ah% :RmKl+Xy%Sˁ3S#qhvD J*fHg'֋~u4rJ1_L uϓ=r ^wu}<h)`ÉRV{ʑy.gߜ0 _*H쑶BU}K:1ք'|ͩwwn|6^ZR1sɤwT"R[zvBʦ-ąm`V# gz<{Ԙ!# zr2 f!dSCd&'Fx$Ec,b7Jί M$:5;1 -Yhw+x&Tno9ɘ^^ (bfqjFB>fQ.HĜZۭ%7s'#J5}1DXGeP!PzWe#%`GTxͼ nv%mL+@+!4D z8A>51n;᫈<$ j]]ҵ+5Uel \qAp3H.P`kݼ I_AD8`4 P!}f~G1]_gs{V BQ. p>si6 -n"1hPi)>ŠG~-ɔț">0ehPc+"CgzF*$d6`m"*cF#j9u$h&piA"ZِĚH1360Vyh1t$Ќ]+/Dg[Si;lRx )|$;um[jzN[J3k=$ Eis*y'_߄&т1=jYmRP.{%IR(b_J[Id1Do5C8Dxɰ&T$ME| fIrRUDliҾ%f1 GA6b͵UVch}I8|H^J` OwG$9R\<=j K=Dh}]aqIѦɨ#D`LJ/DJx8+yq;L$v l@bNfx_Z5axLi֖IsFP1|Jvݑ@=@z{6kU,Nj]AXB)0(Y#<[\X7D?Հ|a7(wwZqb&g]~; E,\ߙinZwXL7lUX}{ emLӔWcQI2eHtj۹݃`cz@gPU8f&ET8h.,3ߎ. N/Y'Rs[ 1V0 @=6^{5JF6lF ZNǤ-n"6>צwIj~T1Kc;kjzn|q"I!y]ϳq6FuU28USurkTAL\&@ߴ1d׻v2V {J*ݪ$]8pwNioKˆԑI%-b 7ClKu]_IkimW<2r-[ .Cfy,xkF=U-^8&eRo@ #Ql׎|ς'_a+~0Z)5ڿzss'2!]ܨ@x͇ e, +*<2Gk<0HB>o( 7 ^?\,5 Z#<"NL1. µ؜h;Pyb rtG[RTX^c=1= 1Y^BUWq] 1+f9f7=ëPRQbύvlhS6rY=gZTp1ERq_p=x /,҉xv䋗Ez_1+ID?'Y-|#cՂtY<@P)kvi/AzGw28fR;b atl' ȲDd d'쭫hl$vۄJsk{w-^JQN_JUz$ g=_%*v4mےI5L3&ꉻppmVB]!jxF(j[:C Âd)f0>pv@Avct+ف3 Ź9K]Ahۦys# oݦ4TL9>Ͽty|ԣp8-$IEkD;iRr ,N酎c=&"".΍MIlL62Ep7f蘆H{ fV&9ƒBoj1 oQ'}[g5!uI_ ssjFsZZկ+|r:gX8ρ*ȐEx_Хix?9evE3[F}s@úROCc"oJɹ% - +$s?4*K| U',9V m+.V(#Y֕DU-3䁉߫=nn$Z~kF-rwo,}m4rbN:p1pjݿ^nczqY ǯΰ˽>/q[7`zQZXr= 5FKχ/]EPL=Ir'{=M )5~'/4i뇬s}0w\:xtܿ.h(H2du6J4W{Ϊ E=ww(&gߖoNQd3"߆E%kUL ;à)$Bs6Z6rKO7FK/ + C;<5uY*rWk&ᧀC)}Q܇g*D=m/anQy̖ƥZ) we}|{N-Up&mkX{m* aXGo6`7w{Y$Zƞ; {~7 %عhmƹъ8%ӔT4~:ωn*IJ@Ul_jt[%2'mN&]tNe۹P"?WGKпShPPkR+wzLTcVndcTABHؕ\zsqTtƆ{e'IIelN@|t7J'#{az3D5T`H[@'FWk u;gGkF b%^- GZv k| uz]sqpLZT\$hkl坎R6&3EgJåi5PLLᄂ"5·Y5Y'܅G; GZg*6ҕ/*"e TcSN]Jڤ\oQ{^5t'8NԿv> CYσ0phu{2 ׮0LHȓbُ(n#' XZ HJ:jcNm+ ,mՌEuO^-w, B6ny[ǙƂχ2ô4YϰkEE߷|xBoĿDg^?D<ޢ+ OԝKQGyՇi*Tڤ5ߒ`4V8H3CW^ */r* &JyyYεpQjJq98)м)_0îl\ăwE[isLteY%1۬V=݆Ež 9 ȗm@R`5R? xû9MI4Hh3{>p5߬0ش`!Q P@؁=5k1u?BϦb(r f7l;_Ė&8 񰭻FƠ77'F7W(N -THF nxZ Oay3(޳l +WWbFf!MX|*B.d=H"hB !0'!`S=&)!Ih)&%E1#IJ. @ڄt+|:| u!WbRvFKصS53PC.-(}>ڢ4Sǀp%D~,Tpٓ? 1(+E$.Y@$,y! mci")}X*/']TI<℥qtv,<9|'٩9?ه|ہ:Kyh%(CZWT-<)-`oC9Rǖ_ !9ׄR@lOO_(%ީ>'u`ȫ~NI3;, 2.y(jЦO1, r j8iLYLu|?ězb̮?7oo#12#,bSSѮ?L(33fŊcCD54OH$z`_` [BδL|HjhlTj,YNȖIf|?JJ:N"/?`Ѧ%']=Q~¤d7/B_\d!ʮ7GtׯLm}ʮ(MP˭eb諸hVh &PJuhpqÀ->E[pʮ5t8/Ju{zu6G{HN32"*q{JUR4qsFHԺćeB%C5vq"3XيU 7NL Vd_NR>!좗zlw (ׁ;fJ :'N>>2/ʉфʰ=N2rxOB1;k6 5]= IK? LaEfIä%Z;p&0ǣ28"A 5c8Уq~1+LR'Ȑ0nfPLyg罏&wxI{oO1R)G h=zӽ3t$VٵBsgzLzXj%$h@ u $v 3kHы&vz0p!/14}@8ܬZr}zl3Nm rmʣkRvmQJ0~:!PT{Aoɭ8`4G} DB(ٜU*e#I$ݠ*V`ڤpehqU j$'t:/n{b+dRkKDpu./u=C(%ˉH5)l ~=:4ToMv!`dR冀 YF;.!eϬvDOsDJőVf)˶}$ty{]DP!gmzzx灱RзUk$Z?9S %λVJu2;rbyE/j+9[s#a\)l=S#ә@|E遧5MR_@*|kz d#2raS (]oZH>R[? Tg:$ft RWpa;O[=<5l 4';N9626f: ]ɘJfU,̐Cj<+lX?ۊ0Lq o*NXxP 6%h \À` z@{)AF Y ٩aŹI0f*HEEEѹ; pnloeJ4k08C[!@3ܯTꆃ*m!Nu` 67q8< a)hQ !ӫ)aE _sL"ձ1Ȅʼn_=9 l ֗y75%9Ӑ Wo eaZK`<6FH+֠ɍ4=!..T ,mܷ^l(wYւ|v̓7S!.l̶Xc%PIݵ9kXsԇ) ?ZBdB;HPhFzvRg#f*FwSFk剪sF~bÄ-jT0ec’*iKw.||_V $! ) ? RsF'{g4XL~f2TEo4lI|԰З5+ $vA.;Ny-2dNc #Ěр'/v4$jCIǿ%4/̃Zz&:~>i y=N˼!OE5,oK_)m q8__P>ߢ&[/U "m/Ŋ@v?ow &_>G)vOqo] -D1naw > |$ȞJzIA9?P2ZuHk$(DbFU,~X}tSw^-=x*ϰ&+@g֒',}\ IɎ~L'Q\.X$*.&(9(nBn#':h̝ \4y7joFI9}.HPc<̫RB\&=Ԫ |uΖWJKJVBͤJ+ 2_ւz뛞!7<#)!` `#%$ @P; ^x̆0'u~JLhXPz)_gX*!4MKҸZhT^^M~ц5JeJO)23Ђ ,Шt*̓cuzAaBfzo% ,cX^p#<@ xu8j?8}839m;):VMSq8L9Juu~\S-d-c V̧%f3z"s>GO3hF_@r.rSIz}FJLM| j+`d^XnF/rڼ*xFTʞJ4\d' )Oqɭ[TNL񫢥H2#/dUD<ə# GYt1!(D8׀w~6&72F|lsLK8[3<`Z;SRq̜U)Pr<>MLOY/ O/I*u b圹+Oys+-0,Wg&lW|;d[ebn[3Pdpr 8cH4D-)#>{UmC낚ñp/{bʈg+\Q]`IA_ jZslÓÒ&cI>ڀ1 r2[pg-&OK7 ˑ%|>b-_ TS?4b4GdV@ 616prDaGh KH5MVX8xk.eG3͕Xnrg5bnN-_t4@6ZM5pm>hé(4]< wkQ~1n 6;q3%rz@=o] D$kףS~&Û_M˜k#_42_R2i@AFRzM3C!2>vsȳSpbV/)5< Nqj}0D4Tk95(!/T\7ɦWFo59?[;ȴiMzZ#BP_RZ7kA@.r$-8LV-je%$hik|- a&_`R7'R{ < PBIB[63 Vehӏy Fv E;m3<$~na,e2(_\imFN~UC.vh߸E!ic-L"#7k^?1m*e^\ֵ×Ƥ$8_D (iy )f[tT?/{d}o,D뇁Ah3W( O|#&ׂ$ A0H- +g'QZo>+M^I2=HaT`'puBjjR$2aV듉6ZCD~{my+ /o'"L)[MOln|"[C6SGjkoo+-Ek\ O\['pg%FO胱OE=vO7tłd c1a "y51(D漑mG@FX8V}zzS*bC xzN3igAsa;y{ZYGAѭ*"QJ}uT4xB`5k?1[e%ǩ@=UN$}>9w@țLr6D#.K}z/#]Jc@mfU)M!7c,VI2!(A1]S?,g)?֎dK٢H$f0uK$WpЇ5F< y*VVxlٞWue+?=^"Z3L,k(CJ$Er[p&bw,{21-"=̠YS ,lŌġUƋH_o 4џd94!Ha Au! rwgBtcte+i`#nxq@aXo'֦b٪U A 5"]:B%e6@t0HǗؤToWWqgD0)d뢞q.Xp$cW|/Lץ7G]YdV`4|dIٓUmoT#gW?l+oM׺U̓Aze>Cew IŸA]vjj%idDˬ6)o{ ݂͉,L 1@KFMo ,dSx 0ئs|7hW  G-sBm;jRyA<QcdM?Ltnnp<'PRCp Yt @K^z:Z'dϯEC=QϜd4;I?T0?  >Uzrb4 wsLjsspo'tm$a?}d+C, d|QWovi5 \1K V:Fb/ ꮲk?N#,pJ1$k*Y[?ߵ2A*-+?"`iovbZiR0PGGIʲFY!;t7@h+][vGFXbLJj\30QAMKnT$Z{\[ pK_Ͽ5>?|w/ M L7?6VӳK -ΚWN6pk?KP x h&W>.)C#T bSɥpV^~r)S2&uW#\HB:u 98xS,5WĦͮ ԜU؜0K.žcP2pXwMAx;&:*4y/;p.訅b]tJܼoI0y[EUJ φz42.+c puHڋRL'Oyͤ3G8Q7KIee,m1tr!_#m4BSku׻\WbkOtHvR<ғ;XcԵ!c4Yub."ϼ)iq$F]?)9#3ޔZG )Tf#6''soeW%!TkrxUd{ q".sg"lV/̼a|AkW'6*lЁ -b>̓#q.g1NXrEd>[Y(w$jMD13%Bӌ\5x- x#)wV؜5{Kc >+3矇^l Su'Ss2'w 9F:ME j-h2?jLV4:UzRqa&Er՜X?p U]nz >/PP+']|L™o&BNisiBNLrhucA 6N_[7s #9k`(uP{R@a(/W9">, 8+u7风k/ 0?{߫-<bnGF#vTj}7O67ܢ]H~UOM;H{&:ۨ 3O$7;:F!s^/ _|M@Jb YyJI u<?DJ)$Ӆ% "#y#Oe]Q 3[ K(@?iDjDG4\iѬ&UwO{F >;6wl/(Pf 3;Iel/aC>31Ն+BvTT9cBRkEsn-{hϘC hVHs)4֢i# Tpovuc&21[ PǮ2X?IxW ,mN}7pczCW}y紛M;bF;N[6UfuĕZrUI2H\Gc; $\"îdKv t  ~g) fUo *"&i)IWɟ ]?yº.ʅXh>"ͭ։؈T@Nw8=*F;=M]vN n]r`lb._Te30<;O`8DѱS@aWr Aq? \v751vgV,`/ ֊_.RwC%dVncQ*vܠlͯ3ࠒW$[I ^u\\L} h2˵:T~qUmXBtKKnԝAW4*t>A}p>"A'"נ$e*&,2FJțI`I6{׊yL_ߠt|,x>7RRoZѹخ0h1_x=ÎB^G]ќn) c1$ԉvrn9-oXBA;@ݜ$P9kܸŀZ E:lQlZ ̀ۼ|3Ah9ňU+Yri-A?"@n'|VlOK4/ /iumJEHC_N.6f t1E|*m`_4J7,7bH~ !yFf$k@OcG H# a8(1X_mDNMŐdE]x=v-4 ]p- )YD 05<, uTQ::v@MF4bנnNWEpkhtBdc'w$Z;jxԍׁ0^P&'%psB5v{rنcz6:!xkl`OH5ڞH'c O5nɪ3qH^jrj!b=k~fp-od)Lx׶sFe)T HtME;⋡H&S:q9ף"/i|b~Ad;gJxѽ΃Cwt"oO_'{;N=gy hw:C7liѪk{}\;l` g\I%bq v?I.04-ZwMt~>,8H_pPیI0D&JݽO;\3?.v9?Ns*!*cY~kw]$OGc\9geں>_y:Fg%d]ҎM1Opͺ^գB>F+HX+EѭZD`R'e A&.64lhO H,0w.(]v%…Jg 9xʇ1i!n˨KS) !!v+7;uI3>8!N"+iv ؒ6Ih9A8fF<Ս+C6w菎b s-* rEq9[*mhMKhp&Eר(}ų}< D[RxR3+)ddP5i'&o4kʩ=֓ L""Rb*, *0 LVxd RDi $.x:u+nˇ›S$& IxGJ_E"6E 75hYʍ81)z[3SW uBL˟ "pe֫lr^:.O[ti)_Z# 1!v8M!@N~ /ӧ9]\03 -Y!6 &0֪%STַhE00-HN8'n<ڏ Vyk%9rqD{58lbX}-w_·fBBd$].?`mCS5Q"x$ W_VYxrn;D? nr-'ai76)>QcqM#7 x #.;Ipi6-u^ljD$ |I !ܹ`˼ ("s H!MF,6;?+x s9l;:CxރT|xv"2HH%k 4Hcvo2OHTLUes vo~?^0ke xs4dnI( i1 S%vW%|$!чѲ5Ţd}'@EOrEupjʇ% ćh̋CZtB>f6kou%z5|=sƘpZ2xA:I %? AKy[*R1'T~e/j2k6qs[h;ZPi6dP(lʅUoM'\ yФO]PoTM}}lK2($*3c1A,]QHfo)7T<@EMJo&GS+!#a|L!g`dZbݬCeGl[5Kh<8@֘.^NX#.D vk~DlDWzZ|87-h> Eiz푃^uH`7}}NQ5kR]P|?7<6ZI1 vfILD`).6vKeJ7"AT>qXU?< 2ipKSi{qAnR0/ҽ?76NF)ϟ߂/UvͰ+ruuG"s.#ɽ'`751y -vSo9]IجX@|Qdo\Y4kݫƼV6( KaEl9Rzz^_O0\-NRު 8Hņ[+ۚB+ 1`/hm6);,~Sif-Bb^nzm8"7fwǙ?>,QB]=q i?ݩdQ1 63D5 A[<=ye2ō& |En f-SAb7 rэFr=f%t2ݪSr׭Q8)2b`Рȸ*Xe2?]Dm.S8ȥE!LX_r) ,\XK"šl R_QFC\'|+A jdy7^*pZ&eZ9]5+$?3i.cTnC)ݙ2=R.p9\YD=5+~M]5֣DRA=O^JΞ #MA!̉#+U#tɳZq-}9]/w `k"(fOڅ e/ߧ0 g$ƷcQM1KBwS2$eAZ r$IiNY}yHs8_j/W^휿,:db%EEickF4MWc%}0:(}cIϲZj9S|Do؟Fd.gA5%q%:P躘i1OXɚjת!=~"yV1cy;H- t~!={$hMXΤ-n6M񧳻J eppH.̕uYgSƹȶEpQ'TjGb9Sr9.ݍ$=FJ?LMt=I}K4_β)%XQ Ɗ7VCdf}b\E`rJ&KGx$pLR򕖘@iev&p #PW(C:Cqmb#Es-rȉdD|6uhN@o~L@T MgDT? Rj"Yм' z^IPd=Q 5Z m)mѐ/,2"N}z<6+ɵTS=l՘ѯR/گ ΙBUӪ]  b8]-lYLfL>OrTsQ37_x)?_ԧcu™vwgdž F+5QBvOPV?ljaFCXqf)rwș.h"2XxBS(e'ߌ֡zacI3J%UJEǸq}C[nJ 6bC- 8eMH[%bY 51@p[<-/pk>?>Z%J3W*/uN+s4ǔ?p$2!g\MjbrѮ-[*'m9(w^ k`/ @ SVd-乱 /͐wrU[=a${8z zGm9T'mp`l ?~9DWr5²QlI|U4,hCRd0dW&>$(u ՜p,VP0!KQw)WF-;$Kxvy!9F{VUُ:%/N62́y#1[L_Od4zz{j#8̮ E2c/U $TEcYn-6N);Kvrms!PoL1Emc7qu\ (=8RR3 +Xv!6["Q 0:ݞ 6b>*iOc(eʜؤYx.XI&o+B0'e1 Mަ;ڸ}c횑C\q4SO[ܤV|DXRL5-^de=~?(Cn%K.B#>5}7dTggT@EhA 6Ҕ^Dg=^M7ݦ.331>M(*l(̜gi2z:(O  "H@}G;%^EO聹ijj<5wKL_*+* M/ذJ(&C7Q?V9~Sn({ .dVϟBq~GY c#4O?oW c. ؇q0M6 C-P;0JI)oq4>VSHQRfܢ` Av(yw+nY\]9Pt<ՓaBY 2XAd =.XrQ F5{aMHܢuUYSVuԨ܅ հW+úTCwW/,iaag*𿜏HX:G!T|o.^X;amW* 1zY,AV3vgTj c6p<*sqJ8I>:>!.#pa*SG 2x12pDi*P #5<> G_!/J%8 CQNZ8d-1oCR}p>2rש vӼp+ST#SՅ(8%#6S)x#c'p@S*їa8`ȕL}J>iy4*7y0*Je2l>JTfO%<'l'2芧PY [R TR*UҨlR*uJJm{S]@ ?a[e{A vrQƺRMuMT}`.-0ڰIDO3xhJCTշa: #9P.fB(tlN#) >QA=(|,+*QF;)W5u)ls#@ê) ma]wBz/X9X/ c( !)h`DJg2̧)M(] _4 DQX$JJ)MCi~V%US& p|‚|#>itD ؎|`rBrWeUnp/FX|RdءWJ `W== U@U %JqaU[yaAJ;<ұ̰{ ^)vf(* !%J`v~օR#Nc@9Ϛg{W#óP+3.P< u(}FI[솭{&`boؽ7^ /xnB8d@pNo׃ r?v(zSQxZ.^8+p8&gp- pP;)?mۆ)_ Gm66R(fK4eYJ|0(MRU0|a\00!::F?hk}S;?0,3m%Loq"oS5A4ANMF CVP8L/"mri DlwN۶m"y׶m۞Nq;iUzvDz O]~5 T nkm-{xC/C״lj<;SsS Cc( }( ETG@k PB0lhhQ:qо]~EfQR|(]*a] i)pUJNi:\I15JY J T C&>GiZax5bl:Ogl( aw ,6./`5i0~:URwPQ؞Ja4K!u%)0N QPXt'TPܐ70# E36cj@P;aP x `6 (G, Ga(t )DG `: $BF F>R8R60YNj2}BJJ! R1( Cߡtbg(D;q]J BR0pK)S((N!(IgPtaݣBKP[\U2<9+͠s/(u( $NP3!Ld5+Jrp7sZG }Ub?)[&*Մk5PnoLCT$p#YJT6Rq;\z*C<xeE98 R;kuyrt)4-L>h"2_DśIД*!TP Z_SQ0y !*3gRq$pT«RGKTa;~ /RS, Uo%۾]Tm[ Pu_"{lLEd%LGEx%soQd>!?D0!@ USwoĴ9KW`RTT=Öz2QY fSs?P?&RBsg()pu<`h;3A#)=HOƒ;lJlx$x7AC*<0P<l ;e΂[(\ vJ=wiJQ1/0lH~}7?(lB p2c0(\H!~?E(̤wt 9q0<.Bzk ` SxƿIafYM;NaJ `|# +R+QzB*Op,c Q8cq /NR{)$lP Ɨe 01oSQxkaT wu0ƿJO `! K\(0#(|G0 o'߃0PfD) [RG(,oS8{(KFQ5½0x&0JN4Jc`JQd7a# $:4 #Ӳ)Mҳ0J!Sϧt= ͔@lcS P[A^HT3ePTϡ {RN E)= e 2K^pv0CpTR`Hg(΃2S0x16Υt hC)?H a[yx#!s#n $ʣv[.uy7oF(O?VO+eR46sie9Ѿ a~OA|^Oy]')gO$A_LZ*Ag'ʑ{G>gg(lO7PGAT<Q*rB_*^z; !MŕA0/T.UT&U;K-Q.TY)먺2Ej[*L DbYC0p\>U[Quu̼1./ Sks`n XOth?eѿa~Of\Et\Gp͸=B|4~|({̂oANMF CVP8L/!G&m wOBD"wO¶$ضgwǶm۶mZ۶mm5]]ɟscpˁ,_pʰmE+NԢ<n)&VnPp5טi+Ǻ'#qP>jA ~{v%SJ\=v.v|_0Q^}Rq$lH9.GGց婔 [)oDZ[ô^ZQ~;):>ͻݡ#۔F;S"m]FIա @q=:E*A2EA5Fh,wq9PO9hr5 !C O_Szb|kŠW4.|BZMHQ(ΔކP!pc/-•aINA|َnQ K2F3BBdDl \*u)R) S+ Zpm,oD9^Up/&ȚFa ]Ca>PV2h Akb42QX cPh! Zao"h=@ K`"ZS(K/ K,R kSh!Fr<` 0: M5}XFi}eXA?0_Zc9Ga1ZcgayZc"aMZbX :(Te(tD% `p ULu KkZ ҏ2 >LdC"c0PhFa.C-2bh~Hk(25\J+dͤ.0Y#^ y U{ C`d #4 Df {$ ]a`o )`yŸ>˰֡4 WW(|-e0l=XFUL#䶔ޅI)J`JBD•|0&U 'G OioR!-#nєNNS;o))}{5R(D>*rJ7KRZ Q6G}O(nE)TR GR\'1SJ KW Ht<[p8qh(N('oQ|sOq<\PřLCK0`xnXR4-Jq)t^ jH:PB')ތgoR*3˨x;b_b5<4#BTkʑ4+@K)'cQj^:@9'wx@9+<p8!Dn xE*O㼰5*gMőYW*~.ǾJ͖U"儧;x4 6z'Pq O S)oird HG!z0U*NC(7rS,nRq">dRy>C[yEYCT_9_*w{{]a`գtt:|6ndkI0ڸʯFʑA<ߧp?%}lϔ7ANMFCVP8L/ m#Q B@P"IߜƔK7l4@CrMml۶mvm\R]mQضoD|g9 =y>~ s V潸 s{Ż#VHx{G0nүtRp]-yt۴i4.2׷Wt7wtV[3)J4v#u= f@HݱpY:)a[o.N G*?}K?:h~rJ/5ivrC"vىT]{; ,m/Dž7&rpX;9Sa\~" ͤ0Z(ǒEr)M9gQ.*MgR:.[EʯQ(Kuc:}VKD16^q:Q8CfK)4J4+F'N{:g6;͎Q7(i?tw)mQsu%!ʡ>CS-Bn]HIjAr Z !ȧ0CR9T ڧP(C A|z xOOm/^惬Yմxtx2bcZ mT jGn#UTgTI ]]u4nzF Tx9aJ)lL+L =Mj @?Eu& Aʧ6_uFpj]z^nN<_دTuTC<`bXH=>xF3kx*3A[%9CuBu_HW8N!|ݣBz 8Kj% JҎmx7M\HHnuEIir5(5p[t6aLJp]'՚]k@à(er) )z *c}AQ(~eASѝ 7o( C[I .U|axvɢ~> P[S, 3))fÃ)jSʯw)/፵< ^Yk)'Qs-xEI('a0x寂4HyGih/7!xL|24W:H<&P>WZ랥(l S^/O(^X"yi\.gbcB1WYQkBp\B9:>CbprxwUʙ67)_i M/Pwr(8BB#^Wp^>Ub&fsIW%͗k`m޳93@B9o ~r (>0iV }IaH-9͎0zڤ ýAwiU&=_]hit>5=Mg202`l:ȝ [0?Z>$rz  LANMFCVP8L/ m#Q B@P"Iq٤oz&`vjضo;mm۶m۶mtl۳6ƶmaܿG}yO&/s:u;H_]'Na^R$MޤU95ВkAZo-o yCw Doh3>8~ctcx*qlF&N9-CoLbL>C~7;5tzGK-Oxa?4Z^A[Sv,;1 @ Mq}Аj3{y_Z\_ %ujW!VCٺnv}&{=@UEŗ~isBW5O1uM2>Պef)!&m)-!zQm燍=N*&>KݭkV1MaB-V횧hbh2lCj9GMJX{FQ ><"Ɣ17 aM2l5)`[Q]{4mF)])>--"ieh)boXfEAnhs6w( JrC[Ǵ|ڲߥt CcxUs b;@kwCkX AIi47P )? <=RJu ( Q 0p /PIӋ\p{B|B38?DW3 )To]iL, ?zR·c `dY Mq6Ou>.zT;NTcO!' A!?R}cQm!T؃T`10v=Ju<Ou ~:P cRݍT[VT,0 ճ8H5mK0~v'vRcPk΁Ө$_-T'#+00ծ(M5.! Z)Tũ=`h_wq#C0'@,|Ga@(>zR=#PJ"si ` 5sjLf=ջ|1<D|!0,[4PPXPj9 qE`T&yQ"0=j )IŸK(,1K(Jb20lFXe~KFQx (c)20h >بp'H).#(]GC|vCwVxx 3.ps

HyЖ:)$((M%R> I#巍ʿ'|[)nqw᪰Ŵ D$Z &bGB`-f…CR +[EQWs_./׍`J$u(1j,#hq%;\wZI?@JܷwCw[߶P_I0m0|O9# )$h2~7 C%6{ER¨ٴi ӺF30~RFf>A'3ЄkhksB?q#`tx^g:Bh;ӏ ӽANMFCVP8L/!ǧm#i B@P"InIИ0_mۦ&IP:H۶m۶mmی.fJ+>QQq}wwDɣ6? ͻ\ &mzoO];w2QVP:UF*Nz GWWc_2na:9!TޛAwnwMwYp]>cs/e4svnVdL L5zƟ'a$*M^92M^2Ose!{_, @ :Iv꭫g<~ڻ>((.NRn_3k౳WݒE's - o(F>(rhV׽BO8zɉ|.tAQ|2vև{ӨN[]&oCz6ԤI\jgNR7UnR>E9| ܔ;|&$}Hp$]n;HRpp/J}2pGM1F;ct3"'AW-RdLM/BW(Ef07)LU)u`r&űtf7Rs fP= Jo`./a65PPȩqS,LWΤ_JJ`ܷT2HJP2'gEt^O]+PQfR= '`U4 AHiGi()\MEMSxbxB'')́5s(= Mr’*ԃn''`vA;Ѱb_D)*,M!NrE~8Ci-|RV%8NF[!ip"3Ui^yR(Հo8n]DA*+0]+ Z—.PngSy\_S ާ%Cxv!*3aE}/7?#`n9+aG`4(-O`6uʛ ߈2S7Q Wvx5~G xS$#.pߔ£m5Nh< =H91lFDx fqr0^ ʙ-u4_T*RhP>C?(g)#s`G>_k/U|} FO(G7Ȫ(O*O_\SV+1j^,-x5_քQsO>NvpOʱ=0Kc2ueMp ojJ jzɿQ^h˿Lɦw9?SEu= j.M8KG9 yJzŰ_>56Cq/974P44-`Sn惪+'-)就OOѳe`0X?!ޗjNK7d_'ANMF CVP8L/!mqA @RHsEK|hH<7l'nwߵm۶ve۶M*N>5yqD7},ڐsÓCn1rƲ-;_8o "v}_GԅƋ_b I?ȧȟw.UWB7NM޳E/:{K<W2]Sߧ3 p:Z>QpuY&B[Xvw DX? ޿S!vO{CP]j a\Rәu-3kl#tVߏdYtv\:G')BF}SFOp= ?2q:sRT U& PY޸8([̠2#\͢qa8kp!U{+ւǵOQqpB`QqF*J1{8[~\z{4u~wQi%O˔t,:n u? bVW0w8t$MyS|(=tt5X GxShN(6RL#hAq;5/SzZSSq=>N)'(})ި/)=m5{EitW;CJ(_Ca7.E:m[^gE, a|Zxg67)UA%Z E忢RZû,ڭz]06 qs#0)/p=:?`oDZ7 [`& pm=05 ̡m\O0=j-0x3E!40)T 1H N0 hоh?ӾiGh߁= iiOzڏ蓴obs`t&0H, >C)4 ( F2!0*}= Ki ?I{K )0EV\Ia-K? V#Zpc5[` p~0 徧0Fʯ;L FaW-0P\ g(q({GJ` J] |ED K:K+H(awP[ aT" ?BOR?(>4MT(c*P=1{(톺j7 UP:#R 'o(È'(}g)DFq 0Rf]J[4f/yweT._ϠxE)|BJU|J'kOQo )&Bq\D |zp%BCWÇ(^j -,Jnj5 R, -/Q_uϧbbxQ\?Bc#3[7m()Y5ORQJ.yO'M2(w3MNR,YO%(Ff“eO Uh峭i36( uʡ SD9) ' (?ǁt%Sby ڗX GziT=T<P:7iTmRq+|:BT+ʑ<&_RlR 󝠡%SAyFK Ç])˅//[ePh.wSq=|`/Wר8 a:|:YC'סG(x"'E`{rd+ OG!&JET<ZCh'=`HT\[L*71>*> Qv&H3Q0kY){C HEE*.ա0҇tqeN#`:* S0ڧT~U Ƈy K.NMs,WL]O/ô?>h \x'xiӀ \t:urXh(>=:pyM;]﯇([Js1Fep-(tιM_QG‚ojߠ+=/xȢcM Qu4Jϕ l-ҨzCoRw,D?GR8!:NDXޮR1j\u9gVn_Էz+[(b_zwR(-_zrRPO|ۢ킈TvV@7m'T[}H?m?š<(Lk4**>|RS1Up8¢؏h˼(.N EkUOx%ta\hrbj8o*BO't=S65?BW:x|Hq2)}F||D) ~+BTw>ADA hMʉF@B'tϠ;G( i:п ~hNi~/h0_S:B_0ύ p @9IMs>6ZpCfEåj!: Z .k(lD(4{N@>>>F]Ka, Marߣ=5Si91ɴ c_=%٭(L)BB `lU };06'!/h7i7~Y-'I[QB{܁BU4PWm)rڢ'0(B/08B?t(tF `py QBS\B0P Yh_ g_~{d_ / { 푒066uIamK;hJ KP߿zv!#ga) M{zYY:g? 0r۞½0hbŸ>fSH( PX{ 0nP )$Ua(T!Lr \ʤNI9s <3 wV C࡮IMUj6-@ L1y S<%b<΍Wwܒ#ANMFCVP8L/!mq@-{wzD_3qoضmmU۶m۶m{l۶vjԮjL1c]8#ΈtGVÿo聙* ]<ɶcgxoj?QF xh/{\A9=^ˣK/wHwr5Pn^˜[>勵++p'<^qO// θl;ʁl9:>Oӡ-}Vf&ɳc!;/Y0Pq~42o 7e+Lw_lzU0w?K/gV;lOH/OԺ׷@vg/ulinKf$uh/MDݹ(wӷԁzL xqKkMTjԜZQ^˭@͙V1ԍK^G*OG\'K'ol=vO)3ť09˥n)LΣRdav55#~@Oik ~Q}Ci )\ ӱ/)dVs2TEduOiw~)~vDPtp]O Hy@Pޣa Zb>ռTo8(9jAN{dwi4U9KPW nS-LB` a| CP|x:,MS ;۩B[iAa @HDXRj,Φo>%էaTEu,^OugŰx CTgT:z8 x"{΀3BXSo/g?kϥzс.EM0*v ;@TODa?TG| ]`iS Pܔðt (vS=WV8F5W0VN:() >g.9B/XחBQu\2],DM(m(e) B@fXu7.>5))fE:&B%)͂5)=Me SaIy S[BX~4VK] gRaAY Em1J_FwG(@7P)oC)vAȻQ R:Pg*Nik !.>إB %wBU7JAE~+/Q lyz;bNQJ(bV"BInHYD??L@bQܛ3 S|9E^x>Lȧ8P, sS(߃8Rtʷ $7SSވP4 Gߣ!XK(LFw`7#M *gRA:PG43Q} W 7b$*d?)JO9&vJ0^[ٵtM(CyjCڟO(pK}aʿ߄TF`2 ͧ' )ew-,w)Sa*65O%wAj/pE Y}j^J@؜[ |@}Bȥ|-|4>L]pɧ(xwr$Q<mvWKCQjNFfR3/]sj[Ap/5*#챧oAy$,XRsO:N1|ʾNMx5jLjNw=~@_aSqRE"E}QX7!>r'vGX{ؙw֒OK`|j G9n= ǶSfYϺ9aANMFCVP8L/!ϧmy@Dmf&¬Um;#IoRQ{l۶mm6Ƕm^{ǶO=¿SËæ.ڰ{)C_XfR]^>uцORǒ]X\yqu>[ x_z2]CQitYE?˺G#f^Á;ޝF{;hu4)B)B&ґB$ҹja2sGLLKB 0|ULW D1(( S/PDͦx&̵ˤ8EH"S)fts(s w,ŜaMʣFBy¸;H#(ta>z1.uGS^ <)#c)oȃ`o<3EOJEyQOywKCyM~oI2i a3Rlʿ"?R NM9 >q`q;/(oG8.~7NyM>%f.`lK 5Ӣ&w5 w,j* [{>lur| ʗ#S3, ܏9Q-+5!lj,0'C;f5gA85svY/C|8r,7)yD &a,5{J5Ԝk[A 5U=Ix ܠfK*lAݘMefW拰Y86+;x꾓M9yj/~*ls ~米TN?'WbGANMFCVP8L/!mw@D*Exj۶86wl۶ms=mFk۶{5m4ɛ9 ]ɇ틷׎jF5/?p`W׼|_C݃"0úuk;oͷߦk;kݫV#c[\>zd.M8Eg&D2~L>D3MhQ9:ƊJsg4N p&/f52hzG9_-1x-PJibV0ݤcwH dvn$h!,~49^^*UmcZ#dսB}1H6+Lur5F;RRUSwm]m-ՄRI[[n J|2ǩ\ys.w52'SNl+/%wQw^ E|_xvg(* Eާ {O)/}OEa"%!ltPrftLf+%g̍uu&$An&vL΢4k0ayJ?BK)9̆yfsLiA wt t[D Or%Hi((|.2[FoޜB!|i,g4| ^|+N oG5-/Px=Ba8ޥEÿyҩKAf' ` S Vt.EWT)TF,&Xjjv=)%(B2,DuV_n˰%|Cu%,^I$s`\$,Dui`8S'P=a${~:ϢgT7T~oz,մ=Gjr:L!*L$2_z5 KC' :&"mt-Z[yaeKT#k9r4ȪOaw()t])D~})FiúBR°,s(eRpB} @hPX6SpBz½ Ay¯aXIp䭔&Iu ’2(\+ >(=m$HX1oa>p,,p½zpҷa>3p Jr]7J: p҅t˔vuӔ~́Nt wv(DpC/QJtu#)x Jqx|ҝdTJ*k/ ` >"\@AF0LG80S27#P5+T ;CLxŌ607̡A m(C@Q)B R )@R~# O(+(RGD zB)_n.R](+;=`-)E|_S?Fߣs'ׇ, @h5AbPB Rf o櫂cjEOef[C3~Gu۔3"RvV*4=Af'Ij mԜ J&EfwY;GԜmMc|]Al&c,lA /v('fÎ|S KM@ 5' ~j7=Í]6~g:>zrVaTzH럤S ag5atj>L ^+iTRF̼<$ANMFCVP8L/!m#aA B@P"IӘcԜŘh6HQHٶm۶mնm۶Smۿs߻o~s% }F`TY_LZK2- zf+Ȧ>95`3ykU x;:.dj\&L?.ߟEwօ&]`A=Pa0fo\_;2i&p,Lu~hmh0uC1M @ɒۣ'4ajWi9fGi|wKoްpʰ#/Kt\oݺd~æ.t?nFP|cy#m6}RBmH*!7\Z!p>SkIWԝ\Njl9A]hRsqI$nH&wTj.g )M[)_!nbRNk 'U|#>Ft۶?P>Z 8{hS,Z 3Jt-, R\ ]J055H`jDV#s-s# (}q>i092WBi v:jn-Tҋ0}7W0CPkQ8_#ߤӕNSȯea0Lb}TJ*]wr(ģb 9uIlN'53),G_)G#6x-xeO:|?-_Dó.2z2,}B0NeSKT_@EW^BS `: SkSjn$̥~ɰ8R}@ÿo+`J3΅sQ'S QSS GQ QP-Fu,C5$-x5sTŷPEotXLyTI6>Duy ` T;գ{? ai0{P6AXXP=+P͍ÿR+GPx(|+ߡ0qYT`a0xwWa[Bva)`[3 _BOi ,Bi<Fê @Di3Ii:/r ,z(PkfPzE$W(@w`cn ᑰbOt,q8y-J/Q,Ju2 J]AJ0)Iu3> iJFQSiK(Fq ܼL)<KJ:G?|:0H\5lF)nWS<^>y: ]w#ߍbާx$&^lxF0ӷ 0óan.;aAʛ͔(( _Q V)~IP kO)7 OԅSO7Q޴Ly?HߢۚpUsjPs=\4;J]r})Qp:vuFr8Zʤ(8ss|m+\ MX[hB͟ķqP 5U#tw"jJy9bd3lMQ[j&gIר6M9v>Mú-%tQ6Τ㬱Q:<V}>HJ  gQ= maGTJNBSX~ANMFCVP8L/@!m#aA @=_$BJ؝{1&ރڶm3I6m۶m۶m+NdFyުw?G?;{?uIwozE* ftqL} zf!V>.kjHEQ_Ua~3%>sB/=YBGo M8C϶ẏ֊X(ǟnỶ5iy99w6LuAs@a #$hlmbUQtʄ!T] i~W3(v7[_v^y{D\=;_qޝzr+[P>~F!7Zaaؿ7gԅ\mڋF'(uVTRWɮE^Q^*,L]l Rgj^Ӗ{ۓ왙 ĝć[SK֦OMQʧS..~RS>^} >~mݻR?az~4#7@b Y"\Jqt-K) Qe S( 07"Jml4*Gb`rbwLRZ)0`v1!Bi ?B.(΁ț~΂AB'gLߚ05FN\{~^v<\©i^@ SXK kP(/A@)¥e L>P脋QED\pQ-\W~ɎPj #`0 k| X~;pQ} ־@ӊBXB `mr`s'~TRz/ka5T:ϦzxXu8I8R>A?IT]lɄ7(۟u> ATW?jh(0 6IpGXCkAh :Gyo#csadFS啕сo*j~pe@ 85"liSue)5g |{>lBޥ|? ?g˂p5M4cquOTR$_wBtsQ}=߲$%H/Lܵ)[I=j;gׁh(:#j#;ׇ\{OajtK[U Njn΢~6 Q2TXBnp5fiԄ׾IMڴ8AͣVpV>rxC"ܔ|BpSxsg[mtq6?AXa8xtQ!'Y#Q:ʙ 33GAW>Rx8L N09P%ȁ(ܐ09)E(uSarXH)mٹlٕ$@M B jR0caDPPT+|({b=j /ަ|C)< Og^`xR!w.G(UTWS>J̦yv-%"H x,FU)KP ()CTŞR} kze(, Ftֶu2է 6)ŧn귰_ oz<ٰxsiT'TSRGPSMTO>Mu,A5* x'.s+Mu,;fSTPPݘ`XۍBT_+>NWa1#w 水&Ha,]D3r㲨fʘ+TCu ae2דŸrȋM5,lMvҥDk?ٔ7 ^8_x4KDO:Ey<^@L)xQ2t1+Mû)Ut/Q`;ZncI̛3˺qP͠Fn:I0\r?̆N*U`ʩW)6z7(_T:G9 ޡ|2R('acʧ?QΙ #S#&OwR#-BW'|_PY*75o+.\f9)B~_8E9grdNxFPjވMԄ:ϵ/Q[IhzC\nM+!vo DW S-+&=ۢWmjSaK5"aj=u/R=Psl*%9+ ^˷aݴt dqV7Y$ [ FG_jsV`u,jBa{c׀_P o/ ^/ԁnormal.dark2e1.0.webp../../normal.light/2/1.0.webpnormal.light21.0.webpRIFF|WEBPVP8X ANIMANMFPwndVP8L7/wWm#Q @=;(Bܹ؈[q΅؋P0D*+d۶mH.m۶m۶m۶m۶mrE#ɈO8.};~$xu؂Ca r'՝ z };̽;r^̦JT{g,m2Kߨ^kݒ_xsdg_Η>j[^T'5C=7!vzͯ`7dL,-%$ں N=!;r+o,u*ǂr.-O5aprERH 3g D즌 e;YLusL] YG^ O\JY e+J~iFjBy ֪a. Z5aG2࿄0 K #`;,ٰS>Ey$P<ߒotPrxMQ &PLSLŸE'I=xQa) )*th O>"'Fr1el(>SO @% >ҕܤՅ+k(CN&\e D.@~3|u;P,EvvSMWM2<7|R vPi ״Q7(#%('_(?+rN&P>d|@FPOy88Ft8-Aph^*g#<}*;BmTESf3 ZIwyKeW(Jl]k@eW(JbK裲; C6R} =0jǒhԆj` # cYoS 4/ yJm 5ڻ0R-\D*k@T|}Tbq(*]&1T|_"Vt_ԖALjLISZ n(̰XQpressed.dark2d1.webp../../pressed.light/2/1.webppressed.light?2?1.webpX?RIFFP?WEBPVP8X ANIMANMF&CVP8L /ANMF^WCVP8L/^'sY.& Uv6/[_ M\@㥁'Buj.h_Vx[ zlT6.6g3 v -{`;ÃwgžL܂`oT~Rf:\N!.p3pJ JaJ {P}N1b8œS\SlN9S\OF-t`Sj؝҂ F%Πo S8 To SVPSJ)BcpJ ZACtV: sp= ,H9 `rAڙ| Lp F \5ag0l.8 7*X-9 A< YANMF" CVP8L /" H~ EmS/3Tz̄CmfCFgUNM muf p9Օ"q9O}O2/?eRhѫGZ գ,<㴋<ѡ/<8u)<Ψ k3GUIU<ZEP/fgIPIcS-v3_;-Ml*m2%Z' ڶWi`AZSFF{G]; GjSn<]dek2G!U|WNܗ+8TG{dKߺ9qmk '9qоzm-TTjz.6+,H=s\tκʞκ(aA:0bf5m랑^,a;|##l$]&̦pU0Q5p͈tud4'8V#1 WF%p{FkXoSna y(b~+:]1+C! 5B"!!,9B,7/U#D{frg TY!\C/^Sˁ1d=9w$':5 Q?tx@\{:{Cl-tgQ.6kĩ\xX!w.js9p-wqf{r? 92OR\8iȡh?WE/̻F(ANMF{rCVP8Lm/{jN#@"#0pCX’û$?I1iI!UY>y&E `dI4bhEqd*u6lC >g`s s @6jK ֶIcLl^H/f\{E?Z;Odmep9c ԑ钅L-1mQFZ+`ZoozΪHU%: 5jH,ݵ}*$,T2N bSQL {a* 7PKiF^]FGK]EG_oKy$(I.EEU (1!ACq~@/F6v)|"} Boeǔjӥ |^R,bC(Y`E|N1_,;\Sm\ ^u(ņ< |.S2> l|]R )tV"~v(>Kaإhu;Oa~(3E=#a"8)ĂG1Z^hh{*j h`4U1-BK\ܤa;P[QunР7it4i4it5i5ܧ:nQtԸ15atZ91SC8 S69*($JleQ~SY&1at xц)3[0|va\)cQȰoֆ\h C>F!pwnANMF:kcCVP8L"/k' m&exp\۶2gNTA=,'wx_ ADa6Lv{ *$ɈE''LD.p#/򖴢勒9Jz(")?1b@1OrB!B>‡mVfjLaff,3 Ǭ#]][zBwpeO{1C.{:war%C/_ A{UW/`FרY[Z;Snjp2sF8A7F8PdDYh2rsmFn.C[=7 =[yr " ]M!gP4N!_(#.#KA(s=DQGQMQX;]RKa5mֶ)A ;Aa֘)ʷHQ^dSdSId"7DAC_[סK13Yb!|BYuW(*"y uN!mU;4&bI=n!˧^'ܧ(3Ic'l$kݦ[-Hz^Dw4 18@vƭ@m. s4+84.tAFc~@GC3҈1J'hT)tVL3 譚fs]5T章j)T!I6UtJGX)r^a i/6ҵR+:{0OmeqlNuj9uS0_QfoΆq*w`-&: 3WpV 0Pͼb61ƻ3r̯bH5$d Omi{9e_!ANMF8wnCVP8L/w'FmSncVwwrB dBw}@_m6bGwg$3jg(; s3M%M!o>%/vtI% bHI">xE(9Mw/Qգzg m.Jò,3q"!EnBhEE(;SAKIxBq]EqkFaو~G\~'E kuT  (zZ(gfgpKe'삧74M h= ^?sE}1 hp}!Thl`ԖePnr)y6ꙷiL(zE^BOu3 k:iT7Ωδh= i=i~,w{)og{ mW{.G3n3iO'S_> a ȽD`J1j=s7QD0mz΁y_4RCXʏ+`f9*ρ[;^GcX^Vp"SLnc ȩ|@Utj}5 ANMF{rCVP8L/{1M/9 ȑ$Vzzf@p!'CְoG8p6s6]I[8m0SyPrS9lj\r#yO8}iǎ#oinkKe@gc^seR9♥-`oi{ýlR*OhxV}i#0k3%_=rBXXËZ~O1PP^jcalصii:V#`9em>nnŽg(܈KhUog `+4|o\K>7,1ӡ:5fkKf΂ڌ 7cFΞ q4߰vjϚFmm:aޫ)tϮ'RܩR@qCw#ފQu01QW@uO)stjP4:.žH)ŖGS){)($ Nn`5Spk"'ONAΡ^.VF2ž( t iP:ߡѵB7g&EFybFUS`HB#nl-ՌC w=SXMaG!K(_t'BgRLuPyB^wS=P3ԧ)YFA":}!4W Ǧ0N/]k`n0ѧs&;gѱaj:uLBnq/Jg/JG/J'M/JH-6Z6k` ZjS`[- pcM - Wdx23{\%~3 n} ׼ki.L#ps .LvR;kj8.}Z޹mTn4ίbHXH䅐1c*|1RzлzBЦ*l2%6)1 p%'NEANMF{qCVP8L/{@qH8٧j 8"`E,[9o5@&б:x眙fض#¹/O.Dmft*,Oxg< ^q/n,LveaBܸ{Q7Ó,Kfag?'ξΟӗ_6NHiy r觟́ )ժ4>>J|(A L @ݔr5wS%~9.Ai>J.QXA(:"E[. )2hz.oSȥ("l/5{(ido]^S nډ;(xX >` >d9u)RfdߧϐO=bODŶEn9!$N@~ D:ܜ@A|EmJ(=(}Aq!d vPf.BdkG>R*(^(e2PP@wQPN|F?C6:%tt{ nӷ@Atonj dyO920uns`l<:ȇ=Ca: y) 7țiHA'N :N/K=G&a3VaןLs}#18p=-7N.+xQpg61.uXI[[o؇ ^b6 -J SFn .Zu_ƫz{|ǕQw%)?`M '8#$!2 i]e]!/yUVtjANMFwnCVP8L/wЖ$IEe_0LOM{qyW/3A$I* =Y "8i϶mm۶m۶m{7Icx XJUJ򐘖G.sPX<`kߍiXnAlv{`PCc,[^{vxȚ\=h;Up5:tF^4E 6zU' 5x{M#^x (j\a}&W"_}AnYa$]8@L~6zws/f#'utxޑȑk[/qogԂ_[QNԍ4:b|`?>^9XIh g{ם]0R'63ۭR;wo~̑1 >(DǏ>a{/1xݷf?= Z ySx_Ln6{>'x'G@`czpH)ԱJ ~E cGVPG×:)LuqOG L8<&aJ֠_$ozl 7ccw>extLB?χfH=ѵ .{pX/?h\WJ*9dΟ,yG] QANMFvnCVP8L/vЖ$I$G'7TfVғ/3=]3F$72nte SzWl@sm۶m۶m[mg 7I 阱w_KڢV+s,6 Wpsep7^ 7So"qa-(d3t9%(hHfKGJiCUʬF8j}v`z|ZQzD1/' |UdZTb1wHBA.V;gl'jDxb blk(uOY 9D!5޾H:dۼq $#Gs鿆rm %p~_/(d)IS;JG 'vj8.ǟ86R9Ê/d|vV"QviN%KU_Nw%' e[h}7ymfG Ƞm|o2&Sã[)6^)a o*:Pct8j)EՂs?<ə±x9Q9G՛s?{3N6Ĭ<7c/ȴMdDJKӥl|;oSv|;9Trd_P~˕E F>)Ϡe}D,'p 60K /:޶H9_YDgc  Cp ?&-܍BcGs+ⓟG3 )@Oy$L@=k73CN<ϙQݘ >c A <v%3nx9yaD{ȟm$Ä[Ӹ)H<4ޡ3w(`xǃo;,Wc,or AkG_;gx5l5c~DulxPZ:A =q2 'y >::$(c1bi`O*4CORNEJ h r+A*lن)LM@O[ȟӢÞ)xb܅C"/i%%@~N+n"]*G/x@88&yz8a$ŊqANMFwnCVP8L/wЖ$I]EvK'fZ /ٶ6\=s=) X6}m۶m۶m۶m۶}+ HJoHnjw\a(:sJ؎s✄M#!|% "~K 8>x]bVkQ: .6H݉˨jq\#\l!~C},R-}T&7CI40MdQqMK:UX5~gqȝQ}nrʸ%-&vء:~Q]SG3DN]Cig@}7H˄8ՙrTpOOC3[m'EgcꟙwmJKLȗJ3!Z%1)6">"xQNdB3Sa*oh>:ھZe.gbeBHj'WiЅ,EYi=!M?hߥf9,3ToQmջzl[m'Tܷ_qo؋ gI`d5lXsb=6>¨z#Um덒XTh@d+b%*.S_). R R} 'VI=6SU[v *$ju!ײF4jq5zE:/Dvnjwbh7X|CutG{aAOݏt~3%&y5Chv}gJlj?z^o?^%;YgL`t^-U;|U1e^n/ma\11}'v'הbZɟ}c)Kj]ܙ\N%*Uo5*5[eϥNr)_1HsK*y.EI݁>tjH|fZ̳s| |qP*Ra!"g&ki0]NQNoNMMT9x6I:SoV'/u:y^Xb M rM*GdcwpOrsD9%2}Y85 ^Onׁ{j1Ój]ퟹ-3_ub&7,uI Y.Ȯ$7KյXsM{ɭ!rƻFR3%O`%%m j` z8In6xM$߮6xM&߬-x%L>$S$W{Z&;DjoIUO5{˲><e gdirqV2 %#Ts SÒ 46L]=:{Y1H{.$*ׁKcvmrltM+ɛY PÓqflڒ Khl7&g'{{7p璼,s~$Ȇ=I>L̄/ip)d`: ANMFzpCVP8L/zЖ$I$rCUfT>l-33_@n#ɑtBFtEdO㴾= #)bm۶ml۶m۶m6϶o@p#Iސvf &LQˮT!d D bp ,4eHJ iCFC]n*AB#fz%otԡ]tk9"u]T sCÃ2ꖟ:S]\A0[0bp#k$E>*'),};{A F抿TK:f/>Yb2*T~ğ0zTgE;Xc/ .v׻3`hwggc\0o [~M)Wg&9Fj߆3≺%řK msbofs;' Gg6qxy gf>1t|bFU"[ؼfLnLiY܁EER1Q ךN+sv)j8¢rHy/ůztg fA$li׫,,H9L?<9qd4W5%F(4=009Xu8d[U& 5o_ԝX/Gk!Nd< ;B |p:(GG 8o1bLkWΩ|#S7:2? q"FzhC4ԧ[hBDn)}lCVAmq>x`%'0LO#xTP[\g<{0LS[qbp((̊1FΑpCzL]b zyXLWb0n6]PE(Q7Y=ʡqg^bkx?o| _{K;tv{<"J\ ꕵW>׮+`|*ˀ4>5>WC\^]X(GN~VtLk]=ؽ])D[?W&1\muSEtH תea*}<*Zv}cp'&gwsUJsWl泌%܏k_+pe5Λ螯,͝y*&zTބ=CtQ)aW,v[ݶ]2EVa_<џq1a_}DW_LغND_nW1kb浖֞60Rtv1a;a{"zFYIL Cig=w{|+n/Aak?+r(jX0jr? #ߏU=ONq藼qXE?k\O>,\%HW)0ҙ%ʵ02E%? ac Ck/ C90>Ϸ04&*04и&4 ֯͝0^{Gjv5) 53ڄ# Cad} #aףHRF3a WE?9 tuMTނDk 㜥?&[aX^YEW7a30*ܢWׇQl=1%(z0v@>1Z'LњW{MNWcˆDZt #.+9pFt'iNoi+pn]n^+D׭N_t1xh!fj8t{-¡r{Hy 7=hAC Ԙp\bhU!$j%.(pTh'I1E{ͰpJ #Eu\8Čg|8™,z4{L511t@<`;=轴=)vVnN[ Dr5&YYtȯ=!>ΰul{d╲rߏ4s쀵$:7akޢW7cDić I4-E'ڥn'̔d<7 ;Tps^Ƅ1,r{6c ctS&åb {VFokօf!^A9Z.Ó(dS?ND\U^b9UDodtkgui-5.7.12/examples/animation-dci/main.cpp000066400000000000000000000120361476226661100210740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DGUI_USE_NAMESPACE static QString iconModeToString(DDciIcon::Mode mode) { switch (mode) { case DDciIcon::Normal: return "Normal"; case DDciIcon::Hover: return "Hover"; case DDciIcon::Pressed: return "Pressed"; case DDciIcon::Disabled: return "Disabled"; default: break; } return nullptr; } class IconWidget : public QMainWindow { public: IconWidget(const QString &iconName) { setCentralWidget(label = new QLabel(this)); label->setAcceptDrops(true); centralWidget()->setAttribute(Qt::WA_MouseTracking); centralWidget()->installEventFilter(this); statusBar()->addWidget(message = new QLabel()); auto normal = new QPushButton("Normal"); connect(normal, &QPushButton::clicked, this, [this] { player.setMode(DDciIcon::Normal); }); auto hover = new QPushButton("Hover"); connect(hover, &QPushButton::clicked, this, [this] { player.setMode(DDciIcon::Hover); }); auto pressed = new QPushButton("Pressed"); connect(pressed, &QPushButton::clicked, this, [this] { player.setMode(DDciIcon::Pressed); }); auto disabled = new QPushButton("Disabled"); connect(disabled, &QPushButton::clicked, this, [this] { player.setMode(DDciIcon::Disabled); }); auto open = new QPushButton("..."); connect(open, &QPushButton::clicked, this, [this] { QString dciFile = QFileDialog::getOpenFileName(this, "select a dci icon file", "", "*.dci"); player.setIcon(DDciIcon(dciFile)); player.setMode(DDciIcon::Normal); }); QWidget *menuWidget = new QWidget(this); QHBoxLayout *layout = new QHBoxLayout(menuWidget); layout->addWidget(normal); layout->addWidget(hover); layout->addWidget(pressed); layout->addWidget(disabled); layout->addWidget(open); setMenuWidget(menuWidget); icon = DDciIcon::fromTheme(iconName); connect(&player, &DDciIconPlayer::updated, this, [this] { auto image = player.currentImage(); label->setPixmap(QPixmap::fromImage(image)); }); connect(&player, &DDciIconPlayer::modeChanged, this, [this] (DDciIcon::Mode old, DDciIcon::Mode newMode) { message->setText(QString("Old State: %1, Current State: %2") .arg(iconModeToString(old)) .arg(iconModeToString(newMode))); }); DDciIconPalette p("pink"); player.setPalette(p); player.setDevicePixelRatio(devicePixelRatioF()); player.setIcon(icon); } private: bool event(QEvent *event) override { if (event->type() == QEvent::WindowActivate) { player.play(DDciIcon::Normal); } return QMainWindow::event(event); } bool eventFilter(QObject *watched, QEvent *event) { if (watched != label) return QMainWindow::eventFilter(watched, event); if (event->type() == QEvent::Enter) { player.setMode(DDciIcon::Hover); } else if (event->type() == QEvent::Leave) { if (player.mode() == DDciIcon::Hover) player.setMode(DDciIcon::Normal); } else if (event->type() == QEvent::MouseButtonPress) { player.setMode(DDciIcon::Pressed); } else if (event->type() == QEvent::MouseButtonRelease) { player.setMode(label->hasMouseTracking() ? DDciIcon::Hover : DDciIcon::Normal); } else if (event->type() == QEvent::DragEnter) { event->accept(); } else if (event->type() == QEvent::Drop) { auto de = static_cast(event); if (de->mimeData()->hasFormat("text/uri-list")) { QString uris = de->mimeData()->data("text/uri-list"); QUrl url(uris.split("\r\n").value(0)); DDciIcon icon(url.path()); if (!icon.isNull()) { player.setIcon(icon); player.setMode(DDciIcon::Normal); } } } else { return false; } return true; } DDciIcon icon; DDciIconPlayer player; QLabel *message = nullptr; QLabel *label = nullptr; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); IconWidget *window = new IconWidget(QStringLiteral("test_heart")); window->setMinimumSize(300, 300); window->show(); return app.exec(); } dtkgui-5.7.12/examples/animation-dci/test_dci_icon.qrc000066400000000000000000000003341476226661100227570ustar00rootroot00000000000000 dci_heart.dci 3depict.dci dtkgui-5.7.12/examples/dnd-example/000077500000000000000000000000001476226661100171245ustar00rootroot00000000000000dtkgui-5.7.12/examples/dnd-example/CMakeLists.txt000066400000000000000000000014571476226661100216730ustar00rootroot00000000000000find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) set(BIN1 dnd-test-client) set(BIN2 dnd-test-server) set(TARGET1 ${BIN1}${DTK_VERSION_MAJOR}) set(TARGET2 ${BIN2}${DTK_VERSION_MAJOR}) add_executable(${TARGET1} dnd-test-client.cpp ) target_link_libraries(${TARGET1} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::DBus ${LIB_NAME} ) add_executable(${TARGET2} dnd-test-server.cpp ) target_link_libraries(${TARGET2} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::DBus ${LIB_NAME} ) set_target_properties(${TARGET1} PROPERTIES OUTPUT_NAME ${BIN1}) set_target_properties(${TARGET2} PROPERTIES OUTPUT_NAME ${BIN2}) install(TARGETS ${TARGET1} DESTINATION "${TOOL_INSTALL_DIR}") install(TARGETS ${TARGET2} DESTINATION "${TOOL_INSTALL_DIR}") dtkgui-5.7.12/examples/dnd-example/dnd-test-client.cpp000066400000000000000000000050471476226661100226340ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfiledragclient.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include DGUI_USE_NAMESPACE static DFileDragClient *c; static QProgressBar *p; class DropArea : public QFrame { Q_OBJECT public: explicit DropArea(QString s) : lb(new QLabel(s, this)) , le(new QLineEdit(this)) { setLayout(new QVBoxLayout); setFrameShape(Shape::Box); layout()->addWidget(lb); layout()->addWidget(le); lb->setAlignment(Qt::AlignmentFlag::AlignCenter); le->setText("/tmp"); le->setPlaceholderText(QString("do not accept drop when edit is empty")); setAcceptDrops(true); } protected: void dragEnterEvent(QDragEnterEvent *e) { if (DFileDragClient::checkMimeData(e->mimeData())) { if (le->text().isEmpty()) e->ignore(); // or e->setDropAction(Qt::IgnoreAction); else e->acceptProposedAction(); DFileDragClient::setTargetUrl(e->mimeData(), QUrl(le->text())); } } void dragMoveEvent(QDragMoveEvent *e) { if (DFileDragClient::checkMimeData(e->mimeData())) { e->acceptProposedAction(); DFileDragClient::setTargetUrl(e->mimeData(), QUrl(le->text())); } } void dropEvent(QDropEvent *e) { if (DFileDragClient::checkMimeData(e->mimeData())) { e->acceptProposedAction(); DFileDragClient::setTargetUrl(e->mimeData(), QUrl(le->text())); c = new DFileDragClient(e->mimeData()); connect(c, &DFileDragClient::progressChanged, p, &QProgressBar::setValue); } } private: QLabel *lb; QLineEdit *le; }; int main(int argc, char **argv) { QApplication a(argc, argv); QDialog d; d.show(); QHBoxLayout *lo = new QHBoxLayout(); lo->addWidget(new DropArea("area 51")); lo->addWidget(new DropArea("area 61")); QScopedPointer pp (new QProgressBar()); p = pp.data(); p->setMinimum(0); p->setMaximum(100); QVBoxLayout *hlo = new QVBoxLayout(); d.setLayout(hlo); hlo->addLayout(lo); hlo->addWidget(p); a.exec(); } #include "dnd-test-client.moc" dtkgui-5.7.12/examples/dnd-example/dnd-test-server.cpp000066400000000000000000000050621476226661100226610ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfiledragserver.h" #include "dfiledrag.h" #include #include #include #include #include #include #include #include #include #include DGUI_USE_NAMESPACE static int p; static DFileDragServer *s = nullptr; static QLabel *lbr = nullptr; class DraggableLabel : public QLabel { Q_OBJECT public: using QLabel::QLabel; Q_SIGNALS: void dragFinished(); protected: void mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::MouseButton::LeftButton) { dragpos = e->pos(); } } void mouseMoveEvent(QMouseEvent *e) { if (!(e->buttons() & Qt::MouseButton::LeftButton) || s) { return; } if ((e->pos() - dragpos).manhattanLength() < QApplication::startDragDistance()) { return; } s = new DFileDragServer(); DFileDrag *drag = new DFileDrag(this, s); QMimeData *m = new QMimeData(); m->setText("your stuff here"); drag->setMimeData(m); connect(drag, &DFileDrag::targetUrlChanged, [drag] { lbr->setText(drag->targetUrl().toString()); }); Qt::DropAction res = drag->exec(Qt::MoveAction); if (res!= Qt::IgnoreAction) Q_EMIT dragFinished(); else { s->deleteLater(); s = nullptr; } } private: QPoint dragpos; }; int main(int argc, char **argv) { QApplication a(argc, argv); QDialog d; d.show(); DraggableLabel l("Drag me", &d); l.setAlignment(Qt::AlignCenter); QTimer t; t.setInterval(50); t.setSingleShot(false); QProgressBar pg; pg.setMinimum(0); pg.setMaximum(100); QLabel lb; lbr = &lb; lb.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); QObject::connect(&l, &DraggableLabel::dragFinished, [&t] { p = -1; t.start(); }); QObject::connect(&t, &QTimer::timeout, [&t, &pg] { if (QRandomGenerator::global()->generate() & 1) { s->setProgress(++p); pg.setValue(p); if(p == 100) { t.stop(); s->deleteLater(); s = nullptr; } } }); QVBoxLayout lo; lo.addWidget(&l); lo.addWidget(&pg); lo.addWidget(&lb); d.setLayout(&lo); a.exec(); } #include "dnd-test-server.moc" dtkgui-5.7.12/examples/frameless-window/000077500000000000000000000000001476226661100202145ustar00rootroot00000000000000dtkgui-5.7.12/examples/frameless-window/CMakeLists.txt000066400000000000000000000005421476226661100227550ustar00rootroot00000000000000find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS X11Extras) pkg_check_modules(XCB IMPORTED_TARGET xcb) set(BIN_NAME frameless-window) add_executable(${BIN_NAME} main.cpp ) target_link_libraries(${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::GuiPrivate Qt${QT_VERSION_MAJOR}::X11Extras PkgConfig::XCB ) dtkgui-5.7.12/examples/frameless-window/main.cpp000066400000000000000000000121701476226661100216450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include void setWindowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, const void *data, quint32 len, uint8_t format) { xcb_connection_t* conn = QX11Info::connection(); xcb_change_property(conn, XCB_PROP_MODE_REPLACE, WId, propAtom, typeAtom, format, len, data); xcb_flush(conn); } void clearWindowProperty(quint32 WId, xcb_atom_t propAtom) { xcb_delete_property_checked(QX11Info::connection(), WId, propAtom); } xcb_atom_t internAtom(xcb_connection_t *connection, const char *name, bool only_if_exists) { if (!name || *name == 0) return XCB_NONE; xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, only_if_exists, strlen(name), name); xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, 0); if (!reply) return XCB_NONE; xcb_atom_t atom = reply->atom; free(reply); return atom; } xcb_atom_t internAtom(const char *name, bool only_if_exists) { return internAtom(QX11Info::connection(), name, only_if_exists); } bool isSupported(xcb_atom_t targetAtom) { // get _NET_SUPPORTED from root window QVector net_wm_atoms; xcb_window_t root = QX11Info::appRootWindow(); int offset = 0; int remaining = 0; xcb_connection_t *xcb_connection = QX11Info::connection(); auto _net_supported = internAtom(QT_STRINGIFY(_NET_SUPPORTED), false); do { xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection, false, root, _net_supported, XCB_ATOM_ATOM, offset, 1024); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection, cookie, NULL); if (!reply) break; remaining = 0; if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { int len = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); int s = net_wm_atoms.size(); net_wm_atoms.resize(s + len); memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t)); remaining = reply->bytes_after; offset += len; } free(reply); } while (remaining > 0); return net_wm_atoms.contains(targetAtom); } bool setNoTitlebar(quint32 WId, bool on) { xcb_atom_t _deepin_no_titlebar = internAtom(QT_STRINGIFY(_DEEPIN_NO_TITLEBAR), false); if (!isSupported(_deepin_no_titlebar)) return false; quint8 value = on; setWindowProperty(WId, _deepin_no_titlebar, XCB_ATOM_CARDINAL, &value, 1, 8); // force enable window decorations, becouse we need the window shadow and border, its contains in decorations. xcb_atom_t _deepin_force_decorate = internAtom(QT_STRINGIFY(_DEEPIN_FORCE_DECORATE), false); if (on) { quint8 value = on; setWindowProperty(WId, _deepin_force_decorate, XCB_ATOM_CARDINAL, &value, 1, 8); } else { clearWindowProperty(WId, _deepin_force_decorate); } return true; } QObject *createNativeSettingsFor(QWindow *window) { // The platform function in dxcb plugin: // https://github.com/linuxdeepin/qt5platform-plugins/blob/master/src/dnativesettings.h static QFunctionPointer build_function = qApp->platformFunction("_d_buildNativeSettings"); if (!build_function) { return nullptr; } QObject *obj = new QObject(window); bool ok = reinterpret_cast(build_function)(obj, window->winId()); if (!ok) { delete obj; return nullptr; } return obj; } class Window : public QWindow { public: bool handleMoveing = false; private: void mouseMoveEvent(QMouseEvent *e) override { if (handleMoveing && e->buttons() == Qt::LeftButton) { handle()->startSystemMove(); } else { QWindow::mouseMoveEvent(e); } } }; int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); Window window; window.resize(200, 200); if (setNoTitlebar(window.winId(), true)) { // If enabled no titlebar mode, the window is no min/max/close buttons, you need to implement it by Qt widgets. // Like as https://github.com/linuxdeepin/dtkwidget/blob/master/src/widgets/dtitlebar.cpp window.handleMoveing = true; auto nativeSettings = createNativeSettingsFor(&window); if (nativeSettings) { nativeSettings->setProperty("DTK/WindowRadius", "100,100"); nativeSettings->setProperty("borderWidth", 2); nativeSettings->setProperty("borderColor", QColor(Qt::red)); nativeSettings->setProperty("shadowOffset", "30,30"); nativeSettings->setProperty("shadowRadius", 30); nativeSettings->setProperty("shadowColor", QColor(Qt::blue)); // See more properties in DPlatformTheme } } window.show(); return app.exec(); } dtkgui-5.7.12/examples/test-taskbar/000077500000000000000000000000001476226661100173325ustar00rootroot00000000000000dtkgui-5.7.12/examples/test-taskbar/CMakeLists.txt000066400000000000000000000006451476226661100220770ustar00rootroot00000000000000find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) set(BIN taskbar) set(TARGET_NAME ${BIN}${DTK_VERSION_MAJOR}) add_executable(${TARGET_NAME} testtaskbarwindow.h testtaskbarwindow.cpp main.cpp ) target_link_libraries(${TARGET_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Gui ${LIB_NAME} ) set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${BIN}) dtkgui-5.7.12/examples/test-taskbar/main.cpp000066400000000000000000000030401476226661100207570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include "testtaskbarwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); auto name = QUuid::createUuid().toString() + QStringLiteral(".desktop"); a.setDesktopFileName(name); QDir appDir = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); QFile desktopFile(appDir.absoluteFilePath(name)); if(!desktopFile.exists()) { desktopFile.open(QIODevice::WriteOnly); desktopFile.write("[Desktop Entry]\n"); desktopFile.write("Type=Application\n"); desktopFile.write("Version=1.1\n"); desktopFile.write("Name=" + QApplication::applicationDisplayName().toUtf8() + "\n"); desktopFile.write("Exec=" + QApplication::applicationFilePath().toUtf8() + "\n"); desktopFile.close(); } TestTaskbarWindow *pTaskbarWindow = new TestTaskbarWindow; pTaskbarWindow->showMaximized(); //这里删除用于测试的desktop文件 QObject::connect(pTaskbarWindow, &TestTaskbarWindow::closeWindow, [&desktopFile] { QFile::remove(desktopFile.fileName()); }); //控制中心修改字体大小可以看到打印输出 QObject::connect(DGuiApplicationHelper::instance()->fontManager(), &DFontManager::fontChanged, [] { qDebug() << DGuiApplicationHelper::instance()->fontManager()->baseFont(); }); return a.exec(); } dtkgui-5.7.12/examples/test-taskbar/testtaskbarwindow.cpp000066400000000000000000000050361476226661100236210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "testtaskbarwindow.h" #include #include #include TestTaskbarWindow::TestTaskbarWindow(QWidget *parent) : QWidget(parent) { QHBoxLayout *pHBoxLayout_1 = new QHBoxLayout; m_pProgressBox = new QCheckBox("progress"); m_pProgress = new QSlider(Qt::Horizontal); m_pProgress->setRange(0, 100); m_pProgress->setMinimumWidth(300); pHBoxLayout_1->addWidget(m_pProgressBox); pHBoxLayout_1->addWidget(m_pProgress); QHBoxLayout *pHBoxLayout_2 = new QHBoxLayout; m_pCounterBox = new QCheckBox("counter"); m_pNumEdit = new QLineEdit; m_pNumEdit->setMinimumWidth(300); m_pNumEdit->setValidator(new QIntValidator); pHBoxLayout_2->addWidget(m_pCounterBox); pHBoxLayout_2->addWidget(m_pNumEdit); m_pUrgencyBox= new QCheckBox("test urgency"); QHBoxLayout *pHBoxLayout_3 = new QHBoxLayout; pHBoxLayout_3->addWidget(m_pUrgencyBox); QVBoxLayout *pVBoxLayout = new QVBoxLayout; setLayout(pVBoxLayout); pVBoxLayout->addStretch(); pVBoxLayout->addLayout(pHBoxLayout_1); pVBoxLayout->addSpacing(30); pVBoxLayout->addLayout(pHBoxLayout_2); pVBoxLayout->addSpacing(50); pVBoxLayout->addLayout(pHBoxLayout_3); pVBoxLayout->addStretch(); m_pTaskbarControl = new DTaskbarControl(this); m_pTaskbarControl->setProgress(false, 0); m_pTaskbarControl->setCounter(false, 0); connect(m_pProgressBox, &QCheckBox::stateChanged, this, [this] (int state) { m_pTaskbarControl->setProgress(state == Qt::Checked, static_cast(m_pProgress->value()) / 100); }); connect(m_pCounterBox, &QCheckBox::stateChanged, this, [this] (int state) { m_pTaskbarControl->setCounterVisible(state == Qt::Checked); }); connect(m_pProgress, &QSlider::valueChanged, this, [this] (int value) { m_pTaskbarControl->setProgress(m_pProgressBox->checkState() == Qt::Checked, static_cast(value) / 100); }); connect(m_pNumEdit, &QLineEdit::textChanged, [this] (const QString &str) { m_pTaskbarControl->setCounter(m_pCounterBox->checkState() == Qt::Checked, str.toInt()); }); connect(m_pUrgencyBox, &QCheckBox::stateChanged, this, [this] (int state) { m_pTaskbarControl->setUrgency(state == Qt::Checked); }); } TestTaskbarWindow::~TestTaskbarWindow() { } void TestTaskbarWindow::closeEvent(QCloseEvent *event) { Q_EMIT closeWindow(); event->accept(); } dtkgui-5.7.12/examples/test-taskbar/testtaskbarwindow.h000066400000000000000000000017051476226661100232650ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef TESTTASKBARWINDOW_H #define TESTTASKBARWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dtaskbarcontrol.h" DGUI_USE_NAMESPACE class TestTaskbarWindow : public QWidget { Q_OBJECT public: explicit TestTaskbarWindow(QWidget *parent = nullptr); ~TestTaskbarWindow(); protected: void closeEvent(QCloseEvent *event); Q_SIGNALS: void closeWindow(); private: DTaskbarControl *m_pTaskbarControl; QCheckBox *m_pProgressBox; QCheckBox *m_pCounterBox; QLineEdit *m_pNumEdit; QSlider *m_pProgress; QCheckBox *m_pUrgencyBox; }; #endif // TESTTASKBARWINDOW_H dtkgui-5.7.12/include/000077500000000000000000000000001476226661100145335ustar00rootroot00000000000000dtkgui-5.7.12/include/DtkGui/000077500000000000000000000000001476226661100157225ustar00rootroot00000000000000dtkgui-5.7.12/include/DtkGui/DDciIcon000066400000000000000000000000261476226661100172570ustar00rootroot00000000000000#include "ddciicon.h" dtkgui-5.7.12/include/DtkGui/DDciIconImagePlayer000066400000000000000000000000341476226661100213760ustar00rootroot00000000000000#include "ddciiconplayer.h" dtkgui-5.7.12/include/DtkGui/DDciIconPalette000066400000000000000000000000351476226661100205760ustar00rootroot00000000000000#include "ddciiconpalette.h" dtkgui-5.7.12/include/DtkGui/DDciIconPlayer000066400000000000000000000000341476226661100204330ustar00rootroot00000000000000#include "ddciiconplayer.h" dtkgui-5.7.12/include/DtkGui/DDesktopServices000066400000000000000000000000361476226661100210650ustar00rootroot00000000000000#include "ddesktopservices.h" dtkgui-5.7.12/include/DtkGui/DFileDrag000066400000000000000000000000271476226661100174250ustar00rootroot00000000000000#include "dfiledrag.h" dtkgui-5.7.12/include/DtkGui/DFileDragClient000066400000000000000000000000351476226661100205630ustar00rootroot00000000000000#include "dfiledragclient.h" dtkgui-5.7.12/include/DtkGui/DFileDragServer000066400000000000000000000000351476226661100206130ustar00rootroot00000000000000#include "dfiledragserver.h" dtkgui-5.7.12/include/DtkGui/DFontManager000066400000000000000000000000321476226661100201450ustar00rootroot00000000000000#include "dfontmanager.h" dtkgui-5.7.12/include/DtkGui/DForeignWindow000066400000000000000000000000341476226661100205270ustar00rootroot00000000000000#include "dforeignwindow.h" dtkgui-5.7.12/include/DtkGui/DGuiApplicationHelper000066400000000000000000000000431476226661100220160ustar00rootroot00000000000000#include "dguiapplicationhelper.h" dtkgui-5.7.12/include/DtkGui/DIcon000066400000000000000000000000231476226661100166340ustar00rootroot00000000000000#include "dicon.h" dtkgui-5.7.12/include/DtkGui/DIconTheme000066400000000000000000000000301476226661100176150ustar00rootroot00000000000000#include "dicontheme.h" dtkgui-5.7.12/include/DtkGui/DImageHandler000066400000000000000000000000331476226661100202650ustar00rootroot00000000000000#include "dimagehandler.h" dtkgui-5.7.12/include/DtkGui/DNativeSettings000066400000000000000000000000351476226661100207160ustar00rootroot00000000000000#include "dnativesettings.h" dtkgui-5.7.12/include/DtkGui/DPalette000066400000000000000000000000261476226661100173450ustar00rootroot00000000000000#include "dpalette.h" dtkgui-5.7.12/include/DtkGui/DPlatformHandle000066400000000000000000000000351476226661100206470ustar00rootroot00000000000000#include "dplatformhandle.h" dtkgui-5.7.12/include/DtkGui/DPlatformTheme000066400000000000000000000000341476226661100205150ustar00rootroot00000000000000#include "dplatformtheme.h" dtkgui-5.7.12/include/DtkGui/DRegionMonitor000066400000000000000000000000341476226661100205410ustar00rootroot00000000000000#include "dregionmonitor.h" dtkgui-5.7.12/include/DtkGui/DSvgRenderer000066400000000000000000000000321476226661100201720ustar00rootroot00000000000000#include "dsvgrenderer.h" dtkgui-5.7.12/include/DtkGui/DTaskbarControl000066400000000000000000000000351476226661100206770ustar00rootroot00000000000000#include "dtaskbarcontrol.h" dtkgui-5.7.12/include/DtkGui/DThumbnailProvider000066400000000000000000000000401476226661100214010ustar00rootroot00000000000000#include "dthumbnailprovider.h" dtkgui-5.7.12/include/DtkGui/DWindowGroupLeader000066400000000000000000000000401476226661100213440ustar00rootroot00000000000000#include "dwindowgroupleader.h" dtkgui-5.7.12/include/DtkGui/DWindowManagerHelper000066400000000000000000000000421476226661100216470ustar00rootroot00000000000000#include "dwindowmanagerhelper.h" dtkgui-5.7.12/include/filedrag/000077500000000000000000000000001476226661100163105ustar00rootroot00000000000000dtkgui-5.7.12/include/filedrag/dfiledrag.h000066400000000000000000000012341476226661100204020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILEDRAG_H #define DFILEDRAG_H #include #include #include #include DGUI_BEGIN_NAMESPACE class DFileDragServer; class DFileDragPrivate; class DFileDrag : public QDrag, public DCORE_NAMESPACE::DObject { Q_OBJECT public: explicit DFileDrag(QObject *source, DFileDragServer *server); QUrl targetUrl(); void setMimeData(QMimeData *data); Q_SIGNALS: void targetUrlChanged(QUrl url); private: D_DECLARE_PRIVATE(DFileDrag) }; DGUI_END_NAMESPACE #endif // DFILEDRAG_H dtkgui-5.7.12/include/filedrag/dfiledragclient.h000066400000000000000000000017641476226661100216110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILEDRAGCLIENT_H #define DFILEDRAGCLIENT_H #include "dfiledragcommon.h" #include #include #include class QMimeData; DGUI_BEGIN_NAMESPACE class DFileDragClientPrivate; class DFileDragClient : public QObject, public DCORE_NAMESPACE::DObject { Q_OBJECT public: explicit DFileDragClient(const QMimeData *data, QObject *parent = nullptr); int progress() const; DFileDragState state() const; Q_SIGNALS: void progressChanged(int progress); void stateChanged(DFileDragState state); void serverDestroyed(); public: static bool checkMimeData(const QMimeData *data); static void setTargetData(const QMimeData *data, QString key, QVariant value); static void setTargetUrl(const QMimeData *data, QUrl url); private: D_DECLARE_PRIVATE(DFileDragClient) }; DGUI_END_NAMESPACE #endif // DFILEDRAGCLIENT_H dtkgui-5.7.12/include/filedrag/dfiledragcommon.h000066400000000000000000000006101476226661100216100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILEDRAGCOMMON_H #define DFILEDRAGCOMMON_H #include DGUI_BEGIN_NAMESPACE enum DFileDragState { Failed = -1, Stalled, Paused, Running, Finished, CustomState = 0x100 }; DGUI_END_NAMESPACE #endif // DFILEDRAGCOMMON_H dtkgui-5.7.12/include/filedrag/dfiledragserver.h000066400000000000000000000015731476226661100216370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILEDRAGSERVER_H #define DFILEDRAGSERVER_H #include "dfiledragcommon.h" #include #include #include class QMimeData; DGUI_BEGIN_NAMESPACE class DFileDragServerPrivate; class DFileDragServer : public QObject, public DCORE_NAMESPACE::DObject { Q_OBJECT public: explicit DFileDragServer(QObject *parent = nullptr); ~DFileDragServer(); QVariant targetData(const QString &key) const; public Q_SLOTS: void setProgress(int progress); void setState(DFileDragState state); Q_SIGNALS: void targetDataChanged(const QString &key); private: D_DECLARE_PRIVATE(DFileDragServer) friend class DDndSourceInterface; friend class DFileDrag; }; DGUI_END_NAMESPACE #endif // DFILEDRAGSERVER_H dtkgui-5.7.12/include/global/000077500000000000000000000000001476226661100157735ustar00rootroot00000000000000dtkgui-5.7.12/include/global/dtkgui_global.h000066400000000000000000000007501476226661100207550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTKGUI_GLOBAL_H #define DTKGUI_GLOBAL_H #pragma once #include #define DGUI_NAMESPACE Gui #define DTK_GUI_NAMESPACE DTK_NAMESPACE::Gui #define DGUI_BEGIN_NAMESPACE namespace DTK_NAMESPACE { namespace DGUI_NAMESPACE { #define DGUI_END_NAMESPACE }} #define DGUI_USE_NAMESPACE using namespace DTK_GUI_NAMESPACE; #endif // DTKGUI_GLOBAL_H dtkgui-5.7.12/include/kernel/000077500000000000000000000000001476226661100160135ustar00rootroot00000000000000dtkgui-5.7.12/include/kernel/dforeignwindow.h000066400000000000000000000015561476226661100212200ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFOREIGNWINDOW_H #define DFOREIGNWINDOW_H #include #include #include DGUI_BEGIN_NAMESPACE class DForeignWindowPrivate; class DForeignWindow : public QWindow, public DTK_CORE_NAMESPACE::DObject { Q_OBJECT Q_PROPERTY(QString wmClass READ wmClass NOTIFY wmClassChanged) Q_PROPERTY(quint32 pid READ pid NOTIFY pidChanged) public: explicit DForeignWindow(QWindow *parent = 0); static DForeignWindow *fromWinId(WId id); QString wmClass() const; quint32 pid() const; Q_SIGNALS: void wmClassChanged(); void pidChanged(); protected: bool event(QEvent *) Q_DECL_OVERRIDE; private: D_DECLARE_PRIVATE(DForeignWindow) }; DGUI_END_NAMESPACE #endif // DFOREIGNWINDOW_H dtkgui-5.7.12/include/kernel/dguiapplicationhelper.h000066400000000000000000000141451476226661100225450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DGUIAPPLICATIONHELPER_H #define DGUIAPPLICATIONHELPER_H #include #include #include #include #include DGUI_BEGIN_NAMESPACE class DPlatformTheme; class DFontManager; class DGuiApplicationHelperPrivate; class DGuiApplicationHelper : public QObject, public DCORE_NAMESPACE::DObject { Q_OBJECT D_DECLARE_PRIVATE(DGuiApplicationHelper) Q_PROPERTY(ColorType themeType READ themeType NOTIFY themeTypeChanged) Q_PROPERTY(ColorType paletteType READ paletteType WRITE setPaletteType NOTIFY paletteTypeChanged) Q_PROPERTY(bool hasUserManual READ hasUserManual) public: enum ColorType { UnknownType, LightType, DarkType }; Q_ENUM(ColorType) enum SingleScope { UserScope, GroupScope, WorldScope }; Q_ENUM(SingleScope) enum SizeMode { NormalMode, CompactMode }; Q_ENUM(SizeMode) enum Attribute { UseInactiveColorGroup = 1 << 0, ColorCompositing = 1 << 1, DontSaveApplicationTheme = 1 << 2, /* readonly flag */ ReadOnlyLimit = 1 << 22, IsDeepinPlatformTheme = ReadOnlyLimit << 0, IsDXcbPlatform = ReadOnlyLimit << 1, IsXWindowPlatform = ReadOnlyLimit << 2, IsTableEnvironment = ReadOnlyLimit << 3, IsDeepinEnvironment = ReadOnlyLimit << 4, IsSpecialEffectsEnvironment = ReadOnlyLimit << 5, IsWaylandPlatform = ReadOnlyLimit << 6, IsTreelandPlatform Q_DECL_ENUMERATOR_DEPRECATED_X("Use DGuiApplicationHelper::IsWaylandPlatform instead") = IsWaylandPlatform, HasAnimations = ReadOnlyLimit << 7, }; Q_ENUM(Attribute) Q_DECLARE_FLAGS(Attributes, Attribute) #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) typedef DGuiApplicationHelper *(*HelperCreator)(); D_DECL_DEPRECATED static void registerInstanceCreator(HelperCreator creator); #endif static DGuiApplicationHelper *instance(); ~DGuiApplicationHelper(); static QColor adjustColor(const QColor &base, qint8 hueFloat, qint8 saturationFloat, qint8 lightnessFloat, qint8 redFloat, qint8 greenFloat, qint8 blueFloat, qint8 alphaFloat); static QImage adjustColor(const QImage &base, qint8 hueFloat, qint8 saturationFloat, qint8 lightnessFloat, qint8 redFloat, qint8 greenFloat, qint8 blueFloat, qint8 alphaFloat); static QColor blendColor(const QColor &substrate, const QColor &superstratum); static DPalette standardPalette(ColorType type); static void generatePaletteColor(DPalette &base, QPalette::ColorRole role, ColorType type); static void generatePaletteColor(DPalette &base, DPalette::ColorType role, ColorType type); static void generatePalette(DPalette &base, ColorType type = UnknownType); static DPalette fetchPalette(const DPlatformTheme *theme); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) Q_DECL_DEPRECATED_X("Use UseInactiveColorGroup enum with setAttribute.") static void setUseInactiveColorGroup(bool on); Q_DECL_DEPRECATED_X("Use ColorCompositing enum with setAttribute.") static void setColorCompositingEnabled(bool on); #endif static bool isXWindowPlatform(); static bool isTabletEnvironment(); static bool isSpecialEffectsEnvironment(); static void setAttribute(Attribute attribute, bool enable); static bool testAttribute(Attribute attribute); DPlatformTheme *systemTheme() const; DPlatformTheme *applicationTheme() const; #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) D_DECL_DEPRECATED DPlatformTheme *windowTheme(QWindow *window) const; #endif DPalette applicationPalette() const; DPalette applicationPalette(ColorType paletteType) const; void setApplicationPalette(const DPalette &palette); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) D_DECL_DEPRECATED DPalette windowPalette(QWindow *window) const; #endif const DFontManager *fontManager() const; static ColorType toColorType(const QColor &color); static ColorType toColorType(const QPalette &palette); ColorType themeType() const; ColorType paletteType() const; static bool setSingleInstance(const QString &key, SingleScope singleScope = UserScope); static void setSingleInstanceInterval(int interval = 3000); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) D_DECL_DEPRECATED static void setSingelInstanceInterval(int interval = 3000); #endif // 获取帮助手册目录 static QStringList userManualPaths(const QString &appName); bool hasUserManual() const; static bool loadTranslator(const QString &fileName, const QList &translateDirs, const QList &localeFallback); static bool loadTranslator(const QList &localeFallback = QList() << QLocale::system()); public Q_SLOTS: #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) D_DECL_DEPRECATED_X("Plase use setPaletteType") void setThemeType(ColorType themeType); #endif void setPaletteType(ColorType paletteType); void handleHelpAction(); static void openUrl(const QString &url); DGuiApplicationHelper::SizeMode sizeMode() const; void setSizeMode(const DGuiApplicationHelper::SizeMode mode); void resetSizeMode(); static inline bool isCompactMode() { return instance()->sizeMode() == DGuiApplicationHelper::CompactMode; } Q_SIGNALS: void themeTypeChanged(ColorType themeType); void paletteTypeChanged(ColorType paletteType); void newProcessInstance(qint64 pid, const QStringList &arguments); void fontChanged(const QFont &font); void applicationPaletteChanged(); void sizeModeChanged(DGuiApplicationHelper::SizeMode sizeMode); protected: explicit DGuiApplicationHelper(); virtual void initialize(); private: D_PRIVATE_SLOT(void _q_initApplicationTheme(bool)) D_PRIVATE_SLOT(void _q_sizeModeChanged(int)) friend class _DGuiApplicationHelper; }; DGUI_END_NAMESPACE #endif // DGUIAPPLICATIONHELPER_H dtkgui-5.7.12/include/kernel/dnativesettings.h000066400000000000000000000027461476226661100214100ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DNATIVESETTINGS_H #define DNATIVESETTINGS_H #include #include #include DGUI_BEGIN_NAMESPACE class DNativeSettingsPrivate; class DNativeSettings : public QObject, public DCORE_NAMESPACE::DObject { Q_OBJECT D_DECLARE_PRIVATE(DNativeSettings) Q_PROPERTY(QByteArrayList allKeys READ allKeys WRITE __setAllKeys NOTIFY allKeysChanged) public: explicit DNativeSettings(quint32 window, const QByteArray &domain = QByteArray(), QObject *parent = nullptr); bool isValid() const; QByteArrayList allKeys() const; QVariant getSetting(const QByteArray &name) const; void setSetting(const QByteArray &name, const QVariant &value); Q_SIGNALS: void allKeysChanged(); void propertyChanged(const QByteArray &name, const QVariant &value); protected: DNativeSettings(DNativeSettingsPrivate &dd, const QMetaObject *metaObject, quint32 window, QObject *parent); DNativeSettings(const QMetaObject *metaObject, quint32 window, const QByteArray &domain, QObject *parent); bool init(const QMetaObject *metaObject, quint32 window); private: void __setAllKeys(const QByteArrayList &keys); friend class DNativeSettingsPrivate; }; DGUI_END_NAMESPACE QT_BEGIN_NAMESPACE QDebug operator<<(QDebug debug, const DTK_GUI_NAMESPACE::DNativeSettings &settings); QT_END_NAMESPACE #endif // DNATIVESETTINGS_H dtkgui-5.7.12/include/kernel/dpalette.h000066400000000000000000000074541476226661100200000ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPALETTE_H #define DPALETTE_H #include #include #include DGUI_BEGIN_NAMESPACE class DPalettePrivate; class DPalette : public QPalette { Q_GADGET public: enum ColorType { NoType, ItemBackground, //列表项的背景色 TextTitle, //标题型文本的颜色 TextTips, //提示性文本的颜色 TextWarning, //警告类型的文本颜色 TextLively, //活跃式文本颜色(不受活动色影响) LightLively, //活跃式按钮(recommend button)背景色中的亮色(不受活跃色影响) DarkLively, //活跃式按钮(recommend button)背景色中的暗色,会从亮色渐变到暗色(不受活跃色影响) FrameBorder, //控件边框颜色 PlaceholderText, //占位类型的文本颜色,可用于输入框占位内容等提示性文字 FrameShadowBorder, //用于跟阴影叠加的边框颜色 ObviousBackground, //明显的背景色 NColorTypes }; Q_ENUM(ColorType) DPalette(); DPalette(const QPalette &palette); DPalette(const DPalette &palette); ~DPalette(); DPalette &operator=(const DPalette &palette); inline const QColor &color(ColorGroup cg, ColorType ct) const { return brush(cg, ct).color(); } const QBrush &brush(ColorGroup cg, ColorType ct) const; inline void setColor(ColorGroup cg, ColorType ct, const QColor &color) { setBrush(cg, ct, color); } inline void setColor(ColorType ct, const QColor &color) { setColor(All, ct, color); } inline void setBrush(ColorType ct, const QBrush &brush) { setBrush(All, ct, brush); } void setBrush(ColorGroup cg, ColorType ct, const QBrush &brush); inline const QColor &color(ColorType ct) const { return color(Current, ct); } inline const QBrush &brush(ColorType ct) const { return brush(Current, ct); } inline const QBrush &itemBackground() const { return brush(ItemBackground); } inline const QBrush &textTitle() const { return brush(TextTitle); } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) D_DECL_DEPRECATED inline const QBrush &textTiele() const { return textTitle();} #endif inline const QBrush &textTips() const { return brush(TextTips); } inline const QBrush &textWarning() const { return brush(TextWarning); } inline const QBrush &textLively() const { return brush(TextLively); } inline const QBrush &lightLively() const { return brush(LightLively); } inline const QBrush &darkLively() const { return brush(DarkLively); } inline const QBrush &frameBorder() const { return brush(FrameBorder); } inline const QBrush &placeholderText() const { return brush(PlaceholderText); } inline const QBrush &frameShadowBorder() const { return brush(FrameShadowBorder); } using QPalette::color; using QPalette::brush; using QPalette::setBrush; using QPalette::setColor; protected: QScopedPointer d; friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &s, const DPalette &p); }; DGUI_END_NAMESPACE QT_BEGIN_NAMESPACE /***************************************************************************** DPalette stream functions *****************************************************************************/ #ifndef QT_NO_DATASTREAM Q_GUI_EXPORT QDataStream &operator<<(QDataStream &ds, const DTK_GUI_NAMESPACE::DPalette &p); Q_GUI_EXPORT QDataStream &operator>>(QDataStream &ds, DTK_GUI_NAMESPACE::DPalette &p); #endif // QT_NO_DATASTREAM #ifndef QT_NO_DEBUG_STREAM Q_GUI_EXPORT QDebug operator<<(QDebug, const DTK_GUI_NAMESPACE::DPalette &); #endif QT_END_NAMESPACE #endif // DPALETTE_H dtkgui-5.7.12/include/kernel/dplatformhandle.h000066400000000000000000000171001476226661100213270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPLATFORMHANDLE_H #define DPLATFORMHANDLE_H #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QWindow; QT_END_NAMESPACE DGUI_BEGIN_NAMESPACE // TODO: class DPlatformHandle will be removed in the future class DPlatformHandle : public QObject { Q_OBJECT Q_PROPERTY(int windowRadius READ windowRadius WRITE setWindowRadius NOTIFY windowRadiusChanged) Q_PROPERTY(int borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged) Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY borderColorChanged) Q_PROPERTY(int shadowRadius READ shadowRadius WRITE setShadowRadius NOTIFY shadowRadiusChanged) Q_PROPERTY(QPoint shadowOffset READ shadowOffset WRITE setShadowOffset NOTIFY shadowOffsetChanged) Q_PROPERTY(QColor shadowColor READ shadowColor WRITE setShadowColor NOTIFY shadowColorChanged) Q_PROPERTY(EffectScene windowEffect READ windowEffect WRITE setWindowEffect NOTIFY windowEffectChanged) Q_PROPERTY(EffectType windowStartUpEffect READ windowStartUpEffect WRITE setWindowStartUpEffect NOTIFY windowStartUpEffectChanged) Q_PROPERTY(QPainterPath clipPath READ clipPath WRITE setClipPath NOTIFY clipPathChanged) Q_PROPERTY(QRegion frameMask READ frameMask WRITE setFrameMask NOTIFY frameMaskChanged) Q_PROPERTY(QMargins frameMargins READ frameMargins NOTIFY frameMarginsChanged) Q_PROPERTY(bool translucentBackground READ translucentBackground WRITE setTranslucentBackground NOTIFY translucentBackgroundChanged) Q_PROPERTY(bool enableSystemResize READ enableSystemResize WRITE setEnableSystemResize NOTIFY enableSystemResizeChanged) Q_PROPERTY(bool enableSystemMove READ enableSystemMove WRITE setEnableSystemMove NOTIFY enableSystemMoveChanged) Q_PROPERTY(bool enableBlurWindow READ enableBlurWindow WRITE setEnableBlurWindow NOTIFY enableBlurWindowChanged) Q_PROPERTY(bool autoInputMaskByClipPath READ autoInputMaskByClipPath WRITE setAutoInputMaskByClipPath NOTIFY autoInputMaskByClipPathChanged) Q_PROPERTY(WId realWindowId READ realWindowId CONSTANT) public: explicit DPlatformHandle(QWindow *window, QObject *parent = 0); ~DPlatformHandle(); static QString pluginVersion(); static bool isDXcbPlatform(); static void enableDXcbForWindow(QWindow *window); static void enableDXcbForWindow(QWindow *window, bool redirectContent); static bool isEnabledDXcb(const QWindow *window); static bool setEnabledNoTitlebarForWindow(QWindow *window, bool enable); static bool isEnabledNoTitlebar(const QWindow *window); struct WMBlurArea { qint32 x = 0; qint32 y = 0; qint32 width = 0; qint32 height = 0; qint32 xRadius = 0; qint32 yRaduis = 0; }; enum WallpaperScaleMode { FollowScreen = 0x00000000, FollowWindow = 0x00010000 }; enum WallpaperFillMode { PreserveAspectCrop = 0x00000000, PreserveAspectFit = 0x00000001 }; enum EffectScene { EffectNoRadius = 0x01, // 取消窗口圆角 EffectNoShadow = 0x02, // 取消窗口阴影 EffectNoBorder = 0x04, // 取消窗口边框 EffectNoStart = 0x10, // 取消启动场景动效 EffectNoClose = 0x20, // 取消关闭场景动效 EffectNoMaximize = 0x40, // 取消最大化场景动效 EffectNoMinimize = 0x80 // 取消最小化场景动效 }; enum EffectType { EffectNormal = 0x01, // 标准缩放动效 EffectCursor = 0x02, // 鼠标位置展开动效 EffectTop = 0x04, // 从上往下展开 EffectBottom = 0x08, // 从下往上展开 EffectOut = 0x10 // 由外向内 }; Q_ENUM(EffectScene) Q_ENUM(EffectType) Q_DECLARE_FLAGS(EffectScenes, EffectScene) Q_DECLARE_FLAGS(EffectTypes, EffectType) Q_ENUM(EffectScenes) Q_ENUM(EffectTypes) static bool setWindowBlurAreaByWM(QWindow *window, const QVector &area); static bool setWindowBlurAreaByWM(QWindow *window, const QList &paths); static bool setWindowWallpaperParaByWM(QWindow *window, const QRect &area, WallpaperScaleMode sMode, WallpaperFillMode fMode); static bool connectWindowManagerChangedSignal(QObject *object, std::function slot); static bool connectHasBlurWindowChanged(QObject *object, std::function slot); bool setWindowBlurAreaByWM(const QVector &area); bool setWindowBlurAreaByWM(const QList &paths); static void setDisableWindowOverrideCursor(QWindow *window, bool disable); int windowRadius() const; int borderWidth() const; QColor borderColor() const; int shadowRadius() const; QPoint shadowOffset() const; QColor shadowColor() const; EffectScene windowEffect(); EffectType windowStartUpEffect(); QPainterPath clipPath() const; QRegion frameMask() const; QMargins frameMargins() const; bool translucentBackground() const; bool enableSystemResize() const; bool enableSystemMove() const; bool enableBlurWindow() const; bool autoInputMaskByClipPath() const; WId realWindowId() const; static WId windowLeader(); public Q_SLOTS: void setWindowRadius(int windowRadius); void setBorderWidth(int borderWidth); void setBorderColor(const QColor &borderColor); void setWindowEffect(EffectScenes effectScene); void setWindowStartUpEffect(EffectTypes effectType); void setShadowRadius(int shadowRadius); void setShadowOffset(const QPoint &shadowOffset); void setShadowColor(const QColor &shadowColor); void setClipPath(const QPainterPath &clipPath); void setFrameMask(const QRegion &frameMask); void setTranslucentBackground(bool translucentBackground); void setEnableSystemResize(bool enableSystemResize); void setEnableSystemMove(bool enableSystemMove); void setEnableBlurWindow(bool enableBlurWindow); void setAutoInputMaskByClipPath(bool autoInputMaskByClipPath); Q_SIGNALS: void frameMarginsChanged(); void windowRadiusChanged(); void borderWidthChanged(); void borderColorChanged(); void shadowRadiusChanged(); void shadowOffsetChanged(); void shadowColorChanged(); void windowEffectChanged(); void windowStartUpEffectChanged(); void clipPathChanged(); void frameMaskChanged(); void translucentBackgroundChanged(); void enableSystemResizeChanged(); void enableSystemMoveChanged(); void enableBlurWindowChanged(); void autoInputMaskByClipPathChanged(); protected: bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; private: QWindow *m_window; }; inline DPlatformHandle::WMBlurArea dMakeWMBlurArea(quint32 x, quint32 y, quint32 width, quint32 height, quint32 xr = 0, quint32 yr = 0) { DPlatformHandle::WMBlurArea a; a.x = x; a.y = y; a.width = width; a.height = height; a.xRadius = xr; a.yRaduis = yr; return a; } DGUI_END_NAMESPACE QT_BEGIN_NAMESPACE DGUI_USE_NAMESPACE QDebug operator<<(QDebug deg, const DPlatformHandle::WMBlurArea &area); QT_END_NAMESPACE #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) Q_DECLARE_METATYPE(QPainterPath) Q_DECLARE_METATYPE(QMargins) #endif Q_DECLARE_METATYPE(QRegion) Q_DECLARE_OPERATORS_FOR_FLAGS(DPlatformHandle::EffectScenes) Q_DECLARE_OPERATORS_FOR_FLAGS(DPlatformHandle::EffectTypes) #endif // DPLATFORMHANDLE_H dtkgui-5.7.12/include/kernel/dplatformtheme.h000066400000000000000000000264731476226661100212130ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPLATFORMTHEME_H #define DPLATFORMTHEME_H #include #include #include DGUI_BEGIN_NAMESPACE class DPlatformThemePrivate; // TODO: class DPlatformTheme will be removed in the future class DPlatformTheme : public DNativeSettings { Q_OBJECT D_DECLARE_PRIVATE(DPlatformTheme) Q_PROPERTY(int cursorBlinkTime READ cursorBlinkTime WRITE setCursorBlinkTime NOTIFY cursorBlinkTimeChanged) Q_PROPERTY(int cursorBlinkTimeout READ cursorBlinkTimeout WRITE setCursorBlinkTimeout NOTIFY cursorBlinkTimeoutChanged) Q_PROPERTY(bool cursorBlink READ cursorBlink WRITE setCursorBlink NOTIFY cursorBlinkChanged) Q_PROPERTY(int doubleClickDistance READ doubleClickDistance WRITE setDoubleClickDistance NOTIFY doubleClickDistanceChanged) Q_PROPERTY(int doubleClickTime READ doubleClickTime WRITE setDoubleClickTime NOTIFY doubleClickTimeChanged) Q_PROPERTY(int dndDragThreshold READ dndDragThreshold WRITE setDndDragThreshold NOTIFY dndDragThresholdChanged) Q_PROPERTY(int windowRadius READ windowRadius WRITE setWindowRadius NOTIFY windowRadiusChanged) Q_PROPERTY(QByteArray themeName READ themeName WRITE setThemeName NOTIFY themeNameChanged) Q_PROPERTY(QByteArray iconThemeName READ iconThemeName WRITE setIconThemeName NOTIFY iconThemeNameChanged) Q_PROPERTY(QByteArray soundThemeName READ soundThemeName WRITE setSoundThemeName NOTIFY soundThemeNameChanged) // Font Q_PROPERTY(QByteArray fontName READ fontName WRITE setFontName NOTIFY fontNameChanged) Q_PROPERTY(QByteArray monoFontName READ monoFontName WRITE setMonoFontName NOTIFY monoFontNameChanged) Q_PROPERTY(qreal fontPointSize READ fontPointSize WRITE setFontPointSize NOTIFY fontPointSizeChanged) Q_PROPERTY(QByteArray gtkFontName READ gtkFontName WRITE setGtkFontName NOTIFY gtkFontNameChanged) Q_PROPERTY(QColor activeColor READ activeColor WRITE setActiveColor NOTIFY activeColorChanged) Q_PROPERTY(QColor darkActiveColor READ darkActiveColor WRITE setDarkActiveColor NOTIFY darkActiveColorChanged) #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) // QPalette Q_PROPERTY(QColor window READ window WRITE setWindow NOTIFY windowChanged) Q_PROPERTY(QColor windowText READ windowText WRITE setWindowText NOTIFY windowTextChanged) Q_PROPERTY(QColor base READ base WRITE setBase NOTIFY baseChanged) Q_PROPERTY(QColor alternateBase READ alternateBase WRITE setAlternateBase NOTIFY alternateBaseChanged) Q_PROPERTY(QColor toolTipBase READ toolTipBase WRITE setToolTipBase NOTIFY toolTipBaseChanged) Q_PROPERTY(QColor toolTipText READ toolTipText WRITE setToolTipText NOTIFY toolTipTextChanged) Q_PROPERTY(QColor text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QColor button READ button WRITE setButton NOTIFY buttonChanged) Q_PROPERTY(QColor buttonText READ buttonText WRITE setButtonText NOTIFY buttonTextChanged) Q_PROPERTY(QColor brightText READ brightText WRITE setBrightText NOTIFY brightTextChanged) Q_PROPERTY(QColor light READ light WRITE setLight NOTIFY lightChanged) Q_PROPERTY(QColor midlight READ midlight WRITE setMidlight NOTIFY midlightChanged) Q_PROPERTY(QColor dark READ dark WRITE setDark NOTIFY darkChanged) Q_PROPERTY(QColor mid READ mid WRITE setMid NOTIFY midChanged) Q_PROPERTY(QColor shadow READ shadow WRITE setShadow NOTIFY shadowChanged) Q_PROPERTY(QColor highlight READ highlight WRITE setHighlight NOTIFY highlightChanged) Q_PROPERTY(QColor highlightedText READ highlightedText WRITE setHighlightedText NOTIFY highlightedTextChanged) Q_PROPERTY(QColor link READ link WRITE setLink NOTIFY linkChanged) Q_PROPERTY(QColor linkVisited READ linkVisited WRITE setLinkVisited NOTIFY linkVisitedChanged) // DPalette Q_PROPERTY(QColor itemBackground READ itemBackground WRITE setItemBackground NOTIFY itemBackgroundChanged) Q_PROPERTY(QColor textTitle READ textTitle WRITE setTextTitle NOTIFY textTitleChanged) Q_PROPERTY(QColor textTips READ textTips WRITE setTextTips NOTIFY textTipsChanged) Q_PROPERTY(QColor textWarning READ textWarning WRITE setTextWarning NOTIFY textWarningChanged) Q_PROPERTY(QColor textLively READ textLively WRITE setTextLively NOTIFY textLivelyChanged) Q_PROPERTY(QColor lightLively READ lightLively WRITE setLightLively NOTIFY lightLivelyChanged) Q_PROPERTY(QColor darkLively READ darkLively WRITE setDarkLively NOTIFY darkLivelyChanged) Q_PROPERTY(QColor frameBorder READ frameBorder WRITE setFrameBorder NOTIFY frameBorderChanged) #endif // DSizeMode Q_PROPERTY(int sizeMode READ sizeMode NOTIFY sizeModeChanged) Q_PROPERTY(int scrollBarPolicy READ scrollBarPolicy NOTIFY scrollBarPolicyChanged) public: explicit DPlatformTheme(quint32 window, QObject *parent = nullptr); DPlatformTheme(quint32 window, DPlatformTheme *parent); ~DPlatformTheme(); bool isValid() const; DPlatformTheme *parentTheme() const; void setFallbackProperty(bool fallback); DPalette palette() const; DPalette fetchPalette(const DPalette &base, bool *ok = nullptr) const; void setPalette(const DPalette &palette); int cursorBlinkTime() const; int cursorBlinkTimeout() const; bool cursorBlink() const; int doubleClickDistance() const; int doubleClickTime() const; int dndDragThreshold() const; int windowRadius() const; int windowRadius(int defaultValue) const; QByteArray themeName() const; QByteArray iconThemeName() const; QByteArray soundThemeName() const; QByteArray fontName() const; QByteArray monoFontName() const; qreal fontPointSize() const; QByteArray gtkFontName() const; QColor activeColor() const; QColor darkActiveColor() const; bool isValidPalette() const; #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QColor window() const; QColor windowText() const; QColor base() const; QColor alternateBase() const; QColor toolTipBase() const; QColor toolTipText() const; QColor text() const; QColor button() const; QColor buttonText() const; QColor brightText() const; QColor light() const; QColor midlight() const; QColor dark() const; QColor mid() const; QColor shadow() const; QColor highlight() const; QColor highlightedText() const; QColor link() const; QColor linkVisited() const; QColor itemBackground() const; QColor textTitle() const; QColor textTips() const; QColor textWarning() const; QColor textLively() const; QColor lightLively() const; QColor darkLively() const; QColor frameBorder() const; #endif int sizeMode() const; int scrollBarPolicy() const; public Q_SLOTS: void setCursorBlinkTime(int cursorBlinkTime); void setCursorBlinkTimeout(int cursorBlinkTimeout); void setCursorBlink(bool cursorBlink); void setDoubleClickDistance(int doubleClickDistance); void setDoubleClickTime(int doubleClickTime); void setDndDragThreshold(int dndDragThreshold); void setThemeName(const QByteArray &themeName); void setIconThemeName(const QByteArray &iconThemeName); void setSoundThemeName(const QByteArray &soundThemeName); void setFontName(const QByteArray &fontName); void setMonoFontName(const QByteArray &monoFontName); void setFontPointSize(qreal fontPointSize); void setGtkFontName(const QByteArray &fontName); void setActiveColor(const QColor activeColor); void setDarkActiveColor(const QColor &activeColor); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) void setWindow(const QColor &window); void setWindowText(const QColor &windowText); void setBase(const QColor &base); void setAlternateBase(const QColor &alternateBase); void setToolTipBase(const QColor &toolTipBase); void setToolTipText(const QColor &toolTipText); void setText(const QColor &text); void setButton(const QColor &button); void setButtonText(const QColor &buttonText); void setBrightText(const QColor &brightText); void setLight(const QColor &light); void setMidlight(const QColor &midlight); void setDark(const QColor &dark); void setMid(const QColor &mid); void setShadow(const QColor &shadow); void setHighlight(const QColor &highlight); void setHighlightedText(const QColor &highlightedText); void setLink(const QColor &link); void setLinkVisited(const QColor &linkVisited); void setItemBackground(const QColor &itemBackground); void setTextTitle(const QColor &textTitle); void setTextTips(const QColor &textTips); void setTextWarning(const QColor &textWarning); void setTextLively(const QColor &textLively); void setLightLively(const QColor &lightLively); void setDarkLively(const QColor &darkLively); void setFrameBorder(const QColor &frameBorder); #endif int dotsPerInch(const QString &screenName = QString()) const; void setDotsPerInch(const QString &screenName, int dpi); void setWindowRadius(int windowRadius); Q_SIGNALS: void cursorBlinkTimeChanged(int cursorBlinkTime); void cursorBlinkTimeoutChanged(int cursorBlinkTimeout); void cursorBlinkChanged(bool cursorBlink); void doubleClickDistanceChanged(int doubleClickDistance); void doubleClickTimeChanged(int doubleClickTime); void dndDragThresholdChanged(int dndDragThreshold); void themeNameChanged(QByteArray themeName); void iconThemeNameChanged(QByteArray iconThemeName); void soundThemeNameChanged(QByteArray soundThemeName); void fontNameChanged(QByteArray fontName); void monoFontNameChanged(QByteArray monoFontName); void fontPointSizeChanged(qreal fontPointSize); void gtkFontNameChanged(QByteArray fontName); void activeColorChanged(QColor activeColor); void darkActiveColorChanged(QColor activeColor); void paletteChanged(DPalette palette); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) void windowChanged(QColor window); void windowTextChanged(QColor windowText); void baseChanged(QColor base); void alternateBaseChanged(QColor alternateBase); void toolTipBaseChanged(QColor toolTipBase); void toolTipTextChanged(QColor toolTipText); void textChanged(QColor text); void buttonChanged(QColor button); void buttonTextChanged(QColor buttonText); void brightTextChanged(QColor brightText); void lightChanged(QColor light); void midlightChanged(QColor midlight); void darkChanged(QColor dark); void midChanged(QColor mid); void shadowChanged(QColor shadow); void highlightChanged(QColor highlight); void highlightedTextChanged(QColor highlightedText); void linkChanged(QColor link); void linkVisitedChanged(QColor linkVisited); void itemBackgroundChanged(QColor itemBackground); void textTitleChanged(QColor textTitle); void textTipsChanged(QColor textTips); void textWarningChanged(QColor textWarning); void textLivelyChanged(QColor textLively); void lightLivelyChanged(QColor lightLively); void darkLivelyChanged(QColor darkLively); void frameBorderChanged(QColor frameBorder); #endif void dotsPerInchChanged(const QString &screen, int dpi); void windowRadiusChanged(int r); void sizeModeChanged(int sizeMode); void scrollBarPolicyChanged(int scrollBarPolicy); private: friend class DPlatformThemePrivate; }; DGUI_END_NAMESPACE #endif // DPLATFORMTHEME_H dtkgui-5.7.12/include/kernel/dregionmonitor.h000066400000000000000000000055401476226661100212270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DREGIONMONITOR_H #define DREGIONMONITOR_H #include #include #include DGUI_BEGIN_NAMESPACE class DRegionMonitorPrivate; class DRegionMonitor : public QObject, public DTK_CORE_NAMESPACE::DObject { Q_OBJECT D_DECLARE_PRIVATE(DRegionMonitor) Q_DISABLE_COPY(DRegionMonitor) Q_PROPERTY(CoordinateType coordinateType READ coordinateType WRITE setCoordinateType NOTIFY coordinateTypeChanged) Q_PROPERTY(RegisterdFlags registerdFlags READ registerFlags WRITE setRegisterFlags NOTIFY registerdFlagsChanged) public: explicit DRegionMonitor(QObject *parent = nullptr); enum RegisterdFlag { Motion = 1 << 0, Button = 1 << 1, Key = 1 << 2 }; Q_DECLARE_FLAGS(RegisterdFlags, RegisterdFlag) enum WatchedFlags { Button_Left = 1, Button_Middle, Button_Right, Wheel_Up, Wheel_Down }; enum CoordinateType { ScaleRatio, Original }; Q_ENUM(CoordinateType) bool registered() const; QRegion watchedRegion() const; RegisterdFlags registerFlags() const; CoordinateType coordinateType() const; Q_SIGNALS: void buttonPress(const QPoint &p, const int flag) const; void buttonRelease(const QPoint &p, const int flag) const; void cursorMove(const QPoint &p) const; void cursorEnter(const QPoint &p) const; void cursorLeave(const QPoint &p) const; void keyPress(const QString &keyname) const; void keyRelease(const QString &keyname) const; void registerdFlagsChanged(RegisterdFlags flags) const; void coordinateTypeChanged(CoordinateType type) const; public Q_SLOTS: void registerRegion(); inline void registerRegion(const QRegion ®ion) { setWatchedRegion(region); registerRegion(); } void unregisterRegion(); void setWatchedRegion(const QRegion ®ion); void setRegisterFlags(RegisterdFlags flags); void setCoordinateType(CoordinateType type); private: Q_PRIVATE_SLOT(d_func(), void _q_ButtonPress(const int, const int, const int, const QString&)) Q_PRIVATE_SLOT(d_func(), void _q_ButtonRelease(const int, const int, const int, const QString&)) Q_PRIVATE_SLOT(d_func(), void _q_CursorMove(const int, const int, const QString &)) Q_PRIVATE_SLOT(d_func(), void _q_CursorEnter(const int, const int, const QString &)) Q_PRIVATE_SLOT(d_func(), void _q_CursorLeave(const int, const int, const QString &)) Q_PRIVATE_SLOT(d_func(), void _q_KeyPress(const QString &, const int, const int, const QString &)) Q_PRIVATE_SLOT(d_func(), void _q_KeyRelease(const QString &, const int, const int, const QString &)) }; Q_DECLARE_OPERATORS_FOR_FLAGS (DRegionMonitor::RegisterdFlags); DGUI_END_NAMESPACE #endif // DREGIONMONITOR_H dtkgui-5.7.12/include/kernel/dwindowgroupleader.h000066400000000000000000000014021476226661100220660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DWINDOWGROUPLEADER_H #define DWINDOWGROUPLEADER_H #include #include QT_BEGIN_NAMESPACE class QWindow; QT_END_NAMESPACE DGUI_BEGIN_NAMESPACE class DWindowGroupLeaderPrivate; class DWindowGroupLeader { public: explicit DWindowGroupLeader(quint32 groupId = 0); ~DWindowGroupLeader(); quint32 groupLeaderId() const; quint32 clientLeaderId() const; void addWindow(QWindow *window); void removeWindow(QWindow *window); private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(DWindowGroupLeader) }; DGUI_END_NAMESPACE #endif // DWINDOWGROUPLEADER_H dtkgui-5.7.12/include/kernel/dwindowmanagerhelper.h000066400000000000000000000104401476226661100223710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DWINDOWMANAGERHELPER_H #define DWINDOWMANAGERHELPER_H #include #include #include DGUI_BEGIN_NAMESPACE class DForeignWindow; class DWindowManagerHelperPrivate; class DWindowManagerHelper : public QObject, public DTK_CORE_NAMESPACE::DObject { Q_OBJECT Q_PROPERTY(bool hasBlurWindow READ hasBlurWindow NOTIFY hasBlurWindowChanged) Q_PROPERTY(bool hasComposite READ hasComposite NOTIFY hasCompositeChanged) Q_PROPERTY(bool hasNoTitlebar READ hasNoTitlebar NOTIFY hasNoTitlebarChanged) Q_PROPERTY(bool hasWallpaperEffect READ hasWallpaperEffect NOTIFY hasWallpaperEffectChanged) public: enum MotifFunction { FUNC_RESIZE = (1L << 1), FUNC_MOVE = (1L << 2), FUNC_MINIMIZE = (1L << 3), FUNC_MAXIMIZE = (1L << 4), FUNC_CLOSE = (1L << 5), FUNC_ALL = FUNC_RESIZE | FUNC_MOVE | FUNC_MINIMIZE | FUNC_MAXIMIZE | FUNC_CLOSE }; Q_ENUM(MotifFunction) Q_DECLARE_FLAGS(MotifFunctions, MotifFunction) Q_FLAG(MotifFunctions) enum MotifDecoration { DECOR_BORDER = (1L << 1), DECOR_RESIZEH = (1L << 2), DECOR_TITLE = (1L << 3), DECOR_MENU = (1L << 4), DECOR_MINIMIZE = (1L << 5), DECOR_MAXIMIZE = (1L << 6), DECOR_ALL = DECOR_BORDER | DECOR_RESIZEH | DECOR_TITLE | DECOR_MENU | DECOR_MINIMIZE | DECOR_MAXIMIZE }; Q_ENUM(MotifDecoration) Q_DECLARE_FLAGS(MotifDecorations, MotifDecoration) Q_FLAG(MotifDecorations) enum WMName { OtherWM, DeepinWM, KWinWM }; Q_ENUM(WMName) enum WmWindowType { UnknowWindowType = 0x000000, NormalType = 0x000001, DesktopType = 0x000002, DockType = 0x000004, ToolbarType = 0x000008, MenuType = 0x000010, UtilityType = 0x000020, SplashType = 0x000040, DialogType = 0x000080, DropDownMenuType = 0x000100, PopupMenuType = 0x000200, TooltipType = 0x000400, NotificationType = 0x000800, ComboType = 0x001000, DndType = 0x002000, KdeOverrideType = 0x004000 }; Q_ENUM(WmWindowType) Q_DECLARE_FLAGS(WmWindowTypes, WmWindowType) Q_FLAG(WmWindowTypes) ~DWindowManagerHelper(); static DWindowManagerHelper *instance(); static void setMotifFunctions(const QWindow *window, MotifFunctions hints); static MotifFunctions setMotifFunctions(const QWindow *window, MotifFunctions hints, bool on); static MotifFunctions getMotifFunctions(const QWindow *window); static void setMotifDecorations(const QWindow *window, MotifDecorations hints); static MotifDecorations setMotifDecorations(const QWindow *window, MotifDecorations hints, bool on); static MotifDecorations getMotifDecorations(const QWindow *window); static void setWmWindowTypes(QWindow *window, WmWindowTypes types); static void setWmClassName(const QByteArray &name); static void popupSystemWindowMenu(const QWindow *window); bool hasBlurWindow() const; bool hasComposite() const; bool hasNoTitlebar() const; bool hasWallpaperEffect() const; QString windowManagerNameString() const; WMName windowManagerName() const; QVector allWindowIdList() const; QVector currentWorkspaceWindowIdList() const; QList currentWorkspaceWindows() const; quint32 windowFromPoint(const QPoint &p); Q_SIGNALS: void windowManagerChanged(); void hasBlurWindowChanged(); void hasCompositeChanged(); void hasNoTitlebarChanged(); void hasWallpaperEffectChanged(); void windowListChanged(); void windowMotifWMHintsChanged(quint32 winId); protected: explicit DWindowManagerHelper(QObject *parent = 0); private: D_DECLARE_PRIVATE(DWindowManagerHelper) }; DGUI_END_NAMESPACE Q_DECLARE_OPERATORS_FOR_FLAGS(DTK_GUI_NAMESPACE::DWindowManagerHelper::MotifFunctions) Q_DECLARE_OPERATORS_FOR_FLAGS(DTK_GUI_NAMESPACE::DWindowManagerHelper::MotifDecorations) Q_DECLARE_OPERATORS_FOR_FLAGS(DTK_GUI_NAMESPACE::DWindowManagerHelper::WmWindowTypes) #endif // DWINDOWMANAGERHELPER_H dtkgui-5.7.12/include/util/000077500000000000000000000000001476226661100155105ustar00rootroot00000000000000dtkgui-5.7.12/include/util/ddciicon.h000066400000000000000000000111271476226661100174370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include "ddciiconpalette.h" #include #include #include DCORE_BEGIN_NAMESPACE class DDciFile; DCORE_END_NAMESPACE DGUI_BEGIN_NAMESPACE typedef void* DDciIconMatchResult; class DDciIconImagePrivate; class DDciIconImage { friend class DDciIcon; public: DDciIconImage() = default; DDciIconImage(const DDciIconImage &other); DDciIconImage &operator=(const DDciIconImage &other) noexcept; DDciIconImage(DDciIconImage && other) noexcept; DDciIconImage &operator=(DDciIconImage &&other) noexcept; void swap(DDciIconImage &other) noexcept { d.swap(other.d); } ~DDciIconImage(); bool operator==(const DDciIconImage &other) const { return d == other.d; } bool operator!=(const DDciIconImage &other) const { return d != other.d; } inline bool isNull() const { return !d; } void reset(); QImage toImage(const DDciIconPalette &palette = DDciIconPalette()) const; void paint(QPainter *painter, const QRectF &rect, Qt::Alignment alignment = Qt::AlignCenter, const DDciIconPalette &palette = DDciIconPalette()) const; bool hasPalette() const; bool supportsAnimation() const; bool atBegin() const; bool atEnd() const; bool jumpToNextImage(); int loopCount() const; int maxImageCount() const; int currentImageDuration() const; int currentImageNumber() const; protected: DDciIconImage(const QSharedPointer &dd) : d(dd) {} QSharedPointer d; }; class DDciIconPrivate; class DDciIcon { public: enum Mode { Normal = 0, Disabled = 1, Hover = 2, Pressed = 3 }; enum Theme { Light = 0, Dark = 1 }; D_DECL_DEPRECATED enum IconAttibute { HasPalette = 0x001 }; using IconAttribute = DDciIcon::IconAttibute; enum IconMatchedFlag { None = 0, DontFallbackMode = 0x01, RegardPaddingsAsSize = 0x02 }; Q_DECLARE_FLAGS(IconMatchedFlags, IconMatchedFlag) Q_FLAGS(IconMatchedFlags); DDciIcon(); explicit DDciIcon(const DCORE_NAMESPACE::DDciFile *dciFile); explicit DDciIcon(const QString &fileName); explicit DDciIcon(const QByteArray &data); DDciIcon(const DDciIcon &other); DDciIcon &operator=(const DDciIcon &other) noexcept; ~DDciIcon(); DDciIcon(DDciIcon && other) noexcept; DDciIcon &operator=(DDciIcon &&other) noexcept; void swap(DDciIcon &other) noexcept { d.swap(other.d); } bool isNull() const; DDciIconMatchResult matchIcon(int size, Theme theme, Mode mode, IconMatchedFlags flags = None) const; int actualSize(DDciIconMatchResult result) const; int actualSize(int size, Theme theme, Mode mode = Normal) const; QList availableSizes(Theme theme, Mode mode = Normal) const; bool isSupportedAttribute(DDciIconMatchResult result, IconAttribute attr) const; static bool isSupportedAttribute(const DDciIconImage &image, IconAttribute attr); QPixmap pixmap(qreal devicePixelRatio, int iconSize, Theme theme, Mode mode = Normal, const DDciIconPalette &palette = DDciIconPalette()) const; QPixmap pixmap(qreal devicePixelRatio, int iconSize, DDciIconMatchResult result, const DDciIconPalette &palette = DDciIconPalette()) const; void paint(QPainter *painter, const QRect &rect, qreal devicePixelRatio, Theme theme, Mode mode = Normal, Qt::Alignment alignment = Qt::AlignCenter, const DDciIconPalette &palette = DDciIconPalette()) const; void paint(QPainter *painter, const QRect &rect, qreal devicePixelRatio, DDciIconMatchResult result, Qt::Alignment alignment = Qt::AlignCenter, const DDciIconPalette &palette = DDciIconPalette()) const; DDciIconImage image(DDciIconMatchResult result, int size, qreal devicePixelRatio) const; static DDciIcon fromTheme(const QString &name); static DDciIcon fromTheme(const QString &name, const DDciIcon &fallback); // TODO: Should be compatible with QIcon private: QSharedDataPointer d; #ifndef QT_NO_DATASTREAM friend QDataStream &operator<<(QDataStream &, const DDciIcon &); friend QDataStream &operator>>(QDataStream &, DDciIcon &); #endif }; #ifndef QT_NO_DATASTREAM QDataStream &operator<<(QDataStream &, const DDciIcon &); QDataStream &operator>>(QDataStream &, DDciIcon &); #endif DGUI_END_NAMESPACE Q_DECLARE_METATYPE(DTK_GUI_NAMESPACE::DDciIcon); dtkgui-5.7.12/include/util/ddciiconpalette.h000066400000000000000000000037161476226661100210230ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DDCIICONPALETTE_H #define DDCIICONPALETTE_H #include #include #include #include QT_BEGIN_NAMESPACE class QPalette; QT_END_NAMESPACE DGUI_BEGIN_NAMESPACE class DDciIconPalette { Q_GADGET Q_PROPERTY(QColor foreground READ foreground WRITE setForeground FINAL) Q_PROPERTY(QColor background READ background WRITE setBackground FINAL) Q_PROPERTY(QColor highlight READ highlight WRITE setHighlight FINAL) Q_PROPERTY(QColor highlightForeground READ highlightForeground WRITE setHighlightForeground FINAL) public: enum PaletteRole { NoPalette = -1, Foreground = 0, Background = 1, HighlightForeground = 2, Highlight = 3, PaletteCount }; DDciIconPalette(QColor foreground = QColor::Invalid, QColor background = QColor::Invalid, QColor highlight = QColor::Invalid, QColor highlightForeground = QColor::Invalid); bool operator==(const DDciIconPalette &other) const; bool operator!=(const DDciIconPalette &other) const; QColor foreground() const; void setForeground(const QColor &foreground); QColor background() const; void setBackground(const QColor &background); QColor highlightForeground() const; void setHighlightForeground(const QColor &highlightForeground); QColor highlight() const; void setHighlight(const QColor &highlight); static QString convertToString(const DDciIconPalette &palette); static DDciIconPalette convertFromString(const QString &data); static DDciIconPalette fromQPalette(const QPalette &pa); private: QVector colors; }; DGUI_END_NAMESPACE QT_BEGIN_NAMESPACE #ifndef QT_NO_DEBUG_STREAM Q_GUI_EXPORT QDebug operator<<(QDebug, const DTK_GUI_NAMESPACE::DDciIconPalette &); #endif QT_END_NAMESPACE #endif // DDCIICONPALETTE_H dtkgui-5.7.12/include/util/ddciiconplayer.h000066400000000000000000000053531476226661100206600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include #include DGUI_BEGIN_NAMESPACE class DDciIconImage; class DDciIconPalette; class DDciIconImagePlayerPrivate; class DDciIconImagePlayer : public QObject, public DCORE_NAMESPACE::DObject { D_DECLARE_PRIVATE(DDciIconImagePlayer) Q_OBJECT Q_PROPERTY(DGUI_NAMESPACE::DDciIconImagePlayer::State state READ state NOTIFY stateChanged) public: enum State { NotRunning, WaitingRead, Running }; Q_ENUM(State) enum Flag { Continue = 1, CacheAll = 2, InvertedOrder = 4, IgnoreLastImageLoop = 8, AllowNonLastImageLoop = 16, ClearCacheOnStop = 32 }; Q_DECLARE_FLAGS(Flags, Flag) explicit DDciIconImagePlayer(QObject *parent = nullptr); void setImages(const QVector &images); QVector images() const; const DDciIconImage ¤tImage() const; bool currentLoopForever() const; bool setPalette(const DDciIconPalette &palette); DDciIconPalette palette() const; void setLoopCount(int count); int loopCount() const; void abortLoop(); QImage readImage(); State state() const; void clearCache(); public Q_SLOTS: bool start(float speed = 1.0, DGUI_NAMESPACE::DDciIconImagePlayer::Flags flags = {}); void stop(); Q_SIGNALS: void started(); void updated(); void finished(); void stateChanged(); private: void timerEvent(QTimerEvent *event) override; }; class DDciIconPlayerPrivate; class DDciIconPlayer : public QObject, public DCORE_NAMESPACE::DObject { D_DECLARE_PRIVATE(DDciIconPlayer) Q_OBJECT public: enum State { Idle, Busy }; Q_ENUM(State) explicit DDciIconPlayer(QObject *parent = nullptr); State state() const; void setIcon(const DDciIcon &icon); DDciIcon icon() const; void setTheme(DDciIcon::Theme theme); DDciIcon::Theme theme() const; void setMode(DDciIcon::Mode mode); DDciIcon::Mode mode() const; void setIconSize(int size); int iconSize() const; void setDevicePixelRatio(qreal devicePixelRatio); qreal devicePixelRatio() const; void setPalette(const DDciIconPalette &palette); QImage currentImage() const; void play(DDciIcon::Mode mode); void stop(); void abort(); Q_SIGNALS: void stateChanged(); void updated(); void modeChanged(DDciIcon::Mode oldMode, DDciIcon::Mode newMode); private: D_PRIVATE_SLOT(void _q_playFromQueue(int)) }; DGUI_END_NAMESPACE Q_DECLARE_OPERATORS_FOR_FLAGS(DTK_GUI_NAMESPACE::DDciIconImagePlayer::Flags) dtkgui-5.7.12/include/util/ddesktopservices.h000066400000000000000000000047441476226661100212530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once #include #include #include DGUI_BEGIN_NAMESPACE class DDesktopServices { public: enum SystemSoundEffect { SSE_Notifications, SEE_Screenshot, SSE_EmptyTrash, SSE_SendFileComplete, SSE_BootUp, SSE_Shutdown, SSE_Logout, SSE_WakeUp, SSE_VolumeChange, SSE_LowBattery, SSE_PlugIn, SSE_PlugOut, SSE_DeviceAdded, SSE_DeviceRemoved, SSE_Error, }; static bool showFolder(const QString &localFilePath, const QString &startupId = QString()); static bool showFolders(const QList &localFilePaths, const QString &startupId = QString()); static bool showFolder(const QUrl &url, const QString &startupId = QString()); static bool showFolders(const QList &urls, const QString &startupId = QString()); static bool showFileItemProperty(const QString &localFilePath, const QString &startupId = QString()); static bool showFileItemProperties(const QList &localFilePaths, const QString &startupId = QString()); static bool showFileItemProperty(const QUrl &url, const QString &startupId = QString()); static bool showFileItemProperties(const QList &urls, const QString &startupId = QString()); static bool showFileItem(const QString &localFilePath, const QString &startupId = QString()); static bool showFileItems(const QList &localFilePaths, const QString &startupId = QString()); static bool showFileItem(const QUrl &url, const QString &startupId = QString()); static bool showFileItems(const QList &urls, const QString &startupId = QString()); static bool trash(const QString &localFilePath); static bool trash(const QList &localFilePaths); static bool trash(const QUrl &url); static bool trash(const QList &urls); static bool playSystemSoundEffect(const SystemSoundEffect &effect); static bool playSystemSoundEffect(const QString &name); static bool previewSystemSoundEffect(const SystemSoundEffect &effect); static bool previewSystemSoundEffect(const QString &name); static QString getNameByEffectType(const SystemSoundEffect &effect); static QString errorMessage(); }; DGUI_END_NAMESPACE #ifdef Q_OS_LINUX Q_DECLARE_METATYPE(DTK_GUI_NAMESPACE::DDesktopServices::SystemSoundEffect) #endif dtkgui-5.7.12/include/util/dfontmanager.h000066400000000000000000000052271476226661100203340ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFONTSIZEMANAGER_H #define DFONTSIZEMANAGER_H #include #include #include #include DGUI_BEGIN_NAMESPACE class DFontManagerPrivate; class DFontManager : public QObject , public DTK_CORE_NAMESPACE::DObject { Q_OBJECT Q_PROPERTY(QFont t1 READ t1 NOTIFY fontChanged) Q_PROPERTY(QFont t2 READ t2 NOTIFY fontChanged) Q_PROPERTY(QFont t3 READ t3 NOTIFY fontChanged) Q_PROPERTY(QFont t4 READ t4 NOTIFY fontChanged) Q_PROPERTY(QFont t5 READ t5 NOTIFY fontChanged) Q_PROPERTY(QFont t6 READ t6 NOTIFY fontChanged) Q_PROPERTY(QFont t7 READ t7 NOTIFY fontChanged) Q_PROPERTY(QFont t8 READ t8 NOTIFY fontChanged) Q_PROPERTY(QFont t9 READ t9 NOTIFY fontChanged) Q_PROPERTY(QFont t10 READ t10 NOTIFY fontChanged) Q_PROPERTY(QFont baseFont READ baseFont WRITE setBaseFont RESET resetBaseFont NOTIFY fontChanged) public: enum SizeType { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NSizeTypes }; Q_ENUM(SizeType) DFontManager(QObject *parent = nullptr); ~DFontManager() override; Q_INVOKABLE int fontPixelSize(SizeType type) const; Q_INVOKABLE void setFontPixelSize(SizeType type, int size); Q_INVOKABLE static int fontPixelSize(const QFont &font); Q_INVOKABLE static QFont get(int pixelSize, const QFont &base); inline const QFont get(SizeType type, const QFont &base) const { return get(fontPixelSize(type), base); } inline const QFont get(SizeType type) const { return get(type, baseFont()); } QFont baseFont() const; void setBaseFont(const QFont &font); void resetBaseFont(); inline const QFont t1() const { return get(T1); } inline const QFont t2() const { return get(T2); } inline const QFont t3() const { return get(T3); } inline const QFont t4() const { return get(T4); } inline const QFont t5() const { return get(T5); } inline const QFont t6() const { return get(T6); } inline const QFont t7() const { return get(T7); } inline const QFont t8() const { return get(T8); } inline const QFont t9() const { return get(T9); } inline const QFont t10() const { return get(T10); } Q_SIGNALS: void fontChanged(); private: D_DECLARE_PRIVATE(DFontManager) }; DGUI_END_NAMESPACE #endif // DFONTSIZEMANAGER_H dtkgui-5.7.12/include/util/dicon.h000066400000000000000000000010121476226661100167470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DICON_H #define DICON_H #include #include DGUI_BEGIN_NAMESPACE class DIcon : public QIcon { public: explicit DIcon(const QIcon &other); virtual ~DIcon(); QPixmap pixmap(const QSize &size, qreal devicePixelRatio, Mode mode = Normal, State state = Off); static QPixmap loadNxPixmap(const QString &fileName); }; DGUI_END_NAMESPACE #endif // DICON_H dtkgui-5.7.12/include/util/dicontheme.h000066400000000000000000000030221476226661100177750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DICONTHEME_H #define DICONTHEME_H #include #include #include DGUI_BEGIN_NAMESPACE namespace DIconTheme { enum Option { DontFallbackToQIconFromTheme = 1 << 0, IgnoreBuiltinIcons = 1 << 1, IgnoreDciIcons = 1 << 2, IgnoreIconCache = 1 << 3 }; Q_DECLARE_FLAGS(Options, Option) class CachedData; class Cached { CachedData *data = nullptr; public: Cached(); ~Cached(); int maxCost() const; void setMaxCost(int cost); void clear(); QIcon findQIcon(const QString &iconName, Options options = Options(), const QIcon &fallback = QIcon()); QString findDciIconFile(const QString &iconName, const QString &themeName, const QString &fallback = {}); }; Cached *cached(); QIcon findQIcon(const QString &iconName, Options options = Options()); QIcon findQIcon(const QString &iconName, const QIcon &fallback, Options options = Options()); QIconEngine *createIconEngine(const QString &iconName, Options options = DontFallbackToQIconFromTheme); QString findDciIconFile(const QString &iconName, const QString &themeName); QStringList dciThemeSearchPaths(); void setDciThemeSearchPaths(const QStringList &path); bool isBuiltinIcon(const QIcon &icon); bool isXdgIcon(const QIcon &icon); } DGUI_END_NAMESPACE #endif // DICONTHEME_H dtkgui-5.7.12/include/util/dimagehandler.h000066400000000000000000000052121476226661100204450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DIMAGEHANDLER_H #define DIMAGEHANDLER_H #include #include #include #include DGUI_BEGIN_NAMESPACE class DImageHandlerPrivate; class DImageHandler : public QObject, public DTK_CORE_NAMESPACE::DObject { Q_OBJECT public: explicit DImageHandler(QObject *parent = nullptr); ~DImageHandler(); void setFileName(const QString &fileName); QString fileName() const; QImage readImage(); QImage thumbnail(const QSize &size, Qt::AspectRatioMode mode); QString imageFormat() const; QSize imageSize(); QHash findAllMetaData(); void clearCache(); bool saveImage(const QString &fileName, const QString &format = QString()); bool saveImage(const QImage &image, const QString &fileName, const QString &format = QString()); bool rotateImage(QImage &image, int angle); bool rotateImageFile(const QString &fileName, int angle); bool isReadable() const; bool isWriteable() const; bool isRotatable() const; QString lastError() const; static QStringList supportFormats(); static QString detectImageFormat(const QString &fileName); static QImage oldColorFilter(const QImage &img); static QImage warmColorFilter(const QImage &img, int intensity = 30); static QImage coolColorFilter(const QImage &img, int intensity = 30); static QImage grayScaleColorFilter(const QImage &img); static QImage antiColorFilter(const QImage &img); static QImage metalColorFilter(const QImage &img); static QImage bilateralFilter(const QImage &img, double spatialDecay = 0.02, double photometricStandardDeviation = 10); static QImage contourExtraction(const QImage &img); static QImage binaryzation(const QImage &img); static QImage grayScale(const QImage &img); static QImage laplaceSharpen(const QImage &img); static QImage sobelEdgeDetector(const QImage &img); static QImage changeLightAndContrast(const QImage &img, int light = 100, int contrast = 150); static QImage changeBrightness(const QImage &img, int brightness); static QImage changeTransparency(const QImage &img, int transparency); static QImage changeStauration(const QImage &img, int saturation); static QImage replacePointColor(const QImage &img, QColor oldColor, QColor newColor); static QImage flipHorizontal(const QImage &img); static QImage flipVertical(const QImage &img); private: D_DECLARE_PRIVATE(DImageHandler) Q_DISABLE_COPY(DImageHandler) }; DGUI_END_NAMESPACE #endif // DIMAGEHANDLER_H dtkgui-5.7.12/include/util/dsvgrenderer.h000066400000000000000000000031311476226661100203510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DSVGRENDERER_H #define DSVGRENDERER_H #include #include #include #include QT_BEGIN_NAMESPACE class QPainter; QT_END_NAMESPACE #ifdef Q_OS_LINUX DGUI_BEGIN_NAMESPACE class DSvgRendererPrivate; class DSvgRenderer : public QObject, public DTK_CORE_NAMESPACE::DObject { Q_PROPERTY(QRectF viewBox READ viewBoxF WRITE setViewBox) public: explicit DSvgRenderer(QObject *parent = Q_NULLPTR); DSvgRenderer(const QString &filename, QObject *parent = Q_NULLPTR); DSvgRenderer(const QByteArray &contents, QObject *parent = Q_NULLPTR); ~DSvgRenderer(); bool isValid() const; QSize defaultSize() const; QRect viewBox() const; QRectF viewBoxF() const; void setViewBox(const QRect &viewbox); void setViewBox(const QRectF &viewbox); QRectF boundsOnElement(const QString &id) const; bool elementExists(const QString &id) const; QImage toImage(const QSize sz, const QString &elementId = QString()) const; public Q_SLOTS: bool load(const QString &filename); bool load(const QByteArray &contents); void render(QPainter *p); void render(QPainter *p, const QRectF &bounds); void render(QPainter *p, const QString &elementId, const QRectF &bounds = QRectF()); private: D_DECLARE_PRIVATE(DSvgRenderer) }; DGUI_END_NAMESPACE #else #include DGUI_BEGIN_NAMESPACE typedef QSvgRenderer DSvgRenderer; DGUI_END_NAMESPACE #endif #endif // DSVGRENDERER_H dtkgui-5.7.12/include/util/dtaskbarcontrol.h000066400000000000000000000021221476226661100210520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTASKBARCONTROL_H #define DTASKBARCONTROL_H #include #include #include #include DGUI_BEGIN_NAMESPACE class DTaskbarControlPrivate; class DTaskbarControl : public QObject, public DTK_CORE_NAMESPACE::DObject { Q_OBJECT public: explicit DTaskbarControl(QObject *parent = nullptr); ~DTaskbarControl(); void setProgress(bool progressVisible, double progress); void setCounter(bool counterVisible, int counter); int counter() const; void setCounterVisible(bool counterVisible); bool counterVisible() const; void setUrgency(bool val); Q_SIGNALS: void counterChanged(int counter); void counterVisibleChanged(bool visible); void progressChanged(double progress); void progressVisibleChanged(bool visible); protected: virtual void sendMessage(const QVariantMap ¶ms); private: D_DECLARE_PRIVATE(DTaskbarControl) }; DGUI_END_NAMESPACE #endif // DTASKBARCONTROL_H dtkgui-5.7.12/include/util/dthumbnailprovider.h000066400000000000000000000034651476226661100215730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILETHUMBNAILPROVIDER_H #define DFILETHUMBNAILPROVIDER_H #include #include #include #include #include QT_BEGIN_NAMESPACE class QMimeType; QT_END_NAMESPACE DGUI_BEGIN_NAMESPACE class DThumbnailProviderPrivate; class DThumbnailProvider : public QThread, public DTK_CORE_NAMESPACE::DObject { Q_OBJECT public: enum Size { Small = 64, Normal = 128, Large = 256, }; static DThumbnailProvider *instance(); bool hasThumbnail(const QFileInfo &info) const; bool hasThumbnail(const QMimeType &mimeType) const; QString thumbnailFilePath(const QFileInfo &info, Size size) const; QString createThumbnail(const QFileInfo &info, Size size); typedef std::function CallBack; void appendToProduceQueue(const QFileInfo &info, Size size, CallBack callback = 0); void removeInProduceQueue(const QFileInfo &info, Size size); QString errorString() const; qint64 defaultSizeLimit() const; void setDefaultSizeLimit(qint64 size); qint64 sizeLimit(const QMimeType &mimeType) const; void setSizeLimit(const QMimeType &mimeType, qint64 size); Q_SIGNALS: void thumbnailChanged(const QString &sourceFilePath, const QString &thumbnailPath) const; void createThumbnailFinished(const QString &sourceFilePath, const QString &thumbnailPath) const; void createThumbnailFailed(const QString &sourceFilePath) const; protected: explicit DThumbnailProvider(QObject *parent = 0); ~DThumbnailProvider(); void run() Q_DECL_OVERRIDE; private: D_DECLARE_PRIVATE(DThumbnailProvider) }; DGUI_END_NAMESPACE #endif // DFILETHUMBNAILPROVIDER_H dtkgui-5.7.12/linglong.yaml000066400000000000000000000011131476226661100156010ustar00rootroot00000000000000package: id: dtkgui name: dtkgui kind: lib version: 5.6.3 descriptipon: | Deepin Tool Kit Gui library \ DtkGui is base library of Deepin Qt/C++ applications. base: id: org.deepin.base version: 23.0.0 depends: - id: qtbase/5.15.7 - id: qtsvg/5.15.7 - id: dtkcommon/5.6.0.1 - id: gsettings-qt/0.3.1.1 - id: dtkcore/5.6.0.2 - id: libqtxdg/3.6.0.1 - id: freeimage/3.18.0 source: kind: local variables: extra_args: | -DBUILD_EXAMPLE=OFF \ -DBUILD_DOCS=OFF \ -DBUILD_VERSION=${VERSION} \ -DVERSION=${VERSION} build: kind: cmake dtkgui-5.7.12/misc/000077500000000000000000000000001476226661100140435ustar00rootroot00000000000000dtkgui-5.7.12/misc/DtkGuiConfig.cmake.in000066400000000000000000000013451476226661100177720ustar00rootroot00000000000000@PACKAGE_INIT@ include(CMakeFindDependencyMacro) find_dependency(Dtk@DTK_VERSION_MAJOR@Core) find_dependency(Qt@QT_VERSION_MAJOR@Network) find_dependency(Qt@QT_VERSION_MAJOR@Gui) include(${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@GuiTargets.cmake) set(DtkGui_LIBRARIES Dtk@DTK_VERSION_MAJOR@::Gui) get_target_property(DtkGui_INCLUDE_DIRS Dtk@DTK_VERSION_MAJOR@::Gui INTERFACE_INCLUDE_DIRECTORIES) get_target_property(DtkGui_LIBRARY_DIRS Dtk@DTK_VERSION_MAJOR@::Gui INTERFACE_LINK_DIRECTORIES) set(DtkGui_TOOL_DIRS "@PACKAGE_TOOL_INSTALL_DIR@") check_required_components(Dtk@DTK_VERSION_MAJOR@Gui) # Keep deprecated variables for compatibility set(DTKGUI_INCLUDE_DIR ${DtkGui_INCLUDE_DIRS}) set(DTKGUI_TOOL_DIR ${DtkGui_TOOL_DIRS}) dtkgui-5.7.12/misc/dtkgui.pc.in000066400000000000000000000006131476226661100162630ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@LIBRARY_INSTALL_DIR@ includedir=${prefix}/@INCLUDE_INSTALL_DIR@ tooldir=${prefix}/@PACKAGE_TOOL_INSTALL_DIR@ Name: dtk@DTK_VERSION_MAJOR@gui Description: Deepin Tool Kit dtkgui header files Version: @PROJECT_VERSION@ Libs: -L${libdir} -ldtk@DTK_VERSION_MAJOR@gui Cflags: -I${includedir} Requires: dtk@DTK_VERSION_MAJOR@core dtkgui-5.7.12/misc/org.deepin.dtk.ui.preference.json000066400000000000000000000020111476226661100222740ustar00rootroot00000000000000{ "magic": "dsg.config.meta", "version": "1.0", "contents": { "titlebarHeight": { "value": -1, "serial": 0, "name": "The height of DTitleBar", "name[zh_CN]": "标题栏高度", "description": "Configure the height of the DTitleBar", "description[zh_CN]": "配置标题栏的高度", "permissions": "readwrite", "visibility": "public" }, "themeType": { "value": 0, "serial": 0, "flags": [], "name": "The application theme type", "name[zh_CN]": "应用主题的颜色", "description": "The application theme type, which can be set to follow the system theme (0), light theme (1), dark theme (2)", "description[zh_CN]": "应用主题的颜色,可以设置为跟随系统(0)、浅色(1)、 深色(2),默认为跟随系统", "permissions": "readwrite", "visibility": "public" } } } dtkgui-5.7.12/misc/qt_lib_dtkgui.pri.in000066400000000000000000000011501476226661100200020ustar00rootroot00000000000000QT.dtkgui.VERSION = @PROJECT_VERSION@ QT.dtkgui.MAJOR_VERSION = @PROJECT_VERSION_MAJOR@ QT.dtkgui.MINOR_VERSION = @PROJECT_VERSION_MINOR@ QT.dtkgui.PATCH_VERSION = @PROJECT_VERSION_PATCH@ QT.dtkgui.name = dtkgui QT.dtkgui.module = dtk@DTK_VERSION_MAJOR@gui QT.dtkgui.tools = @CMAKE_INSTALL_PREFIX@/@TOOL_INSTALL_DIR@ QT.dtkgui.libs = @CMAKE_INSTALL_PREFIX@/@LIBRARY_INSTALL_DIR@ QT.dtkgui.includes = @CMAKE_INSTALL_PREFIX@/@INCLUDE_INSTALL_DIR@ QT.dtkgui.frameworks = QT.dtkgui.depends = core gui dtkcore gui_private dbus network QT.dtkgui.module_config = v2 internal_module ltcg QT.dtkgui.DEFINES = QT_MODULES += dtkgui-5.7.12/rpm/000077500000000000000000000000001476226661100137065ustar00rootroot00000000000000dtkgui-5.7.12/rpm/dtkgui.spec000066400000000000000000000035261476226661100160570ustar00rootroot00000000000000Name: dtkgui Version: 5.5.17 Release: 1%{?dist} Summary: Deepin dtkgui License: LGPLv3+ URL: https://github.com/linuxdeepin/dtkgui %if 0%{?fedora} Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz %else Source0: %{name}-%{version}.orig.tar.xz %endif BuildRequires: qt5-qtx11extras-devel BuildRequires: dtkcommon-devel BuildRequires: dtkcore-devel BuildRequires: librsvg2-devel BuildRequires: gtest-devel BuildRequires: gcc-c++ BuildRequires: annobin BuildRequires: pkgconfig(Qt5Core) BuildRequires: pkgconfig(gsettings-qt) BuildRequires: pkgconfig(gmock) %if 0%{?fedora} BuildRequires: qt5-qtbase-private-devel %{?_qt5:Requires: %{_qt5}%{?_isa} = %{_qt5_version}} %endif BuildRequires: make %description Dtkgui is the GUI module for DDE look and feel. %package devel Summary: Development package for %{name} Requires: %{name}%{?_isa} = %{version}-%{release} Requires: dtkcore-devel%{?_isa} %description devel Header files and libraries for %{name}. %prep %autosetup %build # help find (and prefer) qt5 utilities, e.g. qmake, lrelease export PATH=%{_qt5_bindir}:$PATH %qmake_qt5 PREFIX=%{_prefix} \ DTK_VERSION=%{version} \ LIB_INSTALL_DIR=%{_libdir} \ BIN_INSTALL_DIR=%{_libexecdir}/dtk5 \ TOOL_INSTALL_DIR=%{_libexecdir}/dtk5 %make_build %install %make_install INSTALL_ROOT=%{buildroot} %files %doc README.md %license LICENSE %{_libdir}/lib%{name}.so.5* %{_libexecdir}/dtk5/deepin-gui-settings %{_libexecdir}/dtk5/taskbar %{_libexecdir}/dtk5/dde-kwin-debug %files devel %{_includedir}/libdtk-*/ %{_libdir}/pkgconfig/dtkgui.pc %{_qt5_archdatadir}/mkspecs/modules/qt_lib_dtkgui.pri %{_libdir}/cmake/DtkGui/ %{_libdir}/lib%{name}.so %changelog * Thu Jun 09 2020 uoser - 5.2.2.1-1 - Update to 5.2.2.1 dtkgui-5.7.12/src/000077500000000000000000000000001476226661100136775ustar00rootroot00000000000000dtkgui-5.7.12/src/CMakeLists.txt000066400000000000000000000064511476226661100164450ustar00rootroot00000000000000if("${QT_VERSION_MAJOR}" STREQUAL "6") find_package(Qt6 REQUIRED COMPONENTS Core Widgets WaylandClient) else() find_package(Qt5 REQUIRED COMPONENTS WaylandClient XkbCommonSupport) endif() add_library(${LIB_NAME} SHARED) include(dbus/dbus.cmake) include(filedrag/dfiledrag.cmake) include(kernel/kernel.cmake) include(private/private.cmake) include(util/util.cmake) include(plugins/plugins.cmake) target_sources(${LIB_NAME} PRIVATE ${dbus_SRC} ${filedrag_SRC} ${kernel_SRC} ${util_SRC} ${private_SRC} ) target_include_directories(${LIB_NAME} PUBLIC $ $ $ $ $ $ $ $ ) target_link_libraries(${LIB_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Network Dtk${DTK_VERSION_MAJOR}::Core PRIVATE Qt${QT_VERSION_MAJOR}::GuiPrivate Qt${QT_VERSION_MAJOR}::CorePrivate Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::WaylandClientPrivate ) if("${QT_VERSION_MAJOR}" STREQUAL "5") target_link_libraries(${LIB_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::XkbCommonSupportPrivate ) endif() if(DTK_DISABLE_LIBRSVG) find_package(Qt${QT_VERSION_MAJOR}Svg REQUIRED) target_link_libraries(${LIB_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Svg) else() target_link_libraries(${LIB_NAME} PRIVATE PkgConfig::librsvg) endif() if(NOT DTK_DISABLE_EX_IMAGE_FORMAT AND EX_IMAGE_FORMAT_LIBS_FOUND) target_link_libraries(${LIB_NAME} PRIVATE ${libraw_LIBRARIES} FreeImage::FreeImage ) target_include_directories(${LIB_NAME} PRIVATE ${libraw_INCLUDE_DIRS} ) endif() if(NOT DTK_DISABLE_LIBXDG) target_link_libraries(${LIB_NAME} PRIVATE Qt${QT_VERSION_MAJOR}XdgIconLoader ) endif() set_target_properties(${LIB_NAME} PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR} EXPORT_NAME Gui ) target_include_directories(${LIB_NAME} INTERFACE $ ) target_link_directories(${LIB_NAME} INTERFACE $ ) install(TARGETS ${LIB_NAME} EXPORT Dtk${DTK_VERSION_MAJOR}GuiTargets DESTINATION "${LIBRARY_INSTALL_DIR}") install(EXPORT Dtk${DTK_VERSION_MAJOR}GuiTargets NAMESPACE Dtk${DTK_VERSION_MAJOR}:: FILE Dtk${DTK_VERSION_MAJOR}GuiTargets.cmake DESTINATION "${CONFIG_INSTALL_DIR}") install(DIRECTORY ../include/util/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*") install(DIRECTORY ../include/DtkGui/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*") install(DIRECTORY ../include/global/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*") install(DIRECTORY ../include/kernel/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*") install(DIRECTORY ../include/filedrag/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*") set(EnableCov CACHE BOOL OFF) if (EnableCov) dtk_setup_code_coverage(${LIB_NAME}) endif() dtkgui-5.7.12/src/dbus/000077500000000000000000000000001476226661100146345ustar00rootroot00000000000000dtkgui-5.7.12/src/dbus/dbus.cmake000066400000000000000000000002011476226661100165640ustar00rootroot00000000000000set(dbus_SRC ${CMAKE_CURRENT_LIST_DIR}/xeventmonitor_interface.h ${CMAKE_CURRENT_LIST_DIR}/xeventmonitor_interface.cpp ) dtkgui-5.7.12/src/dbus/xeventmonitor_interface.cpp000066400000000000000000000036421476226661100223060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "xeventmonitor_interface.h" static void registerAreaListMetaType() { // FIX 取消注册qRegisterMetaType,会影响 dock 使用 RegisterAreas dbus接口 // 因为 libdframeworkdbus-dev 也会注册 "AreaList" 为 MonitorRect // qRegisterMetaType("AreaList"); qDBusRegisterMetaType(); } Q_CONSTRUCTOR_FUNCTION(registerAreaListMetaType); QDBusArgument &operator<<(QDBusArgument &a, const ComDeepinApiXEventMonitorInterface::AreaList &rects) { // com.deepin.api.XEventMonitor.RegisterAreas // (Array of [Struct of (Int32, Int32, Int32, Int32)] areas, Int32 flag) // use [x1, y1, x2, y2] instead of [x1, y1, w, h] a.beginArray(qRegisterMetaType()); for (const auto &r : rects) { a.beginStructure(); a << r.left() << r.top() << r.right() << r.bottom(); a.endStructure(); } a.endArray(); return a; } const QDBusArgument &operator>>(const QDBusArgument &a, ComDeepinApiXEventMonitorInterface::AreaList &rects) { a.beginArray(); rects.clear(); int x1 = 0 , y1 = 0 , x2 = 0 , y2 = 0 ; while (!a.atEnd()) { a.beginStructure(); a >> x1 >> y1 >> x2 >> y2; a.endStructure(); rects.append(QRect(QPoint(x1, y1), QPoint(x2, y2))); } a.endArray(); return a; } ComDeepinApiXEventMonitorInterface::ComDeepinApiXEventMonitorInterface(const QString &service, const QString &path, const char *interface, QObject *parent, const QDBusConnection &con) : QDBusAbstractInterface(service, path, interface, con, parent) { } ComDeepinApiXEventMonitorInterface::~ComDeepinApiXEventMonitorInterface() { } dtkgui-5.7.12/src/dbus/xeventmonitor_interface.h000066400000000000000000000051431476226661100217510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef XEVENTMONITOR_INTERFACE_H #define XEVENTMONITOR_INTERFACE_H #include #include #include #include #include #include #include #include class ComDeepinApiXEventMonitorInterface: public QDBusAbstractInterface { Q_OBJECT public: typedef QList AreaList; ComDeepinApiXEventMonitorInterface(const QString &service, const QString &path, const char *interface, QObject *parent = nullptr, const QDBusConnection &con = QDBusConnection::sessionBus()); ~ComDeepinApiXEventMonitorInterface(); public Q_SLOTS: // METHODS inline QDBusPendingReply RegisterArea(int in0, int in1, int in2, int in3, int in4) { QList argumentList; argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2) << QVariant::fromValue(in3) << QVariant::fromValue(in4); return asyncCallWithArgumentList(QStringLiteral("RegisterArea"), argumentList); } inline QDBusPendingReply RegisterAreas(AreaList in0, int in1) { QList argumentList; argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); return asyncCallWithArgumentList(QStringLiteral("RegisterAreas"), argumentList); } inline QDBusPendingReply RegisterFullScreen() { QList argumentList; return asyncCallWithArgumentList(QStringLiteral("RegisterFullScreen"), argumentList); } inline QDBusPendingReply UnregisterArea(const QString &in0) { QList argumentList; argumentList << QVariant::fromValue(in0); return asyncCallWithArgumentList(QStringLiteral("UnregisterArea"), argumentList); } Q_SIGNALS: // SIGNALS void ButtonPress(int in0, int in1, int in2, const QString &in3); void ButtonRelease(int in0, int in1, int in2, const QString &in3); void CancelAllArea(); void CursorInto(int in0, int in1, const QString &in2); void CursorMove(int in0, int in1, const QString &in2); void CursorOut(int in0, int in1, const QString &in2); void KeyPress(const QString &in0, int in1, int in2, const QString &in3); void KeyRelease(const QString &in0, int in1, int in2, const QString &in3); }; namespace com { namespace deepin { namespace api { typedef ::ComDeepinApiXEventMonitorInterface XEventMonitor; } } } #endif dtkgui-5.7.12/src/filedrag/000077500000000000000000000000001476226661100154545ustar00rootroot00000000000000dtkgui-5.7.12/src/filedrag/dfiledrag.cmake000066400000000000000000000003161476226661100203770ustar00rootroot00000000000000file(GLOB FILEDRAG_HEADER ${CMAKE_CURRENT_LIST_DIR}/../../include/filedrag/*.h ) file(GLOB FILEDRAG_SOURCE ${CMAKE_CURRENT_LIST_DIR}/*.cpp ) set(filedrag_SRC ${FILEDRAG_HEADER} ${FILEDRAG_SOURCE} ) dtkgui-5.7.12/src/filedrag/dfiledrag.cpp000066400000000000000000000035711476226661100201070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfiledrag.h" #include "dfiledragserver.h" #include "private/dfiledragcommon_p.h" #include "private/dfiledragserver_p.h" #include #include DGUI_BEGIN_NAMESPACE /*! @private */ class DFileDragPrivate : DCORE_NAMESPACE::DObjectPrivate { DFileDragPrivate(DFileDrag *q, DFileDragServer *_srv) : DObjectPrivate(q) , srv(_srv) {} DFileDragServer *srv; D_DECLARE_PUBLIC(DFileDrag) }; /*! \class Dtk::Gui::DFileDrag \inmodule dtkgui \brief 继承自QDrag,一般在文件拖拽发送方 mouseMoveEvent 中发起拖拽,设置发送数据 和 DFileDragServer 配合使用. \sa Dtk::Gui::DFileDragServer */ /*! \fn void DFileDrag::targetUrlChanged(QUrl url) \brief 信号会在接收方调用 setTargetUrl 时被发送. 可以用于获取被拖拽至的目标目录 \a url 发生改变的目标链接. */ DFileDrag::DFileDrag(QObject *source, DFileDragServer *server) : QDrag(source) , DObject(*new DFileDragPrivate(this, server)) { Q_D(DFileDrag); connect(d->srv, &DFileDragServer::targetDataChanged, this, [this, d](const QString &key) { if (key == DND_TARGET_URL_KEY) { Q_EMIT this->targetUrlChanged(QUrl(d->srv->targetData(key).value())); } }); } /*! \brief DFileDrag::targetUrl \return 返回拖拽文件接收方设置的接收路径 */ QUrl DFileDrag::targetUrl() { Q_D(DFileDrag); return QUrl(d->srv->targetData(DND_TARGET_URL_KEY).value()); } /*! \brief DFileDrag::setMimeData \a data \brief 发起拖拽文件前设置发送数据接口 */ void DFileDrag::setMimeData(QMimeData *data) { Q_D(DFileDrag); d->srv->d_func()->writeMimeData(data); QDrag::setMimeData(data); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/filedrag/dfiledragclient.cpp000066400000000000000000000160111476226661100212770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfiledragclient.h" #include "private/dfiledragcommon_p.h" #include #include #include #include #include #include #include #include #include DGUI_BEGIN_NAMESPACE class DDndClientSignalRelay : public QObject { Q_OBJECT public Q_SLOTS: void progressChanged(QString uuid, int progress); void stateChanged(QString uuid, int state); void serverDestroyed(QString uuid); private: static QWeakPointer relayref; friend class DFileDragClient; }; class DFileDragClientPrivate : DCORE_NAMESPACE::DObjectPrivate { explicit DFileDragClientPrivate(DFileDragClient *q) : DCORE_NAMESPACE::DObjectPrivate(q) {} QUuid uuid; QString service; QSharedPointer iface; QSharedPointer relay; static QHash connectionmap; static QHash> ifacemap; D_DECLARE_PUBLIC(DFileDragClient) friend class DDndClientSignalRelay; }; QHash DFileDragClientPrivate::connectionmap; QHash> DFileDragClientPrivate::ifacemap; QWeakPointer DDndClientSignalRelay::relayref; void DDndClientSignalRelay::progressChanged(QString uuid, int progress) { if (DFileDragClientPrivate::connectionmap.contains(uuid)) { Q_EMIT DFileDragClientPrivate::connectionmap[uuid]->progressChanged(progress); } } void DDndClientSignalRelay::stateChanged(QString uuid, int state) { if (DFileDragClientPrivate::connectionmap.contains(uuid)) { Q_EMIT DFileDragClientPrivate::connectionmap[uuid]->stateChanged(static_cast(state)); } } void DDndClientSignalRelay::serverDestroyed(QString uuid) { if (DFileDragClientPrivate::connectionmap.contains(uuid)) { Q_EMIT DFileDragClientPrivate::connectionmap[uuid]->serverDestroyed(); DFileDragClientPrivate::connectionmap[uuid]->deleteLater(); DFileDragClientPrivate::connectionmap.remove(uuid); } } /*! \class Dtk::Gui::DFileDragClient \inmodule dtkgui \brief 提供拖拽文件时与文件发送方交互的接口. */ /*! \fn void DFileDragClient::progressChanged(int progress) \a progress 当前进度 \brief 信号会在当前进度变化时被发送. */ /*! \fn void DFileDragClient::stateChanged(DFileDragState state) \a state 改变后的新状态 \brief 信号会在当前状态变化时被发送. */ /*! \fn void DFileDragClient::serverDestroyed() \brief 信号会在发送方析构销毁前被发送. \note DFileDragClient 收到后会自删除(deletelater),因此不用去管理 new 出来的 DFileDragClient */ DFileDragClient::DFileDragClient(const QMimeData *data, QObject *parent) : QObject(parent) , DCORE_NAMESPACE::DObject(*new DFileDragClientPrivate(this)) { D_D(DFileDragClient); Q_ASSERT(checkMimeData(data)); d->service = data->data(DND_MIME_SERVICE); d->uuid = QUuid(data->data(DND_MIME_UUID)); d->connectionmap[d->uuid.toString()] = this; if (DDndClientSignalRelay::relayref.isNull()) { d->relay = QSharedPointer(new DDndClientSignalRelay); DDndClientSignalRelay::relayref = d->relay.toWeakRef(); } else { d->relay = DDndClientSignalRelay::relayref.toStrongRef(); } if (!DFileDragClientPrivate::ifacemap.contains(d->service)) { QDBusConnection sessionBus(QDBusConnection::sessionBus()); d->iface = QSharedPointer(new QDBusInterface(d->service, DND_OBJPATH, DND_INTERFACE, sessionBus), [d](QDBusInterface* intf){ QDBusConnection sessionBus(QDBusConnection::sessionBus()); sessionBus.disconnect(d->service, DND_OBJPATH, DND_INTERFACE, "progressChanged", "si", d->relay.data(), SLOT(progressChanged(QString, int))); sessionBus.disconnect(d->service, DND_OBJPATH, DND_INTERFACE, "stateChanged", "si", d->relay.data(), SLOT(stateChanged(QString, int))); sessionBus.disconnect(d->service, DND_OBJPATH, DND_INTERFACE, "serverDestroyed", "s", d->relay.data(), SLOT(serverDestroyed(QString))); intf->deleteLater(); DFileDragClientPrivate::ifacemap.remove(d->service); }); DFileDragClientPrivate::ifacemap[d->service] = d->iface.toWeakRef(); sessionBus.connect(d->service, DND_OBJPATH, DND_INTERFACE, "progressChanged", "si", d->relay.data(), SLOT(progressChanged(QString, int))); sessionBus.connect(d->service, DND_OBJPATH, DND_INTERFACE, "stateChanged", "si", d->relay.data(), SLOT(stateChanged(QString, int))); sessionBus.connect(d->service, DND_OBJPATH, DND_INTERFACE, "serverDestroyed", "s", d->relay.data(), SLOT(serverDestroyed(QString))); } else { d->iface = DFileDragClientPrivate::ifacemap[d->service].toStrongRef(); } } /*! \brief DFileDragClient::progress \return 返回当前拖拽的进度 */ int DFileDragClient::progress() const { D_D(const DFileDragClient); return QDBusReply(d->iface->call("progress", d->uuid.toString())).value(); } /*! \brief DFileDragClient::state \return 返回当前状态,见 DFileDragState */ DFileDragState DFileDragClient::state() const { D_D(const DFileDragClient); return static_cast(QDBusReply(d->iface->call("state", d->uuid.toString())).value()); } /*! \brief DFileDragClient::checkMimeData \a data \return 包含 DND_MIME_PID 格式的数据时返回 true,否则返回 false \note 通常在接收拖放数据的应用的dropEvent(QDropEvent *event)函数中检测当前 event->mimeData() 是否是 DFileDrag */ bool DFileDragClient::checkMimeData(const QMimeData *data) { return data->hasFormat(DND_MIME_SERVICE) && data->hasFormat(DND_MIME_PID); } /*! \brief DFileDragClient::setTargetData \a data 拖放时传入的data,用于获取和发送数据的应用dbus通讯需要的一些信息 \a key \a value \note 向文件发送方设置自定义数据 */ void DFileDragClient::setTargetData(const QMimeData *data, QString key, QVariant value) { Q_ASSERT(checkMimeData(data)); QString service(data->data(DND_MIME_SERVICE)); QString uuid(data->data(DND_MIME_UUID)); QDBusInterface iface(service, DND_OBJPATH, DND_INTERFACE, QDBusConnection::sessionBus()); QDBusReply pid = QDBusConnection::sessionBus().interface()->servicePid(service); if (QString::number(pid).toUtf8() != data->data(DND_MIME_PID)) { return; } iface.call("setData", uuid, key, value.toString()); } /*! \brief DFileDragClient::setTargetUrl \a data \a url \note 告知文件发送方拖拽目标路径 */ void DFileDragClient::setTargetUrl(const QMimeData *data, QUrl url) { setTargetData(data, DND_TARGET_URL_KEY, QVariant::fromValue(url.toString())); } DGUI_END_NAMESPACE #include "dfiledragclient.moc" dtkgui-5.7.12/src/filedrag/dfiledragserver.cpp000066400000000000000000000121131476226661100213260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dfiledragserver.h" #include "private/dfiledragcommon_p.h" #include #include #include #include #include #include #include #include #include #include DGUI_BEGIN_NAMESPACE class DDndSourceInterface; /*! @private */ class DFileDragServerPrivate : public DCORE_NAMESPACE::DObjectPrivate { QMap data; QUuid uuid; explicit DFileDragServerPrivate(DFileDragServer *q); ~DFileDragServerPrivate(); void writeMimeData(QMimeData *dest); QSharedPointer dbusif; static QHash servermap; static QWeakPointer dbusifinst; D_DECLARE_PUBLIC(DFileDragServer) friend class DDndSourceInterface; }; QWeakPointer DFileDragServerPrivate::dbusifinst; QHash DFileDragServerPrivate::servermap; class DDndSourceInterface : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", DND_INTERFACE) public: explicit DDndSourceInterface(QObject *parent = nullptr) : QObject(parent) {} Q_SIGNALS: void serverDestroyed(QString uuid); void stateChanged(QString uuid, int state); void progressChanged(QString uuid, int progress); public Q_SLOTS: void setData(QString uuid, QString key, QString value) { DFileDragServer *srv = DFileDragServerPrivate::servermap.value(uuid); Q_ASSERT(srv); DFileDragServerPrivate *d = srv->d_func(); if (d->data.value(key) != value) { d->data[key] = value; Q_EMIT srv->targetDataChanged(key); } } int state(QString uuid) const {return m_statemap.value(uuid);} int progress(QString uuid) const {return m_progressmap.value(uuid);} private: QHash m_statemap; QHash m_progressmap; friend class DFileDragServer; }; /*! \class Dtk::Gui::DFileDragServer \inmodule dtkgui \brief 提供拖拽文件时与文件接收方交互的接口. */ /*! \fn void DFileDragServer::targetDataChanged(const QString &key) \brief 信号会在接收方调用 setData 变化时被发送, \a key 为改变的键值. */ DFileDragServer::DFileDragServer(QObject *parent) : QObject(parent) , DCORE_NAMESPACE::DObject(*new DFileDragServerPrivate(this)) { D_D(DFileDragServer); DFileDragServerPrivate::servermap[d->uuid.toString()] = this; } DFileDragServer::~DFileDragServer() { D_D(DFileDragServer); Q_EMIT d->dbusif->serverDestroyed(d->uuid.toString()); DFileDragServerPrivate::servermap.remove(d->uuid.toString()); } /*! \brief DFileDragServer::targetData. \a key \return 返回文件接收方设置数据 \a key 对应的 value */ QVariant DFileDragServer::targetData(const QString &key) const { D_D(const DFileDragServer); return d->data.value(key); } /*! \brief DFileDragServer::setProgress. \a progress 当前进度 \brief 拖拽进度更新,接收方会受到 progressChanged 信号. */ void DFileDragServer::setProgress(int progress) { D_D(DFileDragServer); if (d->dbusif && progress != d->dbusif->m_progressmap.value(d->uuid.toString())) { d->dbusif->m_progressmap[d->uuid.toString()] = progress; Q_EMIT d->dbusif->progressChanged(d->uuid.toString(), progress); } } /*! \brief DFileDragServer::setState. \a state \brief 改变状态,接收方会受到 stateChanged 信号. */ void DFileDragServer::setState(DFileDragState state) { D_D(DFileDragServer); if (d->dbusif && state != d->dbusif->m_statemap.value(d->uuid.toString())) { d->dbusif->m_statemap[d->uuid.toString()] = state; Q_EMIT d->dbusif->stateChanged(d->uuid.toString(), state); } } DFileDragServerPrivate::DFileDragServerPrivate(DFileDragServer *q) : DCORE_NAMESPACE::DObjectPrivate(q) , uuid(QUuid::createUuid()) { if (dbusifinst.isNull()) { dbusif = QSharedPointer(new DDndSourceInterface(), [](DDndSourceInterface *intf){ QDBusConnection::sessionBus().unregisterObject(DND_OBJPATH); intf->deleteLater(); }); dbusifinst = dbusif.toWeakRef(); QDBusConnection::sessionBus().registerObject(DND_OBJPATH, DND_INTERFACE, dbusif.data(), QDBusConnection::RegisterOption::ExportAllContents); } else { dbusif = dbusifinst.toStrongRef(); } } DFileDragServerPrivate::~DFileDragServerPrivate() { } void DFileDragServerPrivate::writeMimeData(QMimeData *dest) { dest->setData(DND_MIME_SERVICE, QDBusConnection::sessionBus().baseService().toUtf8()); // qApp->applicationPid() not right in ll-box auto pid = QDBusConnection::sessionBus().interface()->servicePid(QDBusConnection::sessionBus().baseService()); dest->setData(DND_MIME_PID, QString::number(pid).toUtf8()); dest->setData(DND_MIME_UUID, uuid.toString().toUtf8()); } DGUI_END_NAMESPACE #include "dfiledragserver.moc" dtkgui-5.7.12/src/kernel/000077500000000000000000000000001476226661100151575ustar00rootroot00000000000000dtkgui-5.7.12/src/kernel/dforeignwindow.cpp000066400000000000000000000114641476226661100207160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dforeignwindow.h" #include #include #include #include #include #include DGUI_BEGIN_NAMESPACE #define DEFINE_CONST_CHAR(Name) const char _##Name[] = "_d_" #Name // propertys DEFINE_CONST_CHAR(WmClass); DEFINE_CONST_CHAR(ProcessId); class DForeignWindowPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate { public: explicit DForeignWindowPrivate(DForeignWindow *qq) : DObjectPrivate(qq) {} }; /*! \class Dtk::Gui::DForeignWindow \inmodule dtkgui \brief 一个用于获取本地窗口信息的类. 继承于 QWindow,支持 QWindow::geometry QWindow::x QWindow::y QWindow::width QWindow::height QWindow::title QWindow::flags QWindow::visibility QWindow::type QWindow::windowStates QWindow::windowState 等接口的使用,另外扩展 增加了一部分接口,方面更加详细的获取窗口信息。依赖于 dxcb 插件,在未加载 dxcb 插件的应用中使用时结果未知 \sa DWindowManagerHelper::currentWorkspaceWindows \sa Dtk::Widget::DApplication::loadDXcbPlugin \sa Dtk::Widget::DApplication::isDXcbPlatform */ /*! \property DForeignWindow::wmClass \brief 窗口 WM_CLASS 的值 \note 只读 \ref {https://tronche.com/gui/x/icccm/sec-4.html#WM_CLASS}{WM_CLASS} */ /*! \property DForeignWindow::pid \brief 窗口所属进程的 pid \note 只读 \ref {https://specifications.freedesktop.org/wm-spec/1.3/ar01s05.html}{_NET_WM_PID} */ /*! \fn void DForeignWindow::wmClassChanged() \brief 信号会在 wmClass 属性改变时被发送. \sa DForeignWindow::wmClass */ /*! \fn void DForeignWindow::pidChanged() \brief 信号会在 pid 属性的值改变时被发送. \sa DForeignWindow::pid */ /*! \brief 直接构造一个 DForeignWindow 对象和使用 QWindow 对象没有区别. \a parent \sa DForeignWindow::fromWinId */ DForeignWindow::DForeignWindow(QWindow *parent) : QWindow(parent) , DObject(*new DForeignWindowPrivate(this)) { } /*! \brief DForeignWindow::fromWinId. 使用这个窗口id创建一个 DForeignWindow 对象,此对象不会被加到 QGuiApplication::allWindows 中。一般应用在需要获取一个本地窗口信息的场景。示例: \code // a.cpp int main(int argc, char *argv[]) { DApplication a(argc, argv); QWidget w; w.setWindowTitle("deepin"); w.show(); QFile app_win_id("/tmp/window_id.txt"); if (app_win_id.open(QFile::WriteOnly)) { app_win_id.write(QByteArray::number(w.winId())); app_win_id.close(); } return a.exec(); } \endcode \code // b.cpp int main(int argc, char *argv[]) { DApplication::loadDXcbPlugin(); DApplication a(argc, argv); DForeignWindow *fw = nullptr; QFile app_win_id("/tmp/window_id.txt"); if (app_win_id.open(QFile::ReadOnly)) { fw = DForeignWindow::fromWinId(app_win_id.readAll().toInt()); } if (fw) { qDebug() << fw->title(); fw->connect(fw, &DForeignWindow::widthChanged, [&] { qDebug() << fw->width(); }); } return a.exec(); } \endcode 先启动应用 a 再启动应用 b 在应用 b 启动后将看到如下输出: \code "deepin" \endcode 当改变应用 a 中的窗口宽度时,在应用 b 中会看到宽度的输出 \a id \return \warning 不要尝试对由本应用创建的窗口调用此接口,可能会导致窗口行为发生不可逆转的变化 */ DForeignWindow *DForeignWindow::fromWinId(WId id) { if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ForeignWindows)) { qWarning() << "DForeignWindow::fromWinId(): platform plugin does not support foreign windows."; return 0; } DForeignWindow *window = new DForeignWindow; window->setFlags(Qt::ForeignWindow); window->setProperty("_q_foreignWinId", QVariant::fromValue(id)); window->create(); return window; } QString DForeignWindow::wmClass() const { return property(_WmClass).toString(); } quint32 DForeignWindow::pid() const { return qvariant_cast(property(_ProcessId)); } bool DForeignWindow::event(QEvent *e) { if (e->type() == QEvent::DynamicPropertyChange) { QDynamicPropertyChangeEvent *event = static_cast(e); if (event->propertyName() == _WmClass) { Q_EMIT wmClassChanged(); return true; } else if (event->propertyName() == _ProcessId) { Q_EMIT pidChanged(); return true; } } return false; } DGUI_END_NAMESPACE dtkgui-5.7.12/src/kernel/dguiapplicationhelper.cpp000066400000000000000000001753371476226661100222570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dguiapplicationhelper.h" #include "private/dguiapplicationhelper_p.h" #include "dplatformhandle.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_UNIX #include #include #include #include #include #include #include #include #endif #include #include #include #include #ifdef Q_OS_UNIX #include #include #include #include #include #include #include #include #endif #include #include #include #include #ifdef Q_OS_LINUX #include #endif #ifdef Q_OS_UNIX class EnvReplaceGuard { public: EnvReplaceGuard(const int uid); ~EnvReplaceGuard(); char *m_backupLogName; char *m_backupHome; bool initialized = false; }; EnvReplaceGuard::EnvReplaceGuard(const int uid) { if (struct passwd *pwd = getpwuid(static_cast<__uid_t>(uid))) { m_backupLogName = getenv("LOGNAME"); m_backupHome = getenv("HOME"); setenv("LOGNAME", pwd->pw_name, 1); setenv("HOME", pwd->pw_dir, 1); initialized = true; } } EnvReplaceGuard::~EnvReplaceGuard() { if (initialized) { setenv("LOGNAME", m_backupLogName, 1); setenv("HOME", m_backupHome, 1); } } #endif DGUI_BEGIN_NAMESPACE #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) using HelperCreator = DGuiApplicationHelper::HelperCreator; #else using HelperCreator = DGuiApplicationHelper *(*)(); #endif #ifdef QT_DEBUG Q_LOGGING_CATEGORY(dgAppHelper, "dtk.dguihelper") #else Q_LOGGING_CATEGORY(dgAppHelper, "dtk.dguihelper", QtInfoMsg) #endif Q_GLOBAL_STATIC(QLocalServer, _d_singleServer) static quint8 _d_singleServerVersion = 1; Q_GLOBAL_STATIC(DFontManager, _globalFM) #define WINDOW_THEME_KEY "_d_platform_theme" #define APP_THEME_TYPE "themeType" #define DTK_ENABLE_ANIMATIONS "enableDtkAnimations" #define DTK_ANIMATIONS_ENV "D_DTK_DISABLE_ANIMATIONS" Q_GLOBAL_STATIC_WITH_ARGS(DTK_CORE_NAMESPACE::DConfig, _d_dconfig, ("org.deepin.dtk.preference")); /*! @private */ class _DGuiApplicationHelper { public: #define INVALID_HELPER reinterpret_cast(1) inline DGuiApplicationHelper *helper() { // 临时存储一个无效的指针值, 用于此处条件变量的竞争 if (m_helper.testAndSetRelaxed(nullptr, INVALID_HELPER)) { #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) m_helper.storeRelaxed(creator()); m_helper.loadRelaxed()->initialize(); } return m_helper.loadRelaxed(); #else m_helper.store(creator()); m_helper.load()->initialize(); } return m_helper.load(); #endif } inline void clear() { if (m_helper != INVALID_HELPER) delete m_helper.fetchAndStoreRelaxed(nullptr); } static DGuiApplicationHelper *defaultCreator() { return new DGuiApplicationHelper(); } QAtomicPointer m_helper; static HelperCreator creator; }; class LoadManualServiceWorker : public QThread { public: explicit LoadManualServiceWorker(QObject *parent = nullptr); ~LoadManualServiceWorker() override; void checkManualServiceWakeUp(); protected: void run() override; }; LoadManualServiceWorker::LoadManualServiceWorker(QObject *parent) : QThread(parent) { if (!parent) connect(qApp, &QGuiApplication::aboutToQuit, this, std::bind(&LoadManualServiceWorker::exit, this, 0)); } LoadManualServiceWorker::~LoadManualServiceWorker() { } void LoadManualServiceWorker::run() { QDBusInterface("com.deepin.Manual.Search", "/com/deepin/Manual/Search", "com.deepin.Manual.Search"); } void LoadManualServiceWorker::checkManualServiceWakeUp() { if (this->isRunning()) return; start(); } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) class Q_DECL_HIDDEN GuiApplicationEventFilter : public QObject { public: explicit GuiApplicationEventFilter(DGuiApplicationHelperPrivate *transmitter, QObject *parent = nullptr) : QObject(parent) , m_transmitter(transmitter) { } virtual bool eventFilter(QObject *watched, QEvent *event) override { if (watched != qApp) return QObject::eventFilter(watched, event); switch(event->type()) { case QEvent::ApplicationFontChange: { const QFont font(qGuiApp->font()); m_transmitter->q_func()->fontChanged(font); } break; case QEvent::ApplicationPaletteChange: { m_transmitter->onApplicationPaletteChanged(); break; } default: break; } return QObject::eventFilter(watched, event); } private: DGuiApplicationHelperPrivate *m_transmitter = nullptr; }; #endif HelperCreator _DGuiApplicationHelper::creator = _DGuiApplicationHelper::defaultCreator; Q_GLOBAL_STATIC(_DGuiApplicationHelper, _globalHelper) int DGuiApplicationHelperPrivate::waitTime = 3000; DGuiApplicationHelper::Attributes DGuiApplicationHelperPrivate::attributes = DGuiApplicationHelper::UseInactiveColorGroup; static const DGuiApplicationHelper::SizeMode InvalidSizeMode = static_cast(-1); DGuiApplicationHelperPrivate::DGuiApplicationHelperPrivate(DGuiApplicationHelper *qq) : DObjectPrivate(qq) , explicitSizeMode(InvalidSizeMode) { } void DGuiApplicationHelperPrivate::init() { if (qGuiApp) { initApplication(qGuiApp); } else { // 确保qAddPreRoutine只会被调用一次 static auto _ = [] {qAddPreRoutine(staticInitApplication); return true;}(); Q_UNUSED(_) } } void DGuiApplicationHelperPrivate::initApplication(QGuiApplication *app) { D_Q(DGuiApplicationHelper); if (!systemTheme) { // 需要在QGuiApplication创建后再创建DPlatformTheme,否则DPlatformTheme无效. // qGuiApp->platformFunction()会报警告,并返回nullptr. systemTheme = new DPlatformTheme(0, q); // 直接对应到系统级别的主题, 不再对外提供为某个单独程序设置主题的接口. // 程序设置自身主题相关的东西皆可通过 setPaletteType 和 setApplicationPalette 实现. appTheme = systemTheme; } // 跟随application销毁 qAddPostRoutine(staticCleanApplication); // 转发程序自己变化的信号 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) app->installEventFilter(new GuiApplicationEventFilter(this, app)); #else q->connect(app, &QGuiApplication::fontChanged, q, &DGuiApplicationHelper::fontChanged); q->connect(app, &QGuiApplication::paletteChanged, q, [this] { onApplicationPaletteChanged(); }); #endif if (Q_UNLIKELY(!appTheme)) { // 此时说明appTheme可能已经被初始化为了systemtheme if (QGuiApplicationPrivate::is_app_running) { _q_initApplicationTheme(); } else { // 延后初始化数据,因为在调用 clientLeader 前必须要保证QGuiApplication已经完全构造完成 q->metaObject()->invokeMethod(q, "_q_initApplicationTheme", Qt::QueuedConnection, Q_ARG(bool, true)); } } else if (appTheme == systemTheme) { // 此时appTheme等价于systemTheme, 可以直接信号链接 _q_initApplicationTheme(); } systemSizeMode = static_cast(systemTheme->sizeMode()); q->connect(systemTheme, SIGNAL(sizeModeChanged(int)), q, SLOT(_q_sizeModeChanged(int))); } void DGuiApplicationHelperPrivate::staticInitApplication() { if (!_globalHelper.exists()) return; if (DGuiApplicationHelper *helper = _globalHelper->helper()) helper->d_func()->initApplication(qGuiApp); } void DGuiApplicationHelperPrivate::staticCleanApplication() { if (_globalHelper.exists()) _globalHelper->clear(); } DPlatformTheme *DGuiApplicationHelperPrivate::initWindow(QWindow *window) const { DPlatformTheme *theme = new DPlatformTheme(window->winId(), q_func()->applicationTheme()); window->setProperty(WINDOW_THEME_KEY, QVariant::fromValue(theme)); theme->setParent(window); // 跟随窗口销毁 auto onWindowThemeChanged = [window, theme, this] { // 如果程序自定义了调色板, 则没有必要再关心窗口自身平台主题的变化 // 需要注意的是, 这里的信号和事件可能会与 notifyAppThemeChanged 中的重复 // 但是不能因此而移除这里的通知, 当窗口自身所对应的平台主题发生变化时, 这里 // 的通知机制就有了用武之地. if (Q_LIKELY(!isCustomPalette())) { qGuiApp->postEvent(window, new QEvent(QEvent::ThemeChange)); } }; window->connect(theme, &DPlatformTheme::themeNameChanged, window, onWindowThemeChanged); window->connect(theme, &DPlatformTheme::activeColorChanged, window, onWindowThemeChanged); window->connect(theme, &DPlatformTheme::paletteChanged, window, onWindowThemeChanged); return theme; } void DGuiApplicationHelperPrivate::_q_initApplicationTheme(bool notifyChange) { if (!appTheme) { // DPlatfromHandle::windowLeader依赖platformIntegration Q_ASSERT(QGuiApplicationPrivate::platformIntegration()); appTheme = new DPlatformTheme(DPlatformHandle::windowLeader(), systemTheme); } QGuiApplication *app = qGuiApp; auto onAppThemeChanged = [this] { // 只有当程序未自定义调色板时才需要关心DPlatformTheme中themeName和palette的改变 if (!isCustomPalette()) notifyAppThemeChanged(); }; // 监听与程序主题相关的改变 QObject::connect(appTheme, &DPlatformTheme::themeNameChanged, app, onAppThemeChanged); QObject::connect(appTheme, &DPlatformTheme::paletteChanged, app, onAppThemeChanged); QTimer *timer = new QTimer(app); timer->setInterval(100); timer->setSingleShot(true); QObject::connect(timer, &QTimer::timeout, timer, [this] { if (!appPalette) notifyAppThemeChanged(); }); QObject::connect(appTheme, &DPlatformTheme::activeColorChanged, app, [timer]{ timer->start(); }); QObject::connect(appTheme, &DPlatformTheme::darkActiveColorChanged, app, [timer] { timer->start(); }); // appTheme在此之前可能由systemTheme所代替被使用,此时在创建appTheme // 并初始化之后,应当发送信号通知程序主题的改变 if (notifyChange && appTheme->isValid()) { notifyAppThemeChanged(); } } void DGuiApplicationHelperPrivate::notifyAppThemeChanged() { D_Q(DGuiApplicationHelper); notifyAppThemeChangedByEvent(); QMetaObject::invokeMethod(q, [q] () { // 通知主题类型发生变化, 此处可能存在误报的行为, 不过不应该对此做额外的约束 // 此信号的行为应当等价于 applicationPaletteChanged Q_EMIT q->themeTypeChanged(q->themeType()); // 通知调色板对象的改变 Q_EMIT q->applicationPaletteChanged(); }, Qt::QueuedConnection); } void DGuiApplicationHelperPrivate::notifyAppThemeChangedByEvent() { QWindowSystemInterfacePrivate::ThemeChangeEvent event(nullptr); // 此事件会促使QGuiApplication重新从QPlatformTheme中获取系统级别的QPalette. // 而在deepin平台下, 系统级别的QPalette来源自 \a applicationPalette() QGuiApplicationPrivate::processThemeChanged(&event); } void DGuiApplicationHelperPrivate::onApplicationPaletteChanged() { D_Q(DGuiApplicationHelper); // 如果用户没有自定义颜色类型, 则应该通知程序的颜色类型发送变化 if (Q_LIKELY(!isCustomPalette())) { Q_EMIT q->themeTypeChanged(q->toColorType(qGuiApp->palette())); Q_EMIT q->applicationPaletteChanged(); } else { qWarning() << "DGuiApplicationHelper: Don't use QGuiApplication::setPalette on DTK application."; } } bool DGuiApplicationHelperPrivate::isCustomPalette() const { return appPalette || paletteType != DGuiApplicationHelper::UnknownType; } void DGuiApplicationHelperPrivate::setPaletteType(DGuiApplicationHelper::ColorType ct, bool emitSignal) { if (paletteType == ct) return; if (qGuiApp && qGuiApp->testAttribute(Qt::AA_SetPalette)) qWarning() << "DGuiApplicationHelper: Plase check 'QGuiApplication::setPalette'," " Don't use it on DTK application."; paletteType = ct; if (!emitSignal) { notifyAppThemeChangedByEvent(); return; } // 如果未固定调色板, 则paletteType的变化可能会导致调色板改变, 应当通知程序更新数据 if (!appPalette) notifyAppThemeChanged(); D_Q(DGuiApplicationHelper); Q_EMIT q->paletteTypeChanged(paletteType); } void DGuiApplicationHelperPrivate::initPaletteType() const { DCORE_USE_NAMESPACE if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::DontSaveApplicationTheme)) return; if (_d_dconfig.exists()) return; auto applyThemeType = [this](bool emitSignal){ int ct = _d_dconfig->value(APP_THEME_TYPE, DGuiApplicationHelper::UnknownType).toInt(); if (ct > DGuiApplicationHelper::DarkType || ct < DGuiApplicationHelper::UnknownType) ct = DGuiApplicationHelper::UnknownType; const_cast(this)->setPaletteType(DGuiApplicationHelper::ColorType(ct), emitSignal); }; applyThemeType(false); QObject::connect(_d_dconfig, &DConfig::valueChanged, _d_dconfig, [applyThemeType](const QString &key){ if (key != APP_THEME_TYPE) return; applyThemeType(true); }); } void DGuiApplicationHelperPrivate::_q_sizeModeChanged(int mode) { D_Q(DGuiApplicationHelper); qCInfo(dgAppHelper) << "Receiving that system size mode is set to [" << static_cast(mode) << "], and old system size mode is [" << systemSizeMode << "]"; const auto oldSizeMode = fetchSizeMode(); systemSizeMode = static_cast(mode); const auto currentSizeMode = fetchSizeMode(); if (oldSizeMode != currentSizeMode) Q_EMIT q->sizeModeChanged(currentSizeMode); } DGuiApplicationHelper::SizeMode DGuiApplicationHelperPrivate::fetchSizeMode(bool *isSystemSizeMode) const { if (isSystemSizeMode) *isSystemSizeMode = false; // `setSizeMode` > `D_DTK_SIZEMODE` > `systemSizeMode` if (explicitSizeMode != InvalidSizeMode) return explicitSizeMode; static const QString envSizeMode(qEnvironmentVariable("D_DTK_SIZEMODE")); if (!envSizeMode.isEmpty()) { bool ok = false; const auto mode = envSizeMode.toInt(&ok); if (ok) return static_cast(mode); } if (isSystemSizeMode) *isSystemSizeMode = true; return systemSizeMode; } /*! \class Dtk::Gui::DGuiApplicationHelper \inmodule dtkgui \brief DGuiApplicationHelper 应用程序的 GUI ,如主题、调色板等. */ /*! \enum DGuiApplicationHelper::ColorType DGuiApplicationHelper::ColorType 定义了主题类型. \var DGuiApplicationHelper::ColorType DGuiApplicationHelper::UnknownType 未知主题(浅色主题或深色主题) \var DGuiApplicationHelper::ColorType DGuiApplicationHelper::LightType 浅色主题 \var DGuiApplicationHelper::ColorType DGuiApplicationHelper::DarkType 深色主题 */ /*! \enum DGuiApplicationHelper::Attribute DGuiApplicationHelper::Attribute 定义了功能属性 \var DGuiApplicationHelper::Attribute DGuiApplicationHelper::UseInactiveColorGroup 如果开启,当窗口处于Inactive状态时就会使用QPalette::Inactive的颜色,否则窗口将没有任何颜色变化。 \var DGuiApplicationHelper::Attribute DGuiApplicationHelper::ColorCompositing 是否采用半透明样式的调色板。 \var DGuiApplicationHelper::Attribute DGuiApplicationHelper::ReadOnlyLimit 区分只读枚举。 \var DGuiApplicationHelper::Attribute DGuiApplicationHelper::IsDeepinPlatformTheme 获取当前是否使用deepin的platformtheme插件,platformtheme插件可以为Qt程序提供特定的控件样式,默认使用chameleon主题。 \var DGuiApplicationHelper::Attribute DGuiApplicationHelper::IsDXcbPlatform 获取当前使用的是不是dtk的xcb窗口插件,dxcb插件提供了窗口圆角和阴影功能。 \var DGuiApplicationHelper::Attribute DGuiApplicationHelper::IsXWindowPlatform 获取当前是否运行在X11环境中。 \var DGuiApplicationHelper::Attribute DGuiApplicationHelper::IsTableEnvironment 获取当前是否运行在deepin平板环境中,检测XDG_CURRENT_DESKTOP环境变量是不是tablet结尾。 \var DGuiApplicationHelper::Attribute DGuiApplicationHelper::IsDeepinEnvironment 获取当前是否运行在deepin桌面环境中,检测XDG_CURRENT_DESKTOP环境变量是不是deepin。 */ DGuiApplicationHelper::DGuiApplicationHelper() : QObject(nullptr) , DObject(*new DGuiApplicationHelperPrivate(this)) { } void DGuiApplicationHelper::initialize() { D_D(DGuiApplicationHelper); d->init(); } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) /*! \brief 创建 DGuiApplicationHelper 对象. \param creator 函数指针 \note 一定要先调用此函数,再使用 DGuiApplicationHelper::instance() */ void DGuiApplicationHelper::registerInstanceCreator(DGuiApplicationHelper::HelperCreator creator) { if (creator == _DGuiApplicationHelper::creator) return; _DGuiApplicationHelper::creator = creator; if (_globalHelper.exists()) { _globalHelper->clear(); } } #endif inline static int adjustColorValue(int base, qint8 increment, int max = 255) { return increment > 0 ? (max - base) * increment / 100.0 + base : base * (1 + increment / 100.0); } /*! \brief DGuiApplicationHelper::instance返回 DGuiApplicationHelper 对象 \return DGuiApplicationHelper对象 */ DGuiApplicationHelper *DGuiApplicationHelper::instance() { return _globalHelper->helper(); } DGuiApplicationHelper::~DGuiApplicationHelper() { _globalHelper->m_helper = nullptr; } static inline QColor adjustHSLColor(const QColor &base, qint8 hueFloat, qint8 saturationFloat, qint8 lightnessFloat, qint8 alphaFloat = 0) { if (Q_LIKELY(hueFloat || saturationFloat || lightnessFloat || alphaFloat)) { // 按HSL格式调整 int H, S, L, A; base.getHsl(&H, &S, &L, &A); H = H > 0 ? adjustColorValue(H, hueFloat, 359) : H; S = adjustColorValue(S, saturationFloat); L = adjustColorValue(L, lightnessFloat); return QColor::fromHsl(H, S, L, A); } return base; } static inline QColor adjustRGBColor(const QColor &base, qint8 redFloat, qint8 greenFloat, qint8 blueFloat, qint8 alphaFloat = 0) { if (Q_LIKELY(redFloat || greenFloat || blueFloat || alphaFloat)) { // 按RGB格式调整 int R, G, B, A; base.getRgb(&R, &G, &B, &A); R = adjustColorValue(R, redFloat); G = adjustColorValue(G, greenFloat); B = adjustColorValue(B, blueFloat); A = adjustColorValue(A, alphaFloat); return QColor(R, G, B, A); } return base; } /*! \brief 调整颜色. \note 取值范围均为 -100 ~ 100 ,当三原色参数为-100时,颜色为黑色,参数为100时,颜色为白色. 以透明度( alphaFloat )为例,当参数为负数时基础色的 alphaFloat 值减少,现象偏向透明, 参数为正数alphaFloat 值增加,现象偏不透明 \param base 基础色 \param hueFloat 色调 \param saturationFloat 饱和度 \param lightnessFloat 亮度 \param redFloat 红色 \param greenFloat 绿色 \param blueFloat 蓝色 \param alphaFloat Alpha通道(透明度) \return 经过调整的颜色 */ QColor DGuiApplicationHelper::adjustColor(const QColor &base, qint8 hueFloat, qint8 saturationFloat, qint8 lightnessFloat, qint8 redFloat, qint8 greenFloat, qint8 blueFloat, qint8 alphaFloat) { if (Q_UNLIKELY(!base.isValid())) return base; // First do the adjust of spec of this color, Avoid precision loss caused by color spec conversion. if (Q_UNLIKELY(base.spec() == QColor::Hsl)) { QColor newColor = adjustHSLColor(base, hueFloat, saturationFloat, lightnessFloat, alphaFloat); return adjustRGBColor(newColor, redFloat, greenFloat, blueFloat); } // For other specs, first do RGB adjust QColor newColor = adjustRGBColor(base, redFloat, greenFloat, blueFloat, alphaFloat); return adjustHSLColor(newColor, hueFloat, saturationFloat, lightnessFloat); } /*! \brief 调整图片整体像素颜色. \note 取值范围均为 -100 ~ 100 ,当三原色参数为-100时,颜色为黑色,参数为100时,颜色为白色. 以透明度( alphaFloat )为例,当参数为负数时基础色的 alphaFloat 值减少,现象偏向透明, 参数为正数alphaFloat 值增加,现象偏不透明 \param base 基础色 \param hueFloat 色调 \param saturationFloat 饱和度 \param lightnessFloat 亮度 \param redFloat 红色 \param greenFloat 绿色 \param blueFloat 蓝色 \param alphaFloat Alpha通道(透明度) \return 经过调整的图片 */ QImage DGuiApplicationHelper::adjustColor(const QImage &base, qint8 hueFloat, qint8 saturationFloat, qint8 lightnessFloat, qint8 redFloat, qint8 greenFloat, qint8 blueFloat, qint8 alphaFloat) { if (base.isNull()) return base; if (!hueFloat && !saturationFloat && !lightnessFloat && !redFloat && !greenFloat && !blueFloat && !alphaFloat) return base; QImage dest = base; for (int y = 0; y < dest.height(); ++y) { const QRgb *rgb = reinterpret_cast(base.scanLine(y)); for (int x = 0; x < dest.width(); ++x) { QColor base = QColor::fromRgba(rgb[x]); if (base.alpha() == 0) continue; QColor color = adjustColor(base, hueFloat, saturationFloat, lightnessFloat, redFloat, greenFloat, blueFloat, alphaFloat); dest.setPixel(x, y, color.rgba()); } } return dest; } /*! \brief 将两种颜色混合,合成新的颜色. \param substrate 底层颜色 \param superstratum 上层颜色 \return 混合颜色 */ QColor DGuiApplicationHelper::blendColor(const QColor &substrate, const QColor &superstratum) { QColor c2 = superstratum.toRgb(); if (c2.alpha() >= 255) return c2; QColor c1 = substrate.toRgb(); qreal c1_weight = 1 - c2.alphaF(); int r = c1_weight * c1.red() + c2.alphaF() * c2.red(); int g = c1_weight * c1.green() + c2.alphaF() * c2.green(); int b = c1_weight * c1.blue() + c2.alphaF() * c2.blue(); return QColor(r, g, b, c1.alpha()); } static QColor light_qpalette[QPalette::NColorRoles] { QColor(0, 0, 0, 0.7 * 255), //WindowText QColor("#e5e5e5"), //Button QColor("#e6e6e6"), //Light QColor("#e5e5e5"), //Midlight QColor("#e3e3e3"), //Dark QColor("#e4e4e4"), //Mid QColor(0, 0, 0, 0.7 * 255), //Text Qt::black, //BrightText QColor(0, 0, 0, 0.7 * 255), //ButtonText Qt::white, //Base QColor("#f8f8f8"), //Window QColor(0, 0, 0, 0.05 * 255), //Shadow QColor("#0081ff"), //Highlight Qt::white, //HighlightedText QColor("#0082fa"), //Link QColor("#ad4579"), //LinkVisited QColor(0, 0, 0, 0.03 * 255), //AlternateBase Qt::white, //NoRole QColor(255, 255, 255, 0.8 * 255), //ToolTipBase QColor(0, 0, 0, 0.85 * 255) //ToolTipText }; static QColor dark_qpalette[QPalette::NColorRoles] { QColor(255, 255, 255, 0.7 * 255), //WindowText QColor("#444444"), //Button QColor("#484848"), //Light QColor("#474747"), //Midlight QColor("#414141"), //Dark QColor("#434343"), //Mid QColor(255, 255, 255, 0.7 * 255), //Text Qt::white, //BrightText QColor(255, 255, 255, 0.7 * 255), //ButtonText QColor("#282828"), //Base QColor("#252525"), //Window QColor(0, 0, 0, 0.05 * 255), //Shadow QColor("#024CCA"), //Highlight QColor("#F1F6FF"), //HighlightedText QColor("#0082fa"), //Link QColor("#ad4579"), //LinkVisited QColor(0, 0, 0, 0.05 * 255), //AlternateBase Qt::black, //NoRole QColor(45, 45, 45, 0.8 * 255), //ToolTipBase QColor(255, 255, 255, 0.85 * 255) //ToolTipText }; static QColor light_dpalette[DPalette::NColorTypes] { QColor(), //NoType QColor(0, 0, 0, 255 * 0.03), //ItemBackground QColor(0, 0, 0, 0.85 * 255), //TextTitle QColor(0, 0, 0, 0.6 * 255), //TextTips QColor("#FF5736"), //TextWarning Qt::black, //TextLively QColor("#0081FF"), //LightLively QColor("#0081FF"), //DarkLively QColor(0, 0, 0, 0.05 * 255), //FrameBorder QColor(85, 85, 85, 0.4 * 255), //PlaceholderText QColor(0, 0, 0, 0.1 * 255), //FrameShadowBorder QColor(0, 0, 0, 0.1 * 255) //ObviousBackground }; static QColor dark_dpalette[DPalette::NColorTypes] { QColor(), //NoType QColor(255, 255, 255, 255 * 0.05), //ItemBackground QColor(255, 255, 255, 0.85 * 255), //TextTitle QColor(255, 255, 255, 0.6 * 255), //TextTips QColor("#E43F2E"), //TextWarning Qt::white, //TextLively QColor("#0059d2"), //LightLively QColor("#0059d2"), //DarkLively QColor(255, 255, 255, 0.1 * 255), //FrameBorder QColor(192, 198, 212, 0.4 * 255), //PlaceholderText QColor(0, 0, 0, 0.8 * 255), //FrameShadowBorder QColor(255, 255, 255, 0.1 * 255) //ObviousBackground }; /*! \brief 根据主题获取标准调色板. \param type 主题枚举值 \return 调色板 */ DPalette DGuiApplicationHelper::standardPalette(DGuiApplicationHelper::ColorType type) { static const DPalette *light_palette = nullptr, *dark_palette = nullptr; static const DPalette *alpha_light_palette = nullptr, *alpha_dark_palette = nullptr; const bool allowCompositingColor = DGuiApplicationHelper::testAttribute(ColorCompositing); if (type == LightType) { if (Q_UNLIKELY(allowCompositingColor)) { if (Q_LIKELY(alpha_light_palette)) { return *alpha_light_palette; } } if (Q_LIKELY(light_palette)) { return *light_palette; } } else if (type == DarkType) { if (Q_UNLIKELY(allowCompositingColor)) { if (Q_LIKELY(alpha_dark_palette)) { return *alpha_dark_palette; } } if (Q_LIKELY(dark_palette)) { return *dark_palette; } } else { return DPalette(); } DPalette *pa; const QColor *qcolor_list, *dcolor_list; if (type == DarkType) { pa = new DPalette(); if (allowCompositingColor) alpha_dark_palette = pa; else dark_palette = pa; qcolor_list = dark_qpalette; dcolor_list = dark_dpalette; } else { pa = new DPalette(); if (allowCompositingColor) alpha_light_palette = pa; else light_palette = pa; qcolor_list = light_qpalette; dcolor_list = light_dpalette; } for (int i = 0; i < DPalette::NColorRoles; ++i) { QPalette::ColorRole role = static_cast(i); QColor color = qcolor_list[i]; #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) if (role == QPalette::PlaceholderText) { color = dcolor_list[DPalette::PlaceholderText]; } #endif // 处理半透明色 if (allowCompositingColor) { switch (role) { case QPalette::Window: color = type == LightType ? adjustColor(color, 0, 0, 0, 0, 0, 0, -20) : adjustColor(color, 0, 0, -10, 0, 0, 0, -20); break; case QPalette::Base: color = adjustColor(color, 0, 0, 0, 0, 0, 0, -20); break; case QPalette::WindowText: case QPalette::Text: color = adjustColor(color, 0, 0, type == LightType ? -20 : +20, 0, 0, 0, -20); break; case QPalette::ButtonText: color = type == LightType ? adjustColor(color, 0, 0, -20, 0, 0, 0, -20) : adjustColor(color, 0, 0, +20, 0, 0, 0, 0); break; case QPalette::Button: case QPalette::Light: case QPalette::Mid: case QPalette::Midlight: case QPalette::Dark: color = adjustColor(color, 0, 0, -20, 0, 0, 0, -40); break; default: break; } } pa->setColor(DPalette::Active, role, color); generatePaletteColor(*pa, role, type); } for (int i = 0; i < DPalette::NColorTypes; ++i) { DPalette::ColorType role = static_cast(i); QColor color = dcolor_list[i]; // 处理半透明色 if (allowCompositingColor) { switch (role) { case DPalette::ItemBackground: color = adjustColor(color, 0, 0, 100, 0, 0, 0, type == LightType ? -80 : -90); break; case DPalette::TextTitle: color = adjustColor(color, 0, 0, -20, 0, 0, 0, -20); break; case DPalette::TextTips: color = type == LightType ? adjustColor(color, 0, 0, -40, 0, 0, 0, -40) : adjustColor(color, 0, 0, +40, 0, 0, 0, -50); break; default: break; } } pa->setColor(DPalette::Active, role, color); generatePaletteColor(*pa, role, type); } return *const_cast(pa); } template static void generatePaletteColor_helper(DPalette &base, M role, DGuiApplicationHelper::ColorType type) { if (type == DGuiApplicationHelper::UnknownType) { type = DGuiApplicationHelper::toColorType(base); } QColor disable_mask_color, inactive_mask_color; if (type == DGuiApplicationHelper::DarkType) { disable_mask_color = dark_qpalette[QPalette::Window]; inactive_mask_color = dark_qpalette[QPalette::Window]; disable_mask_color.setAlphaF(0.7); inactive_mask_color.setAlphaF(0.6); } else { disable_mask_color = light_qpalette[QPalette::Window]; inactive_mask_color = light_qpalette[QPalette::Window]; disable_mask_color.setAlphaF(0.6); inactive_mask_color.setAlphaF(0.4); } const QColor &color = base.color(QPalette::Normal, role); base.setColor(QPalette::Disabled, role, DGuiApplicationHelper::blendColor(color, disable_mask_color)); QPalette::ColorRole qr = static_cast(role); if (qr == QPalette::Text) { // disable text color olny -60% alpha base.setColor(QPalette::Disabled, role, DGuiApplicationHelper::adjustColor(color, 0, 0, 0, 0, 0, 0, -60)); } if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::Attribute::UseInactiveColorGroup)) base.setColor(QPalette::Inactive, role, DGuiApplicationHelper::blendColor(color, inactive_mask_color)); else base.setColor(QPalette::Inactive, role, color); } /*! \brief 获取调色板颜色. \param base 调色板 \param role 色码 \param type 主题枚举值 \sa QPalette::ColorRole */ void DGuiApplicationHelper::generatePaletteColor(DPalette &base, QPalette::ColorRole role, DGuiApplicationHelper::ColorType type) { if (role == QPalette::Window) { const QBrush &window = base.brush(QPalette::Normal, role); base.setBrush(QPalette::Disabled, role, window); base.setBrush(QPalette::Inactive, role, window); return; } generatePaletteColor_helper(base, role, type); } /*! \brief 加工调色板的颜色. \overload 一般我们只会为调色板的 QPalette::Normal 组设置颜色值, 但是 控件中也需要使用其他组的颜色, 此函数使用一些固定规则为 \a base 填充 QPalette::Disabled 和 QPalette::Inactive 分组的颜色. 不同的颜色类型会使用不同的加工规则, 如果为 LightType 类型, 则将颜色的alpha通道调整为 0.6 后作为 QPalette::Disabled 类的颜色使用, 调整为 0.4 后 作为 QPalette::Inactive 类的颜色使用. 如果为 DarkType 类型, 则将颜色的alpha通道调整为 0.7 后作为 QPalette::Disabled 类的颜色使用, 调整为 0.6 后作为 QPalette::Inactive 类的颜色使用. \param base 被加工的调色板 \param role 加工的项 \param type 加工时所使用的颜色类型, 如果值为 UnknownType 将使用 toColorType 获取颜色类型 */ void DGuiApplicationHelper::generatePaletteColor(DPalette &base, DPalette::ColorType role, DGuiApplicationHelper::ColorType type) { generatePaletteColor_helper(base, role, type); } /*! \brief 加工调色板的颜色. \overload 同 generatePaletteColor, 将直接调用 generatePaletteColor 加工 所有类型的调色板颜色. \param base 被加工的调色板 \param type 加工时所使用的颜色类型, 如果值为 UnknownType 将使用 toColorType 获取颜色类型 */ void DGuiApplicationHelper::generatePalette(DPalette &base, ColorType type) { // 先判断调色板的色调 if (type == UnknownType) { type = toColorType(base); } for (int i = 0; i < QPalette::NColorRoles; ++i) { QPalette::ColorRole role = static_cast(i); generatePaletteColor(base, role, type); } for (int i = 0; i < QPalette::NColorRoles; ++i) { DPalette::ColorType role = static_cast(i); generatePaletteColor(base, role, type); } } static inline QColor getActiveColor(const DPlatformTheme *theme, DGuiApplicationHelper::ColorType type) { QColor activeColor; if (type == DGuiApplicationHelper::DarkType) { activeColor = theme->darkActiveColor(); if (!activeColor.isValid()) { activeColor = theme->activeColor(); } } else { activeColor = theme->activeColor(); } return activeColor; } /*! \brief 获取调色板数据. 首先根据 DPlatformTheme::themeName 获取主题的颜色类型, 如果名称以 "dark" 结尾则认为其颜色类型为 DarkType, 否则为 LightType. 如果主题名称为空, 将使用其父主题的名称( DPlatformTheme::fallbackProperty ). 根据颜色类型将使用 standardPalette 获取基础调色板数据, 在此基础上 从 DPlatformTheme::fetchPalette 获取最终的调色板. \param theme 平台主题对象 \return 调色板数据 */ DPalette DGuiApplicationHelper::fetchPalette(const DPlatformTheme *theme) { DPalette base_palette; const QByteArray theme_name = theme->themeName(); ColorType type = LightType; // 深色主题 if (theme_name.endsWith("dark")) { type = DarkType; } bool ok = false; base_palette = theme->fetchPalette(standardPalette(type), &ok); const QColor &active_color = getActiveColor(theme, type); if (active_color.isValid()) { base_palette.setColor(QPalette::Normal, QPalette::Highlight, active_color); // ok为true时会整体处理palette的所有颜色 if (!ok) { generatePaletteColor(base_palette, QPalette::Highlight, type); } } if (ok) { generatePalette(base_palette, type); } return base_palette; } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) /*! \brief 设置是否将调色板的颜色改为半透明模式. 一般用在主窗口背景为透明、模糊的程序中 \param on 是否开启 */ void DGuiApplicationHelper::setUseInactiveColorGroup(bool on) { DGuiApplicationHelper::setAttribute(Attribute::UseInactiveColorGroup, on); } /*! \brief 设置是否开启混合颜色. \param on 是否开启 */ void DGuiApplicationHelper::setColorCompositingEnabled(bool on) { DGuiApplicationHelper::setAttribute(Attribute::ColorCompositing, on); } #endif bool DGuiApplicationHelper::isXWindowPlatform() { return DGuiApplicationHelper::testAttribute(Attribute::IsXWindowPlatform); } /*! \brief 用于判断当前桌面环境是否是平板电脑环境. \return true 是平板电脑环境 false不是平板电脑环境 */ bool DGuiApplicationHelper::isTabletEnvironment() { return DGuiApplicationHelper::testAttribute(Attribute::IsTableEnvironment); } /*! \brief isAnimationEnvironment 用于判断当前桌面环境是否是开启了动画等特效的环境 \return true开启了 false没有开启 */ bool DGuiApplicationHelper::isSpecialEffectsEnvironment() { return DGuiApplicationHelper::testAttribute(Attribute::IsSpecialEffectsEnvironment); } /*! \brief DGuiApplicationHelper::systemTheme. 返回系统级别的主题, 优先级低于 applicationTheme \return 平台主题对象 \sa applicationTheme \sa windowTheme */ DPlatformTheme *DGuiApplicationHelper::systemTheme() const { D_DC(DGuiApplicationHelper); return d->systemTheme; } /*! \brief DGuiApplicationHelper::applicationTheme. 同 systemTheme \return 平台主题对象 \sa systemTheme \sa windowTheme */ DPlatformTheme *DGuiApplicationHelper::applicationTheme() const { D_DC(DGuiApplicationHelper); // 如果appTheme还未初始化,应当先初始化appTheme if (Q_UNLIKELY(!d->appTheme)) { // 初始程序级别的主题对象 const_cast(d)->_q_initApplicationTheme(false); } return d->appTheme; } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) /*! \brief 返回窗口级别的主题, 优先级高于 windowTheme 和 systemTheme. \param window 主题对象对应的窗口 \return 平台主题对象 \sa applicationTheme() \warning 已废弃, 不再对外暴露为特定窗口设置主题的接口 */ DPlatformTheme *DGuiApplicationHelper::windowTheme(QWindow *window) const { DPlatformTheme *theme = qvariant_cast(window->property(WINDOW_THEME_KEY)); if (theme) { return theme; } D_DC(DGuiApplicationHelper); theme = d->initWindow(window); return theme; } #endif /*! \brief 返回应用程序调色板. 如果使用 setApplicationPalette 设置过一个有效的调色板, 将直接返回保存的调色板. 否则 先计算调色板的ColorType, 再使用这个颜色类型通过 standardPalette 获取标准调色板. 计算 ColorType的数据来源按优先级从高到低排列有以下几种方式: 1. 如果使用 setThemeType 设置过一个有效的颜色类型, 将直接使用 themeType 的值. 2. 如果为QGuiApplication设置过调色板(表现为 QGuiApplication::testAttribute(Qt::AA_SetPalette) 为true), 则将使用 QGuiApplication::palette 通过 toColorType 获取颜色类型. 3. 将根据 applicationTheme 的 DPlatformTheme::themeName 计算颜色类型. 如果ColorType来源自第2种方式, 则会直接使用 QGuiApplication::palette 覆盖标准调色板中的 QPalette 部分, 且程序不会再跟随系统的活动色自动更新调色板. \warning 不应该在DTK程序中使用QGuiApplication/QApplication::setPalette \return 应用程序调色板 */ DPalette DGuiApplicationHelper::applicationPalette(ColorType paletteType) const { D_DC(DGuiApplicationHelper); if (d->appPalette) { return *d->appPalette; } ColorType type = paletteType; bool aa_setPalette = qGuiApp && qGuiApp->testAttribute(Qt::AA_SetPalette); // 此时appTheme可能还未初始化, 因此先使用systemTheme, 待appTheme初始化之后会 // 通知程序调色板发生改变 auto theme = Q_LIKELY(d->appTheme) ? d->appTheme : d->systemTheme; if (type == UnknownType) { if (aa_setPalette) { type = toColorType(qGuiApp->palette()); } else { // 如果程序未自定义调色板, 则直接从平台主题中获取调色板数据 return fetchPalette(theme); } } // 如果程序自定义了palette的类型,将忽略 appTheme 中设置的调色板数据. DPalette pa = standardPalette(type); if (aa_setPalette) { // 如果程序通过QGuiApplication::setPalette自定义了调色板, 则应当尊重程序的选择 // 覆盖DPalette中的的QPalette数据 pa.QPalette::operator =(qGuiApp->palette()); } else { const QColor &active_color = getActiveColor(theme, type); if (active_color.isValid()) { // 应用Active Color pa.setColor(QPalette::Normal, QPalette::Highlight, active_color); generatePaletteColor(pa, QPalette::Highlight, type); } } return pa; } DPalette DGuiApplicationHelper::applicationPalette() const { D_DC(DGuiApplicationHelper); return applicationPalette(d->paletteType); } /*! \brief DGuiApplicationHelper::setApplicationPalette. 自定义应用程序调色板, 如果没有为 QGuiApplication 设置过 QPalette, 则 将触发 QGuiApplication::palette 的更新. 如果仅需要控制程序使用亮色还是暗色的 调色板, 请使用 setThemeType. \note 主动设置调色板的操作会导致程序不再使用 DPlatformTheme 中调色板相关的数据, 也 包括窗口级别的 windowTheme 所对应的 DPlatformTheme, 届时设置 DPlatformTheme 的 themeName 和所有与 \a palette 相关的属性都不再生效. \warning 使用此方式设置的调色板将不会自动跟随活动色的变化 \warning 如果使用过QGuiApplication::setPalette, 此方式可能不会生效 \param palette 要设置的调色板 */ void DGuiApplicationHelper::setApplicationPalette(const DPalette &palette) { D_D(DGuiApplicationHelper); if (qGuiApp && qGuiApp->testAttribute(Qt::AA_SetPalette)) { qWarning() << "DGuiApplicationHelper: Plase check 'QGuiApplication::setPalette', Don't use it on DTK application."; } auto resolve = [](const DPalette &palette) ->bool { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return palette.resolveMask(); #else return palette.resolve(); #endif }; if (d->appPalette) { if (resolve(palette)) { *d->appPalette = palette; } else { d->appPalette.reset(); } } else if (resolve(palette)) { d->appPalette.reset(new DPalette(palette)); } else { return; } // 通知QGuiApplication更新自身的palette和font d->notifyAppThemeChanged(); } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) /*! \brief DGuiApplicationHelper::windowPalette. 返回窗口所对应的调色板数据, 同 applicationPalette, 如果程序中自定义了 调色板, 则直接使用 applicationPalette. 自定义调色板的三种方式如下: 1. 通过 setApplicationPalette 固定调色板 2. 通过 setThemeType 固定调色板的类型 3. 通过 QGuiApplication::setPalette 固定调色板, 需要注意此方法不可逆. 否则将基于窗口所对应的 DPlatformTheme 获取调色板( fetchPalette). \param window \return 调色板 \sa windowTheme(), fetchPalette(), standardPalette(), generatePalette(), applicationPalette() \warning 使用时要同时关注 applicationPaletteChanged() , 收到此信号后可能需要重新获取窗口的调色板 \warning 已废弃, 不再对外暴露控制窗口级别调色板的接口 */ DPalette DGuiApplicationHelper::windowPalette(QWindow *window) const { D_DC(DGuiApplicationHelper); // 如果程序自定义了调色版, 则不再关心窗口对应的平台主题上的设置 if (Q_UNLIKELY(d->isCustomPalette())) { return applicationPalette(); } DPlatformTheme *theme = windowTheme(window); if (Q_UNLIKELY(!theme)) { return applicationPalette(); } return fetchPalette(theme); } #endif /*! \brief DGuiApplicationHelper::fontManager. 程序中唯一的DFontManager对象, 会根据程序的fontChanged信号 更新 DFontManager::baseFontPixelSize \warning 请不要尝试更改它的 baseFontPixelSize 属性 */ const DFontManager *DGuiApplicationHelper::fontManager() const { // 为对象初始化信号链接 if (!_globalFM.exists()) { // fontManager's base font is update from qGuiApp. _globalFM->setBaseFont(qGuiApp->font()); connect(this, &DGuiApplicationHelper::fontChanged, _globalFM, &DFontManager::setBaseFont); } return _globalFM; } /*! \brief 获取颜色的明亮度,将其转换为主题类型的枚举值. 转换的策略为:先将颜色转换为rgb格式,再根据 Y = 0.299R + 0.587G + 0.114B 的公式 计算出颜色的亮度,亮度大于 191 时认为其为浅色,否则认为其为深色。 \param color 需要转换为主题的类型的颜色 \return 颜色类型的枚举值 */ DGuiApplicationHelper::ColorType DGuiApplicationHelper::toColorType(const QColor &color) { if (!color.isValid()) return UnknownType; QColor rgb_color = color.toRgb(); // 获取rgb颜色的亮度(转换为YUV格式) float luminance = 0.299 * rgb_color.redF() + 0.587 * rgb_color.greenF() + 0.114 * rgb_color.blueF(); if (qRound(luminance * 255) > 191) { return LightType; } return DarkType; } /*! \brief 将调色板 \a palette 转换为主题类型的枚举. \overload 使用 QPalette::background 获取颜色的明亮度,将其转换为主题类型的枚举值。 返回调色板的颜色类型 \param palette 调色板 \return 颜色类型的枚举值 */ DGuiApplicationHelper::ColorType DGuiApplicationHelper::toColorType(const QPalette &palette) { return toColorType(palette.window().color()); } /*! \brief 返回程序的主题类型. 当themeType为UnknownType时, 将自动根据 GuiApplication::palette的QPalette::background颜色计算主题 类型, 否则与 paletteType 的值一致. 程序中应当使用此值作为 暗色/亮色主题类型的判断. \return 主题的颜色类型. \sa toColorType */ DGuiApplicationHelper::ColorType DGuiApplicationHelper::themeType() const { D_DC(DGuiApplicationHelper); d->initPaletteType(); if (d->paletteType != UnknownType) { return d->paletteType; } return toColorType(qGuiApp->palette()); } /*! \brief 返回当前已设置的调色板类型. 如果未调用过 setPaletteType, 默认为 UnknownType. \return 返回当前已设置的调色板类型. \warning 与 themetype 不同,此值与程序当前的 QPalette 没有关系。 \sa DGuiApplicationHelper::themeType */ DGuiApplicationHelper::ColorType DGuiApplicationHelper::paletteType() const { D_DC(DGuiApplicationHelper); d->initPaletteType(); return d->paletteType; } /*! \brief 设置DGuiApplicationHelper实例. \param key 实例关键字 \param singleScope 实例使用范围 \return 设置是否成功 \note 此处所用到DGuiApplicationHelperPrivate::waitTime默认值为3000ms,可通过 \note DGuiApplicationHelper::setSingleInstanceInterval设置 */ bool DGuiApplicationHelper::setSingleInstance(const QString &key, DGuiApplicationHelper::SingleScope singleScope) { bool new_server = !_d_singleServer.exists(); if (_d_singleServer->isListening()) { _d_singleServer->close(); } QString socket_key = "_d_dtk_single_instance_"; switch (singleScope) { case GroupScope: _d_singleServer->setSocketOptions(QLocalServer::GroupAccessOption); #ifdef Q_OS_LINUX socket_key += QString("%1_").arg(getgid()); #endif break; case WorldScope: _d_singleServer->setSocketOptions(QLocalServer::WorldAccessOption); break; default: _d_singleServer->setSocketOptions(QLocalServer::UserAccessOption); #ifdef Q_OS_LINUX socket_key += QString("%1_").arg(getuid()); #endif break; } socket_key += key; QString lockfile = socket_key; if (!lockfile.startsWith(QLatin1Char('/'))) { lockfile = QDir::cleanPath(QDir::tempPath()); lockfile += QLatin1Char('/') + socket_key; } lockfile += QStringLiteral(".lock"); static QScopedPointer lock(new QLockFile(lockfile)); // 同一个进程多次调用本接口使用最后一次设置的 key // FIX dcc 使用不同的 key 两次调用 setSingleInstance 后无法启动的问题 qint64 pid = -1; QString hostname, appname; if (lock->isLocked() && lock->getLockInfo(&pid, &hostname, &appname) && pid == getpid()) { qCWarning(dgAppHelper) << "call setSingleInstance again within the same process"; lock->unlock(); lock.reset(new QLockFile(lockfile)); } if (!lock->tryLock()) { qCDebug(dgAppHelper) << "===> new client <===" << getpid(); // 通知别的实例 QLocalSocket socket; socket.connectToServer(socket_key); // 等待到有效数据时认为server实例有效 if (socket.waitForConnected(DGuiApplicationHelperPrivate::waitTime) && socket.waitForReadyRead(DGuiApplicationHelperPrivate::waitTime)) { // 读取数据 qint8 version; qint64 pid; QStringList arguments; QDataStream ds(&socket); ds >> version >> pid >> arguments; qCInfo(dgAppHelper) << "Process is started: pid=" << pid << "arguments=" << arguments; // 把自己的信息告诉第一个实例 ds << _d_singleServerVersion << qApp->applicationPid() << qApp->arguments(); socket.flush(); } return false; } if (!_d_singleServer->listen(socket_key)) { qCWarning(dgAppHelper) << "listen failed:" << _d_singleServer->errorString(); return false; } else { qCDebug(dgAppHelper) << "===> listen <===" << _d_singleServer->serverName() << getpid(); } if (new_server) { qCDebug(dgAppHelper) << "===> new server <===" << _d_singleServer->serverName() << getpid(); QObject::connect(_d_singleServer, &QLocalServer::newConnection, qApp, [] { QLocalSocket *instance = _d_singleServer->nextPendingConnection(); // 先发送数据告诉新的实例自己收到了它的请求 QDataStream ds(instance); ds << _d_singleServerVersion // 协议版本 << qApp->applicationPid() // 进程id << qApp->arguments(); // 启动时的参数 QObject::connect(instance, &QLocalSocket::readyRead, qApp, [instance] { // 读取数据 QDataStream ds(instance); qint8 version; qint64 pid; QStringList arguments; ds >> version >> pid >> arguments; instance->close(); qCInfo(dgAppHelper) << "New instance: pid=" << pid << "arguments=" << arguments; // 通知新进程的信息 if (_globalHelper.exists() && _globalHelper->helper()) Q_EMIT _globalHelper->helper()->newProcessInstance(pid, arguments); }); instance->flush(); //发送数据给新的实例 }); } return true; } /*! \brief 设置从QLocalServer获取消息的等待时间. 用于在重新创建DGuiApplicationHelper单例时,检测DGuiApplicationHelper单例是否存在且有响应 \param interval 等待时间,如 \a interval 为 -1 则没有超时一直等待,默认和 QLocalSocket 一致 3000ms \note 需要在 DGuiApplicationHelper::setSingleInstance 之前调用否则无效。 */ void DGuiApplicationHelper::setSingleInstanceInterval(int interval) { Q_ASSERT_X(!_d_singleServer->isListening(), "DGuiApplicationHelper::setSingleInstanceInterval","Must call before setSingleInstance"); DGuiApplicationHelperPrivate::waitTime = interval; } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) /*! \brief 设置从QLocalServer获取消息的等待时间. \param interval 等待时间,typo 请使用 DGuiApplicationHelper::setSingleInstanceInterval */ void DGuiApplicationHelper::setSingelInstanceInterval(int interval) { DGuiApplicationHelperPrivate::waitTime = interval; } #endif /*! \brief 获取帮助手册目录 \return 帮助手册目录 */ QStringList DGuiApplicationHelper::userManualPaths(const QString &appName) { Q_ASSERT(!appName.isEmpty()); // 获取主目录 DCORE_USE_NAMESPACE QStringList manualPaths; const auto &pathlist = DStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); // 获取所有已存在的帮助手册目录 for (int i = 0; i < pathlist.size(); ++i) { QString strAssetPath = QStringList{pathlist[i], "deepin-manual/manual-assets"}.join(QDir::separator()); for (const QString &type : QDir(strAssetPath).entryList(QDir::NoDotAndDotDot | QDir::Dirs)) { QString appDirPath = QStringList{strAssetPath, type, appName}.join(QDir::separator()); if (QDir(appDirPath).exists()) manualPaths.push_back(appDirPath); } } return manualPaths; } /*! * \brief Determine whether it's a user manual for this application. * \return */ bool DGuiApplicationHelper::hasUserManual() const { return userManualPaths(qApp->applicationName()).size() > 0; } bool DGuiApplicationHelper::loadTranslator(const QString &fileName, const QList &translateDirs, const QList &localeFallback) { DCORE_USE_NAMESPACE; QList dirs = translateDirs; const QList defaultDirPrefix { qApp->applicationDirPath(), QDir::currentPath() }; for (auto item : defaultDirPrefix) dirs << item.join("translations").toString(); QStringList missingQmfiles; for (const auto &locale : localeFallback) { QStringList translateFilenames {QString("%1_%2").arg(fileName).arg(locale.name())}; #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) auto behavior = Qt::SkipEmptyParts; #else auto behavior = QString::SkipEmptyParts; #endif const QStringList parseLocalNameList = locale.name().split("_", behavior); if (parseLocalNameList.length() > 0) translateFilenames << QString("%1_%2").arg(fileName).arg(parseLocalNameList.at(0)); for (const auto &translateFilename : translateFilenames) { for (const auto &dir : dirs) { DPathBuf path(dir); QString translatePath = (path / translateFilename).toString(); if (QFile::exists(translatePath + ".qm")) { qCDebug(dgAppHelper) << "load translate" << translatePath; auto translator = new QTranslator(qApp); translator->load(translatePath); qApp->installTranslator(translator); qApp->setProperty("dapp_locale", locale.name()); return true; } } // fix english does not need to translation. if (locale.language() != QLocale::English) missingQmfiles << translateFilename + ".qm"; } } if (missingQmfiles.size() > 0) { qWarning() << fileName << "can not find qm files" << missingQmfiles; } return false; } bool DGuiApplicationHelper::loadTranslator(const QList &localeFallback) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) auto qTranslationsPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); #else auto qTranslationsPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath); #endif DCORE_USE_NAMESPACE //("/home/user/.local/share", "/usr/local/share", "/usr/share") auto dataDirs = DStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); QList qtranslateDirs = { qTranslationsPath }; for (const auto &path : dataDirs) { DPathBuf pathBuf(path); qtranslateDirs << (pathBuf / "qt" QT_STRINGIFY(QT_VERSION_MAJOR) / "translations").toString(); } loadTranslator("qt", qtranslateDirs, localeFallback); loadTranslator("qtbase", qtranslateDirs, localeFallback); QList translateDirs; auto appName = qApp->applicationName(); for (const auto &path : dataDirs) { DPathBuf pathBuf(path); translateDirs << (pathBuf / appName / "translations").toString(); } // ${translateDir}/${appName}_${localeName}.qm return loadTranslator(appName, translateDirs, localeFallback); } DGuiApplicationHelper::SizeMode DGuiApplicationHelper::sizeMode() const { D_DC(DGuiApplicationHelper); return d->fetchSizeMode(); } void DGuiApplicationHelper::setSizeMode(const DGuiApplicationHelper::SizeMode mode) { D_D(DGuiApplicationHelper); const auto old = d->fetchSizeMode(); d->explicitSizeMode = mode; const auto current = d->fetchSizeMode(); if (old != current) Q_EMIT sizeModeChanged(current); } void DGuiApplicationHelper::resetSizeMode() { D_D(DGuiApplicationHelper); const auto old = d->fetchSizeMode(); d->explicitSizeMode = InvalidSizeMode; const auto current = d->fetchSizeMode(); if (current != old) Q_EMIT sizeModeChanged(current); } void DGuiApplicationHelper::setAttribute(DGuiApplicationHelper::Attribute attribute, bool enable) { if (attribute < Attribute::ReadOnlyLimit) { DGuiApplicationHelperPrivate::attributes.setFlag(attribute, enable); } else { qWarning() << "You are setting for the read-only option."; return; } } bool DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::Attribute attribute) { switch (attribute) { case IsXWindowPlatform: return qGuiApp->platformName() == QByteArrayLiteral("xcb") || qGuiApp->platformName() == QByteArrayLiteral("dxcb"); case IsDXcbPlatform: return DPlatformHandle::isDXcbPlatform(); case IsTableEnvironment: return QGuiApplicationPrivate::instance()->platformIntegration()->services()->desktopEnvironment().toLower().endsWith("tablet"); case IsDeepinPlatformTheme: if (!QGuiApplicationPrivate::platform_name) { return false; } return QString(typeid(*QGuiApplicationPrivate::platform_theme).name()).contains("QDeepinTheme"); case IsDeepinEnvironment: { const auto &de = QGuiApplicationPrivate::instance()->platformIntegration()->services()->desktopEnvironment(); return de.toLower().contains("deepin") || de == "DDE"; } case IsSpecialEffectsEnvironment: { return qgetenv("DTK_DISABLED_SPECIAL_EFFECTS").toInt() != 1; } case IsWaylandPlatform: { static bool isTreeland = qApp->platformName() == QByteArrayLiteral("wayland"); return isTreeland; } case HasAnimations: { static bool isDisable = qEnvironmentVariableIsSet(DTK_ANIMATIONS_ENV); if (isDisable) return false; static bool shouldEnable = _d_dconfig->value(DTK_ENABLE_ANIMATIONS, false).toBool(); return shouldEnable; } default: return DGuiApplicationHelperPrivate::attributes.testFlag(attribute); } } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) /*! \brief DGuiApplicationHelper::setThemeType. \deprecated 同 setPaletteType, 已废弃,请不要再使用。 \param themeType 主题类型. */ void DGuiApplicationHelper::setThemeType(DGuiApplicationHelper::ColorType themeType) { setPaletteType(themeType); } #endif /*! \brief 设置程序所应用的调色板类型. 将固定程序的调色板类型, 此行为可能导致 applicationPalette 变化, 前提是未使用 setApplicationPalette 固定过程序的调色板, 此方法不影响程序的调色板跟随 活动色改变, 可用于控制程序使用亮色还是暗色调色板. \note 主动设置调色板颜色类型的操作会导致程序不再使用 DPlatformTheme 中调色板相关的数据, 也 包括窗口级别的 windowTheme 所对应的 DPlatformTheme, 届时设置 DPlatformTheme 的 themeName 和所有与 palette 相关的属性都不再生效. \param paletteType 主题类型的枚举值 */ void DGuiApplicationHelper::setPaletteType(DGuiApplicationHelper::ColorType paletteType) { if (!qApp) { qWarning() << "Can't call `DGuiApplicationHelper::setPaletteType` before QCoreApplication constructed."; return; } D_D(DGuiApplicationHelper); d->initPaletteType(); d->setPaletteType(paletteType, true); _d_dconfig->setValue(APP_THEME_TYPE, paletteType); } /*! * \brief Open manual for this application. */ void DGuiApplicationHelper::handleHelpAction() { if (!hasUserManual()) { return; } #ifdef Q_OS_LINUX QString appid = qApp->applicationName(); // new interface use applicationName as id QDBusInterface manual("com.deepin.Manual.Open", "/com/deepin/Manual/Open", "com.deepin.Manual.Open"); QDBusPendingCall call = manual.asyncCall("ShowManual", appid); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [appid](QDBusPendingCallWatcher *pWatcher) { QDBusPendingReply reply = *pWatcher; if (reply.isError()) { // fallback to old interface qWarning() << reply.error() << "fallback to dman appid"; QProcess::startDetached("dman", QStringList() << appid); } pWatcher->deleteLater(); }); #else qWarning() << "not support dman now"; #endif } void DGuiApplicationHelper::openUrl(const QString &url) { #ifdef Q_OS_UNIX // workaround for pkexec apps bool ok = false; const int pkexecUid = qEnvironmentVariableIntValue("PKEXEC_UID", &ok); if (ok) { EnvReplaceGuard _env_guard(pkexecUid); Q_UNUSED(_env_guard); QDesktopServices::openUrl(url); } else #endif { QDesktopServices::openUrl(url); } } DGUI_END_NAMESPACE #include "moc_dguiapplicationhelper.cpp" dtkgui-5.7.12/src/kernel/dnativesettings.cpp000066400000000000000000000060461476226661100211040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dnativesettings.h" #include "private/dnativesettings_p.h" #include #include #include #include DGUI_BEGIN_NAMESPACE DNativeSettingsPrivate::DNativeSettingsPrivate(DNativeSettings *qq, const QByteArray &domain) : DObjectPrivate(qq) , domain(domain) { } DNativeSettingsPrivate::~DNativeSettingsPrivate() { } bool DNativeSettingsPrivate::init(const QMetaObject *mo, quint32 window) { QFunctionPointer native_build_setting_fun = qGuiApp->platformFunction("_d_buildNativeSettings"); if (!native_build_setting_fun) return false; D_Q(DNativeSettings); if (!domain.isEmpty()) { q->setProperty("_d_domain", domain); } q->setProperty("_d_metaObject", reinterpret_cast(mo)); return reinterpret_cast(native_build_setting_fun)(q, window); } /*! \class Dtk::Gui::DNativeSettings \inmodule dtkgui \brief 一个用于本地设置的类. */ DNativeSettings::DNativeSettings(quint32 window, const QByteArray &domain, QObject *parent) : DNativeSettings(&DNativeSettings::staticMetaObject, window, domain, parent) { } bool DNativeSettings::isValid() const { D_DC(DNativeSettings); return d->valid; } QByteArrayList DNativeSettings::allKeys() const { D_DC(DNativeSettings); return d->allKeys; } QVariant DNativeSettings::getSetting(const QByteArray &name) const { D_DC(DNativeSettings); // 避免进入死循环 if (!d->valid) return QVariant(); return property(name.constData()); } void DNativeSettings::setSetting(const QByteArray &name, const QVariant &value) { D_D(DNativeSettings); // 避免进入死循环 if (!d->valid) return; setProperty(name.constData(), value); } DNativeSettings::DNativeSettings(DNativeSettingsPrivate &dd, const QMetaObject *metaObject, quint32 window, QObject *parent) : QObject(parent) , DObject(dd) { d_func()->valid = init(metaObject, window); } DNativeSettings::DNativeSettings(const QMetaObject *metaObject, quint32 window, const QByteArray &domain, QObject *parent) : DNativeSettings(*new DNativeSettingsPrivate(this, domain), metaObject, window, parent) { } bool DNativeSettings::init(const QMetaObject *metaObject, quint32 window) { D_D(DNativeSettings); return d->init(metaObject, window); } void DNativeSettings::__setAllKeys(const QByteArrayList &keys) { D_D(DNativeSettings); d->allKeys = keys; Q_EMIT allKeysChanged(); } DGUI_END_NAMESPACE QT_BEGIN_NAMESPACE QDebug operator<<(QDebug debug, const DTK_GUI_NAMESPACE::DNativeSettings &settings) { const QByteArrayList &keys = settings.allKeys(); for (const QByteArray &key : keys) { debug << key << settings.getSetting(key) << #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) Qt::endl; #else endl; #endif } return debug; } QT_END_NAMESPACE dtkgui-5.7.12/src/kernel/dpalette.cpp000066400000000000000000000114011476226661100174620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dpalette.h" DGUI_BEGIN_NAMESPACE struct DPaletteData : public QSharedData { QBrush br[DPalette::NColorGroups][DPalette::NColorTypes]; }; class DPalettePrivate { public: explicit DPalettePrivate(const QSharedDataPointer &d) : data(d) { } QSharedDataPointer data; }; /*! @~english \class Dtk::Gui::DPalette \ingroup guikernal \brief DPalette inherits and extends the QPalette class, providing the unique features of DTK DPalette add new color type */ /*! @~english \brief DPalette::Dpalette constructor function */ DPalette::DPalette() : d(new DPalettePrivate(QSharedDataPointer(new DPaletteData()))) { } /*! @~english \brief DPalette::Dpalette constructor function \a palette parameter is sent to the QPalette constructor function */ DPalette::DPalette(const QPalette &palette) : QPalette(palette) , d(new DPalettePrivate(QSharedDataPointer(new DPaletteData()))) { } /*! @~english \brief DPalette::Dpalette constructor functio \a palette parameter is sent to the QPalette constructor function */ DPalette::DPalette(const DPalette &palette) : QPalette(palette) , d(new DPalettePrivate(palette.d->data)) { } DPalette::~DPalette() {} DPalette &DPalette::operator=(const DPalette &palette) { QPalette::operator=(palette); d->data = palette.d->data; return *this; } /*! @~english \brief DPalette::brush \a cg \a cr \sa QPalette::brush() */ const QBrush &DPalette::brush(QPalette::ColorGroup cg, DPalette::ColorType cr) const { if (cr >= NColorTypes) { return QPalette::brush(cg, QPalette::NoRole); } if (cg == Current) { cg = currentColorGroup(); } else if (cg >= NColorGroups) { cg = Active; } return d->data->br[cg][cr]; } /*! @~english \brief DPalette::setBrush set drawing brush \a cg \a cr \a brush \sa QPalette::setBrush() */ void DPalette::setBrush(QPalette::ColorGroup cg, DPalette::ColorType cr, const QBrush &brush) { if (cg == All) { for (uint i = 0; i < NColorGroups; i++) setBrush(ColorGroup(i), cr, brush); return; } if (cr >= NColorTypes) { return QPalette::setBrush(cg, QPalette::NoRole, brush); } if (cg == Current) { cg = currentColorGroup(); } else if (cg >= NColorGroups) { cg = Active; } d->data->br[cg][cr] = brush; } DGUI_END_NAMESPACE DGUI_USE_NAMESPACE QT_BEGIN_NAMESPACE QDataStream &operator<<(QDataStream &ds, const DPalette &p) { ds << static_cast(p); for (int i = 0; i < DPalette::NColorGroups; ++i) { for (int j = 0; j < DPalette::NColorTypes; ++j) { ds << p.brush(DPalette::ColorGroup(i), DPalette::ColorType(j)); } } return ds; } QDataStream &operator>>(QDataStream &ds, DPalette &p) { ds >> static_cast(p); for (int i = 0; i < DPalette::NColorGroups; ++i) { for (int j = 0; j < DPalette::NColorTypes; ++j) { QBrush brush; ds >> brush; p.setBrush(DPalette::ColorGroup(i), DPalette::ColorType(j), brush); } } return ds; } QDebug operator<<(QDebug dbg, const DPalette &p) { const char *colorGroupNames[] = {"Active", "Disabled", "Inactive", "NColorGroups", "Current", "All", "Normal"}; const char *colorTypeNames[] = { "NoType", "ItemBackground", // 列表项的背景色 "TextTitle", // 标题型文本的颜色 "TextTips", // 提示性文本的颜色 "TextWarning", // 警告类型的文本颜色 "TextLively", // 活跃式文本颜色(不受活动色影响) "LightLively", // 活跃式按钮(recommend button)背景色中的亮色(不受活跃色影响) "DarkLively", // 活跃式按钮(recommend button)背景色中的暗色,会从亮色渐变到暗色(不受活跃色影响) "FrameBorder", // 控件边框颜色 "PlaceholderText", // 占位类型的文本颜色,可用于输入框占位内容等提示性文字 "FrameShadowBorder", // 用于跟阴影叠加的边框颜色 "ObviousBackground", // 明显的背景色 "NColorTypes"}; QDebugStateSaver saver(dbg); dbg << "\r\nDPalette: \r\n"; for (int i = 0; i < DPalette::NColorGroups; ++i) { for (int j = DPalette::NoType + 1; j < DPalette::NColorTypes; ++j) { dbg << colorGroupNames[DPalette::ColorGroup(i)] << colorTypeNames[DPalette::ColorType(j)]; dbg << p.brush(DPalette::ColorGroup(i), DPalette::ColorType(j)) << "\r\n"; } } return dbg; } QT_END_NAMESPACE dtkgui-5.7.12/src/kernel/dplatformhandle.cpp000066400000000000000000001022601476226661100210300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dplatformhandle.h" #include "dplatformwindowinterface_p.h" #include "dguiapplicationhelper.h" #ifndef DTK_DISABLE_XCB #include "plugins/platform/xcb/dxcbplatformwindowinterface.h" #endif #ifndef DTK_DISABLE_TREELAND #include "plugins/platform/treeland/dtreelandplatformwindowinterface.h" #endif DGUI_BEGIN_NAMESPACE static QHash g_platformWindowImpls; static DPlatformWindowInterface *platformWindowImpl(const DPlatformHandle *platformHandle) { return g_platformWindowImpls.value(platformHandle); } /*! \class Dtk::Gui::DPlatformHandle \inmodule dtkgui \brief 一个和Qt dxcb平台插件交互的工具类. 实质性的功能皆在dxcb插件中实现,此插件目前只 支持X11平台,在其它平台上使用这个类不会有任何效果。关于dxcb:它介于Qt应用和Qt xcb平台 插件之间,通过覆写xcb插件中某些对象的虚函数来改变它的一些行为,本质上来讲是Qt xcb插件的 扩展,在X11平台上为DTK应用提供了一些改变窗口效果的功能(比如自定义窗口的边框)、其它和平 台密切相关的实现(比如修复Qt应用在X11平台的一些bug),不能脱离Qt xcb插件独立运行。dxcb 通过重载 QPlatformNativeInterface 提供接口,DPlatformHandle 中使用 QGuiApplication::platformFunction 调用这些接口。Application、dxcb、qt xcb 之间 的关系: \raw HTML

        ┏━━━━━━━━━━━━━━━━┓
        ┃   Application  ┃
        ┗━━━━━━━━━━━━━━━━┛
                ⇅
      ┏━━━━━━━━━━━━━━━━━━━━┓
      ┃     dxcb plugin    ┃
      ┗━━━━━━━━━━━━━━━━━━━━┛
                ⇅
   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
   ┃      qt xcb platform      ┃
   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  
\endraw \ref {http://doc.qt.io/qt-5/qpa.html}{QPA} \ref {https://github.com/linuxdeepin/qt5dxcb-plugin/}{dxcb插件} \sa Dtk::Gui::DPlatformHandle::isDXcbPlatform \sa QGuiApplication::platformNativeInterface \sa Dtk::Widget::DMainWindow \sa DWindowManagerHelper \warning 使用此工具前要确保应用加载了dxcb插件 \warning 因为 QGuiApplication::platformFunction 是在 Qt 5.4.0 版本引入的新接口, 所以 DPlatformHandle 不支持 Qt 5.4.0 以下版本。 */ /*! \property DPlatformHandle::windowRadius \brief 窗口的圆角半径。默认情况下,窗口管理器支持混成时,圆角半径为4,否则为0,并且 会随着窗口管理器开启/关闭混成效果而变化 \note 可读可写 \note 窗口为半屏、全屏或最大化状态时此值不生效 \warning 手动设置值后将无法再随着窗口管理器是否支持混成而自动更新边框宽度 \sa DWindowManagerHelper::hasComposite */ /*! \property DPlatformHandle::borderWidth \brief 窗口的外边框宽度。默认情况下,窗口管理器支持混成时,边框宽度为1,否则对于可以 改变大小的窗口其值为2,否则为1,并且会随着窗口管理器开启/关闭混成效果而变化 \note 可读可写 \warning 手动设置值后将无法再随着窗口管理器是否支持混成而自动更新边框宽度 \sa DWindowManagerHelper::hasComposite */ /*! \property DPlatformHandle::borderColor \brief 窗口外边框的颜色。默认情况下,窗口管理器支持混成时,颜色为 QColor(0, 0, 0, 255 * 0.15), 否则为边框颜色和 #e0e0e0 的混合,并且会随着窗口管理器开启/关闭混成效果而变化 \note 可读可写 \sa DWindowManagerHelper::hasComposite */ /*! \property DPlatformHandle::shadowRadius \brief 窗口的阴影半径。默认为 60 \note 可读可写 \note 窗口管理器不支持混成时此值无效 \sa DWindowManagerHelper::hasComposite */ /*! \property DPlatformHandle::shadowOffset \brief 窗口阴影的偏移量。默认为 QPoint(0,16) \note 可读可写 \note 窗口管理器不支持混成时此值无效 \sa DWindowManagerHelper::hasComposite */ /*! \property DPlatformHandle::shadowColor \brief 窗口阴影的颜色。默认为 QColor(0, 0, 0, 255 * 0.6) \note 可读可写 \note 窗口管理器不支持混成时此值无效 \sa DWindowManagerHelper::hasComposite */ /*! \property DPlatformHandle::clipPath \brief 窗口的裁剪区域。处于路径内部的区域为窗口有效区域,非有效区域内的窗口内容 将无法显示,并且无法收到鼠标和触摸事件。示例: \code QWidget w; QPainterPath path; QFont font; font.setPixelSize(100); path.addText(0, 150, font, "deepin"); DPlatformHandle handle(&w); handle.setClipPath(path); w.resize(400, 200); w.show(); \endcode \image clip_window_demo.gif \note 可读可写 \note 窗口的阴影和外边框绘制和其有效区域密切相关 \warning 设置此属性后将导致 DPlatformHandle::windowRadius 失效 */ /*! \property DPlatformHandle::frameMask \brief 设置 Frame Window 的遮罩,和 \a clipPath 不同的是,它的裁剪包括阴影 部分。示例: \code QWidget w; DPlatformHandle handle(&w); // 为何更好的观察效果,此处将阴影改为蓝色 handle.setShadowColor(Qt::blue); w.resize(400, 200); w.show(); QRect frame_rect = w.rect() + handle.frameMargins(); frame_rect.moveTopLeft(QPoint(0, 0)); handle.setFrameMask(QRegion(frame_rect, QRegion::Ellipse)); \endcode \image frame_mask_demo.png \note 可读可写 \note 由于实现机制限制,使用此属性裁剪 Frame Window 时,无法去除边缘产生的锯齿 */ /*! \property DPlatformHandle::frameMargins \brief Sub Window 相对于 Frame Window 的边距 \image frame_margins.png \note 只读 \warning 在窗口隐藏时不保证此值的正确性 */ /*! \property DPlatformHandle::translucentBackground \brief 如果此属性值为 true,则在更新窗口绘制内容之前会先清空要更新区域内的图像, 否则不清空,默认为 false \note 可读可写 */ /*! \property DPlatformHandle::enableSystemResize \brief 如果此属性值为 true,则允许外界改变窗口的大小(如使用鼠标拖拽窗口边框), 否则不允许。默认为 true \note 无论属性值是多少,Qt::Popup 和 Qt::BypassWindowManagerHint 类型的 窗口都不允许改变大小 \note 可读可写 \note 此属性仅仅控制 dxcb 中的行为,不会影响窗口管理器的行为 \sa QWidget::setFixedSize \sa QWindow::setMinimumSize \sa QWindow::setMaximumSize \sa DWindowManagerHelper::FUNC_RESIZE */ /*! \property DPlatformHandle::enableSystemMove \brief 如果此属性值为 ture,则允许外界移动窗口的位置(如使用鼠标拖拽移动窗口), 否则不允许。默认为 true \note 无论属性值是多少,Qt::Popup 和 Qt::BypassWindowManagerHint 类型的 窗口都不允许改变大小 \note 可读可写 \note 此属性仅仅控制 dxcb 中的行为,不会影响窗口管理器的行为 \sa DWindowManagerHelper::FUNC_MOVE */ /*! \property DPlatformHandle::enableBlurWindow \brief 如果此属性为 true,则窗口有效区域内的背景将呈现出模糊效果,否则无特效。 默认为 false \note 可读可写 \sa DPlatformHandle::setWindowBlurAreaByWM */ /*! \property DPlatformHandle::autoInputMaskByClipPath \brief 如果此属性值为 true,则窗口可输入区域跟随其 \a clipPath 属性,否则不 跟随。默认为 true \note 可输入区域指可接收鼠标或触摸事件的区域 \note 可读可写 */ /*! \property DPlatformHandle::realWindowId \brief Sub Window 的窗口 id,直接使用 QWindow::winId 或 QWidget::winId 获取到的是 Frame Window 的窗口 id \note 只读 */ /*! \fn void DPlatformHandle::frameMarginsChanged() \brief 信号会在 frameMargins 属性的值改变时被发送. */ /*! \fn void DPlatformHandle::windowRadiusChanged() \brief 信号会在 windowRadius 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::borderWidthChanged() \brief 信号会在 borderWidth 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::borderColorChanged() \brief 信号会在 borderColor 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::shadowRadiusChanged() \brief 信号会在 shadowRadius 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::shadowOffsetChanged() \brief 信号会在 shadowOffset 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::shadowColorChanged() \brief 信号会在 shadowColor 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::clipPathChanged() \brief 信号会在 clipPath 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::frameMaskChanged() \brief 信号会在 frameMask 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::translucentBackgroundChanged() \brief 信号会在 translucentBackground 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::enableSystemResizeChanged() \brief 信号会在 enableSystemResize 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::enableSystemMoveChanged() \brief 信号会在 enableSystemMove 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::enableBlurWindowChanged() \brief 信号会在 enableBlurWindow 属性的值改变时被发送 */ /*! \fn void DPlatformHandle::autoInputMaskByClipPathChanged() \brief 信号会在 autoInputMaskByClipPath 属性的值改变时被发送 */ /*! \class Dtk::Gui::DPlatformHandle::WMBlurArea \inmodule dtkgui \brief 描述窗口背景模糊区域的数据结构,包含位置、大小、圆角半径等信息. \var x 水平方向的坐标 \var y 竖直方向的坐标 \var width 区域的宽度 \var height 区域的高度 \var xRadius 水平方向的圆角半径 \var yRaduis 竖直方向的圆角半径 */ static DPlatformWindowInterfaceFactory::Creator OutsideWindowInterfaceCreator = nullptr; void DPlatformWindowInterfaceFactory::registerInterface(Creator creator) { OutsideWindowInterfaceCreator = creator; } static DPlatformWindowInterface *createWindowInterface(QWindow *window, DPlatformHandle *platformHandle) { DPlatformWindowInterface *impl = nullptr; if (OutsideWindowInterfaceCreator) { impl = OutsideWindowInterfaceCreator(window, platformHandle); } if (!impl) { #ifndef DTK_DISABLE_XCB if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsXWindowPlatform)) { impl = new DXCBPlatformWindowInterface(window, platformHandle); } #endif #ifndef DTK_DISABLE_TREELAND if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { impl = new DTreeLandPlatformWindowInterface(window, platformHandle); } #endif } return impl; } /*! \brief DPlatformHandle::DPlatformHandle 将 \a window 对象传递给 enableDXcbForWindow \a window 要开启DTK风格的主窗口 \a parent DPlatformHandle 对象的父对象 \sa DPlatformHandle::enableDXcbForWindow(QWindow *) */ DPlatformHandle::DPlatformHandle(QWindow *window, QObject *parent) : QObject(parent) , m_window(window) { auto impl = createWindowInterface(window, this); if (!impl) { qDebug() << "Use default DPlatformWindowInterface for the window" << window->winId(); impl = new DPlatformWindowInterface(window, this); } g_platformWindowImpls.insert(this, impl); impl->setEnabled(true); } DPlatformHandle::~DPlatformHandle() { if (auto item = g_platformWindowImpls.take(this)) { delete item; } } /*! \brief DPlatformHandle::pluginVersion \return 返回dxcb插件的版本 \note 在旧版dxcb插件中未实现获取版本的接口,将会返回一个空的 QString 对象 */ QString DPlatformHandle::pluginVersion() { #ifndef DTK_DISABLE_XCB return DXCBPlatformWindowInterface::pluginVersion(); #else return {}; #endif } /*! \brief DPlatformHandle::isDXcbPlatform 检查当前程序是否使用了dxcb平台插件。 \return 正在使用返回 true,否则返回 false。 */ bool DPlatformHandle::isDXcbPlatform() { #ifndef DTK_DISABLE_XCB return DXCBPlatformWindowInterface::isDXcbPlatform(); #else return false; #endif } /*! \brief DPlatformHandle::enableDXcbForWindow 将 QWindow 的窗口装饰设置为 DTK 风格,这将使用 Qt::FramelessWindowHint 去除本地窗口管理器 给窗口附加的边框修饰以及窗口阴影效果,并且,会创建一个对应的本地窗口(在X11平台就是指X Window) 作为此窗口的父窗口,父窗口(Frame Window)中将根据子窗口(Sub Window)的有效区域绘制阴影和边 框等效果,默认情况下,子窗口的有效区域为一个圆角矩形,结构如下: \raw HTML
  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  ┃    Frame Window             ┃
  ┃                             ┃
  ┃                             ┃
  ┃     ╭┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅╮     ┃
  ┃     ┋    Sub Window   ┋     ┃
  ┃     ┋                 ┋     ┃
  ┃     ┋                 ┋     ┃
  ┃     ┋                 ┋     ┃
  ┃     ┋                 ┋     ┃
  ┃     ┋                 ┋     ┃
  ┃     ┋                 ┋     ┃
  ┃     ┋                 ┋     ┃
  ┃     ┋                 ┋     ┃
  ┃     ╰┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅╯     ┃
  ┃                             ┃
  ┃                             ┃
  ┃                             ┃
  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  
\endraw 但是,如果窗口管理器自身支持隐藏窗口标题栏,则此方法将优先调用 enableNoTitlebarForWindow 实现同样的效果。 例子: \code QWidget w1; w1.setWindowTitle("使用系统边框的窗口"); w1.show(); DMainWindow w2; QWidget w3; w2.titlebar()->setTitle("使用DTK风格边框带标题栏的窗口"); w3.setWindowTitle("使用DTK风格边框没有标题栏的窗口"); w2.show(); DPlatformHandle::enableDXcbForWindow(&w3); w3.show(); // 因为这个窗口没有标题栏,所以不会显示窗口标题 \endcode \image dtk_and_system_window.jpeg 开启了dxcb的窗口,在窗口外边缘10像素的范围按下鼠标左键可以触发改变窗口大小的行为, 而且会自动将鼠标吸附到对应的窗口边缘,增强了拖拽改变窗口大小的体验。效果: \image dtk_window_cursor_effect.gif 另外,所有到达主窗口的鼠标移动事件如果没有调用 QEvent::accepted ,则会触发主窗 口的移动效果,默认情况下,一个没有子控件的DTK窗口,如果没有重写 QWidget::mouseMoveEvent , 则使用鼠标左键在窗口的任意地方按住并移动都会触发移动窗口的动作。如: \code class Window : public QWidget { public: explicit Window() { } protected: void mouseMoveEvent(QMouseEvent *event) override { event->accept(); } }; \endcode \code Window w; DPlatformHandle::enableDXcbForWindow(&w); w.show(); \endcode 将无法使用鼠标移动窗口w 窗口管理器(如X11平台上的Window Manager)是否支持混成会影响dxcb插件对窗口添加的默认装饰。 \note 在 Deepin 桌面环境中,打开窗口特效则支持混成,关闭窗口特效则不支持混成 支持混成: \image enable_composite.png 不支持混成: \image disable_composite.png 并且,在不支持混成的窗口管理器中,上述“窗口边缘的鼠标吸附”效果也会被禁用。可以使用 DWindowManagerHelper::hasComposite 或 QX11Info::isCompositingManagerRunning 判断当前运行的窗口管理器是否支持混成。 \a window \sa Dtk::Gui::DPlatformHandle::setEnabledNoTitlebarForWindow() */ void DPlatformHandle::enableDXcbForWindow(QWindow *window) { DPlatformHandle handle(window); auto impl = platformWindowImpl(&handle); impl->setEnabled(true); } /*! \brief DPlatformHandle::enableDXcbForWindow 功能上和 DPlatformHandle::enableDXcbForWindow(QWindow *) 一致. \a window \a redirectContent 如果值为 true,Sub Window 将不可见,且它的绘制内容会 被合成到外层的 Frame Window(它的父窗口),否则 Sub Window 和 Frame Window 会分开绘制和显示。默认情况下只需要使用 DPlatformHandle::enableDXcbForWindow(QWindow *), dxcb插件中会自动根据窗口渲染类型选择使用更合适的实现方式,使用 OpenGL 渲染的窗口将开启 redirectContent 模式。 \note 如果窗口内嵌入了其它的本地窗口(如X11平台的X Window),默认情况下,这个窗口 绘制的内容不受dxcb插件的控制,它的绘制内容可能会超过 Sub Window 的有效区域,这种 情况下,应该使用此接口,并将 redirectContent 指定为 true。 \ref {https://www.x.org/releases/X11R7.5/doc/damageproto/damageproto.txt}{X11 Damage} */ void DPlatformHandle::enableDXcbForWindow(QWindow *window, bool redirectContent) { DPlatformHandle handle(window); #ifndef DTK_DISABLE_XCB if (auto impl = dynamic_cast(platformWindowImpl(&handle))) { impl->enableDXcb(redirectContent); } #endif } /*! \brief DPlatformHandle::isEnabledDXcb. \return 如果窗口 \a window 开启了DTK风格的窗口修饰则返回 true,否则返回 false \sa DPlatformHandle::isEnabledNoTitlebar() */ bool DPlatformHandle::isEnabledDXcb(const QWindow *window) { DPlatformHandle handle(const_cast(window)); auto impl = platformWindowImpl(&handle); return impl->isEnabled(); } /*! \brief DPlatformHandle::setEnabledNoTitlebarForWindow. 使用窗口管理器提供的方式隐藏窗口的标题栏,目前已适配 DDE KWin 窗管,在窗口管理器支持的前提下, 此方法将通过设置窗口属性 _DEEPIN_SCISSOR_WINDOW 的值为 1 来开启无标题栏效果。 \a window 被设置的 QWindow 实例. \a enable 是否开启无标题属性. \return 设置成功返回 true,否则返回false. \sa DPlatformHandle::enableDXcbForWindow() \sa DWindowManagerHelper::hasNoTitlebar() */ bool DPlatformHandle::setEnabledNoTitlebarForWindow(QWindow *window, bool enable) { DPlatformHandle handle(window); auto impl = platformWindowImpl(&handle); return impl->setEnabledNoTitlebar(enable); } /*! \brief DPlatformHandle::isEnableNoTitlebar \a window \return 如果窗口使用窗管提供的方式隐藏了标题栏则返回 true,否则返回 false \sa DPlatformHandle::isEnabledDXcb */ bool DPlatformHandle::isEnabledNoTitlebar(const QWindow *window) { DPlatformHandle handle(const_cast(window)); auto impl = platformWindowImpl(&handle); return impl->isEnabledNoTitlebar(); } /*! \brief DPlatformHandle::setWindowBlurAreaByWM 设置窗口背景的模糊区域,示例: \code QWindow w; QVector area_list; DPlatformHandle::WMBlurArea area; area.x = 50; area.y = 50; area.width = 200; area.height = 200; area.xRadius = 10; area.yRaduis = 10; area_list.append(area); DPlatformHandle::setWindowBlurAreaByWM(&w, area_list); QSurfaceFormat format = w.format(); format.setAlphaBufferSize(8); w.setFormat(format); w.resize(300, 300); w.show(); \endcode \image blur_window_demo1.png \a window 目标窗口对象 \a area 模糊区域,此区域范围内的窗口背景将填充为窗口后面内容模糊之后的图像 \return 如果设置成功则返回 true,否则返回 false \note 对于需要显示模糊背景的窗口,需要将其 QSurfaceFormat 的 alpha 通道设置为8 \note 调用此接口设置窗口背景模糊区域后将覆盖之前所设置的区域,包括调用 setWindowBlurAreaByWM(QWindow *, const QList &) 所设置的区域 \note 建议使用 DBlurEffectWidget 实现窗口背景模糊效果 \note 此功能依赖于窗口管理器的实现,目前仅支持 deepin-wm 和 kwin 这两个窗口管理器 \sa Dtk::Widget::DBlurEffectWidget \sa QSurfaceFormat::setAlphaBufferSize \sa QWindow::setFormat \sa DWindowManagerHelper::hasBlurWindow \sa DPlatformHandle::setWindowBlurAreaByWM(QWindow *, const QList &) */ bool DPlatformHandle::setWindowBlurAreaByWM(QWindow *window, const QVector &area) { DPlatformHandle handle(const_cast(window)); #ifndef DTK_DISABLE_XCB if (auto impl = dynamic_cast(platformWindowImpl(&handle))) { return impl->setWindowBlurArea(area); } #endif handle.setEnableBlurWindow(true); return true; } /*! \brief DPlatformHandle::setWindowBlurAreaByWM 设置窗口背景的模糊区域,使用 QPainterPath 描述模糊区域,使用起来更加的灵活,可以 实现任何形状,但是性能要低于使用 QVector 描述模糊区域。示例: \code QWindow w; QList path_list; QPainterPath path; QFont font; font.setPixelSize(100); font.setBold(true); path.addText(0, 150, font, "deepin"); path_list.append(path); DPlatformHandle::setWindowBlurAreaByWM(&w, path_list); QSurfaceFormat format = w.format(); format.setAlphaBufferSize(8); w.setFormat(format); w.resize(300, 300); w.show(); \endcode \image blur_window_demo2.png \a window 目标窗口对象 \a paths 模糊区域,此区域范围内的窗口背景将填充为窗口后面内容模糊之后的图像 \return 如果设置成功则返回 true,否则返回 false \note 调用此接口设置窗口背景模糊区域后将覆盖之前所设置的区域,包括调用 setWindowBlurAreaByWM(QWindow *, QVector &) 设置的窗口背景模糊路径 \note 对于需要显示模糊背景的窗口,需要将其 QSurfaceFormat 的 alpha 通道设置为8 \note 建议使用 DBlurEffectWidget 实现窗口背景模糊效果 \note 此功能依赖于窗口管理器的实现,目前仅支持 deepin-wm 和 kwin 这两个窗口管理器 \warning setWindowBlurAreaByWM(QWindow *, QVector &) 能满足需求请不要使用此接口 \sa Dtk::Widget::DBlurEffectWidget \sa QSurfaceFormat::setAlphaBufferSize \sa QWindow::setFormat \sa DWindowManagerHelper::hasBlurWindow \sa DPlatformHandle::setWindowBlurAreaByWM() */ bool DPlatformHandle::setWindowBlurAreaByWM(QWindow *window, const QList &paths) { DPlatformHandle handle(const_cast(window)); #ifndef DTK_DISABLE_XCB if (auto impl = dynamic_cast(platformWindowImpl(&handle))) { return impl->setWindowBlurArea(paths); } #endif handle.setEnableBlurWindow(true); return true; } /*! \brief DPlatformHandle::setWindowWallpaperParaByWM 设置窗口背景壁纸,示例: \code QWindow w; QRect area; WallpaperScaleMode sMode WallpaperFillMode fMode area.setRect(50, 50, 200, 200); bMode = WallpaperScaleFlag::FollowWindow | WallpaperFillFlag::PreserveAspectCrop; DPlatformHandle::setWindowWallpaperParaByWM(&w, area, bMode); QSurfaceFormat format = w.format(); format.setAlphaBufferSize(8); w.setFormat(format); w.resize(300, 300); w.show(); \endcode \a window 目标窗口对象 \a area 壁纸区域,此区域范围内的窗口背景将填充为用户设置的当前工作区窗口壁纸 \~Chinese \a sMode 控制壁纸缩放是随屏幕还是随窗口 \~Chinese \a fMode 控制壁纸是缩放还是裁剪 \return 如果设置成功则返回 true,否则返回 false \note 对于需要显示opengl壁纸特效的窗口,需要将其 QSurfaceFormat 的 alpha 通道设置为8 \note 需要在window handle有效之后调用否则3d下失效 \note 调用此接口设置窗口背景壁纸区域后将覆盖之前所设置的区域 \note 此功能依赖于窗口管理器的实现,目前仅支持 kwin 窗口管理器 \sa Dtk::Widget::DBlurEffectWidget \sa QSurfaceFormat::setAlphaBufferSize \sa QWindow::setFormat \sa DWindowManagerHelper::hasBlurWindow \sa DPlatformHandle::setWindowBlurAreaByWM(QWindow *, const QList &) */ bool DPlatformHandle::setWindowWallpaperParaByWM(QWindow *window, const QRect &area, WallpaperScaleMode sMode, WallpaperFillMode fMode) { DPlatformHandle handle(window); #ifndef DTK_DISABLE_XCB if (auto impl = dynamic_cast(platformWindowImpl(&handle))) { return impl->setWindowWallpaperPara(area, sMode, fMode); } #endif return false; } /*! \brief DPlatformHandle::connectWindowManagerChangedSignal 将窗口管理器变化的信号链接到 \a object 对象的 \a slot 槽,建议使用 DWindowManager::windowManagerChanged \a object \a slot \return 如果链接成功则返回 true,否则返回 false \sa DWindowManagerHelper::windowManagerChanged() */ bool DPlatformHandle::connectWindowManagerChangedSignal(QObject *object, std::function slot) { #ifndef DTK_DISABLE_XCB return DXCBPlatformWindowInterface::connectWindowManagerChangedSignal(object, slot); #endif return false; } /*! \brief DPlatformHandle::connectHasBlurWindowChanged 将窗口管理器是否支持背景模糊的信号链接到 object 对象的 slot 槽,建议使用 DWindowManager::hasBlurWindowChanged \a object \a slot \return 如果链接成功则返回 true,否则返回 false \sa DWindowManagerHelper::hasBlurWindowChanged */ bool DPlatformHandle::connectHasBlurWindowChanged(QObject *object, std::function slot) { #ifndef DTK_DISABLE_XCB return DXCBPlatformWindowInterface::connectHasBlurWindowChanged(object, slot); #endif return false; } /*! \brief DPlatformHandle::setWindowBlurAreaByWM 这只是一个重载的函数,将调用 setWindowBlurAreaByWM(const QList &paths) 并将构造对象时传递的主窗口当做第一个参数 \a area \return \sa DPlatformHandle::setWindowBlurAreaByWM(const QList &paths) */ bool DPlatformHandle::setWindowBlurAreaByWM(const QVector &area) { return setWindowBlurAreaByWM(m_window, area); } /*! \brief DPlatformHandle::setWindowBlurAreaByWM 这只是一个重载的函数,将调用 setWindowBlurAreaByWM(const QVector &area) 并将构造对象时传递的主窗口当做第一个参数 \a paths \return \sa DPlatformHandle::setWindowBlurAreaByWM() */ bool DPlatformHandle::setWindowBlurAreaByWM(const QList &paths) { return setWindowBlurAreaByWM(m_window, paths); } /*! \brief DPlatformHandle::setDisableWindowOverrideCursor 如果 \a disable 为 true,则禁止窗口 \a window 改变光标样式,否则允许改变光标样式。 窗口被禁止改变光标样式后,使用 QWindow::setCursor 将不会产生任何效果。 \a window \a disable */ void DPlatformHandle::setDisableWindowOverrideCursor(QWindow *window, bool disable) { DPlatformHandle handler(window); #ifndef DTK_DISABLE_XCB if (auto impl = dynamic_cast(platformWindowImpl(&handler))) { impl->setDisableWindowOverrideCursor(disable); } #endif } int DPlatformHandle::windowRadius() const { auto impl = platformWindowImpl(this); return impl->windowRadius(); } int DPlatformHandle::borderWidth() const { auto impl = platformWindowImpl(this); return impl->borderWidth(); } QColor DPlatformHandle::borderColor() const { auto impl = platformWindowImpl(this); return impl->borderColor(); } int DPlatformHandle::shadowRadius() const { auto impl = platformWindowImpl(this); return impl->shadowRadius(); } QPoint DPlatformHandle::shadowOffset() const { auto impl = platformWindowImpl(this); return impl->shadowOffset(); } QColor DPlatformHandle::shadowColor() const { auto impl = platformWindowImpl(this); return impl->shadowColor(); } DPlatformHandle::EffectScene DPlatformHandle::windowEffect() { auto impl = platformWindowImpl(this); return impl->windowEffect(); } DPlatformHandle::EffectType DPlatformHandle::windowStartUpEffect() { auto impl = platformWindowImpl(this); return impl->windowStartUpEffect(); } QPainterPath DPlatformHandle::clipPath() const { auto impl = platformWindowImpl(this); return impl->clipPath(); } QRegion DPlatformHandle::frameMask() const { auto impl = platformWindowImpl(this); return impl->frameMask(); } QMargins DPlatformHandle::frameMargins() const { auto impl = platformWindowImpl(this); return impl->frameMargins(); } bool DPlatformHandle::translucentBackground() const { auto impl = platformWindowImpl(this); return impl->translucentBackground(); } bool DPlatformHandle::enableSystemResize() const { auto impl = platformWindowImpl(this); return impl->enableSystemResize(); } bool DPlatformHandle::enableSystemMove() const { auto impl = platformWindowImpl(this); return impl->enableSystemMove(); } bool DPlatformHandle::enableBlurWindow() const { auto impl = platformWindowImpl(this); return impl->enableBlurWindow(); } bool DPlatformHandle::autoInputMaskByClipPath() const { #ifndef DTK_DISABLE_XCB if (auto impl = dynamic_cast(platformWindowImpl(this))) { return impl->autoInputMaskByClipPath(); } #endif return false; } WId DPlatformHandle::realWindowId() const { #ifndef DTK_DISABLE_XCB if (auto impl = dynamic_cast(platformWindowImpl(this))) { return impl->realWindowId(); } #endif return 0; } WId DPlatformHandle::windowLeader() { #ifndef DTK_DISABLE_XCB return DXCBPlatformWindowInterface::windowLeader(); #endif return 0; } void DPlatformHandle::setWindowRadius(int windowRadius) { auto impl = platformWindowImpl(this); impl->setWindowRadius(windowRadius); } void DPlatformHandle::setBorderWidth(int borderWidth) { auto impl = platformWindowImpl(this); impl->setBorderWidth(borderWidth); } void DPlatformHandle::setBorderColor(const QColor &borderColor) { auto impl = platformWindowImpl(this); impl->setBorderColor(borderColor); } void DPlatformHandle::setWindowEffect(DPlatformHandle::EffectScenes effectScene) { auto impl = platformWindowImpl(this); impl->setWindowEffect(effectScene); } void DPlatformHandle::setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) { auto impl = platformWindowImpl(this); impl->setWindowStartUpEffect(effectType); } void DPlatformHandle::setShadowRadius(int shadowRadius) { auto impl = platformWindowImpl(this); impl->setShadowRadius(shadowRadius); } void DPlatformHandle::setShadowOffset(const QPoint &shadowOffset) { auto impl = platformWindowImpl(this); impl->setShadowOffset(shadowOffset); } void DPlatformHandle::setShadowColor(const QColor &shadowColor) { auto impl = platformWindowImpl(this); impl->setShadowColor(shadowColor); } void DPlatformHandle::setClipPath(const QPainterPath &clipPath) { auto impl = platformWindowImpl(this); impl->setClipPath(clipPath); } void DPlatformHandle::setFrameMask(const QRegion &frameMask) { auto impl = platformWindowImpl(this); impl->setFrameMask(frameMask); } void DPlatformHandle::setTranslucentBackground(bool translucentBackground) { auto impl = platformWindowImpl(this); impl->setTranslucentBackground(translucentBackground); } void DPlatformHandle::setEnableSystemResize(bool enableSystemResize) { auto impl = platformWindowImpl(this); impl->setEnableSystemResize(enableSystemResize); } void DPlatformHandle::setEnableSystemMove(bool enableSystemMove) { auto impl = platformWindowImpl(this); impl->setEnableSystemMove(enableSystemMove); } void DPlatformHandle::setEnableBlurWindow(bool enableBlurWindow) { auto impl = platformWindowImpl(this); impl->setEnableBlurWindow(enableBlurWindow); } void DPlatformHandle::setAutoInputMaskByClipPath(bool autoInputMaskByClipPath) { #ifndef DTK_DISABLE_XCB if (auto impl = dynamic_cast(platformWindowImpl(this))) { impl->setAutoInputMaskByClipPath(autoInputMaskByClipPath); } #endif } bool DPlatformHandle::eventFilter(QObject *obj, QEvent *event) { return QObject::eventFilter(obj, event); } DGUI_END_NAMESPACE QT_BEGIN_NAMESPACE QDebug operator<<(QDebug deg, const DPlatformHandle::WMBlurArea &area) { QDebugStateSaver saver(deg); Q_UNUSED(saver) deg.setAutoInsertSpaces(true); deg << "x:" << area.x << "y:" << area.y << "width:" << area.width << "height:" << area.height << "xRadius:" << area.xRadius << "yRadius:" << area.yRaduis; return deg; } QT_END_NAMESPACE dtkgui-5.7.12/src/kernel/dplatformtheme.cpp000066400000000000000000000630451476226661100207060ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dplatformtheme.h" #include "dguiapplicationhelper.h" #include "private/dplatformtheme_p.h" #ifndef DTK_DISABLE_XCB #include "plugins/platform/xcb/dxcbplatforminterface.h" #endif #ifndef DTK_DISABLE_TREELAND #include "plugins/platform/treeland/dtreelandplatforminterface.h" #endif #include "private/dplatforminterface_p.h" #include #include #include #include #include #include DGUI_BEGIN_NAMESPACE #define DTK_PREFERENCE_NAME "org.deepin.dtk.preference" #define DTK_SIZE_MODE_KEY "sizeMode" #define DTK_SCROLLBAR_POLICY_KEY "scrollBarPolicy" static DPlatformInterfaceFactory::HelperCreator OutsideInterfaceCreator = nullptr; void DPlatformInterfaceFactory::registerInterface(HelperCreator creator) { OutsideInterfaceCreator = creator; } // "/deepin/palette" 为调色板属性的存储位置 // 在x11平台下,将使用_DEEPIN_PALETTE作为存储调色板数据的窗口属性 DPlatformThemePrivate::DPlatformThemePrivate(Dtk::Gui::DPlatformTheme *qq) : DNativeSettingsPrivate(qq, QByteArrayLiteral("/deepin/palette")) { } void DPlatformThemePrivate::onQtColorChanged(QPalette::ColorRole role, const QColor &color) { if (!palette) { palette = new DPalette(); } palette->setColor(QPalette::Normal, role, color); notifyPaletteChanged(); } void DPlatformThemePrivate::onDtkColorChanged(DPalette::ColorType type, const QColor &color) { if (!palette) { palette = new DPalette(); } palette->setColor(QPalette::Normal, type, color); notifyPaletteChanged(); } void DPlatformThemePrivate::notifyPaletteChanged() { if (notifyPaletteChangeTimer && notifyPaletteChangeTimer->isActive()) return; D_Q(DPlatformTheme); if (!notifyPaletteChangeTimer) { notifyPaletteChangeTimer = new QTimer(q); q->connect(notifyPaletteChangeTimer, &QTimer::timeout, q, [q, this] { Q_EMIT q->paletteChanged(*palette); }); } notifyPaletteChangeTimer->start(300); } void DPlatformThemePrivate::onDtkPreferenceDConfigChanged(const QString &key) { D_Q(DPlatformTheme); if (key == DTK_SIZE_MODE_KEY) { sizeMode = static_cast(dtkPreferenceConfig->value(key).toInt()); Q_EMIT q->sizeModeChanged(sizeMode); } else if (key == DTK_SCROLLBAR_POLICY_KEY) { scrollBarPolicy = static_cast(dtkPreferenceConfig->value(key).toInt()); Q_EMIT q->scrollBarPolicyChanged(scrollBarPolicy); } } /*! \class Dtk::Gui::DPlatformTheme \inmodule dtkgui \brief 一个提供窗口主题的类. */ DPlatformTheme::DPlatformTheme(quint32 window, QObject *parent) : DNativeSettings(*new DPlatformThemePrivate(this), &DPlatformTheme::staticMetaObject, window, parent) { D_D(DPlatformTheme); if (OutsideInterfaceCreator) { d->platformInterface = OutsideInterfaceCreator(this); } else { #ifndef DTK_DISABLE_XCB if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsXWindowPlatform)) { d->platformInterface = new DXCBPlatformInterface(0, this); } #endif #ifndef DTK_DISABLE_TREELAND if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { d->platformInterface = new DTreelandPlatformInterface(this); } #endif } if (!d->platformInterface) { d->platformInterface = new DPlatformInterface(this); } d->theme = new DNativeSettings(window, QByteArray(), this); d->dtkPreferenceConfig = DConfig::createGeneric(DTK_PREFERENCE_NAME, "", this); d->sizeMode = static_cast(d->dtkPreferenceConfig->value(DTK_SIZE_MODE_KEY).toInt()); d->scrollBarPolicy = static_cast(d->dtkPreferenceConfig->value(DTK_SCROLLBAR_POLICY_KEY).toInt()); connect(d->dtkPreferenceConfig, &DConfig::valueChanged, this, [this](const QString &key) -> void{ D_D(DPlatformTheme); d->onDtkPreferenceDConfigChanged(key); }); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) connect(this, &DPlatformTheme::windowChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Window, std::placeholders::_1)); connect(this, &DPlatformTheme::windowTextChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::WindowText, std::placeholders::_1)); connect(this, &DPlatformTheme::baseChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Base, std::placeholders::_1)); connect(this, &DPlatformTheme::alternateBaseChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::AlternateBase, std::placeholders::_1)); connect(this, &DPlatformTheme::toolTipBaseChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::ToolTipBase, std::placeholders::_1)); connect(this, &DPlatformTheme::toolTipTextChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::ToolTipText, std::placeholders::_1)); connect(this, &DPlatformTheme::textChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Text, std::placeholders::_1)); connect(this, &DPlatformTheme::buttonChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Button, std::placeholders::_1)); connect(this, &DPlatformTheme::buttonTextChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::ButtonText, std::placeholders::_1)); connect(this, &DPlatformTheme::brightTextChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::BrightText, std::placeholders::_1)); connect(this, &DPlatformTheme::lightChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Light, std::placeholders::_1)); connect(this, &DPlatformTheme::midlightChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Midlight, std::placeholders::_1)); connect(this, &DPlatformTheme::darkChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Dark, std::placeholders::_1)); connect(this, &DPlatformTheme::midChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Mid, std::placeholders::_1)); connect(this, &DPlatformTheme::shadowChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Shadow, std::placeholders::_1)); connect(this, &DPlatformTheme::highlightChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Highlight, std::placeholders::_1)); connect(this, &DPlatformTheme::highlightedTextChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::HighlightedText, std::placeholders::_1)); connect(this, &DPlatformTheme::linkChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::Link, std::placeholders::_1)); connect(this, &DPlatformTheme::linkVisitedChanged, std::bind(&DPlatformThemePrivate::onQtColorChanged, d, QPalette::LinkVisited, std::placeholders::_1)); connect(this, &DPlatformTheme::itemBackgroundChanged, std::bind(&DPlatformThemePrivate::onDtkColorChanged, d, DPalette::ItemBackground, std::placeholders::_1)); connect(this, &DPlatformTheme::textTitleChanged, std::bind(&DPlatformThemePrivate::onDtkColorChanged, d, DPalette::TextTitle, std::placeholders::_1)); connect(this, &DPlatformTheme::textTipsChanged, std::bind(&DPlatformThemePrivate::onDtkColorChanged, d, DPalette::TextTips, std::placeholders::_1)); connect(this, &DPlatformTheme::textWarningChanged, std::bind(&DPlatformThemePrivate::onDtkColorChanged, d, DPalette::TextWarning, std::placeholders::_1)); connect(this, &DPlatformTheme::textLivelyChanged, std::bind(&DPlatformThemePrivate::onDtkColorChanged, d, DPalette::TextLively, std::placeholders::_1)); connect(this, &DPlatformTheme::lightLivelyChanged, std::bind(&DPlatformThemePrivate::onDtkColorChanged, d, DPalette::LightLively, std::placeholders::_1)); connect(this, &DPlatformTheme::darkLivelyChanged, std::bind(&DPlatformThemePrivate::onDtkColorChanged, d, DPalette::DarkLively, std::placeholders::_1)); connect(this, &DPlatformTheme::frameBorderChanged, std::bind(&DPlatformThemePrivate::onDtkColorChanged, d, DPalette::FrameBorder, std::placeholders::_1)); #endif } DPlatformTheme::DPlatformTheme(quint32 window, DPlatformTheme *parent) : DPlatformTheme(window, static_cast(parent)) { d_func()->parent = parent; // 将主题相关的属性改变信号从父主题中继承 // 假设 A 被 B 继承,B 被 C 继承,当 A 中出发属性变化时,不仅要能通知到B,还要能通知到C connect(parent->d_func()->theme, SIGNAL(propertyChanged(const QByteArray &, const QVariant &)), d_func()->theme, SIGNAL(propertyChanged(const QByteArray &, const QVariant &))); } DPlatformTheme::~DPlatformTheme() { D_D(DPlatformTheme); if (d->palette) { delete d->palette; } if (d->platformInterface) { delete d->platformInterface; } } bool DPlatformTheme::isValid() const { return !themeName().isEmpty() || isValidPalette() || activeColor().isValid(); } DPlatformTheme *DPlatformTheme::parentTheme() const { D_DC(DPlatformTheme); return d->parent; } void DPlatformTheme::setFallbackProperty(bool fallback) { D_D(DPlatformTheme); d->fallbackProperty = fallback; } DPalette DPlatformTheme::palette() const { D_DC(DPlatformTheme); if (!d->palette) { if (!isValid()) return DPalette(); DPalette *pa = new DPalette(); const_cast(d)->palette = pa; #define SET_PALETTE_COLOR(Role) \ pa->setColor(DPalette::Role, qvariant_cast(getSetting(QByteArrayLiteral(#Role)))) SET_PALETTE_COLOR(Window); SET_PALETTE_COLOR(WindowText); SET_PALETTE_COLOR(Base); SET_PALETTE_COLOR(AlternateBase); SET_PALETTE_COLOR(ToolTipBase); SET_PALETTE_COLOR(ToolTipText); SET_PALETTE_COLOR(Text); SET_PALETTE_COLOR(Button); SET_PALETTE_COLOR(ButtonText); SET_PALETTE_COLOR(BrightText); SET_PALETTE_COLOR(Light); SET_PALETTE_COLOR(Midlight); SET_PALETTE_COLOR(Dark); SET_PALETTE_COLOR(Mid); SET_PALETTE_COLOR(Shadow); SET_PALETTE_COLOR(Highlight); SET_PALETTE_COLOR(HighlightedText); SET_PALETTE_COLOR(Link); SET_PALETTE_COLOR(LinkVisited); SET_PALETTE_COLOR(ItemBackground); SET_PALETTE_COLOR(TextTitle); SET_PALETTE_COLOR(TextTips); SET_PALETTE_COLOR(TextWarning); SET_PALETTE_COLOR(TextLively); SET_PALETTE_COLOR(LightLively); SET_PALETTE_COLOR(DarkLively); SET_PALETTE_COLOR(FrameBorder); } return *d->palette; } DPalette DPlatformTheme::fetchPalette(const DPalette &base, bool *ok) const { D_DC(DPlatformTheme); DPalette palette = base; if (isValidPalette() && d->palette) { if (ok) { *ok = true; } const DPalette *pa = d->palette; for (int i = 0; i < QPalette::NColorRoles; ++i) { const QColor &color = pa->color(QPalette::Normal, static_cast(i)); if (color.isValid()) { palette.setColor(QPalette::Normal, static_cast(i), color); } } for (int i = 0; i < DPalette::NColorTypes; ++i) { const QColor &color = pa->color(QPalette::Normal, static_cast(i)); if (color.isValid()) { palette.setColor(QPalette::Normal, static_cast(i), color); } } return d->parent ? d->parent->fetchPalette(palette, nullptr) : palette; } return d->parent ? d->parent->fetchPalette(palette, ok) : palette; } void DPlatformTheme::setPalette(const DPalette &palette) { #define SET_PALETTE(Role) \ set##Role(palette.color(QPalette::Normal, DPalette::Role)) #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) SET_PALETTE(Window); SET_PALETTE(WindowText); SET_PALETTE(Base); SET_PALETTE(AlternateBase); SET_PALETTE(ToolTipBase); SET_PALETTE(ToolTipText); SET_PALETTE(Text); SET_PALETTE(Button); SET_PALETTE(ButtonText); SET_PALETTE(BrightText); SET_PALETTE(Light); SET_PALETTE(Midlight); SET_PALETTE(Dark); SET_PALETTE(Mid); SET_PALETTE(Shadow); SET_PALETTE(Highlight); SET_PALETTE(HighlightedText); SET_PALETTE(Link); SET_PALETTE(LinkVisited); SET_PALETTE(ItemBackground); SET_PALETTE(TextTitle); SET_PALETTE(TextTips); SET_PALETTE(TextWarning); SET_PALETTE(TextLively); SET_PALETTE(LightLively); SET_PALETTE(DarkLively); SET_PALETTE(FrameBorder); #endif } int DPlatformTheme::cursorBlinkTime() const { D_DC(DPlatformTheme); return d->platformInterface->cursorBlinkTime(); } int DPlatformTheme::cursorBlinkTimeout() const { D_DC(DPlatformTheme); return d->platformInterface->cursorBlinkTimeout(); } bool DPlatformTheme::cursorBlink() const { D_DC(DPlatformTheme); return d->platformInterface->cursorBlink(); } int DPlatformTheme::doubleClickDistance() const { D_DC(DPlatformTheme); return d->platformInterface->doubleClickDistance(); } int DPlatformTheme::doubleClickTime() const { D_DC(DPlatformTheme); return d->platformInterface->doubleClickTime(); } int DPlatformTheme::dndDragThreshold() const { D_DC(DPlatformTheme); return d->platformInterface->dndDragThreshold(); } int DPlatformTheme::windowRadius() const { D_DC(DPlatformTheme); return d->platformInterface->windowRadius(); } int DPlatformTheme::windowRadius(int defaultValue) const { D_DC(DPlatformTheme); return d->platformInterface->windowRadius(defaultValue); } QByteArray DPlatformTheme::themeName() const { D_DC(DPlatformTheme); return d->platformInterface->themeName(); } QByteArray DPlatformTheme::iconThemeName() const { D_DC(DPlatformTheme); return d->platformInterface->iconThemeName(); } QByteArray DPlatformTheme::soundThemeName() const { D_DC(DPlatformTheme); return d->platformInterface->soundThemeName(); } QByteArray DPlatformTheme::fontName() const { D_DC(DPlatformTheme); return d->platformInterface->fontName(); } QByteArray DPlatformTheme::monoFontName() const { D_DC(DPlatformTheme); return d->platformInterface->monoFontName(); } qreal DPlatformTheme::fontPointSize() const { D_DC(DPlatformTheme); return d->platformInterface->fontPointSize(); } QByteArray DPlatformTheme::gtkFontName() const { D_DC(DPlatformTheme); return d->platformInterface->gtkFontName(); } QColor DPlatformTheme::activeColor() const { D_DC(DPlatformTheme); return d->platformInterface->activeColor(); } QColor DPlatformTheme::darkActiveColor() const { D_DC(DPlatformTheme); return d->platformInterface->darkActiveColor(); } bool DPlatformTheme::isValidPalette() const { return !allKeys().isEmpty(); } #define GET_COLOR(Role) qvariant_cast(getSetting(QByteArrayLiteral(#Role))) #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QColor DPlatformTheme::window() const { D_DC(DPlatformTheme); return d->platformInterface->window(); } QColor DPlatformTheme::windowText() const { D_DC(DPlatformTheme); return d->platformInterface->windowText(); } QColor DPlatformTheme::base() const { D_DC(DPlatformTheme); return d->platformInterface->base(); } QColor DPlatformTheme::alternateBase() const { D_DC(DPlatformTheme); return d->platformInterface->alternateBase(); } QColor DPlatformTheme::toolTipBase() const { D_DC(DPlatformTheme); return d->platformInterface->toolTipBase(); } QColor DPlatformTheme::toolTipText() const { D_DC(DPlatformTheme); return d->platformInterface->toolTipText(); } QColor DPlatformTheme::text() const { D_DC(DPlatformTheme); return d->platformInterface->text(); } QColor DPlatformTheme::button() const { D_DC(DPlatformTheme); return d->platformInterface->button(); } QColor DPlatformTheme::buttonText() const { D_DC(DPlatformTheme); return d->platformInterface->buttonText(); } QColor DPlatformTheme::brightText() const { D_DC(DPlatformTheme); return d->platformInterface->brightText(); } QColor DPlatformTheme::light() const { D_DC(DPlatformTheme); return d->platformInterface->light(); } QColor DPlatformTheme::midlight() const { D_DC(DPlatformTheme); return d->platformInterface->midlight(); } QColor DPlatformTheme::dark() const { D_DC(DPlatformTheme); return d->platformInterface->dark(); } QColor DPlatformTheme::mid() const { D_DC(DPlatformTheme); return d->platformInterface->mid(); } QColor DPlatformTheme::shadow() const { D_DC(DPlatformTheme); return d->platformInterface->shadow(); } QColor DPlatformTheme::highlight() const { D_DC(DPlatformTheme); return d->platformInterface->highlight(); } QColor DPlatformTheme::highlightedText() const { D_DC(DPlatformTheme); return d->platformInterface->highlightedText(); } QColor DPlatformTheme::link() const { D_DC(DPlatformTheme); return d->platformInterface->link(); } QColor DPlatformTheme::linkVisited() const { D_DC(DPlatformTheme); return d->platformInterface->linkVisited(); } QColor DPlatformTheme::itemBackground() const { D_DC(DPlatformTheme); return d->platformInterface->itemBackground(); } QColor DPlatformTheme::textTitle() const { D_DC(DPlatformTheme); return d->platformInterface->textTitle(); } QColor DPlatformTheme::textTips() const { D_DC(DPlatformTheme); return d->platformInterface->textTips(); } QColor DPlatformTheme::textWarning() const { D_DC(DPlatformTheme); return d->platformInterface->textWarning(); } QColor DPlatformTheme::textLively() const { D_DC(DPlatformTheme); return d->platformInterface->textLively(); } QColor DPlatformTheme::lightLively() const { D_DC(DPlatformTheme); return d->platformInterface->lightLively(); } QColor DPlatformTheme::darkLively() const { D_DC(DPlatformTheme); return d->platformInterface->darkLively(); } QColor DPlatformTheme::frameBorder() const { D_DC(DPlatformTheme); return d->platformInterface->frameBorder(); } #endif int DPlatformTheme::dotsPerInch(const QString &screenName) const { D_DC(DPlatformTheme); return d->platformInterface->dotsPerInch(screenName); } /*! \property DPlatformTheme::sizeMode \brief This property holds the sizeMode of the system's SizeMode. */ int DPlatformTheme::sizeMode() const { D_DC(DPlatformTheme); return d->sizeMode; } /*! \property DPlatformTheme::scrollBarPolicy \brief This property holds the scrollBarPolicy of the system. same as Qt::ScrollBarPolicy \retval 0 show as needed auto hide, default \retval 1 always off \retval 2 always on */ int DPlatformTheme::scrollBarPolicy() const { D_DC(DPlatformTheme); return d->scrollBarPolicy; } void DPlatformTheme::setCursorBlinkTime(int cursorBlinkTime) { D_DC(DPlatformTheme); return d->platformInterface->setCursorBlinkTime(cursorBlinkTime); } void DPlatformTheme::setCursorBlinkTimeout(int cursorBlinkTimeout) { D_DC(DPlatformTheme); return d->platformInterface->setCursorBlinkTimeout(cursorBlinkTimeout); } void DPlatformTheme::setCursorBlink(bool cursorBlink) { D_DC(DPlatformTheme); return d->platformInterface->setCursorBlink(cursorBlink); } void DPlatformTheme::setDoubleClickDistance(int doubleClickDistance) { D_DC(DPlatformTheme); return d->platformInterface->setDoubleClickDistance(doubleClickDistance); } void DPlatformTheme::setDoubleClickTime(int doubleClickTime) { D_DC(DPlatformTheme); return d->platformInterface->setDoubleClickTime(doubleClickTime); } void DPlatformTheme::setDndDragThreshold(int dndDragThreshold) { D_DC(DPlatformTheme); return d->platformInterface->setDndDragThreshold(dndDragThreshold); } void DPlatformTheme::setThemeName(const QByteArray &themeName) { D_DC(DPlatformTheme); return d->platformInterface->setThemeName(themeName); } void DPlatformTheme::setIconThemeName(const QByteArray &iconThemeName) { D_DC(DPlatformTheme); return d->platformInterface->setIconThemeName(iconThemeName); } void DPlatformTheme::setSoundThemeName(const QByteArray &soundThemeName) { D_DC(DPlatformTheme); return d->platformInterface->setSoundThemeName(soundThemeName); } void DPlatformTheme::setFontName(const QByteArray &fontName) { D_DC(DPlatformTheme); return d->platformInterface->setFontName(fontName); } void DPlatformTheme::setMonoFontName(const QByteArray &monoFontName) { D_DC(DPlatformTheme); return d->platformInterface->setMonoFontName(monoFontName); } void DPlatformTheme::setFontPointSize(qreal fontPointSize) { D_DC(DPlatformTheme); return d->platformInterface->setFontPointSize(fontPointSize); } void DPlatformTheme::setGtkFontName(const QByteArray &fontName) { D_DC(DPlatformTheme); return d->platformInterface->setGtkFontName(fontName); } void DPlatformTheme::setActiveColor(const QColor activeColor) { D_DC(DPlatformTheme); return d->platformInterface->setActiveColor(activeColor); } void DPlatformTheme::setDarkActiveColor(const QColor &activeColor) { D_DC(DPlatformTheme); return d->platformInterface->setDarkActiveColor(activeColor); } #define SET_COLOR(Role) setSetting(QByteArrayLiteral(#Role), Role) #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) void DPlatformTheme::setWindow(const QColor &window) { D_DC(DPlatformTheme); return d->platformInterface->setWindow(window); } void DPlatformTheme::setWindowText(const QColor &windowText) { D_DC(DPlatformTheme); return d->platformInterface->setWindowText(windowText); } void DPlatformTheme::setBase(const QColor &base) { D_DC(DPlatformTheme); return d->platformInterface->setBase(base); } void DPlatformTheme::setAlternateBase(const QColor &alternateBase) { D_DC(DPlatformTheme); return d->platformInterface->setAlternateBase(alternateBase); } void DPlatformTheme::setToolTipBase(const QColor &toolTipBase) { D_DC(DPlatformTheme); return d->platformInterface->setToolTipBase(toolTipBase); } void DPlatformTheme::setToolTipText(const QColor &toolTipText) { D_DC(DPlatformTheme); return d->platformInterface->setToolTipText(toolTipText); } void DPlatformTheme::setText(const QColor &text) { D_DC(DPlatformTheme); return d->platformInterface->setText(text); } void DPlatformTheme::setButton(const QColor &button) { D_DC(DPlatformTheme); return d->platformInterface->setButton(button); } void DPlatformTheme::setButtonText(const QColor &buttonText) { D_DC(DPlatformTheme); return d->platformInterface->setButtonText(buttonText); } void DPlatformTheme::setBrightText(const QColor &brightText) { D_DC(DPlatformTheme); return d->platformInterface->setBrightText(brightText); } void DPlatformTheme::setLight(const QColor &light) { D_DC(DPlatformTheme); return d->platformInterface->setLight(light); } void DPlatformTheme::setMidlight(const QColor &midlight) { D_DC(DPlatformTheme); return d->platformInterface->setMidlight(midlight); } void DPlatformTheme::setDark(const QColor &dark) { D_DC(DPlatformTheme); return d->platformInterface->setDark(dark); } void DPlatformTheme::setMid(const QColor &mid) { D_DC(DPlatformTheme); return d->platformInterface->setMid(mid); } void DPlatformTheme::setShadow(const QColor &shadow) { D_DC(DPlatformTheme); return d->platformInterface->setShadow(shadow); } void DPlatformTheme::setHighlight(const QColor &highlight) { D_DC(DPlatformTheme); return d->platformInterface->setHighlight(highlight); } void DPlatformTheme::setHighlightedText(const QColor &highlightText) { D_DC(DPlatformTheme); return d->platformInterface->setHighlightedText(highlightText); } void DPlatformTheme::setLink(const QColor &link) { D_DC(DPlatformTheme); return d->platformInterface->setLink(link); } void DPlatformTheme::setLinkVisited(const QColor &linkVisited) { D_DC(DPlatformTheme); return d->platformInterface->setLinkVisited(linkVisited); } void DPlatformTheme::setItemBackground(const QColor &itemBackground) { D_DC(DPlatformTheme); return d->platformInterface->setItemBackground(itemBackground); } void DPlatformTheme::setTextTitle(const QColor &textTitle) { D_DC(DPlatformTheme); return d->platformInterface->setTextTitle(textTitle); } void DPlatformTheme::setTextTips(const QColor &textTips) { D_DC(DPlatformTheme); return d->platformInterface->setTextTips(textTips); } void DPlatformTheme::setTextWarning(const QColor &textWarning) { D_DC(DPlatformTheme); return d->platformInterface->setTextWarning(textWarning); } void DPlatformTheme::setTextLively(const QColor &textLively) { D_DC(DPlatformTheme); return d->platformInterface->setTextLively(textLively); } void DPlatformTheme::setLightLively(const QColor &lightLively) { D_DC(DPlatformTheme); return d->platformInterface->setLightLively(lightLively); } void DPlatformTheme::setDarkLively(const QColor &darkLively) { D_DC(DPlatformTheme); return d->platformInterface->setDarkLively(darkLively); } void DPlatformTheme::setFrameBorder(const QColor &frameBorder) { D_DC(DPlatformTheme); return d->platformInterface->setFrameBorder(frameBorder); } #endif void DPlatformTheme::setDotsPerInch(const QString &screenName, int dpi) { D_DC(DPlatformTheme); return d->platformInterface->setDotsPerInch(screenName, dpi); } void DPlatformTheme::setWindowRadius(int windowRadius) { D_DC(DPlatformTheme); return d->platformInterface->setWindowRadius(windowRadius); } DGUI_END_NAMESPACE #include "moc_dplatformtheme.cpp" dtkgui-5.7.12/src/kernel/dregionmonitor.cpp000066400000000000000000000166061476226661100207330ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dregionmonitor.h" #include "private/dregionmonitor_p.h" #include #include #include #include DGUI_BEGIN_NAMESPACE /*! \class Dtk::Gui::DRegionMonitor \inmodule dtkgui \brief 一个在指定区域内监视鼠标键盘动作的类. */ /*! \enum DRegionMonitor::RegisterdFlag DRegionMonitor::RegisterdFlag 定义了 DRegionMonitor 监听标志。 \var Motion 代表监听鼠标移动。 \var Button 代表监听鼠标按键。 \var Key 代表监听键盘按键。 */ DRegionMonitor::DRegionMonitor(QObject *parent) : QObject(parent), DObject(*new DRegionMonitorPrivate(this)) { D_D(DRegionMonitor); d->init(); } bool DRegionMonitor::registered() const { D_DC(DRegionMonitor); return !d->registerKey.isEmpty(); } QRegion DRegionMonitor::watchedRegion() const { D_DC(DRegionMonitor); return d->watchedRegion; } DRegionMonitor::RegisterdFlags DRegionMonitor::registerFlags() const { D_DC(DRegionMonitor); return d->registerdFlags; } DRegionMonitor::CoordinateType DRegionMonitor::coordinateType() const { D_DC(DRegionMonitor); return d->type; } void DRegionMonitor::registerRegion() { if (registered()) { qWarning() << "region already registered!"; return; } D_D(DRegionMonitor); d->registerMonitorRegion(); } void DRegionMonitor::unregisterRegion() { D_D(DRegionMonitor); d->unregisterMonitorRegion(); } void DRegionMonitor::setWatchedRegion(const QRegion ®ion) { D_D(DRegionMonitor); d->watchedRegion = region; if (registered()) d->registerMonitorRegion(); } /*! \property DRegionMonitor::registerdFlags \brief 监听模式属性. \brief 监听模式,需要注意 DRegionMonitor::Motion 监听鼠标移动会影响性能,默认包含,如果 需要可通过此函数去掉 DRegionMonitor::Motion . registerdFlagChanged 信号会在监听标志 registerdFlags 被改变的时候被触发. \a flags 监听模式. */ void DRegionMonitor::setRegisterFlags(RegisterdFlags flags) { D_D(DRegionMonitor); if (d->registerdFlags == flags) return; d->registerdFlags = flags; if (registered()) d->registerMonitorRegion(); Q_EMIT registerdFlagsChanged(flags); } void DRegionMonitor::setCoordinateType(DRegionMonitor::CoordinateType type) { D_D(DRegionMonitor); d->type = type; } DRegionMonitorPrivate::DRegionMonitorPrivate(DRegionMonitor *q) : DObjectPrivate(q) { if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.deepin.dde.XEventMonitor1"))) { eventInter = new XEventMonitor("org.deepin.dde.XEventMonitor1", "/org/deepin/dde/XEventMonitor1", "org.deepin.dde.XEventMonitor1", q); } else { eventInter = new XEventMonitor("com.deepin.api.XEventMonitor", "/com/deepin/api/XEventMonitor", "com.deepin.api.XEventMonitor", q); } } DRegionMonitorPrivate::~DRegionMonitorPrivate() { if (registered()) unregisterMonitorRegion(); eventInter->deleteLater(); } void DRegionMonitorPrivate::init() { D_Q(DRegionMonitor); QObject::connect(eventInter, SIGNAL(ButtonPress(int,int,int,QString)), q, SLOT(_q_ButtonPress(const int, const int, const int, const QString&))); QObject::connect(eventInter, SIGNAL(ButtonRelease(int,int,int,QString)), q, SLOT(_q_ButtonRelease(const int, const int, const int, const QString&))); QObject::connect(eventInter, SIGNAL(CursorMove(int,int,QString)), q, SLOT(_q_CursorMove(const int, const int, const QString&))); QObject::connect(eventInter, SIGNAL(CursorInto(int,int,QString)), q, SLOT(_q_CursorEnter(const int, const int, const QString&))); QObject::connect(eventInter, SIGNAL(CursorOut(int,int,QString)), q, SLOT(_q_CursorLeave(const int, const int, const QString&))); QObject::connect(eventInter, SIGNAL(KeyPress(QString,int,int,QString)), q, SLOT(_q_KeyPress(const QString&, const int, const int, const QString&))); QObject::connect(eventInter, SIGNAL(KeyRelease(QString,int,int,QString)), q, SLOT(_q_KeyRelease(const QString&, const int, const int, const QString&))); } void DRegionMonitorPrivate::registerMonitorRegion() { if (registered()) unregisterMonitorRegion(); if (watchedRegion.isEmpty()) { // 将监听区域设置为最大 registerKey = eventInter->RegisterArea(INT_MIN, INT_MIN, INT_MAX, INT_MAX, registerdFlags); } else { const QRect rect = watchedRegion.boundingRect(); const int x1 = rect.x(); const int y1 = rect.y(); const int x2 = x1 + rect.width(); const int y2 = y1 + rect.height(); registerKey = eventInter->RegisterArea(x1, y1, x2, y2, registerdFlags); } } void DRegionMonitorPrivate::unregisterMonitorRegion() { if (registerKey.isEmpty()) return; eventInter->UnregisterArea(registerKey); registerKey.clear(); } void DRegionMonitorPrivate::_q_ButtonPress(const int flag, const int x, const int y, const QString &key) { if (registerKey != key) return; D_Q(DRegionMonitor); Q_EMIT q->buttonPress(deviceScaledCoordinate(QPoint(x, y), qApp->devicePixelRatio()), flag); } void DRegionMonitorPrivate::_q_ButtonRelease(const int flag, const int x, const int y, const QString &key) { if (registerKey != key) return; D_Q(DRegionMonitor); Q_EMIT q->buttonRelease(deviceScaledCoordinate(QPoint(x, y), qApp->devicePixelRatio()), flag); } void DRegionMonitorPrivate::_q_CursorMove(const int x, const int y, const QString &key) { if (registerKey != key) return; D_Q(DRegionMonitor); Q_EMIT q->cursorMove(deviceScaledCoordinate(QPoint(x, y), qApp->devicePixelRatio())); } void DRegionMonitorPrivate::_q_CursorEnter(const int x, const int y, const QString &key) { if (registerKey != key) return; D_Q(DRegionMonitor); Q_EMIT q->cursorEnter(deviceScaledCoordinate(QPoint(x, y), qApp->devicePixelRatio())); } void DRegionMonitorPrivate::_q_CursorLeave(const int x, const int y, const QString &key) { if (registerKey != key) return; D_Q(DRegionMonitor); Q_EMIT q->cursorLeave(deviceScaledCoordinate(QPoint(x, y), qApp->devicePixelRatio())); } void DRegionMonitorPrivate::_q_KeyPress(const QString &keyname, const int x, const int y, const QString &key) { if (registerKey != key) return; Q_UNUSED(x); Q_UNUSED(y); D_Q(DRegionMonitor); Q_EMIT q->keyPress(keyname); } void DRegionMonitorPrivate::_q_KeyRelease(const QString &keyname, const int x, const int y, const QString &key) { if (registerKey != key) return; Q_UNUSED(x); Q_UNUSED(y); D_Q(DRegionMonitor); Q_EMIT q->keyRelease(keyname); } const QPoint DRegionMonitorPrivate::deviceScaledCoordinate(const QPoint &p, const double ratio) const { D_QC(DRegionMonitor); if (type == q->Original) { return p; } for (const auto *s : qApp->screens()) { const QRect &g(s->geometry()); const QRect realRect(g.topLeft(), g.size() * ratio); if (realRect.contains(p)) return QPoint(realRect.topLeft() + (p - realRect.topLeft()) / ratio); } return p / ratio; } DGUI_END_NAMESPACE #include "moc_dregionmonitor.cpp" dtkgui-5.7.12/src/kernel/dwindowgroupleader.cpp000066400000000000000000000133671476226661100216020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dwindowgroupleader.h" #include #include #include DGUI_BEGIN_NAMESPACE #define DEFINE_CONST_CHAR(Name) const char _##Name[] = "_d_" #Name DEFINE_CONST_CHAR(groupLeader); DEFINE_CONST_CHAR(createGroupWindow); DEFINE_CONST_CHAR(destoryGroupWindow); DEFINE_CONST_CHAR(setWindowGroup); DEFINE_CONST_CHAR(clientLeader); class DWindowGroupLeaderPrivate { public: explicit DWindowGroupLeaderPrivate(quint32 groupLeader) : groupLeader(groupLeader) { QFunctionPointer clientLeaderFun = qApp->platformFunction(_clientLeader); if (clientLeaderFun) { clientLeader = reinterpret_cast(clientLeaderFun)(); } } quint32 groupLeader; quint32 clientLeader = 0; bool groupLeaderFromUser = false; QList> windowList; void ensureGroupLeader(); bool setWindowGroupLeader(quint32 window, quint32 groupLeader); }; void DWindowGroupLeaderPrivate::ensureGroupLeader() { if (groupLeader != 0) return; QFunctionPointer createGroupWindow = qApp->platformFunction(_createGroupWindow); if (!createGroupWindow) return; groupLeader = reinterpret_cast(createGroupWindow)(); } bool DWindowGroupLeaderPrivate::setWindowGroupLeader(quint32 window, quint32 groupLeader) { QFunctionPointer setWindowGroup = qApp->platformFunction(_setWindowGroup); if (!setWindowGroup) { return false; } reinterpret_cast(setWindowGroup)(window, groupLeader); return true; } /*! \class Dtk::Gui::DWindowGroupLeader \inmodule dtkgui \brief DWindowGroupLeader 用于设置窗口所在的组,可以把多个窗口加到同一个组. 在dxcb平台上,所有未指定组的窗口都会被分配到 DWindowGroupLeader::clientLeaderId 这个组,且在窗口对应的本地窗口被创建时,会对 Qt::Dialog、Qt::Sheet、Qt::Tool、 Qt::SplashScreen、Qt::ToolTip、Qt::Drawer、Qt::Popup 类型的窗口设置 WM_TRANSIENT_FOR 属性,对于此类型的窗口,如果没有手动调用 QWindow::setTransientParent , 则会将其 WM_TRANSIENT_FOR 属性设置为所在组id,得到的效果就是:会保证此窗口显示到这个组所有其它窗口 之上。例子: \code DWindowGroupLeader leader; QWindow wa, wb; QWindow topWindow; leader.addWindow(&wa); leader.addWindow(&wb); leader.addWindow(&topWindow); wa.setTitle("窗口wa"); wa.resize(300, 100); wa.show(); wb.setTitle("窗口wb"); wb.resize(300, 100); wb.show(); topWindow.setTitle("窗口topWindow"); topWindow.setFlag(Qt::Dialog); topWindow.resize(300, 300); topWindow.show(); \endcode 窗口topWindow一直处于窗口wa和wb上层 \image wa_wb_topWindow.gif 如果一个组内同时存在多个未设置过 QWindow::setTransientParent 的 Qt::Dialog(其它会自动设置 WM_TRANSIENT_FOR 属性的窗口也成立)类型的窗口,这些窗口之间不会互相影响显示顺序,具体的规则和 X11 ICCCM 标准一致。 \ref {https://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR} \sa DWindowGroupLeader::clientLeaderId \sa Dtk::Widget::DApplication::loadDXcbPlugin */ /*! \brief DWindowGroupLeader::DWindowGroupLeader \a groupId 为0时会在需要时自动创建一个有效的 groupLeaderId \sa DWindowGroupLeader::groupLeaderId */ DWindowGroupLeader::DWindowGroupLeader(quint32 groupId) : d_ptr(new DWindowGroupLeaderPrivate(groupId)) { if (groupId != 0) d_ptr->groupLeaderFromUser = true; } /*! \brief DWindowGroupLeader::~DWindowGroupLeader 对象销毁时会释放由自己自动创建的 groupLeaderId \sa DWindowGroupLeader::groupLeaderId */ DWindowGroupLeader::~DWindowGroupLeader() { Q_D(DWindowGroupLeader); for (auto window : d->windowList) removeWindow(window); if (!d->groupLeaderFromUser) { QFunctionPointer destoryGroupWindow = qApp->platformFunction(_destoryGroupWindow); if (!destoryGroupWindow) return; reinterpret_cast(destoryGroupWindow)(d->groupLeader); } } /*! \brief DWindowGroupLeader::groupLeaderId \return 返回组的id,类似于 QWindow::winId \warning 如果没有一个有效的id,则会先创建一个新的组id */ quint32 DWindowGroupLeader::groupLeaderId() const { Q_D(const DWindowGroupLeader); const_cast(d)->ensureGroupLeader(); return d->groupLeader; } /*! \brief DWindowGroupLeader::clientLeaderId \return 返回应用程序默认的组id */ quint32 DWindowGroupLeader::clientLeaderId() const { Q_D(const DWindowGroupLeader); return d->clientLeader; } /*! \brief DWindowGroupLeader::addWindow 将窗口添加到这个组 \a window \warning 每个窗口只能有一个组,添加到新的组时,将不再受旧的组所带来的任何影响 */ void DWindowGroupLeader::addWindow(QWindow *window) { Q_ASSERT(window); Q_D(DWindowGroupLeader); d->ensureGroupLeader(); window->setProperty(_groupLeader, d->groupLeader); if (window->handle()) { d->setWindowGroupLeader(window->winId(), d->groupLeader); } d->windowList << window; } /*! \brief DWindowGroupLeader::removeWindow 将窗口从这个组中移除 \a window \warning 窗口被移除后将不再受此组带来的任何影响 */ void DWindowGroupLeader::removeWindow(QWindow *window) { if (!window) return; window->setProperty(_groupLeader, QVariant()); Q_D(DWindowGroupLeader); if (window->handle()) { d->setWindowGroupLeader(window->winId(), d->clientLeader); } } DGUI_END_NAMESPACE dtkgui-5.7.12/src/kernel/dwindowmanagerhelper.cpp000066400000000000000000000620711476226661100220770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dwindowmanagerhelper.h" #include "dforeignwindow.h" #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #define D_XCB_WINDOW_TYPE QNativeInterface::Private::QXcbWindow::WindowType #else #include #define D_XCB_WINDOW_TYPE QXcbWindowFunctions::WmWindowType #endif #include #include #include #ifndef DTK_DISABLE_TREELAND #include "plugins/platform/treeland/dtreelandwindowmanagerhelper.h" #endif DGUI_BEGIN_NAMESPACE #define DEFINE_CONST_CHAR(Name) const char _##Name[] = "_d_" #Name #define MWM_FUNC_ALL (1L << 0) #define MWM_DECOR_ALL (1L << 0) // functions DEFINE_CONST_CHAR(hasBlurWindow); DEFINE_CONST_CHAR(hasComposite); DEFINE_CONST_CHAR(hasNoTitlebar); DEFINE_CONST_CHAR(hasWallpaperEffect); DEFINE_CONST_CHAR(windowManagerName); DEFINE_CONST_CHAR(connectWindowManagerChangedSignal); DEFINE_CONST_CHAR(connectHasBlurWindowChanged); DEFINE_CONST_CHAR(connectHasCompositeChanged); DEFINE_CONST_CHAR(connectHasNoTitlebarChanged); DEFINE_CONST_CHAR(connectHasWallpaperEffectChanged); DEFINE_CONST_CHAR(getCurrentWorkspaceWindows); DEFINE_CONST_CHAR(getWindows); DEFINE_CONST_CHAR(windowFromPoint); DEFINE_CONST_CHAR(connectWindowListChanged); DEFINE_CONST_CHAR(setMWMFunctions); DEFINE_CONST_CHAR(getMWMFunctions); DEFINE_CONST_CHAR(setMWMDecorations); DEFINE_CONST_CHAR(getMWMDecorations); DEFINE_CONST_CHAR(connectWindowMotifWMHintsChanged); DEFINE_CONST_CHAR(popupSystemWindowMenu); DEFINE_CONST_CHAR(setWMClassName); template static inline ReturnT callPlatformFunction(const QByteArray &funcName, Args... args) { QFunctionPointer func = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) func = qApp->platformFunction(funcName); #endif return func ? reinterpret_cast(func)(args...) : ReturnT(); } typedef bool(*func_t)(QObject *object, std::function); static bool connectWindowManagerChangedSignal(QObject *object, std::function slot) { return callPlatformFunction(_connectWindowManagerChangedSignal, object, slot); } static bool connectHasBlurWindowChanged(QObject *object, std::function slot) { return callPlatformFunction(_connectHasBlurWindowChanged, object, slot); } static bool connectHasCompositeChanged(QObject *object, std::function slot) { return callPlatformFunction(_connectHasCompositeChanged, object, slot); } static bool connectHasNoTitlebarChanged(QObject *object, std::function slot) { return callPlatformFunction(_connectHasNoTitlebarChanged, object, slot); } static bool connectHasWallpaperEffectChanged(QObject *object, std::function slot) { return callPlatformFunction(_connectHasWallpaperEffectChanged, object, slot); } static bool connectWindowListChanged(QObject *object, std::function slot) { return callPlatformFunction(_connectWindowListChanged, object, slot); } static bool connectWindowMotifWMHintsChanged(QObject *object, std::function slot) { typedef bool(*quint32_func_t)(QObject *object, std::function); return callPlatformFunction(_connectWindowMotifWMHintsChanged, object, slot); } class DWindowManagerHelperPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate { public: explicit DWindowManagerHelperPrivate(DWindowManagerHelper *qq) : DObjectPrivate(qq) {} mutable QList windowList; }; // TODO abstract an interface to adapt to various WM. #ifndef DTK_DISABLE_TREELAND Q_GLOBAL_STATIC(TreelandWindowManagerHelper, treelandWMHGlobal) #endif class DWindowManagerHelper_ : public DWindowManagerHelper {}; Q_GLOBAL_STATIC(DWindowManagerHelper_, wmhGlobal) /*! \class Dtk::Gui::DWindowManagerHelper \inmodule dtkgui \brief 提供与窗口管理器交互的接口,同 \a DPlatformWindowHandle 依赖 dxcb 插件. dxcb 插件抽象出所有需要和X11平台交互的接口以供上层调用,DTK 使用插件中提供的接口再 次封装提供给应用程序使用,从设计角度讲,DTK库中不应该直接使用任何跟平台相关的接口 (如:X11、Wayland、Windows),在这样的结构支撑下,在一个新的平台上,只需要提供和 dxcb 同样的接口,DTK应用即可无缝迁移。 \sa {https://github.com/linuxdeepin/qt5dxcb-plugin/}{dxcb插件} \sa Dtk::Widget::DApplication::loadDXcbPlugin \sa Dtk::Widget::DApplication::isDXcbPlatform \sa Dtk::Widget::DPlatformWindowHandle */ /*! \property DWindowManagerHelper::hasBlurWindow \brief 窗口管理器是否支持窗口背景模糊特效 \note 在 dxcb 插件中目前只支持 deepin-wm 和 kwin 这两种窗管的模糊特效 \note 只读 */ /*! \property DWindowManagerHelper::hasComposite \brief 窗口管理器是否支持混成效果。如果不支持混成,则表示所有窗口的背景都不能透明, 随之而来也不会有窗口阴影等效果,不规则窗口的边缘也会存在锯齿。 \note 只读 */ /*! \property DWindowManagerHelper::hasNoTitlebar \brief 窗口管理器是否支持隐藏窗口标题栏。如果支持,则 DPlatformWindowHandle::enableDXcbForWindow 会优先使用此方法支持自定义窗口标题栏。 \note 只读 \sa Dtk::Gui::DPlatformHandle::setEnabledNoTitlebarForWindow */ /*! \property DWindowManagerHelper::hasWallpaperEffect \brief 窗口管理器是否支持窗口背景特效绘制。如果支持,则 绘制背景到透明窗口 会使用此方法开启特效窗口壁纸背景绘制。 \note 只读 \sa hasWallpaperEffectChanged() */ /*! \enum Dtk::Gui::DWindowManagerHelper::MotifFunction MotifFunction::MotifFunction 窗口管理器对窗口所能控制的行为 \value FUNC_RESIZE 控制窗口大小。如果存在此标志,则窗口管理器可以改变窗口大小(如使用鼠标拖拽窗口边缘), 否则无法通过外部行为调整窗口大小。 \code DMainWindow w; w.resize(400, 200); w.show(); DWindowManagerHelper::setMotifFunctions(w.windowHandle(), DWindowManagerHelper::FUNC_RESIZE, false); \endcode \image disable_resize_function.gif \note 普通窗口默认存在此标志,对于 Qt::Popup 和 Qt::BypassWindowManagerHint 类型的窗口,不受此标志位影响 \note 设置此标志后也会影响窗口标题栏对应功能入口的状态 \note 对于使用系统标题栏的窗口,此功能和具体窗口管理器实现相关,deepin-wm 中设置 此标志无效。 \sa Dtk::Gui::DPlatformHandle::enableDXcbForWindow \sa Dtk::Gui::DPlatformHandle::isEnabledDXcb \value FUNC_MOVE 控制窗口位置。如果存在此标志,则窗口管理器可以移动窗口(如使用鼠标拖动标题栏),否则 无法通过外部行为移动窗口位置。 \code DWindowManagerHelper::setMotifFunctions(w.windowHandle(), DWindowManagerHelper::FUNC_MOVE, false); \endcode \image disable_move_function.gif \value FUNC_MINIMIZE 最小化窗口。如果存在此标志,则窗口可以被最小化(如点击标题栏的最小化按钮),否则无法 通过外部行为最小化窗口。 \code DWindowManagerHelper::setMotifFunctions(w.windowHandle(), DWindowManagerHelper::FUNC_MINIMIZE, false); \endcode \note 设置此标志后也会影响窗口标题栏对应功能入口的状态 \value FUNC_MAXIMIZE 最大化窗口。如果存在此标志,则窗口可以被最大化(如点击标题栏的最大化按钮),否则无法 通过外部行为最大化窗口。 \code DWindowManagerHelper::setMotifFunctions(w.windowHandle(), DWindowManagerHelper::FUNC_MAXIMIZE, false); \endcode \note 设置此标志后也会影响窗口标题栏对应功能入口的状态 \value FUNC_CLOSE 关闭窗口。如果存在此标志,则窗口可以被关闭(如点击标题栏的关闭按钮或使用Alt+F4快捷键), 否则无法通过外部行为关闭窗口。 \code DWindowManagerHelper::setMotifFunctions(w.windowHandle(), DWindowManagerHelper::FUNC_CLOSE, false); \endcode \note 设置此标志后也会影响窗口标题栏对应功能入口的状态 \value FUNC_ALL 所有功能性行为 */ /*! \enum Dtk::Gui::DWindowManagerHelper::MotifDecoration MotifFunction::MotifDecoration 窗口管理器对窗口添加的修饰。只影响窗口上对应功能 的入口,不影响实际的功能,比如:禁用掉 FUNC_MAXIMIZE 后,还可以使用快捷键最大化窗口 \value DECOR_BORDER 窗口描边。如果存在此标志,则窗口管理器会为窗口绘制描边,否则窗口没有描边。 否则无法通过外部行为调整窗口大小。 \note 只支持使用系统标题栏的窗口,此功能和具体窗口管理器实现相关,deepin-wm 中设置 此标志无效。 \value DECOR_RESIZEH 改变窗口大小。如果存在此标志,则窗口管理器会在窗口的修饰上显示一个更改窗口大小的控件, 否则无此控件。 \note 只支持使用系统标题栏的窗口,此功能和具体窗口管理器实现相关,deepin-wm 中设置 此标志无效。 \value DECOR_TITLE 窗口标题。如果存在此标志,则窗口管理器会在窗口的修饰上显示窗口标题,否则不显示。 \note 只支持使用系统标题栏的窗口,此功能和具体窗口管理器实现相关,deepin-wm 中设置 此标志无效。 \value DECOR_MENU 窗口菜单。如果存在此标志,则窗口管理器会在窗口的修饰上显示一个窗口菜单控件,否则不显示。 \note 只支持使用系统标题栏的窗口,此功能和具体窗口管理器实现相关,deepin-wm 中设置 此标志无效。 \value DECOR_MINIMIZE 窗口最小化。如果存在此标志,则窗口管理器会在窗口的修饰上显示一个最小化窗口控件,否则不显示。 \note 只支持使用系统标题栏的窗口,此功能和具体窗口管理器实现相关,deepin-wm 中设置 此标志无效。 \sa Qt::WindowMinimizeButtonHint \value DECOR_MAXIMIZE 窗口最大化。如果存在此标志,则窗口管理器会在窗口的修饰上显示一个最大化窗口控件,否则不显示。 \note 只支持使用系统标题栏的窗口,此功能和具体窗口管理器实现相关,deepin-wm 中设置 此标志无效。 \sa Qt::WindowMaximizeButtonHint \value DECOR_ALL 所有窗口修饰。 */ /*! \enum Dtk::Gui::DWindowManagerHelper::WMName DWindowManagerHelper::WMName 窗口管理器类型 \value DeepinWM 深度系统桌面环境窗口管理器 \value KWinWM KDE系统桌面环境窗口管理器 \value OtherWM 其它窗口管理器 */ /*! \fn void DWindowManagerHelper::windowManagerChanged() \brief 信号会在当前环境窗口管理器变化时被发送. */ /*! \fn void DWindowManagerHelper::hasBlurWindowChanged() \brief 信号会在 hasBlurWindow 属性的值改变时被发送. */ /*! \fn void DWindowManagerHelper::hasCompositeChanged() \brief 信号会在 hasComposite 属性的值改变时被发送. */ /*! \fn void DWindowManagerHelper::hasNoTitlebarChanged() \brief 信号会在 hasNoTitlebar 属性的值改变时被发送. */ /*! \fn void DWindowManagerHelper::hasWallpaperEffectChanged() \brief 信号会在 hasWallpaperEffect 属性的值改变时被发送. */ /*! \fn void DWindowManagerHelper::windowListChanged() \brief 信号会在当前环境本地窗口列表变化时被发送。包含打开新窗口、关闭窗口、改变窗口的 层叠顺序. */ /*! \fn void DWindowManagerHelper::windowMotifWMHintsChanged(quint32 winId) \brief 信号会在窗口功能或修饰标志改变时被发送. \a winId 窗口id \note 只对当前应用程序中的窗口有效 */ DWindowManagerHelper::~DWindowManagerHelper() { D_DC(DWindowManagerHelper); for (QWindow *w : d->windowList) { w->deleteLater(); } } /*! \brief DWindowManagerHelper::instance DWindowManagerHelper 的单例对象,使用 Q_GLOBAL_STATIC 定义,在第一次调用时实例化。 \return */ DWindowManagerHelper *DWindowManagerHelper::instance() { #ifndef DTK_DISABLE_TREELAND if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { return treelandWMHGlobal; } #endif return wmhGlobal; } /*! \brief DWindowManagerHelper::setMotifFunctions 设置窗口的功能性标志,会覆盖之前的设置 \a window \a hints */ void DWindowManagerHelper::setMotifFunctions(const QWindow *window, MotifFunctions hints) { QFunctionPointer setMWMFunctions = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) setMWMFunctions = qApp->platformFunction(_setMWMFunctions); #endif if (setMWMFunctions && window->handle()) { /* fix bug: 18775, 3391 当所有function标志都设置时,用MWM_FUNC_ALL代替会导致窗管无法正确处理 dock栏发送的关闭消息.所以取消此设置 if (hints == FUNC_ALL) hints = (MotifFunction)MWM_FUNC_ALL; */ reinterpret_cast(setMWMFunctions)(window->handle()->winId(), (quint32)hints); } } /*! \brief DWindowManagerHelper::setMotifFunctions 设置窗口某些标志位的开启状态,不影响其它标志位 \a window \a hints 要设置的标志位 \a on 如果值为 true 则开启标志,否则关闭 \return 返回设置后的窗口标志 */ DWindowManagerHelper::MotifFunctions DWindowManagerHelper::setMotifFunctions(const QWindow *window, MotifFunctions hints, bool on) { MotifFunctions old_hints = getMotifFunctions(window); if (on) hints |= old_hints; else hints = old_hints & ~hints; setMotifFunctions(window, hints); return hints; } /*! \brief DWindowManagerHelper::getMotifFunctions \a window \return 返回窗口当前的功能标志 */ DWindowManagerHelper::MotifFunctions DWindowManagerHelper::getMotifFunctions(const QWindow *window) { QFunctionPointer getMWMFunctions = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) getMWMFunctions = qApp->platformFunction(_getMWMFunctions); #endif if (getMWMFunctions && window->handle()) { quint32 hints = reinterpret_cast(getMWMFunctions)(window->handle()->winId()); if (!(hints & MWM_FUNC_ALL)) return (MotifFunctions)hints; } return FUNC_ALL; } /*! \brief DWindowManagerHelper::setMotifDecorations 设置窗口的修饰性标志,会覆盖之前的设置 \a window \a hints */ void DWindowManagerHelper::setMotifDecorations(const QWindow *window, MotifDecorations hints) { QFunctionPointer setMWMDecorations = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) setMWMDecorations = qApp->platformFunction(_setMWMDecorations); #endif if (setMWMDecorations && window->handle()) { if (hints == DECOR_ALL) hints = (MotifDecoration)MWM_DECOR_ALL; reinterpret_cast(setMWMDecorations)(window->handle()->winId(), (quint32)hints); } } /*! \brief DWindowManagerHelper::setMotifFunctions 设置窗口某些标志位的开启状态,不影响其它标志位 \a window \a hints 要设置的标志位 \a on 如果值为 true 则开启标志,否则关闭 \return 返回设置后的窗口标志 */ DWindowManagerHelper::MotifDecorations DWindowManagerHelper::setMotifDecorations(const QWindow *window, MotifDecorations hints, bool on) { MotifDecorations old_hints = getMotifDecorations(window); if (on) hints |= old_hints; else hints = old_hints & ~hints; setMotifDecorations(window, hints); return hints; } /*! \brief DWindowManagerHelper::getMotifFunctions \a window \return 返回窗口当前的修饰标志 */ DWindowManagerHelper::MotifDecorations DWindowManagerHelper::getMotifDecorations(const QWindow *window) { QFunctionPointer getMWMDecorations = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) getMWMDecorations = qApp->platformFunction(_getMWMDecorations); #endif if (getMWMDecorations && window->handle()) { quint32 hints = reinterpret_cast(getMWMDecorations)(window->handle()->winId()); if (!(hints & MWM_DECOR_ALL)) return (MotifDecorations)hints; } return DECOR_ALL; } /*! \brief DWindowManagerHelper::setWmWindowTypes 直接设置窗口管理器层级提供的窗口类型,如DesktopType和DockType类型也被 桌面环境需要,但是Qt自身并没有提供对应的设置接口 \a window \a types */ void DWindowManagerHelper::setWmWindowTypes(QWindow *window, WmWindowTypes types) { const int _types = static_cast(types); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) typedef QNativeInterface::Private::QXcbWindow QXcbWindow_P; if (auto w = dynamic_cast(window->handle())) { w->setWindowType(static_cast(_types)); } else { qWarning() << "cast" << window << "to platform window failed"; } #else QXcbWindowFunctions::setWmWindowType(window, static_cast(_types)); #endif } /*! \brief DWindowManagerHelper::setWmClassName 设置x11环境上默认使用的wm class name,主要是在窗口创建时用于设置WM_CLASS窗口属性 \a name \note 如果值为空,Qt将在下次使用此值时根据程序名称再次初始化此值 \sa QCoreApplication::applicationName */ void DWindowManagerHelper::setWmClassName(const QByteArray &name) { typedef void (*SetWmNameType)(const QByteArray&); return callPlatformFunction(_setWMClassName, name); } /*! \brief DWindowManagerHelper::popupSystemWindowMenu 显示窗口管理器对窗口的菜单,和有边框的窗口在标题栏上点击鼠标右键弹出的菜单内容一致。 在 DMainWindow 的标题栏上点击鼠标右键会调用此函数打开系统菜单: \image window_system_menu.gif \a window */ void DWindowManagerHelper::popupSystemWindowMenu(const QWindow *window) { return callPlatformFunction(_popupSystemWindowMenu, quint32(window->handle()->winId())); } /*! \brief DWindowManagerHelper::hasBlurWindow \return 如果当前窗口管理器支持窗口背景模糊特效则返回 true,否则返回 false */ bool DWindowManagerHelper::hasBlurWindow() const { #ifndef DTK_DISABLE_TREELAND if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { return treelandWMHGlobal->hasBlurWindow(); } #endif return callPlatformFunction(_hasBlurWindow); } /*! \brief DWindowManagerHelper::hasComposite \return 如果当前窗口管理器支持混成则返回 true,否则返回 false */ bool DWindowManagerHelper::hasComposite() const { #ifndef DTK_DISABLE_TREELAND if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { return treelandWMHGlobal->hasComposite(); } #endif QFunctionPointer hasComposite = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) hasComposite = qApp->platformFunction(_hasComposite); #endif if (!hasComposite) { #ifdef Q_OS_LINUX if (DGuiApplicationHelper::isXWindowPlatform()) { QPlatformNativeInterface *native = qApp->platformNativeInterface(); if (Q_LIKELY(native)) { QScreen *scr = QGuiApplication::primaryScreen(); return native->nativeResourceForScreen(QByteArray("compositingEnabled"), scr); } } #endif // 在其它平台上默认认为混成是开启的 return true; } return callPlatformFunction(_hasComposite); } /*! \brief DWindowManagerHelper::hasNoTitlebar \return 如果窗口管理器当前支持设置隐藏窗口标题栏则返回 true,否则返回 false */ bool DWindowManagerHelper::hasNoTitlebar() const { #ifndef DTK_DISABLE_TREELAND if (DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform)) { return treelandWMHGlobal->hasNoTitlebar(); } #endif return callPlatformFunction(_hasNoTitlebar); } /*! \brief DWindowManagerHelper::hasWallpaperEffect \return 如果窗口管理器当前支持背景图片特效绘制返回 true,否则返回 false */ bool DWindowManagerHelper::hasWallpaperEffect() const { return callPlatformFunction(_hasWallpaperEffect); } /*! \brief DWindowManagerHelper::windowManagerNameString \return 返回窗口管理器名称。在X11平台上,此值为窗口管理器对应窗口的 _NET_WM_NAME 的值 \ref {https://specifications.freedesktop.org/wm-spec/1.3/ar01s03.html}{_NET_SUPPORTING_WM_CHECK} \ref {https://specifications.freedesktop.org/wm-spec/1.3/ar01s05.html}{_NET_WM_NAME} */ QString DWindowManagerHelper::windowManagerNameString() const { return callPlatformFunction(_windowManagerName); } /*! \brief DWindowManagerHelper::windowManagerName \return 返回当前窗口管理器类型 \sa DWindowManagerHelper::windowManagerNameString */ DWindowManagerHelper::WMName DWindowManagerHelper::windowManagerName() const { const QString &wmName = windowManagerNameString(); if (wmName == QStringLiteral("Mutter(DeepinGala)")) { return DeepinWM; } if (wmName == QStringLiteral("KWin")) { return KWinWM; } return OtherWM; } /*! \brief DWindowManagerHelper::allWindowIdList \return 返回当前环境所有本地窗口的窗口id列表 \note 顺序和窗口层叠顺序相关,显示越靠下层的窗口在列表中顺序越靠前 \sa DWindowManagerHelper::currentWorkspaceWindowIdList */ QVector DWindowManagerHelper::allWindowIdList() const { return callPlatformFunction, QVector(*)()>(_getWindows); } /*! \brief DWindowManagerHelper::currentWorkspaceWindowIdList \return 返回当前工作区所有本地窗口的窗口id列表 \note 顺序和窗口层叠顺序相关,显示越靠下层的窗口在列表中顺序越靠前 \sa DWindowManagerHelper::allWindowIdList */ QVector DWindowManagerHelper::currentWorkspaceWindowIdList() const { return callPlatformFunction, QVector(*)()>(_getCurrentWorkspaceWindows); } /*! \brief DWindowManagerHelper::currentWorkspaceWindowIdList \return 返回当前工作区所有本地窗口对象列表。和 currentWorkspaceWindowIdList 类似,只不过自动通过窗口id创建了 DForeignWindow 对象 \note 顺序和窗口层叠顺序相关,显示越靠下层的窗口在列表中顺序越靠前 \note 列表中对象的生命周期由 DForeignWindow 负责 \warning 此列表中不包含由当前应用创建的窗口 \sa DWindowManagerHelper::currentWorkspaceWindowIdList \sa DForeignWindow::fromWinId */ QList DWindowManagerHelper::currentWorkspaceWindows() const { D_DC(DWindowManagerHelper); for (QWindow *w : d->windowList) { w->deleteLater(); } d->windowList.clear(); QList currentApplicationWindowList; const QWindowList &list = qApp->allWindows(); currentApplicationWindowList.reserve(list.size()); for (auto window : list) { if (window->property("_q_foreignWinId").isValid()) continue; currentApplicationWindowList.append(window->winId()); } QVector wmClientList = currentWorkspaceWindowIdList(); for (WId wid : wmClientList) { if (currentApplicationWindowList.contains(wid)) continue; if (DForeignWindow *w = DForeignWindow::fromWinId(wid)) { d->windowList << w; } } return d->windowList; } /*! \brief DWindowManagerHelper::windowFromPoint \return 返回 \a p 位置的窗口 Id,如果出错返回 0 \note 可以通过 DForeignWindow::fromWinId 创建窗口对象 */ quint32 DWindowManagerHelper::windowFromPoint(const QPoint &p) { return callPlatformFunction(_windowFromPoint, p); } /*! \brief DWindowManagerHelper::DWindowManagerHelper 不允许直接实例化此对象 \a parent \sa DWindowManagerHelper::instance */ DWindowManagerHelper::DWindowManagerHelper(QObject *parent) : QObject(parent) , DObject(*new DWindowManagerHelperPrivate(this)) { connectWindowManagerChangedSignal(this, [this] { Q_EMIT windowManagerChanged(); }); connectHasBlurWindowChanged(this, [this] { Q_EMIT hasBlurWindowChanged(); }); connectHasCompositeChanged(this, [this] { Q_EMIT hasCompositeChanged(); }); connectHasNoTitlebarChanged(this, [this] { Q_EMIT hasNoTitlebarChanged(); }); connectHasWallpaperEffectChanged(this, [this] { Q_EMIT hasWallpaperEffectChanged(); }); connectWindowListChanged(this, [this] { Q_EMIT windowListChanged(); }); connectWindowMotifWMHintsChanged(this, [this] (quint32 winId) { Q_EMIT windowMotifWMHintsChanged(winId); }); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/kernel/kernel.cmake000066400000000000000000000003031476226661100174350ustar00rootroot00000000000000file(GLOB KERNEL_HEADER ${CMAKE_CURRENT_LIST_DIR}/../../include/kernel/*.h ) file(GLOB KERNEL_SOURCE ${CMAKE_CURRENT_LIST_DIR}/*.cpp ) set(kernel_SRC ${KERNEL_HEADER} ${KERNEL_SOURCE} ) dtkgui-5.7.12/src/plugins/000077500000000000000000000000001476226661100153605ustar00rootroot00000000000000dtkgui-5.7.12/src/plugins/dplatforminterface.cpp000066400000000000000000000142411476226661100217370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dplatformtheme.h" #include "private/dplatforminterface_p.h" DGUI_BEGIN_NAMESPACE DPlatformInterface::DPlatformInterface(DPlatformTheme *platformTheme) : m_platformTheme(platformTheme) { } DPlatformInterface::~DPlatformInterface() { } int DPlatformInterface::cursorBlinkTime() const { return {}; } int DPlatformInterface::cursorBlinkTimeout() const { return {}; } bool DPlatformInterface::cursorBlink() const { return {}; } int DPlatformInterface::doubleClickDistance() const { return {}; } int DPlatformInterface::doubleClickTime() const { return {}; } int DPlatformInterface::dndDragThreshold() const { return {}; } int DPlatformInterface::windowRadius() const { return -1; } int DPlatformInterface::windowRadius(int defaultValue) const { return defaultValue; } QByteArray DPlatformInterface::themeName() const { return {}; } QByteArray DPlatformInterface::iconThemeName() const { return {}; } QByteArray DPlatformInterface::soundThemeName() const { return {}; } QByteArray DPlatformInterface::fontName() const { return {}; } QByteArray DPlatformInterface::monoFontName() const { return {}; } qreal DPlatformInterface::fontPointSize() const { return {}; } QByteArray DPlatformInterface::gtkFontName() const { return {}; } QColor DPlatformInterface::activeColor() const { return {}; } QColor DPlatformInterface::darkActiveColor() const { return {}; } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QColor DPlatformInterface::window() const { return {}; } QColor DPlatformInterface::windowText() const { return {}; } QColor DPlatformInterface::base() const { return {}; } QColor DPlatformInterface::alternateBase() const { return {}; } QColor DPlatformInterface::toolTipBase() const { return {}; } QColor DPlatformInterface::toolTipText() const { return {}; } QColor DPlatformInterface::text() const { return {}; } QColor DPlatformInterface::button() const { return {}; } QColor DPlatformInterface::buttonText() const { return {}; } QColor DPlatformInterface::brightText() const { return {}; } QColor DPlatformInterface::light() const { return {}; } QColor DPlatformInterface::midlight() const { return {}; } QColor DPlatformInterface::dark() const { return {}; } QColor DPlatformInterface::mid() const { return {}; } QColor DPlatformInterface::shadow() const { return {}; } QColor DPlatformInterface::highlight() const { return {}; } QColor DPlatformInterface::highlightedText() const { return {}; } QColor DPlatformInterface::link() const { return {}; } QColor DPlatformInterface::linkVisited() const { return {}; } QColor DPlatformInterface::itemBackground() const { return {}; } QColor DPlatformInterface::textTitle() const { return {}; } QColor DPlatformInterface::textTips() const { return {}; } QColor DPlatformInterface::textWarning() const { return {}; } QColor DPlatformInterface::textLively() const { return {}; } QColor DPlatformInterface::lightLively() const { return {}; } QColor DPlatformInterface::darkLively() const { return {}; } QColor DPlatformInterface::frameBorder() const { return {}; } #endif int DPlatformInterface::dotsPerInch(const QString &) const { return {}; } int DPlatformInterface::sizeMode() const { return {}; } int DPlatformInterface::scrollBarPolicy() const { return {}; } void DPlatformInterface::setCursorBlinkTime(int) { } void DPlatformInterface::setCursorBlinkTimeout(int) { } void DPlatformInterface::setCursorBlink(bool) { } void DPlatformInterface::setDoubleClickDistance(int) { } void DPlatformInterface::setDoubleClickTime(int) { } void DPlatformInterface::setDndDragThreshold(int) { } void DPlatformInterface::setThemeName(const QByteArray &) { } void DPlatformInterface::setIconThemeName(const QByteArray &) { } void DPlatformInterface::setSoundThemeName(const QByteArray &) { } void DPlatformInterface::setFontName(const QByteArray &) { } void DPlatformInterface::setMonoFontName(const QByteArray &) { } void DPlatformInterface::setFontPointSize(qreal) { } void DPlatformInterface::setGtkFontName(const QByteArray &) { } void DPlatformInterface::setActiveColor(const QColor) { } void DPlatformInterface::setDarkActiveColor(const QColor &) { } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) void DPlatformInterface::setWindow(const QColor &) { } void DPlatformInterface::setWindowText(const QColor &) { } void DPlatformInterface::setBase(const QColor &) { } void DPlatformInterface::setAlternateBase(const QColor &) { } void DPlatformInterface::setToolTipBase(const QColor &) { } void DPlatformInterface::setToolTipText(const QColor &) { } void DPlatformInterface::setText(const QColor &) { } void DPlatformInterface::setButton(const QColor &) { } void DPlatformInterface::setButtonText(const QColor &) { } void DPlatformInterface::setBrightText(const QColor &) { } void DPlatformInterface::setLight(const QColor &) { } void DPlatformInterface::setMidlight(const QColor &) { } void DPlatformInterface::setDark(const QColor &) { } void DPlatformInterface::setMid(const QColor &) { } void DPlatformInterface::setShadow(const QColor &) { } void DPlatformInterface::setHighlight(const QColor &) { } void DPlatformInterface::setHighlightedText(const QColor &) { } void DPlatformInterface::setLink(const QColor &) { } void DPlatformInterface::setLinkVisited(const QColor &) { } void DPlatformInterface::setItemBackground(const QColor &) { } void DPlatformInterface::setTextTitle(const QColor &) { } void DPlatformInterface::setTextTips(const QColor &) { } void DPlatformInterface::setTextWarning(const QColor &) { } void DPlatformInterface::setTextLively(const QColor &) { } void DPlatformInterface::setLightLively(const QColor &) { } void DPlatformInterface::setDarkLively(const QColor &) { } void DPlatformInterface::setFrameBorder(const QColor &) { } #endif void DPlatformInterface::setDotsPerInch(const QString &, int) { } void DPlatformInterface::setWindowRadius(int) { } DGUI_END_NAMESPACE dtkgui-5.7.12/src/plugins/dplatformwindowinterface.cpp000066400000000000000000000070461476226661100231740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "private/dplatformwindowinterface_p.h" DGUI_BEGIN_NAMESPACE DPlatformWindowInterface::DPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle) : m_window(window) , m_platformHandle(platformHandle) { } DPlatformWindowInterface::~DPlatformWindowInterface() { } QWindow *DPlatformWindowInterface::window() const { return m_window; } void DPlatformWindowInterface::setEnabled(bool enabled) { Q_UNUSED(enabled) } bool DPlatformWindowInterface::isEnabled() const { return false; } bool DPlatformWindowInterface::isEnabledNoTitlebar() const { return {}; } bool DPlatformWindowInterface::setEnabledNoTitlebar(bool enable) { Q_UNUSED(enable) return {}; } void DPlatformWindowInterface::setDisableWindowOverrideCursor(bool disable) { Q_UNUSED(disable) } int DPlatformWindowInterface::windowRadius() const { return -1; } void DPlatformWindowInterface::setWindowRadius(int windowRadius) { Q_UNUSED(windowRadius) } int DPlatformWindowInterface::borderWidth() const { return -1; } void DPlatformWindowInterface::setBorderWidth(int borderWidth) { Q_UNUSED(borderWidth) } QColor DPlatformWindowInterface::borderColor() const { return {}; } void DPlatformWindowInterface::setBorderColor(const QColor &borderColor) { Q_UNUSED(borderColor) } int DPlatformWindowInterface::shadowRadius() const { return {}; } void DPlatformWindowInterface::setShadowRadius(int shadowRadius) { Q_UNUSED(shadowRadius) } QPoint DPlatformWindowInterface::shadowOffset() const { return {}; } void DPlatformWindowInterface::setShadowOffset(const QPoint &shadowOffset) { Q_UNUSED(shadowOffset) } QColor DPlatformWindowInterface::shadowColor() const { return {}; } void DPlatformWindowInterface::setShadowColor(const QColor &shadowColor) { Q_UNUSED(shadowColor) } DPlatformHandle::EffectScene DPlatformWindowInterface::windowEffect() { return {}; } void DPlatformWindowInterface::setWindowEffect(DPlatformHandle::EffectScenes effectScene) { Q_UNUSED(effectScene) } DPlatformHandle::EffectType DPlatformWindowInterface::windowStartUpEffect() { return {}; } void DPlatformWindowInterface::setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) { Q_UNUSED(effectType) } QPainterPath DPlatformWindowInterface::clipPath() const { return {}; } void DPlatformWindowInterface::setClipPath(const QPainterPath &clipPath) { Q_UNUSED(clipPath) } QRegion DPlatformWindowInterface::frameMask() const { return {}; } void DPlatformWindowInterface::setFrameMask(const QRegion &frameMask) { Q_UNUSED(frameMask) } QMargins DPlatformWindowInterface::frameMargins() const { return {}; } bool DPlatformWindowInterface::translucentBackground() const { return {}; } void DPlatformWindowInterface::setTranslucentBackground(bool translucentBackground) { Q_UNUSED(translucentBackground) } bool DPlatformWindowInterface::enableSystemResize() const { return {}; } void DPlatformWindowInterface::setEnableSystemResize(bool enableSystemResize) { Q_UNUSED(enableSystemResize) } bool DPlatformWindowInterface::enableSystemMove() const { return {}; } void DPlatformWindowInterface::setEnableSystemMove(bool enableSystemMove) { Q_UNUSED(enableSystemMove) } bool DPlatformWindowInterface::enableBlurWindow() const { return {}; } void DPlatformWindowInterface::setEnableBlurWindow(bool enableBlurWindow) { Q_UNUSED(enableBlurWindow) } DGUI_END_NAMESPACE dtkgui-5.7.12/src/plugins/platform/000077500000000000000000000000001476226661100172045ustar00rootroot00000000000000dtkgui-5.7.12/src/plugins/platform/config.tests/000077500000000000000000000000001476226661100216125ustar00rootroot00000000000000dtkgui-5.7.12/src/plugins/platform/config.tests/treeland_test/000077500000000000000000000000001476226661100244475ustar00rootroot00000000000000dtkgui-5.7.12/src/plugins/platform/config.tests/treeland_test/CMakeLists.txt000066400000000000000000000033011476226661100272040ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later cmake_minimum_required(VERSION 3.16) project(wayland_test) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(AUTOMOC_COMPILER_PREDEFINES ON) find_package(Qt${QT_VERSION_MAJOR} ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Gui WaylandClient) if(${QT_VERSION_MAJOR} STREQUAL "5") find_package(Qt5 REQUIRED COMPONENTS XkbCommonSupport) endif() find_package(PkgConfig REQUIRED) pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client) find_package(TreelandProtocols) set(TreelandProtocols_FOUND ${TreelandProtocols_FOUND}) add_executable(${PROJECT_NAME} main.cpp) if("${QT_VERSION_MAJOR}" STREQUAL "6") qt6_generate_wayland_protocol_client_sources(${PROJECT_NAME} FILES ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml ) else() # ECM setup include(FeatureSummary) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${ECM_MODULE_PATH}") find_package(QtWaylandScanner) ecm_add_qtwayland_client_protocol(TABLET_SRCS PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml BASENAME treeland-personalization-manager-v1 ) target_sources(${PROJECT_NAME} PRIVATE ${TABLET_SRCS}) target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::XkbCommonSupportPrivate ) endif() target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::GuiPrivate Qt${QT_VERSION_MAJOR}::CorePrivate Qt${QT_VERSION_MAJOR}::WaylandClientPrivate ${WAYLAND_CLIENT_LIBRARIES} ) dtkgui-5.7.12/src/plugins/platform/config.tests/treeland_test/main.cpp000066400000000000000000000022721476226661100261020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include "qwayland-treeland-personalization-manager-v1.h" #include #include #include #include #include class PersonalizationWindowContext : public QWaylandClientExtensionTemplate, public QtWayland::treeland_personalization_window_context_v1 { public: PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context) : QWaylandClientExtensionTemplate(1) , QtWayland::treeland_personalization_window_context_v1(context) { set_titlebar(enable_mode::enable_mode_disable); } }; int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); return 0; } dtkgui-5.7.12/src/plugins/platform/treeland/000077500000000000000000000000001476226661100210025ustar00rootroot00000000000000dtkgui-5.7.12/src/plugins/platform/treeland/dtreelandplatforminterface.cpp000066400000000000000000000047511476226661100271050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtreelandplatforminterface.h" #include "dplatformtheme.h" #include "private/dplatforminterface_p.h" #include "personalizationwaylandclientextension.h" #include #include #include DGUI_BEGIN_NAMESPACE DTreelandPlatformInterface::DTreelandPlatformInterface(DPlatformTheme *platformTheme) : DPlatformInterface(platformTheme) { m_manager = PersonalizationManager::instance(); connect(m_manager, &PersonalizationManager::activeChanged, this, [this](){ if (m_manager->isActive()) { initContext(); } }); } void DTreelandPlatformInterface::initContext() { if (m_appearanceContext.isNull()) { m_appearanceContext.reset(new PersonalizationAppearanceContext(m_manager->get_appearance_context(), this)); } if (m_fontContext.isNull()) { m_fontContext.reset(new PersonalizationFontContext(m_manager->get_font_context(), this)); } } QByteArray DTreelandPlatformInterface::iconThemeName() const { return m_iconThemeName; } QByteArray DTreelandPlatformInterface::fontName() const { return m_fontName; } QByteArray DTreelandPlatformInterface::monoFontName() const { return m_monoFontName; } qreal DTreelandPlatformInterface::fontPointSize() const { return m_fontPointSize; } QColor DTreelandPlatformInterface::activeColor() const { return m_activeColor; } QByteArray DTreelandPlatformInterface::themeName() const { return m_themeName; } void DTreelandPlatformInterface::setIconThemeName(const QByteArray &iconThemeName) { if (m_appearanceContext) { m_appearanceContext->set_icon_theme(iconThemeName); } } void DTreelandPlatformInterface::setFontName(const QByteArray &fontName) { if (m_fontContext) { m_fontContext->set_font(fontName); } } void DTreelandPlatformInterface::setMonoFontName(const QByteArray &monoFontName) { if (m_fontContext) { m_fontContext->set_monospace_font(monoFontName); } } void DTreelandPlatformInterface::setFontPointSize(qreal fontPointSize) { if (m_fontContext) { m_fontContext->set_font_size(fontPointSize); } } void DTreelandPlatformInterface::setActiveColor(const QColor activeColor) { if (m_appearanceContext) { m_appearanceContext->set_active_color(activeColor.name()); } } DGUI_END_NAMESPACE dtkgui-5.7.12/src/plugins/platform/treeland/dtreelandplatforminterface.h000066400000000000000000000036511476226661100265500ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTREELANDPLATFORMINTERFACE_H #define DTREELANDPLATFORMINTERFACE_H #include "private/dplatforminterface_p.h" #include #include #include DGUI_BEGIN_NAMESPACE class DTreelandPlatformInterfacePrivate; class PersonalizationManager; class PersonalizationFontContext; class PersonalizationAppearanceContext; class PersonalizationWindowContext; class DTreelandPlatformInterface : public QObject, public DPlatformInterface, public DCORE_NAMESPACE::DObject { Q_OBJECT friend PersonalizationFontContext; friend PersonalizationAppearanceContext; friend PersonalizationWindowContext; public: explicit DTreelandPlatformInterface(DPlatformTheme *platformTheme); QByteArray iconThemeName() const override; QByteArray fontName() const override; QByteArray monoFontName() const override; qreal fontPointSize() const override; QColor activeColor() const override; QByteArray themeName() const override; void setIconThemeName(const QByteArray &iconThemeName) override; void setFontName(const QByteArray &fontName) override; void setMonoFontName(const QByteArray &monoFontName) override; void setFontPointSize(qreal fontPointSize) override; void setActiveColor(const QColor activeColor) override; private: void initContext(); private: PersonalizationManager *m_manager; QScopedPointer m_appearanceContext; QScopedPointer m_fontContext; QColor m_activeColor; int m_titleHeight; QByteArray m_fontName; QByteArray m_monoFontName; QByteArray m_iconThemeName; QByteArray m_cursorThemeName; qreal m_fontPointSize; int m_windowRadius; int m_scrollBarPolicy; QByteArray m_themeName; uint32_t m_blurOpacity; }; DGUI_END_NAMESPACE #endif dtkgui-5.7.12/src/plugins/platform/treeland/dtreelandplatformwindowinterface.cpp000066400000000000000000000263341476226661100303360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #define protected public #include #undef protected #include "dtreelandplatformwindowinterface.h" #include #include #include #include #include #include #include "dvtablehook.h" #include "personalizationwaylandclientextension.h" DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE class Q_DECL_HIDDEN MoveWindowHelper : public QObject { public: explicit MoveWindowHelper(QWindow *w); ~MoveWindowHelper(); static QHash mapped; private: static bool windowEvent(QWindow *w, QEvent *event); void updateEnableSystemMoveFromProperty(); QWindow *m_window; bool m_windowMoving; bool m_enableSystemMove; }; QHash MoveWindowHelper::mapped; MoveWindowHelper::MoveWindowHelper(QWindow *window) : QObject(window) , m_window(window) { mapped[window] = this; updateEnableSystemMoveFromProperty(); } MoveWindowHelper::~MoveWindowHelper() { mapped.remove(static_cast(parent())); } void MoveWindowHelper::updateEnableSystemMoveFromProperty() { if (!m_window) { return; } const QVariant &v = m_window->property("_d_enableSystemMove"); m_enableSystemMove = !v.isValid() || v.toBool(); if (m_enableSystemMove) { DVtableHook::overrideVfptrFun(m_window, &QWindow::event, &MoveWindowHelper::windowEvent); } else if (DVtableHook::hasVtable(m_window)) { DVtableHook::resetVfptrFun(m_window, &QWindow::event); } } bool MoveWindowHelper::windowEvent(QWindow *w, QEvent *event) { MoveWindowHelper *self = mapped.value(w); if (!self) return DVtableHook::callOriginalFun(w, &QWindow::event, event); // TODO Crashed when delete by Vtable. if (event->type() == QEvent::DeferredDelete) { DVtableHook::resetVtable(w); return w->event(event); } // m_window 的 event 被 override 以后,在 windowEvent 里面获取到的 this 就成 m_window 了, // 而不是 DNoTitlebarWlWindowHelper,所以此处 windowEvent 改为 static 并传 self 进来 { static bool isTouchDown = false; static QPointF touchBeginPosition; if (event->type() == QEvent::TouchBegin) { isTouchDown = true; } if (event->type() == QEvent::TouchEnd || event->type() == QEvent::MouseButtonRelease) { isTouchDown = false; } if (isTouchDown && event->type() == QEvent::MouseButtonPress) { touchBeginPosition = static_cast(event)->globalPos(); } // add some redundancy to distinguish trigger between system menu and system move if (event->type() == QEvent::MouseMove) { QPointF currentPos = static_cast(event)->globalPos(); QPointF delta = touchBeginPosition - currentPos; if (delta.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) { return DVtableHook::callOriginalFun(w, &QWindow::event, event); } } } bool is_mouse_move = event->type() == QEvent::MouseMove && static_cast(event)->buttons() == Qt::LeftButton; if (event->type() == QEvent::MouseButtonRelease) { self->m_windowMoving = false; } if (!DVtableHook::callOriginalFun(w, &QWindow::event, event)) return false; // workaround for kwin: Qt receives no release event when kwin finishes MOVE operation, // which makes app hang in windowMoving state. when a press happens, there's no sense of // keeping the moving state, we can just reset ti back to normal. if (event->type() == QEvent::MouseButtonPress) { self->m_windowMoving = false; } if (is_mouse_move && !event->isAccepted() && w->geometry().contains(static_cast(event)->globalPos())) { if (!self->m_windowMoving && self->m_enableSystemMove) { self->m_windowMoving = true; event->accept(); if (w && w->handle()) { #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) static_cast(w->handle())->startSystemMove(QCursor::pos()); #else static_cast(w->handle())->startSystemMove(); #endif } } } return true; } QMap DTreeLandPlatformWindowHelper::windowMap; DTreeLandPlatformWindowHelper *DTreeLandPlatformWindowHelper::get(QWindow *window) { if (!PersonalizationManager::instance()->isSupported()) { return nullptr; } if (!window) { return nullptr; } if (auto helper = windowMap.value(window)) { return helper; } auto helper = new DTreeLandPlatformWindowHelper(window); windowMap[window] = helper; return helper; } DTreeLandPlatformWindowHelper::DTreeLandPlatformWindowHelper(QWindow *window) : QObject(window) { window->installEventFilter(this); if (!PersonalizationManager::instance()->isActive()) { qWarning() << "Personalization is not active" << window; connect(PersonalizationManager::instance(), &PersonalizationManager::activeChanged, this, &DTreeLandPlatformWindowHelper::onActiveChanged, Qt::QueuedConnection); } if (window->handle()) { initWaylandWindow(); } } DTreeLandPlatformWindowHelper::~DTreeLandPlatformWindowHelper() { // see tst_qwindow.cpp tst_QWindow::qobject_castOnDestruction() windowMap.remove(static_cast(parent())); } bool DTreeLandPlatformWindowHelper::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::PlatformSurface) { QPlatformSurfaceEvent *se = static_cast(event); if (se->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { if (PersonalizationManager::instance()->isActive()) { initWaylandWindow(); onSurfaceCreated(); } } } return QObject::eventFilter(watched, event); } void DTreeLandPlatformWindowHelper::initWaylandWindow() { auto waylandWindow = dynamic_cast(window()->handle()); if (!waylandWindow) { qWarning() << "waylandWindow is nullptr!!!"; return; } connect(waylandWindow, &QtWaylandClient::QWaylandWindow::wlSurfaceCreated, this, &DTreeLandPlatformWindowHelper::onSurfaceCreated, Qt::UniqueConnection); connect(waylandWindow, &QtWaylandClient::QWaylandWindow::wlSurfaceDestroyed, this, &DTreeLandPlatformWindowHelper::onSurfaceDestroyed, Qt::UniqueConnection); } void DTreeLandPlatformWindowHelper::onActiveChanged() { if (PersonalizationManager::instance()->isActive()) { qDebug() << "Personalization is actived, window" << window(); if (window()->handle()) { onSurfaceCreated(); } } } void DTreeLandPlatformWindowHelper::onSurfaceCreated() { if (m_isNoTitlebar) { doSetEnabledNoTitlebar(); } if (m_radius > 0) { doSetWindowRadius(); } if (m_isWindowBlur) { doSetEnabledBlurWindow(); } } void DTreeLandPlatformWindowHelper::onSurfaceDestroyed() { if (m_windowContext) { m_windowContext->deleteLater(); m_windowContext = nullptr; } } PersonalizationWindowContext *DTreeLandPlatformWindowHelper::windowContext() const { if (m_windowContext) { return m_windowContext; } auto waylandWindow = dynamic_cast(window()->handle()); if (!waylandWindow) return nullptr; if (!waylandWindow->waylandSurface()) { qWarning() << "waylandSurface is nullptr!!!"; return nullptr; } auto surface = waylandWindow->waylandSurface()->object(); if (!surface) { qWarning() << "wl_surface is nullptr!!!"; return nullptr; } if (!m_windowContext) { const_cast(this)->m_windowContext = new PersonalizationWindowContext(PersonalizationManager::instance()->get_window_context(surface)); } return m_windowContext; } void DTreeLandPlatformWindowHelper::setEnabledNoTitlebar(bool enable) { m_isNoTitlebar = enable; doSetEnabledNoTitlebar(); } void DTreeLandPlatformWindowHelper::setWindowRadius(int windowRadius) { m_radius = windowRadius; doSetWindowRadius(); } void DTreeLandPlatformWindowHelper::setEnableBlurWindow(bool enableBlurWindow) { m_isWindowBlur = enableBlurWindow; doSetEnabledBlurWindow(); } void DTreeLandPlatformWindowHelper::doSetEnabledNoTitlebar() { if (auto context = windowContext()) { context->set_titlebar(m_isNoTitlebar ? PersonalizationWindowContext::enable_mode_disable : PersonalizationWindowContext::enable_mode_enable); } } void DTreeLandPlatformWindowHelper::doSetWindowRadius() { if (auto context = windowContext()) { context->set_round_corner_radius(m_radius); } } void DTreeLandPlatformWindowHelper::doSetEnabledBlurWindow() { if (auto context = windowContext()) { context->set_blend_mode(m_isWindowBlur ? PersonalizationWindowContext::blend_mode_blur : PersonalizationWindowContext::blend_mode_transparent); } } DTreeLandPlatformWindowInterface::DTreeLandPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent) : QObject(parent) , DPlatformWindowInterface(window, platformHandle) { if (!MoveWindowHelper::mapped.value(window)) { Q_UNUSED(new MoveWindowHelper(window)) } } DTreeLandPlatformWindowInterface::~DTreeLandPlatformWindowInterface() { } void DTreeLandPlatformWindowInterface::setEnabled(bool enabled) { if (setEnabledNoTitlebar(enabled)) { return; } } bool DTreeLandPlatformWindowInterface::isEnabled() const { return isEnabledNoTitlebar(); } bool DTreeLandPlatformWindowInterface::isEnabledNoTitlebar() const { return m_isNoTitlebar; } bool DTreeLandPlatformWindowInterface::setEnabledNoTitlebar(bool enable) { if (m_isNoTitlebar == enable) { return true; } m_isNoTitlebar = enable; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setEnabledNoTitlebar(enable); } return true; } int DTreeLandPlatformWindowInterface::windowRadius() const { return m_radius; } void DTreeLandPlatformWindowInterface::setWindowRadius(int windowRadius) { if (m_radius == windowRadius) { return; } m_radius = windowRadius; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setWindowRadius(m_radius); } if (m_platformHandle) { Q_EMIT m_platformHandle->windowRadiusChanged(); } } bool DTreeLandPlatformWindowInterface::enableBlurWindow() const { return m_isWindowBlur; } void DTreeLandPlatformWindowInterface::setEnableBlurWindow(bool enable) { if (m_isWindowBlur == enable) { return; } m_isWindowBlur = enable; if (auto helper = DTreeLandPlatformWindowHelper::get(m_window)) { helper->setEnableBlurWindow(enable); } if (m_platformHandle) { Q_EMIT m_platformHandle->enableBlurWindowChanged(); } } DGUI_END_NAMESPACE dtkgui-5.7.12/src/plugins/platform/treeland/dtreelandplatformwindowinterface.h000066400000000000000000000044501476226661100277760ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTREELANDPLATFORMWINDOWINTERFACE_H #define DTREELANDPLATFORMWINDOWINTERFACE_H #include "dtkgui_global.h" #include "dtreelandplatforminterface.h" #include #include #include "private/dplatformwindowinterface_p.h" DGUI_BEGIN_NAMESPACE class PersonalizationWindowContext; class DTreeLandPlatformWindowHelper : public QObject { Q_OBJECT public: static DTreeLandPlatformWindowHelper *get(QWindow *window); ~DTreeLandPlatformWindowHelper() override; QWindow *window() const { return qobject_cast(parent()); } PersonalizationWindowContext *windowContext() const; void setEnabledNoTitlebar(bool enable); void setWindowRadius(int windowRadius); void setEnableBlurWindow(bool enableBlurWindow); private slots: void onActiveChanged(); void onSurfaceCreated(); void onSurfaceDestroyed(); private: explicit DTreeLandPlatformWindowHelper(QWindow *window); bool eventFilter(QObject *watched, QEvent *event) override; void initWaylandWindow(); void doSetEnabledNoTitlebar(); void doSetWindowRadius(); void doSetEnabledBlurWindow(); private: PersonalizationWindowContext *m_windowContext = nullptr; static QMap windowMap; bool m_isNoTitlebar = false; bool m_isWindowBlur = false; int m_radius = 0; }; class DTreeLandPlatformWindowInterface : public QObject, public DPlatformWindowInterface { Q_OBJECT public: DTreeLandPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent = nullptr); ~DTreeLandPlatformWindowInterface() override; void setEnabled(bool enabled) override; bool isEnabled() const override; bool isEnabledNoTitlebar() const override; bool setEnabledNoTitlebar(bool enable) override; int windowRadius() const override; void setWindowRadius(int windowRadius) override; bool enableBlurWindow() const override; void setEnableBlurWindow(bool enableBlurWindow) override; private: bool m_isNoTitlebar = false; bool m_isWindowBlur = false; int m_radius = 0; }; DGUI_END_NAMESPACE #endif // DTREELANDPLATFORMWINDOWINTERFACE_H dtkgui-5.7.12/src/plugins/platform/treeland/dtreelandwindowmanagerhelper.cpp000066400000000000000000000015641476226661100274410ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtreelandwindowmanagerhelper.h" #include "personalizationwaylandclientextension.h" DGUI_BEGIN_NAMESPACE TreelandWindowManagerHelper::TreelandWindowManagerHelper(QObject *parent) : DWindowManagerHelper(parent) { connect(PersonalizationManager::instance(), &PersonalizationManager::activeChanged, this, [this](){ Q_EMIT hasBlurWindowChanged(); Q_EMIT hasNoTitlebarChanged(); }); } bool TreelandWindowManagerHelper::hasBlurWindow() const { return PersonalizationManager::instance()->isSupported(); } bool TreelandWindowManagerHelper::hasComposite() const { return true; } bool TreelandWindowManagerHelper::hasNoTitlebar() const { return PersonalizationManager::instance()->isSupported(); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/plugins/platform/treeland/dtreelandwindowmanagerhelper.h000066400000000000000000000011311476226661100270740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTREELANDWINDOWMANAGERHELPER_H #define DTREELANDWINDOWMANAGERHELPER_H #include "dtkgui_global.h" #include "dwindowmanagerhelper.h" #include DGUI_BEGIN_NAMESPACE class TreelandWindowManagerHelper : public DWindowManagerHelper { public: explicit TreelandWindowManagerHelper(QObject *parent = 0); bool hasBlurWindow() const; bool hasComposite() const; bool hasNoTitlebar() const; }; DGUI_END_NAMESPACE #endif // DTREELANDWINDOWMANAGERHELPER_H dtkgui-5.7.12/src/plugins/platform/treeland/personalizationwaylandclientextension.cpp000066400000000000000000000133041476226661100314440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "personalizationwaylandclientextension.h" #include #include #include #include #include "dplatformtheme.h" #include #include #include DGUI_BEGIN_NAMESPACE PersonalizationManager::PersonalizationManager() : QWaylandClientExtensionTemplate(treeland_personalization_manager_v1_interface.version) , m_isSupported(false) { QtWaylandClient::QWaylandIntegration *waylandIntegration = static_cast(QGuiApplicationPrivate::platformIntegration()); if (!waylandIntegration) { qWarning() << "waylandIntegration is nullptr!!!"; return; } m_waylandDisplay = waylandIntegration->display(); if (m_waylandDisplay == nullptr) { qWarning() << "waylandDisplay is nullptr!!!"; return; } addListener(); m_isSupported = m_waylandDisplay->hasRegistryGlobal(QString::fromUtf8(treeland_personalization_manager_v1_interface.name)); if (!m_isSupported) { qWarning() << "PersonalizationManager is not support"; } } void PersonalizationManager::addListener() { m_waylandDisplay->addRegistryListener(&handleListenerGlobal, this); } void PersonalizationManager::removeListener() { m_waylandDisplay->removeListener(&handleListenerGlobal, this); } void PersonalizationManager::handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version) { if (interface == treeland_personalization_manager_v1_interface.name) { PersonalizationManager *integration = static_cast(data); if (!integration) { qWarning() << "integration is nullptr!!!"; return; } integration->init(registry, id, version); } } PersonalizationManager *PersonalizationManager::instance() { static PersonalizationManager instance; return &instance; } PersonalizationWindowContext::PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context) : QWaylandClientExtensionTemplate(treeland_personalization_window_context_v1_interface.version) , QtWayland::treeland_personalization_window_context_v1(context) { } PersonalizationAppearanceContext::PersonalizationAppearanceContext(struct ::treeland_personalization_appearance_context_v1 *context, DTreelandPlatformInterface *interface) : QWaylandClientExtensionTemplate(treeland_personalization_appearance_context_v1_interface.version) , QtWayland::treeland_personalization_appearance_context_v1(context) , m_interface(interface) { get_round_corner_radius(); get_icon_theme(); get_active_color(); get_window_theme_type(); get_window_opacity(); } void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_round_corner_radius(int32_t radius) { m_interface->m_windowRadius = radius; emit m_interface->m_platformTheme->windowRadiusChanged(radius); } void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_icon_theme(const QString &theme_name) { m_interface->m_iconThemeName = theme_name.toUtf8(); emit m_interface->m_platformTheme->iconThemeNameChanged(theme_name.toUtf8()); } void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_active_color(const QString &active_color) { m_interface->m_activeColor = active_color; emit m_interface->m_platformTheme->activeColorChanged(active_color); } void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_window_theme_type(uint32_t type) { QString theme = QStringLiteral("deepin"); if (type == PersonalizationAppearanceContext::theme_type::theme_type_dark) { theme = theme + QStringLiteral("-dark"); } m_interface->m_themeName = theme.toUtf8(); emit m_interface->m_platformTheme->themeNameChanged(theme.toUtf8()); } void PersonalizationAppearanceContext::treeland_personalization_appearance_context_v1_window_opacity(uint32_t opacity) { m_interface->m_blurOpacity = opacity; } PersonalizationFontContext::PersonalizationFontContext(struct ::treeland_personalization_font_context_v1 *context, DTreelandPlatformInterface *interface) : QWaylandClientExtensionTemplate(treeland_personalization_font_context_v1_interface.version) , QtWayland::treeland_personalization_font_context_v1(context) , m_interface(interface) { get_font(); get_monospace_font(); get_font_size(); } void PersonalizationFontContext::treeland_personalization_font_context_v1_font(const QString &font_name) { m_interface->m_fontName = font_name.toUtf8(); emit m_interface->m_platformTheme->fontNameChanged(font_name.toUtf8()); } void PersonalizationFontContext::treeland_personalization_font_context_v1_monospace_font(const QString &font_name) { m_interface->m_monoFontName = font_name.toUtf8(); emit m_interface->m_platformTheme->monoFontNameChanged(font_name.toUtf8()); } void PersonalizationFontContext::treeland_personalization_font_context_v1_font_size(uint32_t font_size) { // treeland侧无法存储浮点数,约定 font_size 为 10 倍的 pointSize qreal pointSize = font_size / 10.0; pointSize = qBound(8.25, pointSize, 15.00); m_interface->m_fontPointSize = pointSize; emit m_interface->m_platformTheme->fontPointSizeChanged(pointSize); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/plugins/platform/treeland/personalizationwaylandclientextension.h000066400000000000000000000065101476226661100311120ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef PERSONALIZATIONWAYLANDCLIENTEXTENSION_H #define PERSONALIZATIONWAYLANDCLIENTEXTENSION_H #include "dtreelandplatforminterface.h" #include "qwayland-treeland-personalization-manager-v1.h" #include #include #include #include DGUI_BEGIN_NAMESPACE class PersonalizationAppearanceContext; class PersonalizationCursorContext; class PersonalizationFontContext; class DTreelandPlatformInterfacePrivate; class PersonalizationManager: public QWaylandClientExtensionTemplate, public QtWayland::treeland_personalization_manager_v1 { Q_OBJECT public: static PersonalizationManager *instance(); [[nodiscard]]inline bool isSupported() const { return m_isSupported; } private: void addListener(); void removeListener(); explicit PersonalizationManager(); static void handleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version); private: QtWaylandClient::QWaylandDisplay *m_waylandDisplay; bool m_isSupported; }; class PersonalizationWindowContext : public QWaylandClientExtensionTemplate, public QtWayland::treeland_personalization_window_context_v1 { Q_OBJECT public: explicit PersonalizationWindowContext(struct ::treeland_personalization_window_context_v1 *context); }; class PersonalizationAppearanceContext : public QWaylandClientExtensionTemplate, public QtWayland::treeland_personalization_appearance_context_v1 { Q_OBJECT public: explicit PersonalizationAppearanceContext(struct ::treeland_personalization_appearance_context_v1 *context, DTreelandPlatformInterface *interface); protected: void treeland_personalization_appearance_context_v1_round_corner_radius(int32_t radius) override; void treeland_personalization_appearance_context_v1_icon_theme(const QString &theme_name) override; void treeland_personalization_appearance_context_v1_active_color(const QString &active_color) override; void treeland_personalization_appearance_context_v1_window_theme_type(uint32_t type) override; void treeland_personalization_appearance_context_v1_window_opacity(uint32_t opacity) override; private: DTreelandPlatformInterface *m_interface; }; class PersonalizationFontContext : public QWaylandClientExtensionTemplate, public QtWayland::treeland_personalization_font_context_v1 { Q_OBJECT public: explicit PersonalizationFontContext(struct ::treeland_personalization_font_context_v1 *context, DTreelandPlatformInterface *interface); protected: void treeland_personalization_font_context_v1_font(const QString &font_name) override; void treeland_personalization_font_context_v1_monospace_font(const QString &font_name) override; void treeland_personalization_font_context_v1_font_size(uint32_t font_size) override; private: DTreelandPlatformInterface *m_interface; }; DGUI_END_NAMESPACE #endif // PERSONALIZATIONWAYLANDCLIENTEXTENSION_H dtkgui-5.7.12/src/plugins/platform/treeland/treeland.cmake000066400000000000000000000003001476226661100235730ustar00rootroot00000000000000file(GLOB TREELAND_HEADER ${CMAKE_CURRENT_LIST_DIR}/*.h ) file(GLOB TREELAND_SOURCE ${CMAKE_CURRENT_LIST_DIR}/*.cpp ) set(treeland_SRC ${TREELAND_HEADER} ${TREELAND_SOURCE} ) dtkgui-5.7.12/src/plugins/platform/xcb/000077500000000000000000000000001476226661100177605ustar00rootroot00000000000000dtkgui-5.7.12/src/plugins/platform/xcb/dxcbplatforminterface.cpp000066400000000000000000000401071476226661100250340ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dxcbplatforminterface.h" #include "dxcbplatforminterface_p.h" #include #include #include #include #include #include "dplatformtheme.h" #include "dguiapplicationhelper.h" #include DGUI_BEGIN_NAMESPACE #define DEFINE_CONST_CHAR(Name) const char _##Name[] = "_d_" #Name #define FETCH_PROPERTY(Name, Function) \ D_DC(DXCBPlatformInterface); \ QVariant value = d->theme->getSetting(QByteArrayLiteral(Name)); \ if (d->fallbackProperty && !value.isValid() && d->parent) \ return d->parent->Function(); \ #define FETCH_PROPERTY_WITH_ARGS(Name, Function, Args) \ D_DC(DXCBPlatformInterface); \ QVariant value = d->theme->getSetting(Name); \ if (d->fallbackProperty && !value.isValid() && d->parent) \ return d->parent->Function(Args); \ DXCBPlatformInterfacePrivate::DXCBPlatformInterfacePrivate(DXCBPlatformInterface *qq) :DCORE_NAMESPACE::DObjectPrivate(qq) { } void DXCBPlatformInterfacePrivate::_q_onThemePropertyChanged(const QByteArray &name, const QVariant &value) { D_Q(DXCBPlatformInterface); // 转发属性变化的信号,此信号来源可能为parent theme或“非调色板”的属性变化。 // 使用队列的形式转发,避免多次发出同样的信号 // q->staticMetaObject.invokeMethod(q, "propertyChanged", Qt::QueuedConnection, // Q_ARG(const QByteArray&, name), Q_ARG(const QVariant&, value)); if (QByteArrayLiteral("Gtk/FontName") == name) { Q_EMIT q->m_platformTheme->gtkFontNameChanged(value.toByteArray()); return; } if (name.startsWith("Qt/DPI/")) { const QString &screen_name = QString::fromLocal8Bit(name.mid(7)); if (!screen_name.isEmpty()) { bool ok = false; int dpi = value.toInt(&ok); Q_EMIT q->m_platformTheme->dotsPerInchChanged(screen_name, ok ? dpi : -1); } return; } if (QByteArrayLiteral("Xft/DPI") == name) { bool ok = false; int dpi = value.toInt(&ok); Q_EMIT q->m_platformTheme->dotsPerInchChanged(QString(), ok ? dpi : -1); } const QByteArrayList &list = name.split('/'); if (list.count() != 2) return; QByteArray pn = list.last(); if (pn.isEmpty()) return; // 转换首字母为小写 pn[0] = QChar(pn.at(0)).toLower().toLatin1(); // 直接使用静态的meta object,防止通过metaObject函数调用到dynamic metaobject const QMetaObject *mo = &DPlatformTheme::staticMetaObject; int index = mo->indexOfProperty(pn.constData()); if (index < 0) return; const QMetaProperty &p = mo->property(index); bool is_parent_signal = q->sender() != theme; // 当自己的属性有效时应该忽略父主题的属性变化信号,优先以自身的属性值为准。 if (is_parent_signal && p.read(q).isValid()) { return; } if (p.hasNotifySignal()) { // invoke会做Q_ASSERT(mobj->cast(object))判断, DPlatformTheme的dynamic metaObject为 // qt5platform-plugin插件的DNativeSettings. 导致崩溃. // invokeOnGadget与invoke代码逻辑一致, 只是少了异步支持. // return; if (!p.notifySignal().invokeOnGadget(q->m_platformTheme, QGenericArgument(value.typeName(), value.constData()))) qWarning() << "_q_onThemePropertyChanged() error when notify signal" << p.notifySignal().name(); } } DXCBPlatformInterface::DXCBPlatformInterface(quint32 window, DPlatformTheme *platformTheme) : DPlatformInterface(platformTheme) , Core::DObject(*new DXCBPlatformInterfacePrivate(this)) { D_D(DXCBPlatformInterface); d->theme = new DNativeSettings(window, QByteArray(), platformTheme); connect(d->theme, SIGNAL(propertyChanged(const QByteArray &, const QVariant &)), this, SLOT(_q_onThemePropertyChanged(const QByteArray &, const QVariant &))); } int DXCBPlatformInterface::cursorBlinkTime() const { FETCH_PROPERTY("Net/CursorBlinkTime", cursorBlinkTime) return value.toInt(); } int DXCBPlatformInterface::cursorBlinkTimeout() const { FETCH_PROPERTY("Net/CursorBlinkTimeout", cursorBlinkTimeout) return value.toInt(); } bool DXCBPlatformInterface::cursorBlink() const { FETCH_PROPERTY("Net/CursorBlink", cursorBlink) return value.toInt(); } int DXCBPlatformInterface::doubleClickDistance() const { FETCH_PROPERTY("Net/DoubleClickDistance", doubleClickDistance) return value.toInt(); } int DXCBPlatformInterface::doubleClickTime() const { FETCH_PROPERTY("Net/DoubleClickTime", doubleClickTime) return value.toInt(); } int DXCBPlatformInterface::dndDragThreshold() const { FETCH_PROPERTY("Net/DndDragThreshold", dndDragThreshold) return value.toInt(); } int DXCBPlatformInterface::windowRadius() const { return windowRadius(-1); } int DXCBPlatformInterface::windowRadius(int defaultValue) const { Q_D(const DXCBPlatformInterface); QVariant value = d->theme->getSetting(QByteArrayLiteral("DTK/WindowRadius")); bool ok = false; if (d->fallbackProperty && !value.isValid() && d->parent) return d->parent->windowRadius(defaultValue); int radius = value.toInt(&ok); return ok ? radius : defaultValue; } QByteArray DXCBPlatformInterface::themeName() const { FETCH_PROPERTY("Net/ThemeName", themeName) return value.toByteArray(); } QByteArray DXCBPlatformInterface::iconThemeName() const { FETCH_PROPERTY("Net/IconThemeName", iconThemeName) return value.toByteArray(); } QByteArray DXCBPlatformInterface::soundThemeName() const { FETCH_PROPERTY("Net/SoundThemeName", soundThemeName) return value.toByteArray(); } QByteArray DXCBPlatformInterface::fontName() const { FETCH_PROPERTY("Qt/FontName", fontName) return value.toByteArray(); } QByteArray DXCBPlatformInterface::monoFontName() const { FETCH_PROPERTY("Qt/MonoFontName", monoFontName) return value.toByteArray(); } qreal DXCBPlatformInterface::fontPointSize() const { FETCH_PROPERTY("Qt/FontPointSize", fontPointSize) return value.toDouble(); } QByteArray DXCBPlatformInterface::gtkFontName() const { FETCH_PROPERTY("Gtk/FontName", gtkFontName) return value.toByteArray(); } QColor DXCBPlatformInterface::activeColor() const { FETCH_PROPERTY("Qt/ActiveColor", activeColor) return qvariant_cast(value); } QColor DXCBPlatformInterface::darkActiveColor() const { FETCH_PROPERTY("Qt/DarkActiveColor", darkActiveColor) return qvariant_cast(value); } static QColor getSetting(const QByteArray &key) { qWarning() << "Not implemented, key:" << key; return {}; } #define GET_COLOR(Role) qvariant_cast(getSetting(QByteArrayLiteral(#Role))) #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QColor DXCBPlatformInterface::window() const { return GET_COLOR(window); } QColor DXCBPlatformInterface::windowText() const { return GET_COLOR(windowText); } QColor DXCBPlatformInterface::base() const { return GET_COLOR(base); } QColor DXCBPlatformInterface::alternateBase() const { return GET_COLOR(alternateBase); } QColor DXCBPlatformInterface::toolTipBase() const { return GET_COLOR(toolTipBase); } QColor DXCBPlatformInterface::toolTipText() const { return GET_COLOR(toolTipText); } QColor DXCBPlatformInterface::text() const { return GET_COLOR(text); } QColor DXCBPlatformInterface::button() const { return GET_COLOR(button); } QColor DXCBPlatformInterface::buttonText() const { return GET_COLOR(buttonText); } QColor DXCBPlatformInterface::brightText() const { return GET_COLOR(brightText); } QColor DXCBPlatformInterface::light() const { return GET_COLOR(light); } QColor DXCBPlatformInterface::midlight() const { return GET_COLOR(midlight); } QColor DXCBPlatformInterface::dark() const { return GET_COLOR(dark); } QColor DXCBPlatformInterface::mid() const { return GET_COLOR(mid); } QColor DXCBPlatformInterface::shadow() const { return GET_COLOR(shadow); } QColor DXCBPlatformInterface::highlight() const { return GET_COLOR(highlight); } QColor DXCBPlatformInterface::highlightedText() const { return GET_COLOR(highlightedText); } QColor DXCBPlatformInterface::link() const { return GET_COLOR(link); } QColor DXCBPlatformInterface::linkVisited() const { return GET_COLOR(linkVisited); } QColor DXCBPlatformInterface::itemBackground() const { return GET_COLOR(itemBackground); } QColor DXCBPlatformInterface::textTitle() const { return GET_COLOR(textTitle); } QColor DXCBPlatformInterface::textTips() const { return GET_COLOR(textTips); } QColor DXCBPlatformInterface::textWarning() const { return GET_COLOR(textWarning); } QColor DXCBPlatformInterface::textLively() const { return GET_COLOR(textLively); } QColor DXCBPlatformInterface::lightLively() const { return GET_COLOR(lightLively); } QColor DXCBPlatformInterface::darkLively() const { return GET_COLOR(darkLively); } QColor DXCBPlatformInterface::frameBorder() const { return GET_COLOR(frameBorder); } #endif int DXCBPlatformInterface::dotsPerInch(const QString &screenName) const { bool ok = false; if (!screenName.isEmpty()) { FETCH_PROPERTY_WITH_ARGS("Qt/DPI/" + screenName.toLocal8Bit(), dotsPerInch, screenName); int dpi = value.toInt(&ok); if (ok) return dpi; } FETCH_PROPERTY_WITH_ARGS("Xft/DPI", dotsPerInch, screenName); int dpi = value.toInt(&ok); return ok ? dpi : -1; } /*! \property DXCBPlatformInterface::sizeMode \brief This property holds the sizeMode of the system's SizeMode. */ int DXCBPlatformInterface::sizeMode() const { D_DC(DXCBPlatformInterface); QVariant value = d->theme->getSetting(QByteArrayLiteral("DTK/SizeMode")); return value.toInt(); } /*! \property DXCBPlatformInterface::scrollBarPolicy \brief This property holds the scrollBarPolicy of the system. same as Qt::ScrollBarPolicy \retval 0 show as needed auto hide, default \retval 1 always off \retval 2 always on */ int DXCBPlatformInterface::scrollBarPolicy() const { FETCH_PROPERTY("Qt/ScrollBarPolicy", scrollBarPolicy) return qvariant_cast(value); } void DXCBPlatformInterface::setCursorBlinkTime(int cursorBlinkTime) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/CursorBlinkTime", cursorBlinkTime); } void DXCBPlatformInterface::setCursorBlinkTimeout(int cursorBlinkTimeout) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/CursorBlinkTimeout", cursorBlinkTimeout); } void DXCBPlatformInterface::setCursorBlink(bool cursorBlink) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/CursorBlink", cursorBlink); } void DXCBPlatformInterface::setDoubleClickDistance(int doubleClickDistance) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/DoubleClickDistance", doubleClickDistance); } void DXCBPlatformInterface::setDoubleClickTime(int doubleClickTime) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/DoubleClickTime", doubleClickTime); } void DXCBPlatformInterface::setDndDragThreshold(int dndDragThreshold) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/DndDragThreshold", dndDragThreshold); } void DXCBPlatformInterface::setThemeName(const QByteArray &themeName) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/ThemeName", themeName); } void DXCBPlatformInterface::setIconThemeName(const QByteArray &iconThemeName) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/IconThemeName", iconThemeName); } void DXCBPlatformInterface::setSoundThemeName(const QByteArray &soundThemeName) { D_D(DXCBPlatformInterface); d->theme->setSetting("Net/SoundThemeName", soundThemeName); } void DXCBPlatformInterface::setFontName(const QByteArray &fontName) { D_D(DXCBPlatformInterface); d->theme->setSetting("Qt/FontName", fontName); } void DXCBPlatformInterface::setMonoFontName(const QByteArray &monoFontName) { D_D(DXCBPlatformInterface); d->theme->setSetting("Qt/MonoFontName", monoFontName); } void DXCBPlatformInterface::setFontPointSize(qreal fontPointSize) { D_D(DXCBPlatformInterface); d->theme->setSetting("Qt/FontPointSize", fontPointSize); } void DXCBPlatformInterface::setGtkFontName(const QByteArray &fontName) { D_D(DXCBPlatformInterface); d->theme->setSetting("Gtk/FontName", fontName); } void DXCBPlatformInterface::setActiveColor(const QColor activeColor) { D_D(DXCBPlatformInterface); d->theme->setSetting("Qt/ActiveColor", activeColor); } void DXCBPlatformInterface::setDarkActiveColor(const QColor &activeColor) { D_D(DXCBPlatformInterface); d->theme->setSetting("Qt/DarkActiveColor", activeColor); } static void setSetting(const QByteArray &key, const QColor &color) { qWarning() << "Not implemented, key: " << key << "value: " << color; } #define SET_COLOR(Role) setSetting(QByteArrayLiteral(#Role), Role) #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) void DXCBPlatformInterface::setWindow(const QColor &window) { SET_COLOR(window); } void DXCBPlatformInterface::setWindowText(const QColor &windowText) { SET_COLOR(windowText); } void DXCBPlatformInterface::setBase(const QColor &base) { SET_COLOR(base); } void DXCBPlatformInterface::setAlternateBase(const QColor &alternateBase) { SET_COLOR(alternateBase); } void DXCBPlatformInterface::setToolTipBase(const QColor &toolTipBase) { SET_COLOR(toolTipBase); } void DXCBPlatformInterface::setToolTipText(const QColor &toolTipText) { SET_COLOR(toolTipText); } void DXCBPlatformInterface::setText(const QColor &text) { SET_COLOR(text); } void DXCBPlatformInterface::setButton(const QColor &button) { SET_COLOR(button); } void DXCBPlatformInterface::setButtonText(const QColor &buttonText) { SET_COLOR(buttonText); } void DXCBPlatformInterface::setBrightText(const QColor &brightText) { SET_COLOR(brightText); } void DXCBPlatformInterface::setLight(const QColor &light) { SET_COLOR(light); } void DXCBPlatformInterface::setMidlight(const QColor &midlight) { SET_COLOR(midlight); } void DXCBPlatformInterface::setDark(const QColor &dark) { SET_COLOR(dark); } void DXCBPlatformInterface::setMid(const QColor &mid) { SET_COLOR(mid); } void DXCBPlatformInterface::setShadow(const QColor &shadow) { SET_COLOR(shadow); } void DXCBPlatformInterface::setHighlight(const QColor &highlight) { SET_COLOR(highlight); } void DXCBPlatformInterface::setHighlightedText(const QColor &highlightText) { SET_COLOR(highlightText); } void DXCBPlatformInterface::setLink(const QColor &link) { SET_COLOR(link); } void DXCBPlatformInterface::setLinkVisited(const QColor &linkVisited) { SET_COLOR(linkVisited); } void DXCBPlatformInterface::setItemBackground(const QColor &itemBackground) { SET_COLOR(itemBackground); } void DXCBPlatformInterface::setTextTitle(const QColor &textTitle) { SET_COLOR(textTitle); } void DXCBPlatformInterface::setTextTips(const QColor &textTips) { SET_COLOR(textTips); } void DXCBPlatformInterface::setTextWarning(const QColor &textWarning) { SET_COLOR(textWarning); } void DXCBPlatformInterface::setTextLively(const QColor &textLively) { SET_COLOR(textLively); } void DXCBPlatformInterface::setLightLively(const QColor &lightLively) { SET_COLOR(lightLively); } void DXCBPlatformInterface::setDarkLively(const QColor &darkLively) { SET_COLOR(darkLively); } void DXCBPlatformInterface::setFrameBorder(const QColor &frameBorder) { SET_COLOR(frameBorder); } #endif void DXCBPlatformInterface::setDotsPerInch(const QString &screenName, int dpi) { D_D(DXCBPlatformInterface); if (screenName.isEmpty()) { d->theme->setSetting("Xft/DPI", dpi); } else { d->theme->setSetting("Qt/DPI/" + screenName.toLocal8Bit(), dpi); } } void DXCBPlatformInterface::setWindowRadius(int windowRadius) { D_D(DXCBPlatformInterface); d->theme->setSetting("DTK/WindowRadius", windowRadius); } DGUI_END_NAMESPACE #include "moc_dxcbplatforminterface.cpp" dtkgui-5.7.12/src/plugins/platform/xcb/dxcbplatforminterface.h000066400000000000000000000124621476226661100245040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DXCBPLATFORMINTERFACE_H #define DXCBPLATFORMINTERFACE_H #include "private/dplatforminterface_p.h" #include DGUI_BEGIN_NAMESPACE class DXCBPlatformInterfacePrivate; class DXCBPlatformInterface : public QObject, public DPlatformInterface, public DCORE_NAMESPACE::DObject { Q_OBJECT D_DECLARE_PRIVATE(DXCBPlatformInterface) public: explicit DXCBPlatformInterface(quint32 window, DPlatformTheme *platformTheme); int cursorBlinkTime() const override; int cursorBlinkTimeout() const override; bool cursorBlink() const override; int doubleClickDistance() const override; int doubleClickTime() const override; int dndDragThreshold() const override; int windowRadius() const override; int windowRadius(int defaultValue) const override; QByteArray themeName() const override; QByteArray iconThemeName() const override; QByteArray soundThemeName() const override; QByteArray fontName() const override; QByteArray monoFontName() const override; qreal fontPointSize() const override; QByteArray gtkFontName() const override; QColor activeColor() const override; QColor darkActiveColor() const override; #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QColor window() const override; QColor windowText() const override; QColor base() const override; QColor alternateBase() const override; QColor toolTipText() const override; QColor toolTipBase() const override; QColor text() const override; QColor button() const override; QColor buttonText() const override; QColor brightText() const override; QColor light() const override; QColor midlight() const override; QColor dark() const override; QColor mid() const override; QColor shadow() const override; QColor highlight() const override; QColor highlightedText() const override; QColor link() const override; QColor linkVisited() const override; QColor itemBackground() const override; QColor textTitle() const override; QColor textTips() const override; QColor textWarning() const override; QColor textLively() const override; QColor lightLively() const override; QColor darkLively() const override; QColor frameBorder() const override; #endif int sizeMode() const override; int scrollBarPolicy() const override; public Q_SLOTS: void setCursorBlinkTime(int cursorBlinkTime) override; void setCursorBlinkTimeout(int cursorBlinkTimeout) override; void setCursorBlink(bool cursorBlink) override; void setDoubleClickDistance(int doubleClickDistance) override; void setDoubleClickTime(int doubleClickTime) override; void setDndDragThreshold(int dndDragThreshold) override; void setThemeName(const QByteArray &themeName) override; void setIconThemeName(const QByteArray &iconThemeName) override; void setSoundThemeName(const QByteArray &soundThemeName) override; void setFontName(const QByteArray &fontName) override; void setMonoFontName(const QByteArray &monoFontName) override; void setFontPointSize(qreal fontPointSize) override; void setGtkFontName(const QByteArray &fontName) override; void setActiveColor(const QColor activeColor) override; void setDarkActiveColor(const QColor &activeColor) override; #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) void setWindow(const QColor &window) override; void setWindowText(const QColor &windowText) override; void setBase(const QColor &base) override; void setAlternateBase(const QColor &alternateBase) override; void setToolTipBase(const QColor &toolTipBase) override; void setToolTipText(const QColor &toolTipText) override; void setText(const QColor &text) override; void setButton(const QColor &button) override; void setButtonText(const QColor &buttonText) override; void setBrightText(const QColor &brightText) override; void setLight(const QColor &light) override; void setMidlight(const QColor &midlight) override; void setDark(const QColor &dark) override; void setMid(const QColor &mid) override; void setShadow(const QColor &shadow) override; void setHighlight(const QColor &highlight) override; void setHighlightedText(const QColor &highlightedText) override; void setLink(const QColor &link) override; void setLinkVisited(const QColor &linkVisited) override; void setItemBackground(const QColor &itemBackground) override; void setTextTitle(const QColor &textTitle) override; void setTextTips(const QColor &textTips) override; void setTextWarning(const QColor &textWarning) override; void setTextLively(const QColor &textLively) override; void setLightLively(const QColor &lightLively) override; void setDarkLively(const QColor &darkLively) override; void setFrameBorder(const QColor &frameBorder) override; #endif int dotsPerInch(const QString &screenName = QString()) const override; void setDotsPerInch(const QString &screenName, int dpi) override; void setWindowRadius(int windowRadius) override; private: friend class DPlatformThemePrivate; D_PRIVATE_SLOT(void _q_onThemePropertyChanged(const QByteArray &name, const QVariant &value)) }; DGUI_END_NAMESPACE #endif // DXCBPLATFORMINTERFACE_H dtkgui-5.7.12/src/plugins/platform/xcb/dxcbplatforminterface_p.h000066400000000000000000000015351476226661100250220ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DXCBPLATFORMINTERFACE_P_H #define DXCBPLATFORMINTERFACE_P_H #include "dxcbplatforminterface.h" #include "private/dplatforminterface_p.h" #include #include DGUI_BEGIN_NAMESPACE class DNativeSettings; class DPlatformTheme; class DXCBPlatformInterfacePrivate : public DCORE_NAMESPACE::DObjectPrivate { public: D_DECLARE_PUBLIC(DXCBPlatformInterface) DXCBPlatformInterfacePrivate(DXCBPlatformInterface *qq); void _q_onThemePropertyChanged(const QByteArray &name, const QVariant &value); public: DPlatformTheme *parent = nullptr; bool fallbackProperty = true; DNativeSettings *theme; QHash m_properties; }; DGUI_END_NAMESPACE #endif // DNATIVESETTINGS_P_H dtkgui-5.7.12/src/plugins/platform/xcb/dxcbplatformwindowinterface.cpp000066400000000000000000000544251476226661100262740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dxcbplatformwindowinterface.h" #include "dguiapplicationhelper.h" #include "dplatformtheme.h" #include "dwindowmanagerhelper.h" #include #include #include #include DGUI_BEGIN_NAMESPACE #define DXCB_PLUGIN_KEY "dxcb" #define DXCB_PLUGIN_SYMBOLIC_PROPERTY "_d_isDxcb" #define DEFINE_CONST_CHAR(Name) const char _##Name[] = "_d_" #Name DEFINE_CONST_CHAR(useDxcb); DEFINE_CONST_CHAR(redirectContent); DEFINE_CONST_CHAR(netWmStates); DEFINE_CONST_CHAR(windowRadius); DEFINE_CONST_CHAR(borderWidth); DEFINE_CONST_CHAR(borderColor); DEFINE_CONST_CHAR(windowEffect); DEFINE_CONST_CHAR(windowStartUpEffect); DEFINE_CONST_CHAR(shadowRadius); DEFINE_CONST_CHAR(shadowOffset); DEFINE_CONST_CHAR(shadowColor); DEFINE_CONST_CHAR(clipPath); DEFINE_CONST_CHAR(frameMask); DEFINE_CONST_CHAR(frameMargins); DEFINE_CONST_CHAR(translucentBackground); DEFINE_CONST_CHAR(enableSystemResize); DEFINE_CONST_CHAR(enableSystemMove); DEFINE_CONST_CHAR(enableBlurWindow); DEFINE_CONST_CHAR(windowBlurAreas); DEFINE_CONST_CHAR(windowBlurPaths); DEFINE_CONST_CHAR(windowWallpaperParas); DEFINE_CONST_CHAR(autoInputMaskByClipPath); DEFINE_CONST_CHAR(resolve_mask); enum PropRole { WindowRadius, // TO BE CONTINUE }; // functions DEFINE_CONST_CHAR(setWmBlurWindowBackgroundArea); DEFINE_CONST_CHAR(setWmBlurWindowBackgroundPathList); DEFINE_CONST_CHAR(setWmBlurWindowBackgroundMaskImage); DEFINE_CONST_CHAR(setWmWallpaperParameter); DEFINE_CONST_CHAR(setWindowProperty); DEFINE_CONST_CHAR(pluginVersion); DEFINE_CONST_CHAR(disableOverrideCursor); DEFINE_CONST_CHAR(enableDxcb); DEFINE_CONST_CHAR(isEnableDxcb); DEFINE_CONST_CHAR(setEnableNoTitlebar); DEFINE_CONST_CHAR(isEnableNoTitlebar); DEFINE_CONST_CHAR(clientLeader); static void resolve(QObject *obj, PropRole role) { int mask = obj->property(_resolve_mask).toInt(); obj->setProperty(_resolve_mask, (mask |= 1 << role)); } static bool resolved(QObject *obj, PropRole role) { int mask = obj->property(_resolve_mask).toInt(); return mask & (1 << role); } static void setWindowProperty(QWindow *window, const char *name, const QVariant &value) { if (!window) return; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) static QFunctionPointer setWindowProperty = qApp->platformFunction(_setWindowProperty); #else constexpr QFunctionPointer setWindowProperty = nullptr; #endif if (!setWindowProperty) { window->setProperty(name, value); return; } reinterpret_cast(setWindowProperty)(window, name, value); } DXCBPlatformWindowInterface::DXCBPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent) : QObject(parent) , DPlatformWindowInterface(window, platformHandle) { if (window) { window->installEventFilter(this); } } DXCBPlatformWindowInterface::~DXCBPlatformWindowInterface() { } QString DXCBPlatformWindowInterface::pluginVersion() { QFunctionPointer pv = 0; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) pv = qApp->platformFunction(_pluginVersion); #endif if (Q_UNLIKELY(!pv)) return QString(); return reinterpret_cast(pv)(); } bool DXCBPlatformWindowInterface::isDXcbPlatform() { if (!qApp) return false; static bool _is_dxcb = qApp->platformName() == DXCB_PLUGIN_KEY || qApp->property(DXCB_PLUGIN_SYMBOLIC_PROPERTY).toBool(); return _is_dxcb; } bool DXCBPlatformWindowInterface::connectWindowManagerChangedSignal(QObject *object, std::function slot) { if (object) { return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::windowManagerChanged, object, slot); } return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::windowManagerChanged, slot); } bool DXCBPlatformWindowInterface::connectHasBlurWindowChanged(QObject *object, std::function slot) { if (object) { return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::hasBlurWindowChanged, object, slot); } return QObject::connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::hasBlurWindowChanged, slot); } WId DXCBPlatformWindowInterface::windowLeader() { QFunctionPointer clientLeader = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) clientLeader = qApp->platformFunction(_clientLeader); #endif if (!clientLeader) { return 0; } return reinterpret_cast(clientLeader)(); } void DXCBPlatformWindowInterface::setEnabled(bool enabled) { // 优先使用窗口管理器中实现的no titlebar接口实现自定义窗口修饰器的效果 if (setEnabledNoTitlebar(enabled)) { return; } if (!isDXcbPlatform()) return; QFunctionPointer enable_dxcb = nullptr; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) enable_dxcb = qApp->platformFunction(_enableDxcb); #endif if (enable_dxcb) { (*reinterpret_cast(enable_dxcb))(m_window); } else if (m_window->handle()) { Q_ASSERT_X(m_window->property(_useDxcb).toBool(), "DXCBPlatformWindowInterfacer:", "Must be called before window handle has been created. See also QWindow::handle()"); } else { m_window->setProperty(_useDxcb, enabled); } } void DXCBPlatformWindowInterface::enableDXcb(bool redirectContent) { m_window->setProperty(_redirectContent, redirectContent); setEnabled(true); } bool DXCBPlatformWindowInterface::isEnabled() const { if (isEnabledNoTitlebar()) return true; QFunctionPointer is_enable_dxcb = nullptr; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) is_enable_dxcb = qApp->platformFunction(_isEnableDxcb); #endif if (is_enable_dxcb) { return (*reinterpret_cast(is_enable_dxcb))(m_window); } return m_window->property(_useDxcb).toBool(); } bool DXCBPlatformWindowInterface::eventFilter(QObject *obj, QEvent *event) { if (obj == m_window && m_platformHandle) { if (event->type() == QEvent::DynamicPropertyChange) { QDynamicPropertyChangeEvent *e = static_cast(event); if (e->propertyName() == _windowRadius) { Q_EMIT m_platformHandle->windowRadiusChanged(); } else if (e->propertyName() == _borderWidth) { Q_EMIT m_platformHandle->borderWidthChanged(); } else if (e->propertyName() == _borderColor) { Q_EMIT m_platformHandle->borderColorChanged(); } else if (e->propertyName() == _shadowRadius) { Q_EMIT m_platformHandle->shadowRadiusChanged(); } else if (e->propertyName() == _shadowOffset) { Q_EMIT m_platformHandle->shadowOffsetChanged(); } else if (e->propertyName() == _shadowColor) { Q_EMIT m_platformHandle->shadowColorChanged(); } else if (e->propertyName() == _clipPath) { Q_EMIT m_platformHandle->clipPathChanged(); } else if (e->propertyName() == _frameMask) { Q_EMIT m_platformHandle->frameMaskChanged(); } else if (e->propertyName() == _frameMargins) { Q_EMIT m_platformHandle->frameMarginsChanged(); } else if (e->propertyName() == _translucentBackground) { Q_EMIT m_platformHandle->translucentBackgroundChanged(); } else if (e->propertyName() == _enableSystemResize) { Q_EMIT m_platformHandle->enableSystemResizeChanged(); } else if (e->propertyName() == _enableSystemMove) { Q_EMIT m_platformHandle->enableSystemMoveChanged(); } else if (e->propertyName() == _enableBlurWindow) { Q_EMIT m_platformHandle->enableBlurWindowChanged(); } else if (e->propertyName() == _autoInputMaskByClipPath) { Q_EMIT m_platformHandle->autoInputMaskByClipPathChanged(); } } } return QObject::eventFilter(obj, event); } static void initWindowRadius(QWindow *window) { if (window->property(_windowRadius).isValid()) return; auto theme = DGuiApplicationHelper::instance()->systemTheme(); int radius = theme->windowRadius(12); //###(zccrs): 暂时在此处给窗口默认设置为12px的圆角 setWindowProperty(window, _windowRadius, radius); // Qt::UniqueConnection will report a warning // to `unique connections require a pointer to member function of a QObject subclass`. const char *uniqueueConnectionFlag("_d_uniqueueConnectionFlag"); bool connected = window->property(uniqueueConnectionFlag).toBool(); if (!connected) { window->setProperty(uniqueueConnectionFlag, true); window->connect(theme, &DPlatformTheme::windowRadiusChanged, window, [window] (int radius) { if (!resolved(window, PropRole::WindowRadius)) setWindowProperty(window, _windowRadius, radius); }); } } class Q_DECL_HIDDEN CreatorWindowEventFilter : public QObject { public: CreatorWindowEventFilter(QObject *par= nullptr): QObject(par){} public: bool eventFilter(QObject *watched, QEvent *event) override { if (event->type() == QEvent::PlatformSurface) { QPlatformSurfaceEvent *se = static_cast(event); if (se->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { // 若收到此信号, 则 WinID 已被创建 auto window = qobject_cast(watched); initWindowRadius(window); } } return QObject::eventFilter(watched, event); } }; bool DXCBPlatformWindowInterface::isEnabledNoTitlebar() const { QFunctionPointer is_enable_no_titlebar = nullptr; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) is_enable_no_titlebar = qApp->platformFunction(_isEnableNoTitlebar); #endif if (is_enable_no_titlebar) { return (*reinterpret_cast(is_enable_no_titlebar))(m_window); } return false; } bool DXCBPlatformWindowInterface::setEnabledNoTitlebar(bool enable) { if (isEnabledNoTitlebar() == enable) return true; QFunctionPointer enable_no_titlear = nullptr; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) enable_no_titlear = qApp->platformFunction(_setEnableNoTitlebar); #endif if (enable_no_titlear) { bool ok = (*reinterpret_cast(enable_no_titlear))(m_window, enable); if (ok && enable) { if (m_window->handle()) { initWindowRadius(m_window); } else { m_window->installEventFilter(new CreatorWindowEventFilter(m_window)); } } return ok; } return false; } inline DPlatformHandle::WMBlurArea operator *(const DPlatformHandle::WMBlurArea &area, qreal scale) { if (qFuzzyCompare(scale, 1.0)) return area; DPlatformHandle::WMBlurArea new_area; new_area.x = qRound64(area.x * scale); new_area.y = qRound64(area.y * scale); new_area.width = qRound64(area.width * scale); new_area.height = qRound64(area.height * scale); new_area.xRadius = qRound64(area.xRadius * scale); new_area.yRaduis = qRound64(area.yRaduis * scale); return new_area; } /*! \brief DXCBPlatformWindowInterface::setWindowBlurAreaByWM 设置窗口背景的模糊区域,示例: \code QWindow w; QVector area_list; DXCBPlatformWindowInterface::WMBlurArea area; area.x = 50; area.y = 50; area.width = 200; area.height = 200; area.xRadius = 10; area.yRaduis = 10; area_list.append(area); DXCBPlatformWindowInterface::setWindowBlurAreaByWM(&w, area_list); QSurfaceFormat format = w.format(); format.setAlphaBufferSize(8); w.setFormat(format); w.resize(300, 300); w.show(); \endcode \image blur_window_demo1.png \a window 目标窗口对象 \a area 模糊区域,此区域范围内的窗口背景将填充为窗口后面内容模糊之后的图像 \return 如果设置成功则返回 true,否则返回 false \note 对于需要显示模糊背景的窗口,需要将其 QSurfaceFormat 的 alpha 通道设置为8 \note 调用此接口设置窗口背景模糊区域后将覆盖之前所设置的区域,包括调用 setWindowBlurAreaByWM(QWindow *, const QList &) 所设置的区域 \note 建议使用 DBlurEffectWidget 实现窗口背景模糊效果 \note 此功能依赖于窗口管理器的实现,目前仅支持 deepin-wm 和 kwin 这两个窗口管理器 \sa Dtk::Widget::DBlurEffectWidget \sa QSurfaceFormat::setAlphaBufferSize \sa QWindow::setFormat \sa DWindowManagerHelper::hasBlurWindow \sa DXCBPlatformWindowInterface::setWindowBlurAreaByWM(QWindow *, const QList &) */ bool DXCBPlatformWindowInterface::setWindowBlurArea(const QVector &area) { if (!m_window) { return false; } if (isEnabled()) { QVector areas; for (auto item : area) areas << item.x << item.y << item.width << item.height << item.xRadius << item.yRaduis; setWindowProperty(m_window, _windowBlurAreas, QVariant::fromValue(areas)); return true; } QFunctionPointer setWmBlurWindowBackgroundArea = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) setWmBlurWindowBackgroundArea = qApp->platformFunction(_setWmBlurWindowBackgroundArea); #endif if (!setWmBlurWindowBackgroundArea) { qWarning("setWindowBlurAreaByWM is not support"); return false; } QSurfaceFormat format = m_window->format(); format.setAlphaBufferSize(8); m_window->setFormat(format); const qreal device_ratio = m_window->devicePixelRatio(); if (qFuzzyCompare(device_ratio, 1.0)) { return reinterpret_cast&)>(setWmBlurWindowBackgroundArea)(m_window->winId(), area); } QVector new_areas; new_areas.reserve(area.size()); for (const DPlatformHandle::WMBlurArea &a : area) { new_areas.append(a * device_ratio); } return reinterpret_cast&)>(setWmBlurWindowBackgroundArea)(m_window->winId(), new_areas); } inline QPainterPath operator *(const QPainterPath &path, qreal scale) { if (qFuzzyCompare(1.0, scale)) return path; QPainterPath new_path = path; for (int i = 0; i < path.elementCount(); ++i) { const QPainterPath::Element &e = path.elementAt(i); new_path.setElementPositionAt(i, qRound(e.x * scale), qRound(e.y * scale)); } return new_path; } bool DXCBPlatformWindowInterface::setWindowBlurArea(const QList &paths) { if (!m_window) { return false; } if (isEnabled()) { setWindowProperty(m_window, _windowBlurPaths, QVariant::fromValue(paths)); return true; } QFunctionPointer setWmBlurWindowBackgroundPathList = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) setWmBlurWindowBackgroundPathList = qApp->platformFunction(_setWmBlurWindowBackgroundPathList); #endif if (!setWmBlurWindowBackgroundPathList) { qWarning("setWindowBlurAreaByWM is not support"); return false; } QSurfaceFormat format = m_window->format(); format.setAlphaBufferSize(8); m_window->setFormat(format); const qreal device_ratio = m_window->devicePixelRatio(); if (qFuzzyCompare(device_ratio, 1.0)) { return reinterpret_cast&)>(setWmBlurWindowBackgroundPathList)(m_window->winId(), paths); } QList new_paths; new_paths.reserve(paths.size()); for (const QPainterPath &p : paths) { new_paths.append(p * device_ratio); } return reinterpret_cast&)>(setWmBlurWindowBackgroundPathList)(m_window->winId(), new_paths); } bool DXCBPlatformWindowInterface::setWindowWallpaperPara(const QRect &area, DPlatformHandle::WallpaperScaleMode sMode, DPlatformHandle::WallpaperFillMode fMode) { if (!m_window) { return false; } QFunctionPointer setWmWallpaperParameter = Q_NULLPTR; #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) setWmWallpaperParameter = qApp->platformFunction(_setWmWallpaperParameter); #endif if (!setWmWallpaperParameter) { qWarning("setWindowWallpaperParaByWM is not support"); return false; } QSurfaceFormat format = m_window->format(); format.setAlphaBufferSize(8); m_window->setFormat(format); quint32 bMode = sMode | fMode; // 激活 backing store m_window->setProperty("_d_dxcb_wallpaper", QVariant::fromValue(QPair(area, bMode))); if (!m_window->handle()) { return true; } else { qWarning() << "because the window handle has been created, so 2D mode will have no effect"; } const qreal device_ratio = m_window->devicePixelRatio(); if (qFuzzyCompare(device_ratio, 1.0) || !area.isValid()) { return reinterpret_cast(setWmWallpaperParameter)(m_window->winId(), area, bMode); } QRect new_area(area.x() * device_ratio, area.y() * device_ratio, area.width() * device_ratio, area.height() * device_ratio); return reinterpret_cast(setWmWallpaperParameter)(m_window->winId(), new_area, bMode); } void DXCBPlatformWindowInterface::setDisableWindowOverrideCursor(bool disable) { m_window->setProperty(_disableOverrideCursor, disable); } int DXCBPlatformWindowInterface::windowRadius() const { return m_window->property(_windowRadius).toInt(); } void DXCBPlatformWindowInterface::setWindowRadius(int windowRadius) { setWindowProperty(m_window, _windowRadius, windowRadius); resolve(m_window, PropRole::WindowRadius); } int DXCBPlatformWindowInterface::borderWidth() const { return m_window->property(_borderWidth).toInt(); } void DXCBPlatformWindowInterface::setBorderWidth(int borderWidth) { setWindowProperty(m_window, _borderWidth, borderWidth); } QColor DXCBPlatformWindowInterface::borderColor() const { return qvariant_cast(m_window->property(_borderColor)); } void DXCBPlatformWindowInterface::setBorderColor(const QColor &borderColor) { setWindowProperty(m_window, _borderColor, QVariant::fromValue(borderColor)); } int DXCBPlatformWindowInterface::shadowRadius() const { return m_window->property(_shadowRadius).toInt(); } void DXCBPlatformWindowInterface::setShadowRadius(int shadowRadius) { setWindowProperty(m_window, _shadowRadius, shadowRadius); } QPoint DXCBPlatformWindowInterface::shadowOffset() const { return m_window->property(_shadowOffset).toPoint(); } void DXCBPlatformWindowInterface::setShadowOffset(const QPoint &shadowOffset) { setWindowProperty(m_window, _shadowOffset, shadowOffset); } QColor DXCBPlatformWindowInterface::shadowColor() const { return qvariant_cast(m_window->property(_shadowColor)); } void DXCBPlatformWindowInterface::setShadowColor(const QColor &shadowColor) { setWindowProperty(m_window, _shadowColor, QVariant::fromValue(shadowColor)); } DPlatformHandle::EffectScene DXCBPlatformWindowInterface::windowEffect() { return qvariant_cast(m_window->property(_windowEffect)); } void DXCBPlatformWindowInterface::setWindowEffect(DPlatformHandle::EffectScenes effectScene) { setWindowProperty(m_window, _windowEffect, static_cast(effectScene)); } DPlatformHandle::EffectType DXCBPlatformWindowInterface::windowStartUpEffect() { return qvariant_cast(m_window->property(_windowStartUpEffect)); } void DXCBPlatformWindowInterface::setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) { setWindowProperty(m_window, _windowStartUpEffect, static_cast(effectType)); } QPainterPath DXCBPlatformWindowInterface::clipPath() const { return qvariant_cast(m_window->property(_clipPath)); } void DXCBPlatformWindowInterface::setClipPath(const QPainterPath &clipPath) { setWindowProperty(m_window, _clipPath, QVariant::fromValue(clipPath)); } QRegion DXCBPlatformWindowInterface::frameMask() const { return qvariant_cast(m_window->property(_frameMask)); } void DXCBPlatformWindowInterface::setFrameMask(const QRegion &frameMask) { setWindowProperty(m_window, _frameMask, QVariant::fromValue(frameMask)); } QMargins DXCBPlatformWindowInterface::frameMargins() const { return qvariant_cast(m_window->property(_frameMargins)); } bool DXCBPlatformWindowInterface::translucentBackground() const { return m_window->property(_translucentBackground).toBool(); } void DXCBPlatformWindowInterface::setTranslucentBackground(bool translucentBackground) { setWindowProperty(m_window, _translucentBackground, translucentBackground); } bool DXCBPlatformWindowInterface::enableSystemResize() const { return m_window->property(_enableSystemResize).toBool(); } void DXCBPlatformWindowInterface::setEnableSystemResize(bool enableSystemResize) { setWindowProperty(m_window, _enableSystemResize, enableSystemResize); } bool DXCBPlatformWindowInterface::enableSystemMove() const { return m_window->property(_enableSystemMove).toBool(); } void DXCBPlatformWindowInterface::setEnableSystemMove(bool enableSystemMove) { setWindowProperty(m_window, _enableSystemMove, enableSystemMove); } bool DXCBPlatformWindowInterface::enableBlurWindow() const { return m_window->property(_enableBlurWindow).toBool(); } void DXCBPlatformWindowInterface::setEnableBlurWindow(bool enableBlurWindow) { setWindowProperty(m_window, _enableBlurWindow, enableBlurWindow); } bool DXCBPlatformWindowInterface::autoInputMaskByClipPath() const { return m_window->property(_autoInputMaskByClipPath).toBool(); } void DXCBPlatformWindowInterface::setAutoInputMaskByClipPath(bool autoInputMaskByClipPath) { setWindowProperty(m_window, _autoInputMaskByClipPath, autoInputMaskByClipPath); } WId DXCBPlatformWindowInterface::realWindowId() const { return qvariant_cast(m_window->property("_d_real_content_window")); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/plugins/platform/xcb/dxcbplatformwindowinterface.h000066400000000000000000000063001476226661100257260ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DXCBPLATFORMWINDOWINTERFACE_H #define DXCBPLATFORMWINDOWINTERFACE_H #include "private/dplatformwindowinterface_p.h" #include DGUI_BEGIN_NAMESPACE class DXCBPlatformWindowInterface : public QObject, public DPlatformWindowInterface { Q_OBJECT public: DXCBPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle, QObject *parent = nullptr); ~DXCBPlatformWindowInterface() override; static QString pluginVersion(); static bool isDXcbPlatform(); static bool connectWindowManagerChangedSignal(QObject *object, std::function slot); static bool connectHasBlurWindowChanged(QObject *object, std::function slot); static WId windowLeader(); void enableDXcb(bool redirectContent); bool setWindowBlurArea(const QVector &area); bool setWindowBlurArea(const QList &paths); bool setWindowWallpaperPara(const QRect &area, DPlatformHandle::WallpaperScaleMode sMode, DPlatformHandle::WallpaperFillMode fMode); bool autoInputMaskByClipPath() const; void setAutoInputMaskByClipPath(bool autoInputMaskByClipPath); WId realWindowId() const; void setEnabled(bool enabled) override; bool isEnabled() const override; void setDisableWindowOverrideCursor(bool disable) override; bool isEnabledNoTitlebar() const override; bool setEnabledNoTitlebar(bool enable) override; int windowRadius() const override; void setWindowRadius(int windowRadius) override; int borderWidth() const override; void setBorderWidth(int borderWidth) override; QColor borderColor() const override; void setBorderColor(const QColor &borderColor) override; int shadowRadius() const override; void setShadowRadius(int shadowRadius) override; QPoint shadowOffset() const override; void setShadowOffset(const QPoint &shadowOffset) override; QColor shadowColor() const override; void setShadowColor(const QColor &shadowColor) override; DPlatformHandle::EffectScene windowEffect() override; void setWindowEffect(DPlatformHandle::EffectScenes effectScene) override; DPlatformHandle::EffectType windowStartUpEffect() override; void setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType) override; QPainterPath clipPath() const override; void setClipPath(const QPainterPath &clipPath) override; QRegion frameMask() const override; void setFrameMask(const QRegion &frameMask) override; QMargins frameMargins() const override; bool translucentBackground() const override; void setTranslucentBackground(bool translucentBackground) override; bool enableSystemResize() const override; void setEnableSystemResize(bool enableSystemResize) override; bool enableSystemMove() const override; void setEnableSystemMove(bool enableSystemMove) override; bool enableBlurWindow() const override; void setEnableBlurWindow(bool enableBlurWindow) override; protected: bool eventFilter(QObject *watched, QEvent *event) override; }; DGUI_END_NAMESPACE #endif // DXCBPLATFORMWINDOWINTERFACE_H dtkgui-5.7.12/src/plugins/platform/xcb/xcb.cmake000066400000000000000000000002471476226661100215410ustar00rootroot00000000000000file(GLOB XCB_HEADER ${CMAKE_CURRENT_LIST_DIR}/*.h ) file(GLOB XCB_SOURCE ${CMAKE_CURRENT_LIST_DIR}/*.cpp ) set(xcb_SRC ${XCB_HEADER} ${XCB_SOURCE} ) dtkgui-5.7.12/src/plugins/plugins.cmake000066400000000000000000000050161476226661100200450ustar00rootroot00000000000000option(DTK_DISABLE_XCB "Disable XCB Protocols" OFF) option(DTK_DISABLE_TREELAND "Disable Treeland Protocols" OFF) file(GLOB PLATFORM_INTERFACE_HEADER ${CMAKE_CURRENT_LIST_DIR}/*.h ) file(GLOB PLATFORM_INTERFACE_SOURCE ${CMAKE_CURRENT_LIST_DIR}/*.cpp ) set(platform_interface_SRC ${PLATFORM_INTERFACE_HEADER} ${PLATFORM_INTERFACE_SOURCE} ) target_sources(${LIB_NAME} PRIVATE ${platform_interface_SRC} ) set(PRIVATE_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/private/dplatforminterface_p.h) set(PRIVATE_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/dtk${PROJECT_VERSION_MAJOR}/DGui/Private") # XCB if(NOT DTK_DISABLE_XCB) message("Support XCB!") include(plugins/platform/xcb/xcb.cmake) target_sources(${LIB_NAME} PRIVATE ${xcb_SRC} ) else() target_compile_definitions(${LIB_NAME} PRIVATE DTK_DISABLE_XCB) endif() # Treeland try_compile(DEEPIN_WAYLAND_TEST_COMPILE_RESULT ${CMAKE_CURRENT_BINARY_DIR}/treeland_test ${CMAKE_CURRENT_LIST_DIR}/platform/config.tests/treeland_test treeland_test CMAKE_FLAGS -DQT_VERSION_MAJOR=${QT_VERSION_MAJOR}) if(NOT DEEPIN_WAYLAND_TEST_COMPILE_RESULT) message("wayland_test failed, disable treeland support") set(DTK_DISABLE_TREELAND ON) endif() if(NOT DTK_DISABLE_TREELAND) find_package(TreelandProtocols) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS WaylandClient) set(TreelandProtocols_FOUND ${TreelandProtocols_FOUND}) endif() if(NOT DTK_DISABLE_TREELAND AND TreelandProtocols_FOUND) message("Support Treeland!") if("${QT_VERSION_MAJOR}" STREQUAL "6") qt6_generate_wayland_protocol_client_sources(${LIB_NAME} FILES ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml ) else() # ECM setup include(FeatureSummary) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${ECM_MODULE_PATH}") find_package(QtWaylandScanner) ecm_add_qtwayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml BASENAME treeland-personalization-manager-v1 ) target_sources(${LIB_NAME} PRIVATE ${CLIENT_LIB_SRCS} ) endif() include(plugins/platform/treeland/treeland.cmake) target_sources(${LIB_NAME} PRIVATE ${treeland_SRC} ) else() target_compile_definitions(${LIB_NAME} PRIVATE DTK_DISABLE_TREELAND) endif() install(FILES ${PRIVATE_HEADER_FILES} DESTINATION "${PRIVATE_INCLUDE_INSTALL_DIR}") dtkgui-5.7.12/src/private/000077500000000000000000000000001476226661100153515ustar00rootroot00000000000000dtkgui-5.7.12/src/private/dfiledragcommon_p.h000066400000000000000000000006731476226661100212010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DDNDCOMMON_H #define DDNDCOMMON_H #define DND_INTERFACE "com.deepin.dtk.FileDrag" #define DND_OBJPATH "/Ddnd" #define DND_MIME_SERVICE "x-dtk-file-drag/service" #define DND_MIME_PID "x-dtk-file-drag/pid" #define DND_MIME_UUID "x-dtk-file-drag/uuid" #define DND_TARGET_URL_KEY "targetUrl" #endif // DDNDCOMMON_H dtkgui-5.7.12/src/private/dfiledragserver_p.h000066400000000000000000000015401476226661100212110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFILEDRAGSERVER_P_H #define DFILEDRAGSERVER_P_H #include "dfiledragserver.h" #include #include #include DGUI_BEGIN_NAMESPACE class DDndSourceInterface; class DFileDragServer; class DFileDragServerPrivate : public DCORE_NAMESPACE::DObjectPrivate { QMap data; QUuid uuid; DFileDragServerPrivate(DFileDragServer *q); ~DFileDragServerPrivate(); void writeMimeData(QMimeData *dest); static DDndSourceInterface *dbusif; static int refcnt; static QHash servermap; D_DECLARE_PUBLIC(DFileDragServer) friend class DDndSourceInterface; friend class DFileDrag; }; DGUI_END_NAMESPACE #endif // DFILEDRAGSERVER_P_H dtkgui-5.7.12/src/private/dfontmanager_p.h000066400000000000000000000013071476226661100205070ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DFONTSIZEMANAGER_P_H #define DFONTSIZEMANAGER_P_H #include #include #include "dfontmanager.h" DGUI_BEGIN_NAMESPACE class DFontManagerPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate { public: DFontManagerPrivate(DFontManager *qq); int fontPixelSize[DFontManager::NSizeTypes] = {40, 30, 24, 20, 17, 14, 13, 12, 11, 10}; int baseFontSizeType = DFontManager::T6; // 字号的差值 int fontPixelSizeDiff = 0; QFont baseFont; private: D_DECLARE_PUBLIC(DFontManager) }; DGUI_END_NAMESPACE #endif // DFONTSIZEMANAGER_P_H dtkgui-5.7.12/src/private/dguiapplicationhelper_p.h000066400000000000000000000036671476226661100224310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DGUIAPPLICATIONHELPER_P_H #define DGUIAPPLICATIONHELPER_P_H #include "dguiapplicationhelper.h" #include "dplatformtheme.h" #include QT_BEGIN_NAMESPACE class QLocalServer; QT_END_NAMESPACE DGUI_BEGIN_NAMESPACE /*! @private */ class DGuiApplicationHelperPrivate : public DCORE_NAMESPACE::DObjectPrivate { public: D_DECLARE_PUBLIC(DGuiApplicationHelper) DGuiApplicationHelperPrivate(DGuiApplicationHelper *qq); void init(); void initApplication(QGuiApplication *app); static void staticInitApplication(); static void staticCleanApplication(); DPlatformTheme *initWindow(QWindow *window) const; void _q_initApplicationTheme(bool notifyChange = false); void _q_sizeModeChanged(int mode); DGuiApplicationHelper::SizeMode fetchSizeMode(bool *isSystemSizeMode = nullptr) const; void notifyAppThemeChanged(); void notifyAppThemeChangedByEvent(); void onApplicationPaletteChanged(); // 返回程序是否自定义了调色板 inline bool isCustomPalette() const; void setPaletteType(DGuiApplicationHelper::ColorType ct, bool emitSignal); void initPaletteType() const; DGuiApplicationHelper::ColorType paletteType = DGuiApplicationHelper::UnknownType; // 系统级别的主题设置 DPlatformTheme *systemTheme = nullptr; QScopedPointer appPalette; // 获取QLocalSever消息的等待时间 static int waitTime; static DGuiApplicationHelper::Attributes attributes; DGuiApplicationHelper::SizeMode systemSizeMode = DGuiApplicationHelper::NormalMode; DGuiApplicationHelper::SizeMode explicitSizeMode; private: // 应用程序级别的主题设置 DPlatformTheme *appTheme = nullptr; }; Q_DECLARE_OPERATORS_FOR_FLAGS(DGuiApplicationHelper::Attributes) DGUI_END_NAMESPACE #endif // DGUIAPPLICATIONHELPER_P_H dtkgui-5.7.12/src/private/dnativesettings_p.h000066400000000000000000000012721476226661100212560ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DNATIVESETTINGS_P_H #define DNATIVESETTINGS_P_H #include #include #include DGUI_BEGIN_NAMESPACE class DNativeSettingsPrivate : public DCORE_NAMESPACE::DObjectPrivate { D_DECLARE_PUBLIC(DNativeSettings) public: DNativeSettingsPrivate(DNativeSettings *qq, const QByteArray &domain); ~DNativeSettingsPrivate(); bool init(const QMetaObject *mo, quint32 window); public: QByteArray domain; bool valid = false; QByteArrayList allKeys; }; DGUI_END_NAMESPACE #endif // DNATIVESETTINGS_P_H dtkgui-5.7.12/src/private/dplatforminterface_p.h000066400000000000000000000122731476226661100217170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPLATFORMINTERFACE_H #define DPLATFORMINTERFACE_H #include #include #include "dtkgui_global.h" DGUI_BEGIN_NAMESPACE class DPlatformTheme; class LIBDTKCORESHARED_EXPORT DPlatformInterface { public: explicit DPlatformInterface(DPlatformTheme *platformTheme); virtual ~DPlatformInterface(); virtual int cursorBlinkTime() const; virtual int cursorBlinkTimeout() const; virtual bool cursorBlink() const; virtual int doubleClickDistance() const; virtual int doubleClickTime() const; virtual int dndDragThreshold() const; virtual int windowRadius() const; virtual int windowRadius(int defaultValue) const; virtual QByteArray themeName() const; virtual QByteArray iconThemeName() const; virtual QByteArray soundThemeName() const; virtual QByteArray fontName() const; virtual QByteArray monoFontName() const; virtual qreal fontPointSize() const; virtual QByteArray gtkFontName() const; virtual QColor activeColor() const; virtual QColor darkActiveColor() const; #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) virtual QColor window() const; virtual QColor windowText() const; virtual QColor base() const; virtual QColor alternateBase() const; virtual QColor toolTipBase() const; virtual QColor toolTipText() const; virtual QColor text() const; virtual QColor button() const; virtual QColor buttonText() const; virtual QColor brightText() const; virtual QColor light() const; virtual QColor midlight() const; virtual QColor dark() const; virtual QColor mid() const; virtual QColor shadow() const; virtual QColor highlight() const; virtual QColor highlightedText() const; virtual QColor link() const; virtual QColor linkVisited() const; virtual QColor itemBackground() const; virtual QColor textTitle() const; virtual QColor textTips() const; virtual QColor textWarning() const; virtual QColor textLively() const; virtual QColor lightLively() const; virtual QColor darkLively() const; virtual QColor frameBorder() const; #endif virtual int sizeMode() const; virtual int scrollBarPolicy() const; public: virtual void setCursorBlinkTime(int cursorBlinkTime); virtual void setCursorBlinkTimeout(int cursorBlinkTimeout); virtual void setCursorBlink(bool cursorBlink); virtual void setDoubleClickDistance(int doubleClickDistance); virtual void setDoubleClickTime(int doubleClickTime); virtual void setDndDragThreshold(int dndDragThreshold); virtual void setThemeName(const QByteArray &themeName); virtual void setIconThemeName(const QByteArray &iconThemeName); virtual void setSoundThemeName(const QByteArray &soundThemeName); virtual void setFontName(const QByteArray &fontName); virtual void setMonoFontName(const QByteArray &monoFontName); virtual void setFontPointSize(qreal fontPointSize); virtual void setGtkFontName(const QByteArray &fontName); virtual void setActiveColor(const QColor activeColor); virtual void setDarkActiveColor(const QColor &activeColor); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) virtual void setWindow(const QColor &window); virtual void setWindowText(const QColor &windowText); virtual void setBase(const QColor &base); virtual void setAlternateBase(const QColor &alternateBase); virtual void setToolTipBase(const QColor &toolTipBase); virtual void setToolTipText(const QColor &toolTipText); virtual void setText(const QColor &text); virtual void setButton(const QColor &button); virtual void setButtonText(const QColor &buttonText); virtual void setBrightText(const QColor &brightText); virtual void setLight(const QColor &light); virtual void setMidlight(const QColor &midlight); virtual void setDark(const QColor &dark); virtual void setMid(const QColor &mid); virtual void setShadow(const QColor &shadow); virtual void setHighlight(const QColor &highlight); virtual void setHighlightedText(const QColor &highlightedText); virtual void setLink(const QColor &link); virtual void setLinkVisited(const QColor &linkVisited); virtual void setItemBackground(const QColor &itemBackground); virtual void setTextTitle(const QColor &textTitle); virtual void setTextTips(const QColor &textTips); virtual void setTextWarning(const QColor &textWarning); virtual void setTextLively(const QColor &textLively); virtual void setLightLively(const QColor &lightLively); virtual void setDarkLively(const QColor &darkLively); virtual void setFrameBorder(const QColor &frameBorder); #endif virtual int dotsPerInch(const QString &screenName = QString()) const; virtual void setDotsPerInch(const QString &screenName, int dpi); virtual void setWindowRadius(int windowRadius); protected: DPlatformTheme *m_platformTheme; }; class LIBDTKCORESHARED_EXPORT DPlatformInterfaceFactory { public: using HelperCreator = DPlatformInterface * (*)(DPlatformTheme*); static void registerInterface(HelperCreator creator); }; DGUI_END_NAMESPACE #endif // DNATIVESETTINGS_P_H dtkgui-5.7.12/src/private/dplatformtheme_p.h000066400000000000000000000034271476226661100210620ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPLATFORMTHEME_P_H #define DPLATFORMTHEME_P_H #include "private/dplatforminterface_p.h" #include "dplatformtheme.h" #include "dnativesettings_p.h" #include #include DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE class DPlatformThemePrivate : public DNativeSettingsPrivate { public: D_DECLARE_PUBLIC(DPlatformTheme) DPlatformThemePrivate(DPlatformTheme *qq); // 接收parent主题或非调色板DNativeSettings对象(theme对象)的属性变化通知 // 调色板相关的属性变化与此无关 void onQtColorChanged(QPalette::ColorRole role, const QColor &color); void onDtkColorChanged(DPalette::ColorType type, const QColor &color); void notifyPaletteChanged(); // 父主题,可以从其继承除调色板之外的所有窗口设置 DPlatformTheme *parent = nullptr; // 用于控制是否fallback到父主题中获取属性 bool fallbackProperty = true; // 默认时,DPlatformTheme会从/deepin/palette域下获取调色板相关的属性值 // 此处的DNativeSettings用于获取除调色板之外的属性设置 DNativeSettings *theme; // 缓存的调色板数据 DPalette *palette = nullptr; // 减少调色板changed信号的通知频率 QTimer *notifyPaletteChangeTimer = nullptr; DConfig *dtkPreferenceConfig = nullptr; DPlatformInterface *platformInterface = nullptr; DGuiApplicationHelper::SizeMode sizeMode = DGuiApplicationHelper::NormalMode; Qt::ScrollBarPolicy scrollBarPolicy = Qt::ScrollBarAsNeeded; public slots: void onDtkPreferenceDConfigChanged(const QString &key); }; DGUI_END_NAMESPACE #endif // DPLATFORMTHEME_P_H dtkgui-5.7.12/src/private/dplatformwindowinterface_p.h000066400000000000000000000051471476226661100231510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPLATFORMWINDOWINTERFACE_P_H #define DPLATFORMWINDOWINTERFACE_P_H #include #include #include "dplatformhandle.h" DGUI_BEGIN_NAMESPACE class LIBDTKCORESHARED_EXPORT DPlatformWindowInterface { public: explicit DPlatformWindowInterface(QWindow *window, DPlatformHandle *platformHandle); virtual ~DPlatformWindowInterface(); QWindow* window() const; virtual void setEnabled(bool enabled); virtual bool isEnabled() const; virtual bool isEnabledNoTitlebar() const; virtual bool setEnabledNoTitlebar(bool enable); virtual void setDisableWindowOverrideCursor(bool disable); virtual int windowRadius() const; virtual void setWindowRadius(int windowRadius); virtual int borderWidth() const; virtual void setBorderWidth(int borderWidth); virtual QColor borderColor() const; virtual void setBorderColor(const QColor &borderColor); virtual int shadowRadius() const; virtual void setShadowRadius(int shadowRadius); virtual QPoint shadowOffset() const; virtual void setShadowOffset(const QPoint &shadowOffset); virtual QColor shadowColor() const; virtual void setShadowColor(const QColor &shadowColor); virtual DPlatformHandle::EffectScene windowEffect(); virtual void setWindowEffect(DPlatformHandle::EffectScenes effectScene); virtual DPlatformHandle::EffectType windowStartUpEffect(); virtual void setWindowStartUpEffect(DPlatformHandle::EffectTypes effectType); virtual QPainterPath clipPath() const; virtual void setClipPath(const QPainterPath &clipPath); virtual QRegion frameMask() const; virtual void setFrameMask(const QRegion &frameMask); virtual QMargins frameMargins() const; virtual bool translucentBackground() const; virtual void setTranslucentBackground(bool translucentBackground); virtual bool enableSystemResize() const; virtual void setEnableSystemResize(bool enableSystemResize); virtual bool enableSystemMove() const; virtual void setEnableSystemMove(bool enableSystemMove); virtual bool enableBlurWindow() const; virtual void setEnableBlurWindow(bool enableBlurWindow); protected: QPointer m_window; QPointer m_platformHandle; }; class LIBDTKCORESHARED_EXPORT DPlatformWindowInterfaceFactory { public: using Creator = DPlatformWindowInterface * (*)(QWindow *, DPlatformHandle*); static void registerInterface(Creator creator); }; DGUI_END_NAMESPACE #endif // DPLATFORMWINDOWINTERFACE_P_H dtkgui-5.7.12/src/private/dregionmonitor_p.h000066400000000000000000000033321476226661100211010ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DREGIONMONITOR_P_H #define DREGIONMONITOR_P_H #include "dregionmonitor.h" #include "xeventmonitor_interface.h" #include #include #include #include DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE using XEventMonitor = ::com::deepin::api::XEventMonitor; class DRegionMonitorPrivate : public DObjectPrivate { D_DECLARE_PUBLIC(DRegionMonitor) public: DRegionMonitorPrivate(DRegionMonitor *q); ~DRegionMonitorPrivate(); bool registered() const { return !registerKey.isEmpty(); } void init(); void registerMonitorRegion(); void unregisterMonitorRegion(); void _q_ButtonPress(const int flag, const int x, const int y, const QString &key); void _q_ButtonRelease(const int flag, const int x, const int y, const QString &key); void _q_CursorMove(const int x, const int y, const QString &key); void _q_CursorEnter(const int x, const int y, const QString &key); void _q_CursorLeave(const int x, const int y, const QString &key); void _q_KeyPress(const QString &keyname, const int x, const int y, const QString &key); void _q_KeyRelease(const QString &keyname, const int x, const int y, const QString &key); const QPoint deviceScaledCoordinate(const QPoint &p, const double ratio) const; XEventMonitor *eventInter; QRegion watchedRegion; QString registerKey; DRegionMonitor::CoordinateType type = DRegionMonitor::ScaleRatio; DRegionMonitor::RegisterdFlags registerdFlags = DRegionMonitor::Motion | DRegionMonitor::Button | DRegionMonitor::Key; }; DGUI_END_NAMESPACE #endif // DREGIONMONITOR_P_H dtkgui-5.7.12/src/private/dtaskbarcontrol_p.h000066400000000000000000000012211476226661100212310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTASKBARCONTROL_P_H #define DTASKBARCONTROL_P_H #include #include #include #include "dtaskbarcontrol.h" DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE class DTaskbarControlPrivate : public DObjectPrivate { D_DECLARE_PUBLIC(DTaskbarControl) public: DTaskbarControlPrivate(DTaskbarControl *q); ~DTaskbarControlPrivate(); int m_counter; bool m_counterVisible; double m_progress; bool m_progressVisible; }; DGUI_END_NAMESPACE #endif // DTASKBARCONTROL_P_H dtkgui-5.7.12/src/private/private.cmake000066400000000000000000000010061476226661100200220ustar00rootroot00000000000000set(private_SRC ${CMAKE_CURRENT_LIST_DIR}/dnativesettings_p.h ${CMAKE_CURRENT_LIST_DIR}/dguiapplicationhelper_p.h ${CMAKE_CURRENT_LIST_DIR}/dplatformtheme_p.h ${CMAKE_CURRENT_LIST_DIR}/dfiledragcommon_p.h ${CMAKE_CURRENT_LIST_DIR}/dfiledragserver_p.h ${CMAKE_CURRENT_LIST_DIR}/dregionmonitor_p.h ${CMAKE_CURRENT_LIST_DIR}/dtaskbarcontrol_p.h ${CMAKE_CURRENT_LIST_DIR}/dfontmanager_p.h ${CMAKE_CURRENT_LIST_DIR}/dplatforminterface_p.h ${CMAKE_CURRENT_LIST_DIR}/dplatformwindowinterface_p.h ) dtkgui-5.7.12/src/util/000077500000000000000000000000001476226661100146545ustar00rootroot00000000000000dtkgui-5.7.12/src/util/ddciicon.cpp000066400000000000000000001123361476226661100171420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddciicon.h" #include "dguiapplicationhelper.h" #include "dicontheme.h" #include #include #include #include #include #include #include #include #include #include DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE #define MODE_NORMAL "normal" #define MODE_DISABLED "disabled" #define MODE_HOVER "hover" #define MODE_PRESSED "pressed" #define THEME_LIGHT "light" #define THEME_DARK "dark" #define ALPHA8STRING "alpha8" struct DDciIconEntry { struct ScalableLayer { int imagePixelRatio = 0; struct Layer { int prior = 0; DDciIconPalette::PaletteRole role = DDciIconPalette::NoPalette; QByteArray format; QByteArray data; bool isAlpha8Format = false; qint8 hue = 0; qint8 saturation = 0; qint8 lightness = 0; qint8 red = 0; qint8 green = 0; qint8 blue = 0; qint8 alpha = 0; qint16 padding = 0; }; QVector layers; }; int iconSize = 0; qint16 maxPaddings = 0; DDciIcon::Mode mode = DDciIcon::Normal; DDciIcon::Theme theme = DDciIcon::Light; QVector scalableLayers; inline bool isNull() const { return scalableLayers.isEmpty(); } }; struct EntryNode { int iconSize = 0; qint16 maxPaddings = 0; QVector entries; }; using EntryNodeList = QVector; class EntryPropertyParser { public: static void registerSteps(); static void doParse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties); private: static struct Step { virtual ~Step() {} Step *nextStep = nullptr; virtual QVector parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) = 0; } *root; struct PriorStep : public Step { QVector parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) override; }; struct FormatAndAlpha8Step : public Step { QVector parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) override; }; struct PaddingStep : public Step { QVector parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) override; }; struct PaletteStep : public Step { QVector parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) override; }; }; EntryPropertyParser::Step *EntryPropertyParser::root = nullptr; void EntryPropertyParser::registerSteps() { static PriorStep priorSt; static FormatAndAlpha8Step formatSt; static PaddingStep paddingSt; static PaletteStep paletteSt; priorSt.nextStep = &formatSt; formatSt.nextStep = &paddingSt; paddingSt.nextStep = &paletteSt; paletteSt.nextStep = nullptr; root = &priorSt; } void EntryPropertyParser::doParse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) { Q_ASSERT(layer); if (!root) registerSteps(); EntryPropertyParser::Step *step = root; QVector ps = properties; while (step) { // If the input information flow is empty, it means that the next steps do not need to be continued if (ps.isEmpty()) break; ps = step->parse(layer, ps); step = step->nextStep; } } QVector EntryPropertyParser::PriorStep::parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) { bool ok = false; QVector ps = properties; layer->prior = ps.takeFirst().toString().toInt(&ok); if (!ok) return {}; // error priority. return ps; } QVector EntryPropertyParser::FormatAndAlpha8Step::parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) { QVector ps = properties; const QString alpha8OrFormat = ps.takeLast().toString(); if (alpha8OrFormat.compare(ALPHA8STRING, Qt::CaseInsensitive) == 0) { // Alpha8 format layer->isAlpha8Format = true; layer->format = ps.takeLast().toLatin1(); } else { // normal format layer->format = alpha8OrFormat.toLatin1(); } return ps; } QVector EntryPropertyParser::PaddingStep::parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) { QVector ps = properties; // Take the padding property auto it = std::find_if(ps.cbegin(), ps.cend(), [](const QStringView &p) { return p.endsWith(QLatin1Char('p')); }); if (it != ps.cend()) { layer->padding = it->left(it->length() - 1).toString().toShort(); ps.removeOne(*it); } return ps; } QVector EntryPropertyParser::PaletteStep::parse(DDciIconEntry::ScalableLayer::Layer *layer, const QVector &properties) { QVector ps = properties; QStringView palettes = ps.takeFirst(); // `role_hue_saturation_lightness_red_green_blue_alpha` or `role` if (palettes.toString().contains(QLatin1Char('_'))) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // QVector is an alias for QList in Qt6 const QVector paletteProps = palettes.split(QLatin1Char('_')); #elif QT_VERSION >= QT_VERSION_CHECK(5, 15, 2) // QStringView::split() has been added in 5.12.2. const QVector paletteProps = QVector::fromList(palettes.split(QLatin1Char('_'))); #else QStringList strList = palettes.toString().split(QLatin1Char('_')); QList viewList; for (auto str : strList) { viewList.append(QStringView(str)); } const QVector paletteProps = QVector::fromList(viewList); #endif if (paletteProps.length() != 8) return ps; int role = paletteProps.at(0).toString().toInt(); if (role < DDciIconPalette::NoPalette || role > DDciIconPalette::PaletteCount) role = DDciIconPalette::NoPalette; layer->role = DDciIconPalette::PaletteRole(role); layer->hue = static_cast(paletteProps.at(1).toString().toShort()); layer->saturation = static_cast(paletteProps.at(2).toString().toShort()); layer->lightness = static_cast(paletteProps.at(3).toString().toShort()); layer->red = static_cast(paletteProps.at(4).toString().toShort()); layer->green = static_cast(paletteProps.at(5).toString().toShort()); layer->blue = static_cast(paletteProps.at(6).toString().toShort()); layer->alpha = static_cast(paletteProps.at(7).toString().toShort()); } else { // only palette int role = palettes.toString().toInt(); if (role < DDciIconPalette::NoPalette || role > DDciIconPalette::PaletteCount) role = DDciIconPalette::NoPalette; layer->role = DDciIconPalette::PaletteRole(role); } return ps; } void alpha8ImageDeleter(void *image) { delete static_cast(image); } static QImage readImageData(QImageReader &reader, qreal pixmapScale, bool isAlpha8Format) { QImage image; if (reader.canRead()) { bool scaled = false; int imageSize = qMax(reader.size().width(), reader.size().height()); int scaledSize = qRound(pixmapScale * imageSize); if (!isAlpha8Format && reader.supportsOption(QImageIOHandler::ScaledSize)) { reader.setScaledSize(reader.size().scaled(scaledSize, scaledSize, Qt::KeepAspectRatio)); scaled = true; } QImage *imagePtr = ℑ if (isAlpha8Format) imagePtr = new QImage(); reader.read(imagePtr); if (isAlpha8Format) { QImage tt(imagePtr->bits(), imagePtr->width(), imagePtr->width(), imagePtr->bytesPerLine(), QImage::Format_Alpha8, alpha8ImageDeleter, static_cast(imagePtr)); return tt.scaled(scaledSize, scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); } if (!scaled) image = image.scaled(scaledSize, scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); } else { qWarning() << reader.errorString() << reader.format(); } return image; } class DDciIconImagePrivate { public: DDciIconImagePrivate(const DDciIconImagePrivate &other) : imageSize(other.imageSize) , devicePixelRatio(other.devicePixelRatio) , imageScale(other.imageScale) , layers(other.layers) { } DDciIconImagePrivate(qreal imageSize, qreal devicePixelRatio, qreal imageScale, const DDciIconEntry::ScalableLayer &sLayer) : imageSize(imageSize) , devicePixelRatio(devicePixelRatio) , imageScale(imageScale) , layers(sLayer.layers) { } void init(); inline bool loaded() const { return layers.size() == readers.size(); } inline void ensureLoad() { if (loaded()) return; init(); } const qreal imageSize; const qreal devicePixelRatio; const qreal imageScale; const QVector layers; struct ReaderData { ReaderData() {} ~ReaderData() {} ReaderData(const ReaderData &other) : index(other.index) , buffer(nullptr) , reader(nullptr) , pastImageDelay(other.pastImageDelay) , currentImage(other.currentImage) , currentImageIsValid(other.currentImageIsValid) , m_currentImageEndTime(other.m_currentImageEndTime) {} ReaderData(ReaderData &&other) { index = std::move(other.index); buffer.swap(other.buffer); reader.swap(other.reader); pastImageDelay = std::move(other.pastImageDelay); currentImage.swap(other.currentImage); currentImageIsValid = std::move(other.currentImageIsValid); m_currentImageEndTime = std::move(other.m_currentImageEndTime); } qsizetype index = 0; std::unique_ptr buffer; std::unique_ptr reader; int pastImageDelay = 0; QImage currentImage; bool currentImageIsValid = false; int m_currentImageEndTime = 0; inline void initCurrentImage(const DDciIconImagePrivate *d) { if (currentImageIsValid) return; // Ensure can get a valid QImageReader::nextImageDelay(), Because // using QImageReader::nextImageDelay() needs call QImageReader::read() before. currentImage = readImageData(*reader, d->imageScale, d->layers.at(index).isAlpha8Format); currentImageIsValid = true; m_currentImageEndTime = pastImageDelay + reader->nextImageDelay(); } inline bool jumpToNextImage(DDciIconImagePrivate *d) { Q_ASSERT(reader->supportsAnimation()); pastImageDelay += reader->nextImageDelay(); ++d->pastImageCount; if (!reader->canRead()) return false; currentImage = QImage(); currentImageIsValid = false; initCurrentImage(d); return true; } inline int currentImageEndTime() const { Q_ASSERT(currentImageIsValid); return m_currentImageEndTime; } inline bool currentImageIsEnd(const DDciIconImagePrivate *d) const { return d->currentPastImageDelay > 0 && d->currentPastImageDelay >= currentImageEndTime(); } }; QVector readers; bool supportsAnimation = false; int totalMaxImageCount = 0; int maxLoopCount = -2; ReaderData *readAnimationNextData(); ReaderData *animation = nullptr; int currentImageNumber = 0; int pastImageCount = 0; int currentPastImageDelay = 0; }; class DDciIconPrivate : public QSharedData { public: DDciIconPrivate() : dciFile(nullptr) { } DDciIconPrivate(const DDciIconPrivate &other) : QSharedData(other) , dciFile(other.dciFile) { } ~DDciIconPrivate(); DDciIconEntry *loadIcon(const QString &parentDir, const QString &imageDir); void loadIconList(); void ensureLoaded(); DDciIconEntry *tryMatchIcon(int iconSize, DDciIcon::Theme theme, DDciIcon::Mode mode, DDciIcon::IconMatchedFlags flags = DDciIcon::None) const; static void paint(QPainter *painter, const QRectF &rect, Qt::Alignment alignment, const QVector &layers, QVector *layerReaders, const DDciIconPalette &palette, qreal pixmapScale); static void paint(QPainter *painter, const QRect &rect, qreal devicePixelRatio, Qt::Alignment alignment, const DDciIconEntry *entry, const DDciIconPalette &palette, qreal pixmapScale); inline static bool hasPalette(const QVector &layers) { return std::any_of(layers.cbegin(), layers.cend(), [](const DDciIconEntry::ScalableLayer::Layer &layer) { return layer.role != DDciIconPalette::NoPalette; }); } bool hasPalette(DDciIconMatchResult result) const; static inline bool entryIsValid(const DDciIconEntry *entry) { return entry && !entry->isNull(); } QSharedPointer dciFile; EntryNodeList icons; }; // In Qt 6, registration of comparators, and QDebug and QDataStream streaming operators is // done automatically. Consequently, \c QMetaType::registerEqualsComparator(), // \c QMetaType::registerComparators(), \c qRegisterMetaTypeStreamOperators() and // \c QMetaType::registerDebugStreamOperator() do no longer exist. Calls to those methods // have to be removed when porting to Qt 6. #if !defined(QT_NO_DATASTREAM) && (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) __attribute__((constructor)) static void registerMetaType() { qRegisterMetaTypeStreamOperators("DDciIcon"); } #endif static inline bool toMode(const QStringView &name, DDciIcon::Mode *mode) { if (name == QLatin1String(MODE_NORMAL)) { *mode = DDciIcon::Normal; return true; } if (name == QLatin1String(MODE_DISABLED)) { *mode = DDciIcon::Disabled; return true; } if (name == QLatin1String(MODE_HOVER)) { *mode = DDciIcon::Hover; return true; } if (name == QLatin1String(MODE_PRESSED)) { *mode = DDciIcon::Pressed; return true; } return false; } static inline bool toTheme(const QStringView &name, DDciIcon::Theme *theme) { if (name == QLatin1String(THEME_LIGHT)) { *theme = DDciIcon::Light; return true; } if (name == QLatin1String(THEME_DARK)) { *theme = DDciIcon::Dark; return true; } return false; } // DCI 内部目录使用 '/' 作为路径分隔符 static inline QString joinPath(const QString &s1, const QString &s2) { return s1 + QLatin1Char('/') + s2; } static QImage readImageData(const QByteArray &data, const QByteArray &format, qreal pixmapScale, bool isAlpha8Format) { if (data.isEmpty()) return QImage(); QBuffer rawDataBuffer; rawDataBuffer.setData(data); rawDataBuffer.open(QBuffer::ReadOnly); QImageReader reader(&rawDataBuffer); if (!format.isEmpty()) reader.setFormat(format); return readImageData(reader, pixmapScale, isAlpha8Format); } static int findIconsByLowerBoundSize(const EntryNodeList &list, const int size, bool regardPaddingsAsSize) { const auto compFun1 = [] (const EntryNode &n1, const EntryNode &n2) { return n1.iconSize < n2.iconSize; }; const auto compFun2 = [] (const EntryNode &n1, const EntryNode &n2) { return n1.iconSize + n1.maxPaddings < n2.iconSize + n2.maxPaddings; }; EntryNode target; target.iconSize = size; target.maxPaddings = 0; auto neighbor = std::lower_bound(list.cbegin(), list.cend(), target, regardPaddingsAsSize ? compFun2 : compFun1); if (neighbor != list.cend()) return static_cast(neighbor - list.constBegin()); return -1; } static QRectF alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSizeF &size, const QRectF &rect) { alignment = QGuiApplicationPrivate::visualAlignment(direction, alignment); qreal x = rect.x(); qreal y = rect.y(); qreal w = size.width(); qreal h = size.height(); if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter) y += rect.size().height()/2 - h/2; else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom) y += rect.size().height() - h; if ((alignment & Qt::AlignRight) == Qt::AlignRight) x += rect.size().width() - w; else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter) x += rect.size().width()/2 - w/2; return QRectF(x, y, w, h); } DDciIconPrivate::~DDciIconPrivate() { for (auto icon : icons) qDeleteAll(icon.entries); } // Note that QStringView is a non-owning, read-only view of a QString // so we need to make sure that the original QString object stays alive // for as long as we're using the QStringView. static inline QVector fromQStringList(const QStringList &list) { QVector views; views.reserve(list.size()); std::copy(list.begin(), list.end(), std::back_inserter(views)); return views; } DDciIconEntry *DDciIconPrivate::loadIcon(const QString &parentDir, const QString &imageDir) { // Mode-Theme auto props = imageDir.split(QLatin1Char('.')); const QVector &iconProps = fromQStringList(props); if (iconProps.count() != 2) // Error file name. return nullptr; DDciIcon::Mode mode; DDciIcon::Theme theme; if (!toMode(iconProps[0], &mode)) return nullptr; if (!toTheme(iconProps[1], &theme)) return nullptr; DDciIconEntry *icon = new DDciIconEntry(); icon->mode = mode; icon->theme = theme; const QString &stateDir = joinPath(parentDir, imageDir); for (const QString &scaleString : dciFile->list(stateDir, true)) { bool ok = false; int scale = scaleString.toInt(&ok); // No restrictions on icons with scale ratio greater than 3. if (!ok) continue; DDciIconEntry::ScalableLayer scaleIcon; scaleIcon.imagePixelRatio = scale; const QString &path = joinPath(stateDir, scaleString); for (const QString &layerPath : dciFile->list(path, true)) { props = layerPath.split(QLatin1Char('.')); const QVector &layerProps = fromQStringList(props); DDciIconEntry::ScalableLayer::Layer layer; EntryPropertyParser::doParse(&layer, layerProps); layer.data = dciFile->dataRef(joinPath(path, layerPath)); // The sequence number starts with 1, convert it into index. scaleIcon.layers.insert(layer.prior - 1, layer); icon->maxPaddings = qMax(icon->maxPaddings, layer.padding); } icon->scalableLayers.append(scaleIcon); } return icon; } void DDciIconPrivate::loadIconList() { const QStringList &listOfSize = dciFile->list(QLatin1String("/"), true); for (const QString &dir : listOfSize) { bool ok = false; int size = dir.toInt(&ok); if (!ok) continue; EntryNode node; node.iconSize = size; node.maxPaddings = 0; const QString &dirPath = joinPath(QLatin1String(), dir); for (const QString &imageDir : dciFile->list(dirPath, true)) { auto icon = loadIcon(dirPath, imageDir); if (!icon || icon->isNull()) continue; icon->iconSize = size; node.entries << icon; node.maxPaddings = qMax(node.maxPaddings, icon->maxPaddings); } if (node.entries.isEmpty()) continue; icons << std::move(node); } } void DDciIconPrivate::ensureLoaded() { // TODO: Modified to resemble the addFile function in QIcon. if (!dciFile->isValid()) return; loadIconList(); } DDciIconEntry *DDciIconPrivate::tryMatchIcon(int iconSize, DDciIcon::Theme theme, DDciIcon::Mode mode, DDciIcon::IconMatchedFlags flags) const { if (icons.isEmpty()) return nullptr; auto neighborIndex = findIconsByLowerBoundSize(icons, iconSize, flags & DDciIcon::RegardPaddingsAsSize); if (neighborIndex < 0) { neighborIndex = static_cast(icons.size() - 1); } const auto &listOfSize = icons.at(neighborIndex); QVector iconWeight; iconWeight.resize(listOfSize.entries.size()); for (int i = 0; i < listOfSize.entries.size(); ++i) { qint8 weight = 0; const DDciIconEntry *icon = listOfSize.entries.at(i); if (icon->mode == mode) { weight += 2; } else if (flags.testFlag(DDciIcon::DontFallbackMode) || icon->mode != DDciIcon::Normal) { weight = -1; continue; } if (icon->theme == theme) { weight += 1; } else { weight = -1; continue; } iconWeight[i] = weight; } const auto targetIcon = std::max_element(iconWeight.constBegin(), iconWeight.constEnd()); if (targetIcon != iconWeight.constEnd() && *targetIcon > 0) return listOfSize.entries.at(targetIcon - iconWeight.constBegin()); return nullptr; } static const DDciIconEntry::ScalableLayer &findScalableLayer(const DDciIconEntry *entry, qreal devicePixelRatio) { const DDciIconEntry::ScalableLayer *maxLayer = nullptr; const int imagePixelRatio = qCeil(devicePixelRatio); for (const auto &i : qAsConst(entry->scalableLayers)) { if (!maxLayer || i.imagePixelRatio > maxLayer->imagePixelRatio) maxLayer = &i; if (i.imagePixelRatio > imagePixelRatio) return i; } Q_ASSERT(maxLayer); return *maxLayer; } void DDciIconPrivate::paint(QPainter *painter, const QRectF &rect, Qt::Alignment alignment, const QVector &layers, QVector *layerReaders, const DDciIconPalette &palette, qreal pixmapScale) { const bool useImageReader = layerReaders && !layerReaders->isEmpty(); Q_ASSERT(!useImageReader || layerReaders->size() == layers.size()); for (auto layerIter = layers.begin(); layerIter != layers.end(); ++layerIter) { QImage layer; if (useImageReader) { const qsizetype index = layerIter - layers.begin(); auto &reader = layerReaders->operator [](index); if (reader->currentImageIsValid) { layer = reader->currentImage; } else { layer = readImageData(*reader->reader, pixmapScale, layerIter->isAlpha8Format); reader->currentImage = layer; reader->currentImageIsValid = true; } } else { if (layerIter->data.isEmpty()) continue; layer = readImageData(layerIter->data, layerIter->format, pixmapScale, layerIter->isAlpha8Format); } if (layer.isNull()) continue; QColor fillColor; switch (layerIter->role) { case DDciIconPalette::Foreground: fillColor = palette.foreground(); break; case DDciIconPalette::Background: fillColor = palette.background(); break; case DDciIconPalette::HighlightForeground: fillColor = palette.highlightForeground(); break; case DDciIconPalette::Highlight: fillColor = palette.highlight(); break; default: break; } // ###(Chen Bin) Can't compose image when this image's format is Format_Alpha8. if (layer.format() == QImage::Format_Alpha8) layer = layer.convertToFormat(QImage::Format_ARGB32_Premultiplied); if (fillColor.isValid()) { QPainter render(&layer); fillColor = DGuiApplicationHelper::adjustColor(fillColor, layerIter->hue, layerIter->saturation, layerIter->lightness, layerIter->red, layerIter->green, layerIter->blue, layerIter->alpha); render.setCompositionMode(QPainter::CompositionMode_SourceIn); render.fillRect(layer.rect(), fillColor); } QRectF targetRect =alignedRect(painter->layoutDirection(), alignment, layer.size(), rect); if (rect.width() < targetRect.width()) targetRect = rect; painter->drawImage(targetRect, layer); } } void DDciIconPrivate::paint(QPainter *painter, const QRect &rect, qreal devicePixelRatio, Qt::Alignment alignment, const DDciIconEntry *entry, const DDciIconPalette &palette, qreal pixmapScale) { qreal pixelRatio = devicePixelRatio; bool useHighDpiPixmaps = #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) true; #else qApp->testAttribute(Qt::AA_UseHighDpiPixmaps); #endif if (pixelRatio <= 0 && painter->device() && useHighDpiPixmaps) pixelRatio = painter->device()->devicePixelRatio(); if (pixelRatio <= 0) pixelRatio = 1.0; auto scalableLayer = findScalableLayer(entry, devicePixelRatio); paint(painter, rect, alignment, scalableLayer.layers, nullptr, palette, pixelRatio * pixmapScale / scalableLayer.imagePixelRatio); } bool DDciIconPrivate::hasPalette(DDciIconMatchResult result) const { auto entry = static_cast(result); if (!entryIsValid(entry)) return false; if (entry->scalableLayers.isEmpty()) return false; auto scaledLayer = entry->scalableLayers.first(); return hasPalette(scaledLayer.layers); } DDciIcon::DDciIcon() : d(new DDciIconPrivate()) { } DDciIcon::DDciIcon(const DDciFile *dciFile) : DDciIcon() { d->dciFile.reset(dciFile); d->ensureLoaded(); } DDciIcon::DDciIcon(const QString &fileName) : DDciIcon() { d->dciFile.reset(new DDciFile(fileName)); d->ensureLoaded(); } DDciIcon::DDciIcon(const QByteArray &data) : DDciIcon() { d->dciFile.reset(new DDciFile(data)); d->ensureLoaded(); } DDciIcon::DDciIcon(const DDciIcon &other) : d(other.d) { } DDciIcon &DDciIcon::operator=(const DDciIcon &other) noexcept { d = other.d; return *this; } DDciIcon::~DDciIcon() {} DDciIcon::DDciIcon(DDciIcon &&other) noexcept : d(other.d) { other.d = nullptr; } DDciIcon &DDciIcon::operator=(DDciIcon &&other) noexcept { swap(other); return *this; } bool DDciIcon::isNull() const { return d->icons.isEmpty(); } DDciIconMatchResult DDciIcon::matchIcon(int size, Theme theme, Mode mode, IconMatchedFlags flags) const { return d->tryMatchIcon(size, theme, mode, flags); } int DDciIcon::actualSize(DDciIconMatchResult result) const { auto entry = static_cast(result); if (!d->entryIsValid(entry)) return -1; return entry->iconSize; } int DDciIcon::actualSize(int size, DDciIcon::Theme theme, DDciIcon::Mode mode) const { auto entry = d->tryMatchIcon(size, theme, mode); return actualSize(entry); } QList DDciIcon::availableSizes(DDciIcon::Theme theme, DDciIcon::Mode mode) const { if (d->icons.isEmpty()) return {}; QList sizes; std::for_each(d->icons.begin(), d->icons.end(), [theme, mode, &sizes](const EntryNode &node) { auto it = std::find_if(node.entries.begin(), node.entries.end(), [theme, mode](const DDciIconEntry *entry) { if (entry->mode == mode && entry->theme == theme) return true; return false; }); if (it != node.entries.end()) sizes.append((*it)->iconSize); }); return sizes; } bool DDciIcon::isSupportedAttribute(DDciIconMatchResult result, IconAttribute attr) const { switch (attr) { case HasPalette: return d->hasPalette(result); default: break; } return false; } bool DDciIcon::isSupportedAttribute(const DDciIconImage &image, IconAttribute attr) { if (image.isNull()) return false; switch (attr) { case HasPalette: return DDciIconPrivate::hasPalette(image.d->layers); default: break; } return false; } QPixmap DDciIcon::pixmap(qreal devicePixelRatio, int iconSize, DDciIcon::Theme theme, DDciIcon::Mode mode, const DDciIconPalette &palette) const { auto entry = d->tryMatchIcon(iconSize, theme, mode); return pixmap(devicePixelRatio, iconSize, entry, palette); } QPixmap DDciIcon::pixmap(qreal devicePixelRatio, int iconSize, DDciIconMatchResult result, const DDciIconPalette &palette) const { auto image = this->image(result, iconSize, devicePixelRatio); if (image.isNull()) return QPixmap(); return QPixmap::fromImage(image.toImage(palette)); } void DDciIcon::paint(QPainter *painter, const QRect &rect, qreal devicePixelRatio, DDciIcon::Theme theme, DDciIcon::Mode mode, Qt::Alignment alignment, const DDciIconPalette &palette) const { int canvarsSize = qMax(rect.width(), rect.height()); auto entry = d->tryMatchIcon(canvarsSize, theme, mode, RegardPaddingsAsSize); return paint(painter, rect, devicePixelRatio, entry, alignment, palette); } void DDciIcon::paint(QPainter *painter, const QRect &rect, qreal devicePixelRatio, DDciIconMatchResult result, Qt::Alignment alignment, const DDciIconPalette &palette) const { auto entry = static_cast(result); if (!d->entryIsValid(entry)) return; qreal canvarsSize = qMax(rect.width(), rect.height()); const qreal pixmapScale = canvarsSize / (entry->iconSize + entry->maxPaddings * 2); d->paint(painter, rect, devicePixelRatio, alignment, entry, palette, pixmapScale); } DDciIconImage DDciIcon::image(DDciIconMatchResult result, int size, qreal devicePixelRatio) const { auto entry = static_cast(result); if (!d->entryIsValid(entry)) return DDciIconImage(); auto scalableLayer = findScalableLayer(entry, devicePixelRatio); int iconSize = size; if (iconSize <= 0) iconSize = entry->iconSize; Q_ASSERT_X((iconSize > 0), "DDciIcon::generatePixmap", "You must specify the icon size."); const qreal pixmapScale = qreal(iconSize) / entry->iconSize; const qreal imageSize = (entry->maxPaddings * 2 + entry->iconSize) * pixmapScale; const qreal imageScale = pixmapScale * devicePixelRatio / scalableLayer.imagePixelRatio; auto image = QSharedPointer(new DDciIconImagePrivate(imageSize, devicePixelRatio, imageScale, scalableLayer)); return DDciIconImage(image); } DDciIcon DDciIcon::fromTheme(const QString &name) { if (QDir::isAbsolutePath(name)) return DDciIcon(name); DDciIcon icon; QString iconName = name; // FIX uengine appname is empty, will cause qt_assert if (!QCoreApplication::applicationName().isEmpty() && !DSGApplication::id().isEmpty()) { // allow the icon theme to override the icon for a given application iconName.prepend(DSGApplication::id() + "/"); } QString iconPath; QString iconThemeName =DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName(); if (auto cached = DIconTheme::cached()) { iconPath = cached->findDciIconFile(iconName, iconThemeName); } else { iconPath = DIconTheme::findDciIconFile(iconName, iconThemeName); } if (!iconPath.isEmpty()) icon = DDciIcon(iconPath); return icon; } DDciIcon DDciIcon::fromTheme(const QString &name, const DDciIcon &fallback) { DDciIcon icon = fromTheme(name); if (icon.isNull() || icon.availableSizes(Light).isEmpty() || icon.availableSizes(Dark).isEmpty()) return fallback; return icon; } #ifndef QT_NO_DATASTREAM QDataStream &operator<<(QDataStream &s, const DDciIcon &icon) { if (icon.isNull()) return s << QByteArray(); auto dciFile = icon.d->dciFile; const QByteArray &data = dciFile->toData(); s << data; return s; } QDataStream &operator>>(QDataStream &s, DDciIcon &icon) { QByteArray data; s >> data; icon = DDciIcon(data); return s; } DDciIconImage::DDciIconImage(const DDciIconImage &other) : d(other.d) { } DDciIconImage &DDciIconImage::operator=(const DDciIconImage &other) noexcept { d = other.d; return *this; } DDciIconImage::~DDciIconImage() { reset(); } DDciIconImage::DDciIconImage(DDciIconImage &&other) noexcept : d(other.d) { } DDciIconImage &DDciIconImage::operator=(DDciIconImage &&other) noexcept { swap(other); return *this; } void DDciIconImage::reset() { if (!d) return; qDeleteAll(d->readers); d->readers.clear(); d->supportsAnimation = false; d->totalMaxImageCount = 0; d->maxLoopCount = -2; d->animation = nullptr; d->currentImageNumber = 0; d->pastImageCount = 0; d->currentPastImageDelay = 0; } QImage DDciIconImage::toImage(const DDciIconPalette &palette) const { const int imageSize = qRound(d->imageSize * d->devicePixelRatio); QImage image(imageSize, imageSize, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); QPainter painter(&image); painter.setRenderHint(QPainter::SmoothPixmapTransform); paint(&painter, image.rect(), Qt::AlignCenter, palette); image.setDevicePixelRatio(d->devicePixelRatio); return image; } void DDciIconImage::paint(QPainter *painter, const QRectF &rect, Qt::Alignment alignment, const DDciIconPalette &palette) const { DDciIconPrivate::paint(painter, rect, alignment, d->layers, &d->readers, palette, d->imageScale); } bool DDciIconImage::hasPalette() const { return DDciIcon::isSupportedAttribute(*this, DDciIcon::HasPalette); } bool DDciIconImage::supportsAnimation() const { if (!d) return false; d->ensureLoad(); return d->supportsAnimation; } bool DDciIconImage::atBegin() const { return d && d->pastImageCount == 0; } bool DDciIconImage::atEnd() const { return d && d->supportsAnimation && d->pastImageCount >= d->totalMaxImageCount - 1; } bool DDciIconImage::jumpToNextImage() { d->ensureLoad(); if (!d->animation) return false; // Jump to next frame for current animation image d->animation->jumpToNextImage(d.get()); d->currentPastImageDelay = d->animation->pastImageDelay; d->animation = d->readAnimationNextData(); if (d->animation) { ++d->currentImageNumber; // Clear old images if icon animation is not last frame for (auto &reader : d->readers) { if (reader->currentImageIsEnd(d.get())) reader->currentImage = QImage(); } } return d->animation; } int DDciIconImage::loopCount() const { if (!d) return 0; d->ensureLoad(); return d->maxLoopCount; } int DDciIconImage::maxImageCount() const { if (!d) return 0; d->ensureLoad(); if (!d->supportsAnimation) return 0; return d->totalMaxImageCount; } int DDciIconImage::currentImageDuration() const { if (!d) return -1; d->ensureLoad(); if (!d->animation) return -1; return d->animation->pastImageDelay + d->animation->reader->nextImageDelay() - d->currentPastImageDelay; } int DDciIconImage::currentImageNumber() const { return d ? d->currentImageNumber : -1; } void DDciIconImagePrivate::init() { readers.reserve(layers.size()); for (const auto &layer : qAsConst(layers)) { ReaderData *data = new ReaderData; Q_ASSERT(data); auto buffer = new QBuffer(); data->buffer.reset(buffer); auto reader = new QImageReader(); data->reader.reset(reader); readers.append(data); data->index = readers.size() - 1; buffer->setData(layer.data); buffer->open(QIODevice::ReadOnly); Q_ASSERT(buffer->isOpen()); reader->setDevice(buffer); reader->setFormat(layer.format); if (reader->supportsAnimation()) { supportsAnimation = true; totalMaxImageCount += reader->imageCount(); maxLoopCount = qMax(maxLoopCount, reader->loopCount()); } } if (supportsAnimation) animation = readAnimationNextData(); } DDciIconImagePrivate::ReaderData *DDciIconImagePrivate::readAnimationNextData() { const ReaderData *next = nullptr; for (auto &reader : readers) { if (!reader->reader->supportsAnimation()) continue; // Ensure can get a valid QImageReader::nextImageDelay(), Because // using QImageReader::nextImageDelay() needs call QImageReader::read() before. reader->initCurrentImage(this); if (reader->currentImageIsEnd(this) && !reader->jumpToNextImage(this)) continue; if (!next || reader->currentImageEndTime() < next->currentImageEndTime()) next = reader; } return const_cast(next); } #endif DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/ddciiconpalette.cpp000066400000000000000000000106701476226661100205170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddciiconpalette.h" #include #include #include #include DGUI_BEGIN_NAMESPACE DDciIconPalette::DDciIconPalette(QColor foreground, QColor background, QColor highlight, QColor highlightForeground) { colors.reserve(PaletteCount); colors.insert(Foreground, foreground); colors.insert(Background, background); colors.insert(HighlightForeground, highlightForeground); colors.insert(Highlight, highlight); } bool DDciIconPalette::operator==(const DDciIconPalette &other) const { for (int i = Foreground; i < PaletteCount; ++i) { if (colors.at(i) != other.colors.at(i)) return false; } return true; } bool DDciIconPalette::operator!=(const DDciIconPalette &other) const { return !(*this == other); } QColor DDciIconPalette::foreground() const { return colors.at(Foreground); } void DDciIconPalette::setForeground(const QColor &foreground) { colors[Foreground] = foreground; } QColor DDciIconPalette::background() const { return colors[Background]; } void DDciIconPalette::setBackground(const QColor &background) { colors[Background] = background; } QColor DDciIconPalette::highlightForeground() const { return colors[HighlightForeground]; } void DDciIconPalette::setHighlightForeground(const QColor &highlightForeground) { colors[HighlightForeground] = highlightForeground; } QColor DDciIconPalette::highlight() const { return colors[Highlight]; } void DDciIconPalette::setHighlight(const QColor &highlight) { colors[Highlight] = highlight; } static QString _d_dciIconPaletteHost() { return QLatin1String("dtk.dci.palette"); } QString DDciIconPalette::convertToString(const DDciIconPalette &palette) { QUrl url; url.setHost(_d_dciIconPaletteHost()); QUrlQuery query; if (palette.foreground().isValid()) query.addQueryItem(QLatin1String("foreground"), palette.foreground().name(QColor::HexArgb)); if (palette.background().isValid()) query.addQueryItem(QLatin1String("background"), palette.background().name(QColor::HexArgb)); if (palette.highlight().isValid()) query.addQueryItem(QLatin1String("highlight"), palette.highlight().name(QColor::HexArgb)); if (palette.highlightForeground().isValid()) query.addQueryItem(QLatin1String("highlightForeground"), palette.highlightForeground().name(QColor::HexArgb)); url.setQuery(query); return url.toString(); } DDciIconPalette DDciIconPalette::convertFromString(const QString &data) { QUrl url(data); if (url.host() != _d_dciIconPaletteHost()) return DDciIconPalette(); QUrlQuery query(url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1)); QColor foreground; if (query.hasQueryItem(QLatin1String("foreground"))) foreground = query.queryItemValue(QLatin1String("foreground")); QColor background; if (query.hasQueryItem(QLatin1String("background"))) background = query.queryItemValue(QLatin1String("background")); QColor highlight; if (query.hasQueryItem(QLatin1String("highlight"))) highlight = query.queryItemValue(QLatin1String("highlight")); QColor highlightForeground; if (query.hasQueryItem(QLatin1String("highlightForeground"))) highlightForeground = query.queryItemValue(QLatin1String("highlightForeground")); return DDciIconPalette(foreground, background, highlight, highlightForeground); } DDciIconPalette DDciIconPalette::fromQPalette(const QPalette &pa) { return DDciIconPalette(pa.windowText().color(), pa.window().color(), pa.highlight().color(), pa.highlightedText().color()); } DGUI_END_NAMESPACE QT_BEGIN_NAMESPACE DGUI_USE_NAMESPACE #ifndef QT_NO_DEBUG_STREAM static inline QString getColorName(QColor color) { if (color.isValid()) return color.name(QColor::HexArgb); return QLatin1String("InValid"); }; QDebug operator<<(QDebug dbg, const DDciIconPalette &pal) { QDebugStateSaver saver(dbg); QDebug nospace = dbg.nospace(); nospace << "DDciIconPalette(foreground: " << getColorName(pal.foreground()) << ",background: " << getColorName(pal.background()) << ",highlight: " << getColorName(pal.highlight()) << ",highlightForeground: " << getColorName(pal.highlightForeground()) << ")"; return dbg; } #endif QT_END_NAMESPACE dtkgui-5.7.12/src/util/ddciiconplayer.cpp000066400000000000000000001000471476226661100203530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddciiconplayer.h" #include "ddciicon.h" #include #include #include #include #include DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE #ifdef QT_DEBUG Q_LOGGING_CATEGORY(diPlayer, "dtk.dciicon.player") #else Q_LOGGING_CATEGORY(diPlayer, "dtk.dciicon.player", QtInfoMsg) #endif class DDciIconImagePlayerPrivate : DObjectPrivate { public: DDciIconImagePlayerPrivate(DDciIconImagePlayer *qq) : DObjectPrivate(qq) {} bool initCurrent(); bool ensureCurrent(); void clearCache(); void setState(DDciIconImagePlayer::State newState); inline bool reversed() const { return flags.testFlag(DDciIconImagePlayer::InvertedOrder); } inline bool hasCache(int imageIndex, int frameNumber) const { if (imageIndex < 0 || frameNumber < 0) return false; if (cachedFrames.size() <= imageIndex) return false; const auto &i = cachedFrames.at(imageIndex); if (i.size() <= frameNumber) return false; return true; } inline bool currentHasCache() const { return current >= 0 && currentFrameNumber >= 0 && hasCache(current, currentFrameNumber); } D_DECLARE_PUBLIC(DDciIconImagePlayer) QVector images; DDciIconPalette palette; inline DDciIconImage ¤tImage() { return images[current]; } DDciIconImagePlayer::State state = DDciIconImagePlayer::NotRunning; DDciIconImagePlayer::Flags flags; float speed = 1.0; // loop count for all images sequential animation int userLoopCount = 1; struct Frame { QImage image; int duration; }; QVector> cachedFrames; inline QVector ¤tCache() { return cachedFrames[current]; } int timerId = 0; // loop count for all images sequential animation, init from "userLoopCount" when start int loopCount = 1; int current = 0; int currentLoopCount = 0; int currentFrameNumber = 0; }; inline static bool jumpImageTo(DDciIconImage &image, int number) { if (number < 0) return false; if (image.currentImageNumber() > number) image.reset(); for (int i = image.currentImageNumber(); i < number; ++i) if (!image.jumpToNextImage()) return false;; return true; } bool DDciIconImagePlayerPrivate::initCurrent() { if (!currentImage().supportsAnimation()) return false; if (reversed()) { if (currentFrameNumber < 0) currentFrameNumber = currentCache().size() - 1; } else { if (currentFrameNumber < 0) currentFrameNumber = 0; } if (!currentHasCache()) { if (!jumpImageTo(currentImage(), currentFrameNumber)) return false; } if ((flags & DDciIconImagePlayer::CacheAll) && cachedFrames.size() <= current) { cachedFrames.append(QVector()); } if (current == images.size() - 1) { if (flags.testFlag(DDciIconImagePlayer::IgnoreLastImageLoop)) { currentLoopCount = 1; } else { currentLoopCount = currentImage().loopCount(); } } else if (flags.testFlag(DDciIconImagePlayer::AllowNonLastImageLoop)) { currentLoopCount = currentImage().loopCount(); } else { currentLoopCount = 1; } if (currentLoopCount == 0) currentLoopCount = 1; return true; } bool DDciIconImagePlayerPrivate::ensureCurrent() { while (current >= 0 && current < images.size()) { if (initCurrent()) return true; current += reversed() ? -1 : 1; currentFrameNumber = -1; } return false; } void DDciIconImagePlayerPrivate::clearCache() { cachedFrames.clear(); } void DDciIconImagePlayerPrivate::setState(DDciIconImagePlayer::State newState) { if (state == newState) return; state = newState; Q_EMIT q_func()->stateChanged(); } DDciIconImagePlayer::DDciIconImagePlayer(QObject *parent) : QObject(parent) , DObject(*new DDciIconImagePlayerPrivate(this)) { } void DDciIconImagePlayer::setImages(const QVector &images) { D_D(DDciIconImagePlayer); if (d->images == images) return; if (d->state != NotRunning) stop(); Q_ASSERT(d->state == NotRunning); d->images = images; d->current = -1; d->currentFrameNumber = -1; d->clearCache(); } QVector DDciIconImagePlayer::images() const { D_DC(DDciIconImagePlayer); return d->images; } const DDciIconImage &DDciIconImagePlayer::currentImage() const { D_DC(DDciIconImagePlayer); static DDciIconImage nullImage; if (d->state == NotRunning) return nullImage; return d->images.at(d->current); } bool DDciIconImagePlayer::currentLoopForever() const { D_DC(DDciIconImagePlayer); return d->state != NotRunning && d->currentLoopCount < 0; } bool DDciIconImagePlayer::setPalette(const DDciIconPalette &palette) { D_D(DDciIconImagePlayer); if (d->palette == palette) return false; d->palette = palette; bool hasPalette = false; for (const auto &i : qAsConst(d->images)) if (i.hasPalette()) hasPalette = true; if (!hasPalette) return true; if (d->state == NotRunning) { d->clearCache(); } else { d->flags |= ClearCacheOnStop; } return true; } DDciIconPalette DDciIconImagePlayer::palette() const { D_DC(DDciIconImagePlayer); return d->palette; } void DDciIconImagePlayer::setLoopCount(int count) { D_D(DDciIconImagePlayer); if (count <= 0) return; if (d->state != NotRunning) { d->loopCount += (count - d->userLoopCount); } d->userLoopCount = count; } int DDciIconImagePlayer::loopCount() const { D_DC(DDciIconImagePlayer); return d->userLoopCount; } void DDciIconImagePlayer::abortLoop() { D_D(DDciIconImagePlayer); if (d->state == NotRunning) return; d->flags = (d->flags | IgnoreLastImageLoop) & (~AllowNonLastImageLoop); d->currentLoopCount = 0; d->loopCount = 0; } QImage DDciIconImagePlayer::readImage() { D_D(DDciIconImagePlayer); if (d->state != WaitingRead) return QImage(); QImage image; int timerIntervel = 0; if (d->currentHasCache()) { image = d->currentCache().at(d->currentFrameNumber).image; timerIntervel = qRound(d->currentCache().at(d->currentFrameNumber).duration / d->speed); } else { Q_ASSERT(!d->reversed()); Q_ASSERT(d->currentImage().currentImageNumber() == d->currentFrameNumber); image = d->currentImage().toImage(d->palette); if (d->flags & CacheAll) { Q_ASSERT(d->currentImage().currentImageNumber() == d->currentFrameNumber); Q_ASSERT(d->currentCache().size() == d->currentFrameNumber); d->currentCache().append({image, d->currentImage().currentImageDuration()}); } timerIntervel = qRound(d->currentImage().currentImageDuration() / d->speed); } d->timerId = startTimer(timerIntervel < 0 ? 0 : timerIntervel); if (d->timerId == 0) { qCWarning(diPlayer, "Can't start timer, will abort the animations."); stop(); Q_EMIT finished(); return image; } d->setState(Running); return image; } DDciIconImagePlayer::State DDciIconImagePlayer::state() const { D_DC(DDciIconImagePlayer); return d->state; } void DDciIconImagePlayer::clearCache() { D_D(DDciIconImagePlayer); d->clearCache(); } bool DDciIconImagePlayer::start(float speed, Flags flags) { D_D(DDciIconImagePlayer); if (d->state != NotRunning) return false; if (d->images.isEmpty()) return false; d->flags = flags; if (!d->flags.testFlag(Continue) || d->current < 0) { d->current = d->reversed() ? d->images.size() - 1 : 0; } if (d->reversed()) { d->flags |= CacheAll; if (d->cachedFrames.isEmpty()) { d->cachedFrames.resize(d->images.size()); for (int i = 0; i <= d->current; ++i) { DDciIconImage &image = d->images[i]; if (!image.supportsAnimation()) continue; image.reset(); do { d->cachedFrames[i].append({image.toImage(d->palette), image.currentImageDuration()}); } while (image.jumpToNextImage()); } } else if (!flags.testFlag(Continue)) { auto &image = d->images[d->cachedFrames.size() - 1]; if (image.supportsAnimation() && jumpImageTo(image, d->cachedFrames.last().size())) { do { d->cachedFrames.last().append({image.toImage(d->palette), image.currentImageDuration()}); } while (image.jumpToNextImage()); } for (int i = d->cachedFrames.size(); i < d->images.size(); ++i) { d->cachedFrames.append(QVector()); auto &image = d->images[i]; if (!image.supportsAnimation()) continue; image.reset(); do { d->cachedFrames[i].append({image.toImage(d->palette), image.currentImageDuration()}); } while (image.jumpToNextImage()); } d->currentFrameNumber = d->currentCache().size() - 1; } } else { if (flags.testFlag(Continue)) { if (d->current < 0) d->current = 0; } else { d->current = 0; d->currentFrameNumber = 0; } // Init cache if (flags.testFlag(CacheAll) && d->cachedFrames.isEmpty() && (d->current > 0 || d->currentFrameNumber > 0)) { d->cachedFrames.resize(d->images.size()); DDciIconImage &image = d->images[d->current]; if (image.supportsAnimation()) { image.reset(); do { d->cachedFrames[d->current].append({image.toImage(d->palette), image.currentImageDuration()}); } while (image.jumpToNextImage()); } } } d->speed = speed > 0.0 ? speed : 1.0; d->loopCount = d->userLoopCount; if (!d->ensureCurrent()) return false; d->setState(WaitingRead); Q_EMIT started(); Q_EMIT updated(); return true; } void DDciIconImagePlayer::stop() { D_D(DDciIconImagePlayer); if (d->state == NotRunning) return; if (d->timerId > 0) { killTimer(d->timerId); d->timerId = 0; } if (d->flags & ClearCacheOnStop) d->clearCache(); d->setState(NotRunning); } void DDciIconImagePlayer::timerEvent(QTimerEvent *event) { D_D(DDciIconImagePlayer); if (event->timerId() != d->timerId) return QObject::timerEvent(event); killTimer(d->timerId); d->timerId = 0; bool finished = false; const int newFrameNumber = d->currentFrameNumber + (d->reversed() ? -1 : 1); if (!d->hasCache(d->current, newFrameNumber)) { if (d->reversed()) { finished = true; } else { finished = !jumpImageTo(d->currentImage(), newFrameNumber); } } #define IGNORE_LOOP qEnvironmentVariableIsSet("D_DTK_DCI_PLAYER_IGNORE_ANIMATION_LOOP") if (finished) { if (d->currentLoopCount != 0 && --d->currentLoopCount && !IGNORE_LOOP) { // reset value d->currentFrameNumber = -1; // replay current image bool ok = d->initCurrent(); Q_ASSERT(ok); finished = false; } else { const int newCurrent = d->current + (d->reversed() ? -1 : 1); if (newCurrent >= 0 && newCurrent < d->images.size()) { d->current = newCurrent; d->currentFrameNumber = -1; if (d->ensureCurrent()) finished = false; } } } else { d->currentFrameNumber = newFrameNumber; } if (finished && d->loopCount != 0 && (--d->loopCount) && !IGNORE_LOOP) { d->current = d->reversed() ? d->images.size() - 1 : 0; d->currentFrameNumber = -1; if (d->ensureCurrent()) finished = false; } if (finished) { stop(); Q_EMIT this->finished(); } else { d->setState(WaitingRead); Q_EMIT updated(); } } static QString iconModeToString(DDciIcon::Mode mode) { switch (mode) { case DDciIcon::Normal: return QStringLiteral("Normal"); case DDciIcon::Hover: return QStringLiteral("Hover"); case DDciIcon::Pressed: return QStringLiteral("Pressed"); case DDciIcon::Disabled: return QStringLiteral("Disabled"); default: break; } return nullptr; } class DDciIconPlayerPrivate : public DObjectPrivate { public: DDciIconPlayerPrivate(DDciIconPlayer *qq) : DObjectPrivate(qq) {} void ensureInit(); void initPlayer(); bool ensureHoverModeLastImage(); void play(DDciIcon::Mode mode, DDciIconImagePlayer::Flags flags); bool play(DDciIcon::Mode fromMode, DDciIcon::Mode toMode, DDciIconImagePlayer::Flags extraflags = {}); inline void _q_playFromQueue(int extraflags = 0) { if (player && player->state() != DDciIconImagePlayer::NotRunning) return; if (animationJobs.isEmpty()) return; const auto &job = animationJobs.first(); bool ok = play(static_cast(job.from), static_cast(job.to), DDciIconImagePlayer::Flags(static_cast(extraflags))); if (!ok) { qCDebug(diPlayer, "Don't play any animations, from mode is \"%s\", to mode is \"%s\"", qPrintable(iconModeToString(job.from)), qPrintable(iconModeToString(job.to))); animationJobs.removeFirst(); } // else: the job will remove on animation finished } void playToQueue(); inline bool start(DDciIcon::Mode forMode, qreal speed = 1.0, DDciIconImagePlayer::Flags flags = {}) { qCDebug(diPlayer) << "Start animation for" << iconModeToString(forMode); const bool ok = player->start(speed, flags); if (ok && forMode == DDciIcon::Hover && !flags.testFlag(DDciIconImagePlayer::InvertedOrder)) { // When from Pressed mode to Hover mode, needs stop at the hover mode animation last frame. saveImageForHoverModeOnFinished = true; } if (ok) { setState(DDciIconPlayer::Busy); } else if (diPlayer().isDebugEnabled()) { qCDebug(diPlayer, "Failed on start animation for \"%s\"", qPrintable(iconModeToString(forMode))); } return ok; } inline void reset() { if (player && player->state() != DDciIconImagePlayer::NotRunning) { player->stop(); } normal = DDciIconImage(); hover = DDciIconImage(); pressed = DDciIconImage(); disabled = DDciIconImage(); hoverModeLastImage = QImage(); } inline bool isValid() const { return !normal.isNull(); } inline void setImage(const QImage &image) { this->image = image; Q_EMIT q_func()->updated(); } inline void setImage(DDciIcon::Mode mode) { auto &image = getImage(mode); if (image.atBegin()) { setImage(image.toImage(player->palette())); } else { setImage(icon.pixmap(devicePixelRatio, iconSize, theme, mode, player->palette()).toImage()); } } inline void setFinishedImage(DDciIcon::Mode mode) { finishedImage = icon.pixmap(devicePixelRatio, iconSize, theme, mode, player->palette()).toImage(); } inline const DDciIconImage &getImage(DDciIcon::Mode mode) const { if (mode == DDciIcon::Hover) { return hover; } else if (mode == DDciIcon::Pressed) { return pressed; } else if (mode == DDciIcon::Disabled) { return disabled; } Q_ASSERT(mode == DDciIcon::Normal); return normal; } inline void setState(DDciIconPlayer::State newState) { if (state == newState) return; state = newState; Q_EMIT q_func()->stateChanged(); } DDciIconPlayer::State state = DDciIconPlayer::Idle; DDciIcon icon; DDciIcon::Theme theme = DDciIcon::Light; DDciIcon::Mode mode = DDciIcon::Normal; DDciIcon::Mode lastMode = DDciIcon::Normal; int iconSize = -1; qreal devicePixelRatio = 1.0; DDciIconImage normal; DDciIconImage hover; DDciIconImage pressed; DDciIconImage disabled; DDciIconImagePlayer *player = nullptr; struct Animation { DDciIcon::Mode from; DDciIcon::Mode to; }; QVector animationJobs; bool saveImageForHoverModeOnFinished = false; QImage image; QImage finishedImage; QImage hoverModeLastImage; D_DECLARE_PUBLIC(DDciIconPlayer) }; void DDciIconPlayerPrivate::ensureInit() { initPlayer(); if (!normal.isNull()) return; if (icon.isNull()) return; normal = icon.image(icon.matchIcon(iconSize, theme, DDciIcon::Normal, DDciIcon::DontFallbackMode), iconSize, devicePixelRatio); hover = icon.image(icon.matchIcon(iconSize, theme, DDciIcon::Hover, DDciIcon::DontFallbackMode), iconSize, devicePixelRatio); pressed = icon.image(icon.matchIcon(iconSize, theme, DDciIcon::Pressed, DDciIcon::DontFallbackMode), iconSize, devicePixelRatio); disabled = icon.image(icon.matchIcon(iconSize, theme, DDciIcon::Disabled, DDciIcon::DontFallbackMode), iconSize, devicePixelRatio); } void DDciIconPlayerPrivate::initPlayer() { if (player) return; player = new DDciIconImagePlayer(q_func()); D_Q(DDciIconPlayer); QObject::connect(player, &DDciIconImagePlayer::updated, q, [this]() { setImage(player->readImage()); }); QObject::connect(player, &DDciIconImagePlayer::finished, q, [q, this]() { qCDebug(diPlayer, "Current animation finished!"); if (saveImageForHoverModeOnFinished) { saveImageForHoverModeOnFinished = false; hoverModeLastImage = image; } if (!animationJobs.isEmpty()) { // Remove the finished animation animationJobs.removeFirst(); qCDebug(diPlayer, "Number of animations remaining is %i", animationJobs.size()); if (!animationJobs.isEmpty()) { _q_playFromQueue(); return; } } if (!finishedImage.isNull()) { setImage(finishedImage); finishedImage = QImage(); } if (mode == DDciIcon::Normal || mode == DDciIcon::Disabled) { player->clearCache(); } setState(DDciIconPlayer::Idle); }); } bool DDciIconPlayerPrivate::ensureHoverModeLastImage() { if (!hoverModeLastImage.isNull()) return true; if (!hover.supportsAnimation()) return false; DDciIconImage image; const bool currentHoverImageIsUsable = hover.atEnd() || !player || player->state() != DDciIconImagePlayer::NotRunning; if (!currentHoverImageIsUsable) { if (icon.isNull()) return false; image = icon.image(icon.matchIcon(iconSize, theme, DDciIcon::Hover, DDciIcon::DontFallbackMode), iconSize, devicePixelRatio); } if (image.isNull()) return false; while (!image.atEnd()) { if (!image.jumpToNextImage()) break; } if (!image.atEnd()) return false; Q_ASSERT(player); hoverModeLastImage = image.toImage(player->palette()); return !hoverModeLastImage.isNull(); } void DDciIconPlayerPrivate::play(DDciIcon::Mode mode, DDciIconImagePlayer::Flags flags) { if (diPlayer().isDebugEnabled()) { qCDebug(diPlayer) << "Immediate play animation for" << iconModeToString(mode); } ensureInit(); if (normal.isNull()) return; // Ensure the old animations clean animationJobs.clear(); player->stop(); finishedImage = QImage(); const DDciIconImage &image = getImage(mode); if (!image.supportsAnimation()) return; player->setImages({image}); start(mode, 1.0, flags); } bool DDciIconPlayerPrivate::play(DDciIcon::Mode fromMode, DDciIcon::Mode toMode, DDciIconImagePlayer::Flags extraflags) { ensureInit(); finishedImage = QImage(); if (normal.isNull()) { setImage(QImage()); return false; } if (fromMode == DDciIcon::Normal) { if (toMode == DDciIcon::Normal) { setImage(DDciIcon::Normal); } else if (toMode == DDciIcon::Hover) { if (hover.isNull()) { return false; } if (hover.supportsAnimation()) { player->setImages({hover}); return start(toMode, 1.0, DDciIconImagePlayer::CacheAll | extraflags); } else { setImage(DDciIcon::Hover); } } else if (toMode == DDciIcon::Pressed) { if (pressed.isNull()) { return false; } if (pressed.supportsAnimation()) { if (hover.supportsAnimation()) { player->setImages({hover, pressed}); return start(toMode, 2.0, DDciIconImagePlayer::CacheAll | extraflags); } else { player->setImages({pressed}); return start(toMode, 1.0, DDciIconImagePlayer::CacheAll | extraflags); } } else { setImage(DDciIcon::Pressed); } } else if (toMode == DDciIcon::Disabled) { if (disabled.isNull()) return false; if (disabled.supportsAnimation()) { player->setImages({disabled}); return start(toMode, 1.0, DDciIconImagePlayer::IgnoreLastImageLoop | extraflags); } else { setImage(DDciIcon::Disabled); } } } else if (fromMode == DDciIcon::Hover) { Q_ASSERT(toMode != DDciIcon::Hover); if (toMode == DDciIcon::Normal) { if (hover.supportsAnimation()) { setFinishedImage(DDciIcon::Normal); player->setImages({hover}); return start(toMode, 1.0, DDciIconImagePlayer::InvertedOrder | DDciIconImagePlayer::IgnoreLastImageLoop | DDciIconImagePlayer::ClearCacheOnStop | extraflags); } else { setImage(DDciIcon::Normal); } } else if (toMode == DDciIcon::Hover) { } else if (toMode == DDciIcon::Pressed) { if (pressed.isNull()) { if (hover.supportsAnimation()) { player->setImages({hover}); return start(toMode, 1.0, DDciIconImagePlayer::InvertedOrder | DDciIconImagePlayer::IgnoreLastImageLoop | extraflags); } else { setImage(DDciIcon::Normal); } return false; } if (pressed.supportsAnimation()) { player->setImages({pressed}); return start(toMode, 1.0, DDciIconImagePlayer::CacheAll | extraflags); } else { setImage(DDciIcon::Pressed); } } else if (toMode == DDciIcon::Disabled) { if (disabled.isNull()) { setImage(DDciIcon::Normal); return false; } if (disabled.supportsAnimation()) { player->setImages({disabled}); return start(toMode, 1.0, DDciIconImagePlayer::IgnoreLastImageLoop | extraflags); } else { setImage(DDciIcon::Disabled); } } } else if (fromMode == DDciIcon::Pressed) { Q_ASSERT(toMode != DDciIcon::Pressed); if (toMode == DDciIcon::Normal) { if (!pressed.supportsAnimation()) { setImage(DDciIcon::Normal); return false; } setFinishedImage(DDciIcon::Normal); if (hover.supportsAnimation()) { player->setImages({hover, pressed}); return start(toMode, 2.0, DDciIconImagePlayer::InvertedOrder | DDciIconImagePlayer::IgnoreLastImageLoop | extraflags); } else { player->setImages({pressed}); return start(toMode, 1.0, DDciIconImagePlayer::InvertedOrder | DDciIconImagePlayer::IgnoreLastImageLoop | extraflags); } } else if (toMode == DDciIcon::Hover) { if (pressed.isNull()) { if (hover.supportsAnimation()) { player->setImages({hover}); return start(toMode, 1.0, DDciIconImagePlayer::CacheAll | extraflags); } else { setImage(DDciIcon::Hover); } return false; } if (pressed.supportsAnimation()) { ensureHoverModeLastImage(); finishedImage = hoverModeLastImage; player->setImages({pressed}); return start(toMode, 1.0, DDciIconImagePlayer::InvertedOrder | DDciIconImagePlayer::IgnoreLastImageLoop | extraflags); } else { setImage(DDciIcon::Hover); } } else if (toMode == DDciIcon::Pressed) { } else if (toMode == DDciIcon::Disabled) { if (disabled.isNull()) { setImage(DDciIcon::Normal); return false; } if (disabled.supportsAnimation()) { player->setImages({disabled}); return start(toMode, 1.0, DDciIconImagePlayer::IgnoreLastImageLoop | extraflags); } else { setImage(DDciIcon::Disabled); } } } else if (fromMode == DDciIcon::Disabled) { Q_ASSERT(toMode != DDciIcon::Disabled); if (disabled.supportsAnimation()) { setFinishedImage(DDciIcon::Normal); player->setImages({disabled}); return start(toMode, 1.0, DDciIconImagePlayer::InvertedOrder | DDciIconImagePlayer::IgnoreLastImageLoop | extraflags); } else { setImage(DDciIcon::Normal); } } return false; } void DDciIconPlayerPrivate::playToQueue() { DDciIconImagePlayer::Flags extraFlags = {}; if (diPlayer().isDebugEnabled()) { qCDebug(diPlayer, "Request play animation in queue, from mode is \"%s\", to mode is \"%s\"", qPrintable(iconModeToString(lastMode)), qPrintable(iconModeToString(mode))); } if (!animationJobs.isEmpty()) { if (diPlayer().isDebugEnabled()) { qCDebug(diPlayer, "Old Animation Queue:"); for (int i = 0; i < animationJobs.count(); ++i) { const Animation &job = animationJobs.at(i); qCDebug(diPlayer, " %d. from mode is \"%s\", to mode is \"%s\"", i + 1, qPrintable(iconModeToString(job.from)), qPrintable(iconModeToString(job.to))); } } // Ignore the same request if (animationJobs.last().from == lastMode && animationJobs.last().to == mode) { qCDebug(diPlayer, "Same as the last animation, ignores this request"); return; } if (animationJobs.last().from == mode && animationJobs.last().to == lastMode) { if (animationJobs.size() > 1) { animationJobs.removeLast(); qCDebug(diPlayer, "Offsets the last unplayed animation, discards the animation, and ignores this request"); return; } else { if (player && player->state() != DDciIconImagePlayer::NotRunning) { extraFlags |= DDciIconImagePlayer::Continue; player->stop(); animationJobs.removeFirst(); } } } } else { if (player) player->stop(); qCDebug(diPlayer, "Old Animation queue is empty"); } animationJobs.append({lastMode, mode}); if (player && player->state() != DDciIconImagePlayer::NotRunning) { player->abortLoop(); Q_ASSERT(!player->currentLoopForever()); // Don't stop current animation, wating play to end. // Ensure the continuity of the animation when multiple states change continuously. // An example is changing from the Normal state to the Hover state and then to the // Pressed state in a short period of time. At this time, the animation in the // hover state may not have finished playing. qCDebug(diPlayer, "Wait the current animation finished to continue play the new animation."); return; } QMetaObject::invokeMethod(q_func(), "_q_playFromQueue", Qt::QueuedConnection, Q_ARG(int, extraFlags)); } DDciIconPlayer::DDciIconPlayer(QObject *parent) : QObject(parent) , DObject(*new DDciIconPlayerPrivate(this)) { } DDciIconPlayer::State DDciIconPlayer::state() const { D_DC(DDciIconPlayer); return d->state; } void DDciIconPlayer::setIcon(const DDciIcon &icon) { D_D(DDciIconPlayer); d->icon = icon; d->reset(); d->playToQueue(); } DDciIcon DDciIconPlayer::icon() const { D_DC(DDciIconPlayer); return d->icon; } void DDciIconPlayer::setTheme(DDciIcon::Theme theme) { D_D(DDciIconPlayer); if (d->theme == theme) return; d->theme = theme; d->reset(); d->playToQueue(); } DDciIcon::Theme DDciIconPlayer::theme() const { D_DC(DDciIconPlayer); return d->theme; } void DDciIconPlayer::setMode(DDciIcon::Mode mode) { D_D(DDciIconPlayer); if (d->mode == mode) return; d->lastMode = d->mode; d->mode = mode; Q_EMIT modeChanged(d->lastMode, mode); if (diPlayer().isDebugEnabled()) { qCDebug(diPlayer) << this << "Old Mode:" << iconModeToString(d->lastMode) << "New Mode" << iconModeToString(d->mode); } if (mode == DDciIcon::Disabled) abort(); d->playToQueue(); } DDciIcon::Mode DDciIconPlayer::mode() const { D_DC(DDciIconPlayer); return d->mode; } void DDciIconPlayer::setIconSize(int size) { D_D(DDciIconPlayer); if (d->iconSize == size) return; d->iconSize = size; d->reset(); d->playToQueue(); } int DDciIconPlayer::iconSize() const { D_DC(DDciIconPlayer); return d->iconSize; } void DDciIconPlayer::setDevicePixelRatio(qreal devicePixelRatio) { D_D(DDciIconPlayer); if (qFuzzyCompare(d->devicePixelRatio, devicePixelRatio)) return; d->devicePixelRatio = devicePixelRatio; d->reset(); d->playToQueue(); } qreal DDciIconPlayer::devicePixelRatio() const { D_DC(DDciIconPlayer); return d->devicePixelRatio; } void DDciIconPlayer::setPalette(const DDciIconPalette &palette) { D_D(DDciIconPlayer); d->initPlayer(); if (d->player->setPalette(palette)) { if (d->hover.hasPalette()) d->hoverModeLastImage = QImage(); const auto &image = d->getImage(d->mode); if (image.hasPalette()) d->playToQueue(); } } QImage DDciIconPlayer::currentImage() const { D_DC(DDciIconPlayer); return d->image; } void DDciIconPlayer::play(DDciIcon::Mode mode) { D_D(DDciIconPlayer); d->play(mode, DDciIconImagePlayer::IgnoreLastImageLoop); } void DDciIconPlayer::stop() { D_D(DDciIconPlayer); if (d->player) d->player->stop(); d->setState(Idle); } void DDciIconPlayer::abort() { D_D(DDciIconPlayer); d->animationJobs.clear(); if (d->player) d->player->stop(); d->setState(Idle); } DGUI_END_NAMESPACE #include "moc_ddciiconplayer.cpp" dtkgui-5.7.12/src/util/ddesktopservices_linux.cpp000066400000000000000000000146321476226661100221660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddesktopservices.h" #include #include #include DGUI_BEGIN_NAMESPACE #define EASY_CALL_DBUS(name) \ QDBusInterface *interface = fileManager1DBusInterface(); \ return interface && \ interface->call(#name, urls2uris(urls), startupId).type() != \ QDBusMessage::ErrorMessage; static const QStringList SOUND_EFFECT_LIST { "message", "camera-shutter", "trash-empty", "x-deepin-app-sent-to-desktop", "desktop-login", "system-shutdown", "desktop-logout", "suspend-resume", "audio-volume-change", "power-unplug-battery-low", "power-plug", "power-unplug", "device-added", "device-removed", "dialog-error", }; static QDBusInterface *fileManager1DBusInterface() { static QDBusInterface interface(QStringLiteral("org.freedesktop.FileManager1"), QStringLiteral("/org/freedesktop/FileManager1"), QStringLiteral("org.freedesktop.FileManager1")); return &interface; } static QStringList urls2uris(const QList &urls) { QStringList list; list.reserve(urls.size()); for (const QUrl &url : urls) { list << url.toString(); } return list; } static QList path2urls(const QList &paths) { QList list; list.reserve(paths.size()); for (const QString &path : paths) { list << QUrl::fromLocalFile(path); } return list; } static QDBusInterface soundEffectInterface() { #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) const auto& infc = QDBusConnection::sessionBus().interface(); QStringList activatableServiceNames = infc->activatableServiceNames(); bool isNewInterface = activatableServiceNames.contains(QLatin1String("org.deepin.dde.SoundEffect1")); #else bool isNewInterface = false; // Qt 5.14 以下就直接用旧的接口 #endif const QLatin1String service(isNewInterface ? "org.deepin.dde.SoundEffect1" :"com.deepin.daemon.SoundEffect"); const QLatin1String path(isNewInterface ? "/org/deepin/dde/SoundEffect1" : "/com/deepin/daemon/SoundEffect"); const QLatin1String interface(isNewInterface ? "org.deepin.dde.SoundEffect1" :"com.deepin.daemon.SoundEffect"); // 使用后端 dbus 接口播放系统音频,音频存放目录: /usr/share/sounds/deepin/stereo/ return QDBusInterface(service, path, interface); } static bool systemSoundEffectEnabled(const QString &name) { auto soundEffect = soundEffectInterface(); if (!soundEffect.property("Enabled").toBool()) return false; QDBusReply reply = soundEffect.call("IsSoundEnabled", name); return reply.isValid() && reply.value(); } bool DDesktopServices::showFolder(const QString &localFilePath, const QString &startupId) { return showFolder(QUrl::fromLocalFile(localFilePath), startupId); } bool DDesktopServices::showFolders(const QList &localFilePaths, const QString &startupId) { return showFolders(path2urls(localFilePaths), startupId); } bool DDesktopServices::showFolder(const QUrl &url, const QString &startupId) { return showFolders(QList() << url, startupId); } bool DDesktopServices::showFolders(const QList &urls, const QString &startupId) { EASY_CALL_DBUS(ShowFolders) } bool DDesktopServices::showFileItemProperty(const QString &localFilePath, const QString &startupId) { return showFileItemProperty(QUrl::fromLocalFile(localFilePath), startupId); } bool DDesktopServices::showFileItemProperties(const QList &localFilePaths, const QString &startupId) { return showFileItemProperties(path2urls(localFilePaths), startupId); } bool DDesktopServices::showFileItemProperty(const QUrl &url, const QString &startupId) { return showFileItemProperties(QList() << url, startupId); } bool DDesktopServices::showFileItemProperties(const QList &urls, const QString &startupId) { EASY_CALL_DBUS(ShowItemProperties) } bool DDesktopServices::showFileItem(const QString &localFilePath, const QString &startupId) { return showFileItem(QUrl::fromLocalFile(localFilePath), startupId); } bool DDesktopServices::showFileItems(const QList &localFilePaths, const QString &startupId) { return showFileItems(path2urls(localFilePaths), startupId); } bool DDesktopServices::showFileItem(const QUrl &url, const QString &startupId) { return showFileItems(QList() << url, startupId); } bool DDesktopServices::showFileItems(const QList &urls, const QString &startupId) { EASY_CALL_DBUS(ShowItems) } bool DDesktopServices::trash(const QString &localFilePath) { return trash(QUrl::fromLocalFile(localFilePath)); } bool DDesktopServices::trash(const QList &localFilePaths) { return trash(path2urls(localFilePaths)); } bool DDesktopServices::trash(const QUrl &url) { return trash(QList() << url); } bool DDesktopServices::trash(const QList &urls) { QDBusInterface *interface = fileManager1DBusInterface(); return interface && interface->call("Trash", urls2uris(urls)).type() != QDBusMessage::ErrorMessage; } bool DDesktopServices::playSystemSoundEffect(const DDesktopServices::SystemSoundEffect &effect) { return playSystemSoundEffect(SOUND_EFFECT_LIST.at(static_cast(effect))); } bool DDesktopServices::playSystemSoundEffect(const QString &name) { if (!systemSoundEffectEnabled(name)) return false; return previewSystemSoundEffect(name); } bool DDesktopServices::previewSystemSoundEffect(const DDesktopServices::SystemSoundEffect &effect) { return previewSystemSoundEffect(SOUND_EFFECT_LIST.at(static_cast(effect))); } bool DDesktopServices::previewSystemSoundEffect(const QString &name) { if (name.isEmpty()) { return false; } // 使用后端 dbus 接口播放系统音频,音频存放目录: /usr/share/sounds/deepin/stereo/ return soundEffectInterface().call("PlaySound", name).type() != QDBusMessage::ErrorMessage; } QString DDesktopServices::getNameByEffectType(const DDesktopServices::SystemSoundEffect &effect) { return SOUND_EFFECT_LIST.at(static_cast(effect)); } QString DDesktopServices::errorMessage() { return fileManager1DBusInterface()->lastError().message(); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/dfontmanager.cpp000066400000000000000000000067701476226661100200370ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #define private public #include #undef private #include "dfontmanager.h" #include "dfontmanager_p.h" #include #include DGUI_BEGIN_NAMESPACE DFontManagerPrivate::DFontManagerPrivate(DFontManager *qq) : DTK_CORE_NAMESPACE::DObjectPrivate(qq) { baseFont.setPixelSize(fontPixelSize[baseFontSizeType]); } /*! \class Dtk::Gui::DFontManager \inmodule dtkgui \brief 字体大小设置的一个类,系统默认只设置T6. */ DFontManager::DFontManager(QObject *parent) : QObject(parent) , DTK_CORE_NAMESPACE::DObject(*new DFontManagerPrivate(this)) { } DFontManager::~DFontManager() { } /*! \enum Dtk::Gui::DFontManager::SizeType DFontManager::SizeType 定义了 DFontManager 的系统字体的定义的大小; 而系统只会设置 T6 为系统默认的字体 \value T1 系统级别为 T1 的字体大小, 默认是40 px \value T2 系统级别为 T2 的字体大小, 默认是30 px \value T3 系统级别为 T3 的字体大小, 默认是24 px \value T4 系统级别为 T4 的字体大小, 默认是20 px \value T5 系统级别为 T5 的字体大小, 默认是17 px \value T6 系统级别为 T6 的字体大小, 默认是14 px \value T7 系统级别为 T7 的字体大小, 默认是13 px \value T8 系统级别为 T8 的字体大小, 默认是12 px \value T9 系统级别为 T9 的字体大小, 默认是11 px \value T10 系统级别为 T10 的字体大小, 默认是10 px \omitvalue NSizeTypes */ /*! \brief 获取字体像素的大小. \a type 字体枚举类型 \return 返回字体像素的大小 */ int DFontManager::fontPixelSize(DFontManager::SizeType type) const { D_DC(DFontManager); if (type >= NSizeTypes) { return 0; } return d->fontPixelSize[type] + d->fontPixelSizeDiff; } /*! \brief 设置字体像素大小. \a type 字体枚举类型 \a size 字体大小 */ void DFontManager::setFontPixelSize(DFontManager::SizeType type, int size) { D_D(DFontManager); if (type >= NSizeTypes) { return; } if (d->fontPixelSize[type] == size) { return; } d->fontPixelSize[type] = size; } /*! \brief 设置字体的通用像素大小. \a font 预设计的字体像素的大小 */ void DFontManager::setBaseFont(const QFont &font) { D_D(DFontManager); if (d->baseFont == font) return; d->baseFont = font; d->fontPixelSizeDiff = fontPixelSize(font) - d->fontPixelSize[d->baseFontSizeType]; Q_EMIT fontChanged(); } QFont DFontManager::baseFont() const { D_DC(DFontManager); return d->baseFont; } void DFontManager::resetBaseFont() { D_DC(DFontManager); QFont font; font.setPixelSize(d->fontPixelSize[d->baseFontSizeType]); setBaseFont(font); } /*! \brief 获取字体. \a pixelSize 字体的像素大小 \a base 要基于的字体 \return 返回设置字体大小后的字体 */ QFont DFontManager::get(int pixelSize, const QFont &base) { QFont font = base; font.setPixelSize(pixelSize); // Ensure that the FamilyResolved flag is set in order for Qt to correctly set fonts font.setFamilies(base.families()); return font; } int DFontManager::fontPixelSize(const QFont &font) { int px = font.pixelSize(); if (px == -1) { px = qRound(std::floor(((font.pointSizeF() * font.d->dpi) / 72) * 100 + 0.5) / 100); } return px; } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/dicon.cpp000066400000000000000000000053121476226661100164550ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dicon.h" #include #include #include DGUI_BEGIN_NAMESPACE DIcon::DIcon(const QIcon &other) : QIcon(other) { } DIcon::~DIcon() { } /*! Icon::pixmap * Returns a pixmap with the requested \a size, \a devicePixelRatio, \a mode, and \a state, generating one if necessary. * * \sa QIcon::actualsize(), QIcon::paint() */ QPixmap DIcon::pixmap(const QSize &size, qreal devicePixelRatio, QIcon::Mode mode, QIcon::State state) { DataPtr d = data_ptr(); if (!d) return QPixmap(); if (qFuzzyCompare(devicePixelRatio, -1)) devicePixelRatio = qApp->devicePixelRatio(); if (!(devicePixelRatio > 1.0)) { QPixmap pixmap = d->engine->pixmap(size, mode, state); pixmap.setDevicePixelRatio(1.0); return pixmap; } QPixmap pixmap = d->engine->scaledPixmap(size * devicePixelRatio, mode, state, devicePixelRatio); auto pixmapDevicePixelRatio = [](qreal displayDevicePixelRatio, const QSize &requestedSize, const QSize &actualSize)->qreal { QSize targetSize = requestedSize * displayDevicePixelRatio; if ((actualSize.width() == targetSize.width() && actualSize.height() <= targetSize.height()) || (actualSize.width() <= targetSize.width() && actualSize.height() == targetSize.height())) { return displayDevicePixelRatio; } qreal scale = 0.5 * (qreal(actualSize.width()) / qreal(targetSize.width()) + qreal(actualSize.height() / qreal(targetSize.height()))); return qMax(qreal(1.0), displayDevicePixelRatio * scale); }; pixmap.setDevicePixelRatio(pixmapDevicePixelRatio(devicePixelRatio, size, pixmap.size())); return pixmap; } /*! * @brief DIcon::loadNxPixmap loads the suitable @Nx image. * @param fileName is the original resource file name. * @return the hiDPI ready QPixmap. */ QPixmap DIcon::loadNxPixmap(const QString &fileName) { qreal sourceDevicePixelRatio = 1.0; qreal devicePixelRatio = qApp->devicePixelRatio(); QPixmap pixmap; if (!qFuzzyCompare(sourceDevicePixelRatio, devicePixelRatio)) { QImageReader reader; reader.setFileName(qt_findAtNxFile(fileName, devicePixelRatio, &sourceDevicePixelRatio)); if (reader.canRead()) { reader.setScaledSize(reader.size() * (devicePixelRatio / sourceDevicePixelRatio)); pixmap = QPixmap::fromImage(reader.read()); pixmap.setDevicePixelRatio(devicePixelRatio); } } else { pixmap.load(fileName); } return pixmap; } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/dicontheme.cpp000066400000000000000000000211751476226661100175050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dicontheme.h" #include "private/dbuiltiniconengine_p.h" #include "private/dciiconengine_p.h" #include "private/diconproxyengine_p.h" #ifndef DTK_DISABLE_LIBXDG #include "private/xdgiconproxyengine_p.h" #else #include #include #include #endif #include #include #include #include #include #include DGUI_BEGIN_NAMESPACE DCORE_USE_NAMESPACE static inline QString joinPath(const QString &basePath, const QString &path) { if (path.isEmpty()) return basePath; return basePath + QDir::separator() + path; } static inline QStringList systemDciThemePaths() { QStringList paths; const auto dataPaths = DStandardPaths::paths(DStandardPaths::DSG::DataDir); paths.reserve(dataPaths.size()); for (const auto &dataPath : dataPaths) { paths.push_back(joinPath(dataPath, QLatin1String("icons"))); } return paths; } static inline QString applicationDciThemePath() { return QLatin1String(":/dsg/icons"); } static inline QString applicationBuiltInIconPath() { return QLatin1String(":/dsg/built-in-icons"); } static QString findDciIconFromPath(const QString &iconName, const QString &themeName, const QString path) { if (path.isEmpty() || iconName.isEmpty()) return nullptr; QString themePath = joinPath(path, themeName); QFileInfo themeInfo(themePath); if (!themeInfo.exists() || !themeInfo.isDir()) return nullptr; /* * iconName has two types, like as: * 1. example.dci * 2. org.deepin.app/example.dci * * We do not need to consider the icon name, * just whether the file exists. */ QString iconNameWithSuffix(iconName); // Focus that the icon name can not contain the dci suffix. iconNameWithSuffix += QLatin1String(".dci"); QString iconPath = joinPath(themePath, iconNameWithSuffix); if (!QDir::cleanPath(iconPath).startsWith(QDir::cleanPath(themePath))) // Wrongful return nullptr; QFileInfo iconInfo(iconPath); if (iconInfo.exists() && iconInfo.isFile()) return iconPath; return nullptr; } QIconEngine *DIconTheme::createIconEngine(const QString &iconName, Options options) { return new DIconProxyEngine(iconName, options); } QIcon DIconTheme::findQIcon(const QString &iconName, Options options) { if (QDir::isAbsolutePath(iconName)) { return QIcon(iconName); } auto engine = createIconEngine(iconName, options); // fallback to QIcon::fromTheme if (!options.testFlag(DontFallbackToQIconFromTheme) && !engine) return QIcon::fromTheme(iconName); return QIcon(engine); } QIcon DIconTheme::findQIcon(const QString &iconName, const QIcon &fallback, Options options) { QIcon icon = findQIcon(iconName, options); return !icon.isNull() ? icon : fallback; } bool DIconTheme::isBuiltinIcon(const QIcon &icon) { if (icon.isNull()) return false; QIconEngine *engine = const_cast(icon).data_ptr()->engine; if (auto proxyEngine = dynamic_cast(engine)) return !proxyEngine->proxyKey().compare("DBuiltinIconEngine"); return dynamic_cast(engine); } bool DIconTheme::isXdgIcon(const QIcon &icon) { #ifdef DTK_DISABLE_LIBXDG return false; #else if (icon.isNull()) return false; QIconEngine *engine = const_cast(icon).data_ptr()->engine; if (auto proxyEngine = dynamic_cast(engine)) return !proxyEngine->proxyKey().compare("XdgIconProxyEngine"); return dynamic_cast(engine); #endif } class DIconTheme::CachedData { public: QCache cache; QCache dciIconPathCache; }; DIconTheme::Cached::Cached() : data(new CachedData()) { } DIconTheme::Cached::~Cached() { delete data; } int DIconTheme::Cached::maxCost() const { return data->cache.maxCost(); } void DIconTheme::Cached::setMaxCost(int cost) { data->cache.setMaxCost(cost); data->dciIconPathCache.setMaxCost(cost); } void DIconTheme::Cached::clear() { data->cache.clear(); data->dciIconPathCache.clear(); } QIcon DIconTheme::Cached::findQIcon(const QString &iconName, Options options, const QIcon &fallback) { const QString themeName = QIcon::themeName(); const QString cacheKey = themeName + QChar('/') + iconName + QChar('/') + QString::number(static_cast(options)); if (data->cache.contains(cacheKey)) { auto cacheIcon = data->cache.object(cacheKey); if (cacheIcon->isNull()) return fallback; return *cacheIcon; } auto newIcon = new QIcon(DIconTheme::findQIcon(iconName, options)); if (newIcon->isNull()) { return fallback; } else { data->cache.insert(cacheKey, newIcon); } return *newIcon; } QString DIconTheme::Cached::findDciIconFile(const QString &iconName, const QString &themeName, const QString &fallback) { const QString cacheKey = themeName + QLatin1Char('/') + iconName; if (data->dciIconPathCache.contains(cacheKey)) { const QString *cachePath = data->dciIconPathCache.object(cacheKey); if (cachePath->isEmpty()) return fallback; return *cachePath; } QString *path = new QString(DIconTheme::findDciIconFile(iconName, themeName)); data->dciIconPathCache.insert(cacheKey, path); if (path->isEmpty()) return fallback; return *path; } static inline QStringList getDciThemePaths() { QStringList paths = systemDciThemePaths(); paths.push_back(applicationDciThemePath()); return paths; } Q_GLOBAL_STATIC(DIconTheme::Cached, _globalCache) Q_GLOBAL_STATIC_WITH_ARGS(QStringList, _dciThemePath, (getDciThemePaths())) static void cleanGlobalCache() { if (_globalCache.exists()) _globalCache->clear(); } DIconTheme::Cached *DIconTheme::cached() { if (Q_UNLIKELY(!_globalCache.exists() && !_globalCache.isDestroyed())) { qAddPostRoutine(cleanGlobalCache); } return _globalCache(); } QString DIconTheme::findDciIconFile(const QString &iconName, const QString &themeName) { if (iconName.isEmpty()) return nullptr; const QString cleanIconName = QDir::cleanPath(iconName); if (iconName.startsWith('/') || iconName.endsWith('/') || cleanIconName.length() != iconName.length() || cleanIconName.startsWith("../")) // Wrongful return nullptr; const int splitCharPos = iconName.lastIndexOf('/'); QString effectiveIconName = iconName; // If the icon name syntax is "AAA/BBB", then the "AAA" is the icon group name, the "BBB" is the actual icon // name. eg: "org.deepin.app/accounts", hypothesis the icon search path is "/usr/share/dsg/icons" and // icon theme name is "theme_name", then the icon files list for find is: // "/usr/share/dsg/icons/theme_name/org.deepin.app/accounts.dci" // "qrc:/dsg/icons/theme_name/org.deepin.app/accounts.dci" // fallback to the qrc directory // "/usr/share/dsg/icons/theme_name/accounts.dci" // ignore the icon group name // "qrc:/dsg/icons/theme_name/accounts.dci" // ignore the icon group name // "/usr/share/dsg/icons/accounts.dci" // ignore the icon theme // "qrc:/dsg/icons/accounts.dci" // ignore the icon theme // "qrc:/dsg/built-in-icons/accounts.dci" // fallback to built-in icons const auto &searchPaths = DIconTheme::dciThemeSearchPaths(); for (const QString &themePath : searchPaths) { QString iconPath = findDciIconFromPath(effectiveIconName, themeName, themePath); if (!iconPath.isEmpty()) return iconPath; } if (splitCharPos > 0) { effectiveIconName = iconName.mid(splitCharPos + 1); Q_ASSERT(!effectiveIconName.isEmpty()); for (const QString &themePath : searchPaths) { QString iconPath = findDciIconFromPath(effectiveIconName, themeName, themePath); if (!iconPath.isEmpty()) return iconPath; } } // fallback to without theme directory for (const QString &themePath : searchPaths) { QString iconPath = findDciIconFromPath(effectiveIconName, nullptr, themePath); if (!iconPath.isEmpty()) return iconPath; } return findDciIconFromPath(effectiveIconName, nullptr, applicationBuiltInIconPath()); } QStringList DIconTheme::dciThemeSearchPaths() { return *_dciThemePath; } void DIconTheme::setDciThemeSearchPaths(const QStringList &path) { *_dciThemePath = path; } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/dimagehandler.cpp000066400000000000000000001306011476226661100201450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dimagehandler.h" #include "private/dimagehandlerlibs_p.h" #include #include #include #include #include #include #include #include #define SAVE_QUAITY_VALUE 100 struct SupportFormats { QHash freeImageFormats; QHash movieFormats; QStringList libRawFormats; QStringList qtSupportFormats; QStringList saveableFormats; QStringList qtRotatableFormats; QStringList supportFormats; SupportFormats(); }; Q_GLOBAL_STATIC(SupportFormats, SupportFormatsInstance) #ifndef DTK_DISABLE_EX_IMAGE_FORMAT Q_GLOBAL_STATIC(DLibFreeImage, DLibFreeImageInstance) Q_GLOBAL_STATIC(DLibRaw, DLibRawInstance) #endif SupportFormats::SupportFormats() { #ifndef DTK_DISABLE_EX_IMAGE_FORMAT // LibFreeImage support formats freeImageFormats["BMP"] = FIF_BMP; freeImageFormats["ICO"] = FIF_ICO; freeImageFormats["JPG"] = FIF_JPEG; freeImageFormats["JPE"] = FIF_JPEG; freeImageFormats["JPS"] = FIF_JPEG; freeImageFormats["JPEG"] = FIF_JPEG; freeImageFormats["JNG"] = FIF_JNG; freeImageFormats["KOALA"] = FIF_KOALA; freeImageFormats["KOA"] = FIF_KOALA; freeImageFormats["LBM"] = FIF_LBM; freeImageFormats["IFF"] = FIF_LBM; freeImageFormats["MNG"] = FIF_MNG; freeImageFormats["PBM"] = FIF_PBM; freeImageFormats["PBMRAW"] = FIF_PBMRAW; freeImageFormats["PCD"] = FIF_PCD; freeImageFormats["PCX"] = FIF_PCX; freeImageFormats["PGM"] = FIF_PGM; freeImageFormats["PGMRAW"] = FIF_PGMRAW; freeImageFormats["PNG"] = FIF_PNG; freeImageFormats["PPM"] = FIF_PPM; freeImageFormats["PPMRAW"] = FIF_PPMRAW; freeImageFormats["RAS"] = FIF_RAS; freeImageFormats["TGA"] = FIF_TARGA; freeImageFormats["TARGA"] = FIF_TARGA; freeImageFormats["TIFF"] = FIF_TIFF; freeImageFormats["TIF"] = FIF_TIFF; freeImageFormats["WBMP"] = FIF_WBMP; freeImageFormats["PSD"] = FIF_PSD; freeImageFormats["CUT"] = FIF_CUT; freeImageFormats["XBM"] = FIF_XBM; freeImageFormats["XPM"] = FIF_XPM; freeImageFormats["DDS"] = FIF_DDS; freeImageFormats["GIF"] = FIF_GIF; // Warning: Build fails in arch linux. // In libfreeimage.h from arch linux freeimage3.18.0-15 package: // The G3 fax format plugin is deliberately disabled in the Fedora build of // FreeImage as it requires that FreeImage uses a private copy of libtiff // which is a no no because of security reasons. # if 0 freeImageFormats["FAX"] = FIF_FAXG3; freeImageFormats["G3"] = FIF_FAXG3; # endif freeImageFormats["SGI"] = FIF_SGI; freeImageFormats["EXR"] = FIF_EXR; freeImageFormats["PCT"] = FIF_PICT; freeImageFormats["PIC"] = FIF_PICT; freeImageFormats["PICT"] = FIF_PICT; freeImageFormats["PIC"] = FIF_PICT; freeImageFormats["WEBP"] = FIF_WEBP; freeImageFormats["JXR"] = FIF_JXR; movieFormats["MNG"] = FIF_MNG; movieFormats["GIF"] = FIF_GIF; movieFormats["WEBP"] = FIF_WEBP; // LibRaw support images libRawFormats << "CR2" << "CRW" << "DCR" << "KDC" << "MRW" << "NEF" << "ORF" << "PEF" << "RAF" << "SRF" << "DNG" << "RAW"; #endif // For some formats, Qt will support after loading image plugins. QList qtReadableFormats = QImageReader::supportedImageFormats(); for (QByteArray &format : qtReadableFormats) { qtSupportFormats << QString::fromUtf8(format).toUpper(); } // Qt support formats internal. qtSupportFormats << "PNM" << "MEF" << "PXM"; saveableFormats << "BMP" << "JPG" << "JPEG" << "JPS" << "JPE" << "PNG" << "PGM" << "PPM" << "PNM" << "TGA" << "XPM" << "ICO" << "JNG" #ifndef ISSW_64 << "WBMP" #endif << "RAS"; // For those formats, Qt process faster than FreeImage. qtRotatableFormats << "ICNS" << "JPG" << "JPEG" << "PNG" << "BMP"; QSet formats; #ifndef DTK_DISABLE_EX_IMAGE_FORMAT // Check libFreeImage load succeeded. if (DLibFreeImageInstance()->isValid()) { // Use FreeImage load .pcx image. qtSupportFormats.removeAll("PCX"); for (auto itr = freeImageFormats.begin(); itr != freeImageFormats.end(); ++itr) { formats.insert(itr.key()); } for (auto itr = movieFormats.begin(); itr != movieFormats.end(); ++itr) { formats.insert(itr.key()); } } // Add libRaw support formats. if (DLibRawInstance()->isValid()) { for (const QString &format : libRawFormats) { formats.insert(format); } } #endif if (formats.isEmpty()) { supportFormats = qtSupportFormats; } else { // Add qt default support formats. for (const QString &format : qtSupportFormats) { formats.insert(format); } supportFormats = formats.values(); } } DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE #ifndef DTK_DISABLE_EX_IMAGE_FORMAT QString detectImageFormatInternal(const QString &fileName, FREE_IMAGE_FORMAT &format); #else QString detectImageFormatInternal(const QString &fileName); #endif class DImageHandlerPrivate : public DObjectPrivate { D_DECLARE_PUBLIC(DImageHandler) public: enum ImageOption { Readable = 0x1, Wirteable = 0x2, Rotatable = 0x4, SupportFreeImage = 0x8 }; Q_DECLARE_FLAGS(ImageOptions, ImageOption); explicit DImageHandlerPrivate(DImageHandler *qq); bool formatReadable(const QString &fileFormat) const; bool formatWriteable(const QString &fileFormat) const; bool loadStaticImageFromFile(const QString &fileName, QImage &image); #ifndef DTK_DISABLE_EX_IMAGE_FORMAT bool loadImageWithFreeImage(const QString &fileName, QImage &image, FREE_IMAGE_FORMAT fifForamt, QString fileFormat); #endif bool rotateImageFile(const QString &fileName, int angle); bool rotateImage(QImage &image, int angle); void adjustImageToRealOrientation(QImage &image, ExifImageOrientation orientation); QString fileName; ImageOptions options; QImage cachedImage; QString cachedFormat; QString lastError; }; Q_DECLARE_OPERATORS_FOR_FLAGS(DImageHandlerPrivate::ImageOptions) DImageHandlerPrivate::DImageHandlerPrivate(DImageHandler *qq) : DObjectPrivate(qq) { } bool DImageHandlerPrivate::formatReadable(const QString &fileFormat) const { if (fileFormat.isEmpty()) { return false; } #ifndef DTK_DISABLE_EX_IMAGE_FORMAT if (DLibFreeImageInstance()->isValid()) { if (SupportFormatsInstance()->supportFormats.contains(fileFormat)) { return true; } } #endif return SupportFormatsInstance()->supportFormats.contains(fileFormat); } bool DImageHandlerPrivate::formatWriteable(const QString &fileFormat) const { if (fileFormat.isEmpty()) { return false; } #ifndef DTK_DISABLE_EX_IMAGE_FORMAT if (DLibFreeImageInstance()->isValid()) { if (SupportFormatsInstance()->saveableFormats.contains(fileFormat)) { return true; } } #endif return SupportFormatsInstance()->saveableFormats.contains(fileFormat); } bool DImageHandlerPrivate::loadStaticImageFromFile(const QString &fileName, QImage &image) { D_Q(DImageHandler); QFileInfo fileInfo(fileName); if (0 == fileInfo.size()) { lastError = QString("Error file!"); return false; } #ifndef DTK_DISABLE_EX_IMAGE_FORMAT FREE_IMAGE_FORMAT fifFormat = FIF_UNKNOWN; QString fileFormat = detectImageFormatInternal(fileName, fifFormat); if (DLibFreeImageInstance()->isValid()) { // Using free image meta type. QHash dataMap = DLibFreeImageInstance()->findAllMetaData(fileName); fileFormat = dataMap.value("FileFormat").toUpper(); } // For some formats, need use Qt image reader load, to aviod some errors on different hardware architectures. bool usingQImage = ((FIF_PICT == fifFormat) && ("PCT" != fileFormat)); if (usingQImage || SupportFormatsInstance()->qtSupportFormats.contains(fileFormat)) { #else QString fileFormat = detectImageFormatInternal(fileName); #endif QImageReader reader(fileName); reader.setAutoTransform(true); if (reader.imageCount() > 0 || "ICNS" != fileFormat) { image = reader.read(); if (!image.isNull()) { return true; } else { // Try loading image with a forced format. reader.setFormat(fileFormat.toLower().toUtf8()); image = reader.read(); if (!image.isNull()) { return true; #ifndef DTK_DISABLE_EX_IMAGE_FORMAT } else if (DLibFreeImageInstance()->isValid() && DLibFreeImageInstance()->FreeImage_FIFSupportsReading(fifFormat)) { // Try load with FreeImage. return loadImageWithFreeImage(fileName, image, fifFormat, fileFormat); #endif } else { lastError = QString("Load image by qt failed, %1, use format: %2").arg(reader.errorString()).arg(fileFormat); return false; } } } #ifndef DTK_DISABLE_EX_IMAGE_FORMAT } else if (SupportFormatsInstance()->libRawFormats.contains(fileFormat) && DLibRawInstance()->isValid()) { // Use libRaw load. image = DLibRawInstance()->loadImage(fileName, lastError); return !image.isNull(); } else if (DLibFreeImageInstance()->isValid()) { // Use FreeImage load. return loadImageWithFreeImage(fileName, image, fifFormat, fileFormat); } #endif lastError = QString("Unsupport image format: %1").arg(fileFormat); return false; } #ifndef DTK_DISABLE_EX_IMAGE_FORMAT bool DImageHandlerPrivate::loadImageWithFreeImage(const QString &fileName, QImage &image, FREE_IMAGE_FORMAT fifFormat, QString fileFormat) { if (!DLibFreeImageInstance()->isValid()) { return false; } if (FIF_UNKNOWN != fifFormat || SupportFormatsInstance()->freeImageFormats.contains(fileFormat)) { if (FIF_UNKNOWN == fifFormat) { fifFormat = FREE_IMAGE_FORMAT(SupportFormatsInstance()->freeImageFormats.value(fileFormat, FIF_UNKNOWN)); } static const int MAX_JP2_SUPPORT_SIZE = 40960000; if (FIF_JP2 == fifFormat && QFileInfo(fileName).size() > MAX_JP2_SUPPORT_SIZE) { lastError = QString("Load image failed, JP2 image size to big, format: %1").arg(fileFormat); return false; } FIBITMAP *dib = DLibFreeImageInstance()->FreeImage_Load(fifFormat, fileName.toUtf8().data(), 0); if (!dib) { lastError = QString("Load image failed, format: %1").arg(fileFormat); return false; } image = DLibFreeImageInstance()->FIBITMAPToQImage(dib); if (image.isNull()) { DLibFreeImageInstance()->FreeImage_Unload(dib); lastError = QString("Convert to QImage failed: %1").arg(fileFormat); return false; } DLibFreeImageInstance()->FreeImage_Unload(dib); return true; } lastError = QString("Unsupport image format: %1").arg(fileFormat); return false; } #endif bool DImageHandlerPrivate::rotateImageFile(const QString &fileName, int angle) { D_Q(DImageHandler); if (0 != (angle % 90)) { lastError = QString("Unsupported angle."); return false; } QString format = q->detectImageFormat(fileName); if (SupportFormatsInstance()->qtRotatableFormats.contains(format)) { QImage image(fileName); #ifndef DTK_DISABLE_EX_IMAGE_FORMAT // Some image formats support use EXIF info store orientation info. if (DLibFreeImageInstance()->isValid()) { // Using libFreeImage to get EXIF information. ExifImageOrientation orientation = DLibFreeImageInstance()->imageOrientation(fileName); adjustImageToRealOrientation(image, orientation); } #endif if (rotateImage(image, angle)) { image.save(fileName, format.toLatin1().data(), SAVE_QUAITY_VALUE); return true; } return false; } #ifndef DTK_DISABLE_EX_IMAGE_FORMAT if (DLibFreeImageInstance()->isValid()) { return DLibFreeImageInstance()->rotateImageFile(fileName, angle, lastError); } #endif lastError = QString("Unsupported format: %1").arg(format); return false; } bool DImageHandlerPrivate::rotateImage(QImage &image, int angle) { if (image.isNull()) { lastError = QString("Image is null."); return false; } if (0 != (angle % 90)) { lastError = QString("Rotate angle not base of 90, angle: %1").arg(angle); return false; } QImage imageCopy(image); if (!imageCopy.isNull()) { QTransform rotateMatrix; rotateMatrix.rotate(angle); image = imageCopy.transformed(rotateMatrix, Qt::SmoothTransformation); return true; } lastError = QString("Image is null."); return false; } void DImageHandlerPrivate::adjustImageToRealOrientation(QImage &image, ExifImageOrientation orientation) { switch (orientation) { // TopLeft unnecessary rotate/flip case TopRight: // Horizontal flip image = image.mirrored(true, false); break; case BottomRight: rotateImage(image, 180); break; case BottomLeft: // Vertical flip image = image.mirrored(false, true); break; case LeftTop: // Clockwise 90 degrees and horizontal flip rotateImage(image, 90); image = image.mirrored(true, false); break; case RightTop: rotateImage(image, 90); break; case RightBottom: // Clockwise 90 degrees and vertical flip rotateImage(image, 90); image = image.mirrored(false, true); break; case LeftBottom: // Counterclockwise 90 degrees rotateImage(image, -90); break; default: break; } } DImageHandler::DImageHandler(QObject *parent) : QObject(parent) , DObject(*new DImageHandlerPrivate(this)) { } DImageHandler::~DImageHandler() {} void DImageHandler::setFileName(const QString &fileName) { D_D(DImageHandler); if (fileName == d->fileName) { return; } d->fileName = fileName; d->options &= 0; clearCache(); if (!d->fileName.isEmpty()) { d->cachedFormat = detectImageFormat(fileName); d->options.setFlag(DImageHandlerPrivate::Readable, d->formatReadable(d->cachedFormat)); if (d->formatWriteable(d->cachedFormat)) { d->options.setFlag(DImageHandlerPrivate::Wirteable); d->options.setFlag(DImageHandlerPrivate::Rotatable); } } } QString DImageHandler::fileName() const { D_DC(DImageHandler); return d->fileName; } QImage DImageHandler::readImage() { D_D(DImageHandler); if (!isReadable()) { d->lastError = QString("File is not readable"); return QImage(); } if (!d->cachedImage.isNull()) { return d->cachedImage; } d->loadStaticImageFromFile(d->fileName, d->cachedImage); return d->cachedImage; } QImage DImageHandler::thumbnail(const QSize &size, Qt::AspectRatioMode mode) { D_D(DImageHandler); if (d->cachedImage.isNull()) { d->loadStaticImageFromFile(d->fileName, d->cachedImage); } return d->cachedImage.scaled(size, mode); } QString DImageHandler::imageFormat() const { D_DC(DImageHandler); return d->cachedFormat; } QSize DImageHandler::imageSize() { D_D(DImageHandler); if (isReadable() && d->cachedImage.isNull()) { d->loadStaticImageFromFile(d->fileName, d->cachedImage); } return d->cachedImage.size(); } QHash DImageHandler::findAllMetaData() { D_D(DImageHandler); if (!isReadable()) { return {}; } #ifndef DTK_DISABLE_EX_IMAGE_FORMAT if (DLibFreeImageInstance()->isValid()) { return DLibFreeImageInstance()->findAllMetaData(d->fileName); } #endif return {}; } bool DImageHandler::saveImage(const QString &fileName, const QString &format) { D_D(DImageHandler); if (d->cachedImage.isNull()) { if (!d->loadStaticImageFromFile(d->fileName, d->cachedImage)) { return false; } } return saveImage(d->cachedImage, fileName, format); } bool DImageHandler::saveImage(const QImage &image, const QString &fileName, const QString &format) { D_D(DImageHandler); QString realFormat = format.toUpper(); if (realFormat.isEmpty()) { // Detect save file format. #ifndef DTK_DISABLE_EX_IMAGE_FORMAT FREE_IMAGE_FORMAT fifFormat = FIF_UNKNOWN; realFormat = detectImageFormatInternal(fileName, fifFormat); if (FIF_UNKNOWN != fifFormat) { realFormat = SupportFormatsInstance()->freeImageFormats.key(fifFormat); } #else realFormat = detectImageFormatInternal(fileName); #endif } if (!SupportFormatsInstance()->saveableFormats.contains(realFormat.toUpper())) { d->lastError = QString("Unsupport image save format: %1").arg(realFormat); return false; } if (!image.save(fileName, realFormat.toUtf8().data(), SAVE_QUAITY_VALUE)) { d->lastError = QString("Save image by qt failed, format: %1").arg(realFormat); return false; } return true; } bool DImageHandler::rotateImage(QImage &image, int angle) { D_D(DImageHandler); return d->rotateImage(image, angle); } bool DImageHandler::rotateImageFile(const QString &fileName, int angle) { D_D(DImageHandler); return d->rotateImageFile(fileName, angle); } bool DImageHandler::isReadable() const { D_DC(DImageHandler); return d->options.testFlag(DImageHandlerPrivate::Readable); } bool DImageHandler::isWriteable() const { D_DC(DImageHandler); return d->options.testFlag(DImageHandlerPrivate::Wirteable); } bool DImageHandler::isRotatable() const { D_DC(DImageHandler); return d->options.testFlag(DImageHandlerPrivate::Rotatable); } void DImageHandler::clearCache() { D_D(DImageHandler); d->cachedImage = QImage(); d->cachedFormat.clear(); d->lastError.clear(); } QString DImageHandler::lastError() const { return d_func()->lastError; } QStringList DImageHandler::supportFormats() { return SupportFormatsInstance()->supportFormats; } #ifndef DTK_DISABLE_EX_IMAGE_FORMAT QString detectImageFormatInternal(const QString &fileName, FREE_IMAGE_FORMAT &format) #else QString detectImageFormatInternal(const QString &fileName) #endif { QFileInfo info(fileName); QString fileSuffix = info.suffix().toUpper(); QByteArray tempPath = fileName.toUtf8(); #ifndef DTK_DISABLE_EX_IMAGE_FORMAT format = FIF_UNKNOWN; // Check load lib FreeImage succeeded. if (DLibFreeImageInstance()->isValid()) { format = DLibFreeImageInstance()->FreeImage_GetFileType(tempPath.data(), 0); if (FIF_UNKNOWN != format && format != SupportFormatsInstance()->freeImageFormats[fileSuffix]) { // Some format don't load with FreeImage. QString fifFileFormat = SupportFormatsInstance()->freeImageFormats.key(format); if (!fifFileFormat.isEmpty()) { fileSuffix = fifFileFormat; } } if (format == FIF_TIFF) { fileSuffix = "TIFF"; } } #endif if (fileSuffix.isEmpty()) { QFile file(fileName); if (!file.open(QFile::ReadOnly)) { return QString(""); } const QByteArray data = file.read(64); // Check bmp file. if (data.startsWith("BM")) { return "BMP"; } // Check dds file. if (data.startsWith("DDS")) { return "DDS"; } // Check gif file. if (data.startsWith("GIF8")) { return "GIF"; } // Check Max OS icons file. if (data.startsWith("icns")) { return "ICNS"; } // Check jpeg file. if (data.startsWith("\xff\xd8")) { return "JPG"; } // Check mng file. if (data.startsWith("\x8a\x4d\x4e\x47\x0d\x0a\x1a\x0a")) { return "MNG"; } // Check net pbm file (BitMap). if (data.startsWith("P1") || data.startsWith("P4")) { return "PBM"; } // Check pgm file (GrayMap). if (data.startsWith("P2") || data.startsWith("P5")) { return "PGM"; } // Check ppm file (PixMap). if (data.startsWith("P3") || data.startsWith("P6")) { return "PPM"; } // Check png file. if (data.startsWith("\x89PNG\x0d\x0a\x1a\x0a")) { return "PNG"; } // Check svg file. if (data.indexOf(" -1) { return "SVG"; } // Check tiff file. if (data.startsWith("MM\x00\x2a") || data.startsWith("II\x2a\x00")) { // big-endian, little-endian. return "TIFF"; } // Check webp file. if (data.startsWith("RIFFr\x00\x00\x00WEBPVP")) { return "WEBP"; } // Check xbm file. if (data.indexOf("#define max_width ") > -1 && data.indexOf("#define max_height ") > -1) { return "XBM"; } // Check xpm file. if (data.startsWith("/* XPM */")) { return "XPM"; } return QString(""); } return fileSuffix; } QString DImageHandler::detectImageFormat(const QString &fileName) { #ifndef DTK_DISABLE_EX_IMAGE_FORMAT FREE_IMAGE_FORMAT format = FIF_UNKNOWN; return detectImageFormatInternal(fileName, format); #else return detectImageFormatInternal(fileName); #endif } QImage DImageHandler::oldColorFilter(const QImage &img) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); if (nullptr == rgb) { return QImage(); } int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { float r = 0.393 * rgb[i * 3] + 0.769 * rgb[i * 3 + 1] + 0.189 * rgb[i * 3 + 2]; float g = 0.349 * rgb[i * 3] + 0.686 * rgb[i * 3 + 1] + 0.168 * rgb[i * 3 + 2]; float b = 0.272 * rgb[i * 3] + 0.534 * rgb[i * 3 + 1] + 0.131 * rgb[i * 3 + 2]; r = qBound(0, r, 255.0); g = qBound(0, g, 255.0); b = qBound(0, b, 255.0); rgb[i * 3] = r; rgb[i * 3 + 1] = g; rgb[i * 3 + 2] = b; } return imgCopy; } QImage DImageHandler::warmColorFilter(const QImage &img, int intensity) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); if (nullptr == rgb) { return QImage(); } QColor frontColor; int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { int r = rgb[i * 3] + intensity; int g = rgb[i * 3 + 1] + intensity; int b = rgb[i * 3 + 2]; rgb[i * 3] = r > 255 ? 255 : r; rgb[i * 3 + 1] = g > 255 ? 255 : g; rgb[i * 3 + 2] = b > 255 ? 255 : b; } return imgCopy; } QImage DImageHandler::coolColorFilter(const QImage &img, int intensity) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); if (nullptr == rgb) { return QImage(); } QColor frontColor; int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { int r = rgb[i * 3]; int g = rgb[i * 3 + 1]; int b = rgb[i * 3 + 2] + intensity; rgb[i * 3] = r > 255 ? 255 : r; rgb[i * 3 + 1] = g > 255 ? 255 : g; rgb[i * 3 + 2] = b > 255 ? 255 : b; } return imgCopy; } QImage DImageHandler::grayScaleColorFilter(const QImage &img) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); if (nullptr == rgb) { return QImage(); } QColor frontColor; int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { int average = (rgb[i * 3] + rgb[i * 3 + 1] + rgb[i * 3 + 2]) / 3; rgb[i * 3] = average > 255 ? 255 : average; rgb[i * 3 + 1] = average > 255 ? 255 : average; rgb[i * 3 + 2] = average > 255 ? 255 : average; } return imgCopy; } QImage DImageHandler::antiColorFilter(const QImage &img) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); if (nullptr == rgb) { return QImage(); } int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { rgb[i * 3] = 255 - rgb[i * 3]; rgb[i * 3 + 1] = 255 - rgb[i * 3 + 1]; rgb[i * 3 + 2] = 255 - rgb[i * 3 + 2]; } return imgCopy; } QImage DImageHandler::metalColorFilter(const QImage &img) { QImage baseImage = QImage(img); QImage darkImage = DImageHandler::changeBrightness(img, -100); QImage greyImage = DImageHandler::grayScale(darkImage); QPainter painter; QImage newImage = baseImage.scaled(QSize(img.width(), img.height())); painter.begin(&newImage); painter.setOpacity(0.5); painter.drawImage(0, 0, greyImage); painter.end(); return newImage; } QImage DImageHandler::bilateralFilter(const QImage &img, double spatialDecay, double photometricStandardDeviation) { QImage imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); double c = -0.5 / (photometricStandardDeviation * photometricStandardDeviation); double mu = spatialDecay / (2 - spatialDecay); double *exptable = new double[256]; double *g_table = new double[256]; #pragma omp parallel for for (int i = 0; i <= 255; i++) { exptable[i] = (1 - spatialDecay) * exp(c * i * i); g_table[i] = mu * i; } int width = img.width(); int height = img.height(); int length = width * height; double *data2Red = new double[length]; double *data2Green = new double[length]; double *data2Blue = new double[length]; int size = imgCopy.width() * imgCopy.height(); uint8_t *rgb = imgCopy.bits(); #pragma omp parallel for for (int i = 0; i < size; i++) { data2Red[i] = rgb[i * 3]; data2Green[i] = rgb[i * 3 + 1]; data2Blue[i] = rgb[i * 3 + 2]; } double *gRed = new double[length]; double *pRed = new double[length]; double *rRed = new double[length]; double *gGreen = new double[length]; double *pGreen = new double[length]; double *rGreen = new double[length]; double *gBlue = new double[length]; double *pBlue = new double[length]; double *rBlue = new double[length]; memcpy(pRed, data2Red, sizeof(double) * length); memcpy(rRed, data2Red, sizeof(double) * length); memcpy(pGreen, data2Green, sizeof(double) * length); memcpy(rGreen, data2Green, sizeof(double) * length); memcpy(pBlue, data2Blue, sizeof(double) * length); memcpy(rBlue, data2Blue, sizeof(double) * length); double rho0 = 1.0 / (2 - spatialDecay); #pragma omp parallel for for (int k2 = 0; k2 < height; ++k2) { int startIndex = k2 * width; double mu2 = 0.0; for (int k = startIndex + 1, K = startIndex + width; k < K; ++k) { int div0Red = fabs(pRed[k] - pRed[k - 1]); mu2 = exptable[div0Red]; pRed[k] = pRed[k - 1] * mu2 + pRed[k] * (1.0 - mu2); int div0Green = fabs(pGreen[k] - pGreen[k - 1]); mu2 = exptable[div0Green]; pGreen[k] = pGreen[k - 1] * mu2 + pGreen[k] * (1.0 - mu2); int div0Blue = fabs(pBlue[k] - pBlue[k - 1]); mu2 = exptable[div0Blue]; pBlue[k] = pBlue[k - 1] * mu2 + pBlue[k] * (1.0 - mu2); } for (int k = startIndex + width - 2; startIndex <= k; --k) { int div0Red = fabs(rRed[k] - rRed[k + 1]); mu2 = exptable[div0Red]; rRed[k] = rRed[k + 1] * mu2 + rRed[k] * (1.0 - mu2); int div0Green = fabs(rGreen[k] - rGreen[k + 1]); mu2 = exptable[div0Green]; rGreen[k] = rGreen[k + 1] * mu2 + rGreen[k] * (1.0 - mu2); int div0Blue = fabs(rBlue[k] - rBlue[k + 1]); mu2 = exptable[div0Blue]; rBlue[k] = rBlue[k + 1] * mu2 + rBlue[k] * (1.0 - mu2); } for (int k = startIndex, K = startIndex + width; k < K; k++) { rRed[k] = (rRed[k] + pRed[k]) * rho0 - g_table[(int)data2Red[k]]; rGreen[k] = (rGreen[k] + pGreen[k]) * rho0 - g_table[(int)data2Green[k]]; rBlue[k] = (rBlue[k] + pBlue[k]) * rho0 - g_table[(int)data2Blue[k]]; } } int m = 0; for (int k2 = 0; k2 < height; k2++) { int n = k2; for (int k1 = 0; k1 < width; k1++) { gRed[n] = rRed[m]; gGreen[n] = rGreen[m]; gBlue[n] = rBlue[m]; m++; n += height; } } memcpy(pRed, gRed, sizeof(double) * height * width); memcpy(rRed, gRed, sizeof(double) * height * width); memcpy(pGreen, gGreen, sizeof(double) * height * width); memcpy(rGreen, gGreen, sizeof(double) * height * width); memcpy(pBlue, gBlue, sizeof(double) * height * width); memcpy(rBlue, gBlue, sizeof(double) * height * width); #pragma omp parallel for for (int k1 = 0; k1 < width; ++k1) { int startIndex = k1 * height; double mu1 = 0.0; for (int k = startIndex + 1, K = startIndex + height; k < K; ++k) { int div0Red = fabs(pRed[k] - pRed[k - 1]); mu1 = exptable[div0Red]; pRed[k] = pRed[k - 1] * mu1 + pRed[k] * (1.0 - mu1); int div0Green = fabs(pGreen[k] - pGreen[k - 1]); mu1 = exptable[div0Green]; pGreen[k] = pGreen[k - 1] * mu1 + pGreen[k] * (1.0 - mu1); int div0Blue = fabs(pBlue[k] - pBlue[k - 1]); mu1 = exptable[div0Blue]; pBlue[k] = pBlue[k - 1] * mu1 + pBlue[k] * (1.0 - mu1); } for (int k = startIndex + height - 2; startIndex <= k; --k) { int div0Red = fabs(rRed[k] - rRed[k + 1]); mu1 = exptable[div0Red]; rRed[k] = rRed[k + 1] * mu1 + rRed[k] * (1.0 - mu1); int div0Green = fabs(rGreen[k] - rGreen[k + 1]); mu1 = exptable[div0Green]; rGreen[k] = rGreen[k + 1] * mu1 + rGreen[k] * (1.0 - mu1); int div0Blue = fabs(rBlue[k] - rBlue[k + 1]); mu1 = exptable[div0Blue]; rBlue[k] = rBlue[k + 1] * mu1 + rBlue[k] * (1.0 - mu1); } } double init_gain_mu = spatialDecay / (2 - spatialDecay); #pragma omp parallel for for (int k = 0; k < length; ++k) { rRed[k] = (rRed[k] + pRed[k]) * rho0 - gRed[k] * init_gain_mu; rGreen[k] = (rGreen[k] + pGreen[k]) * rho0 - gGreen[k] * init_gain_mu; rBlue[k] = (rBlue[k] + pBlue[k]) * rho0 - gBlue[k] * init_gain_mu; } m = 0; int nRowBytes = (width * 24 + 31) / 32 * 4; int lineNum_24 = 0; for (int k1 = 0; k1 < width; ++k1) { int n = k1; for (int k2 = 0; k2 < height; ++k2) { data2Red[n] = rRed[m]; data2Green[n] = rGreen[m]; data2Blue[n] = rBlue[m]; lineNum_24 = k2 * nRowBytes; rgb[lineNum_24 + k1 * 3] = data2Red[n]; rgb[lineNum_24 + k1 * 3 + 1] = data2Green[n]; rgb[lineNum_24 + k1 * 3 + 2] = data2Blue[n]; m++; n += width; } } delete[] data2Red; data2Red = nullptr; delete[] data2Green; data2Green = nullptr; delete[] data2Blue; data2Blue = nullptr; delete[] pRed; pRed = nullptr; delete[] rRed; rRed = nullptr; delete[] gRed; gRed = nullptr; delete[] pGreen; pGreen = nullptr; delete[] rGreen; rGreen = nullptr; delete[] gGreen; gGreen = nullptr; delete[] pBlue; pBlue = nullptr; delete[] rBlue; rBlue = nullptr; delete[] gBlue; gBlue = nullptr; delete[] exptable; exptable = nullptr; delete[] g_table; g_table = nullptr; return imgCopy; } QImage DImageHandler::contourExtraction(const QImage &img) { int width = img.width(); int height = img.height(); QImage binImg = binaryzation(img); QImage newImg = QImage(width, height, QImage::Format_RGB888); newImg.fill(Qt::white); uint8_t *rgb = newImg.bits(); uint8_t *binrgb = binImg.bits(); int nRowBytes = (width * 24 + 31) / 32 * 4; #pragma omp parallel for for (int y = 1; y < height - 1; y++) { for (int x = 1; x < width - 1; x++) { int pixel[8]; memset(pixel, 0, 8 * sizeof(int)); int lineNum_24 = y * nRowBytes; if (binrgb[lineNum_24 + x * 3] == 0) { rgb[lineNum_24 + x * 3] = 0; rgb[lineNum_24 + x * 3 + 1] = 0; rgb[lineNum_24 + x * 3 + 2] = 0; pixel[0] = binrgb[(y - 1) * nRowBytes + (x - 1) * 3]; pixel[1] = binrgb[(y)*nRowBytes + (x - 1) * 3]; pixel[2] = binrgb[(y + 1) * nRowBytes + (x - 1) * 3]; pixel[3] = binrgb[(y - 1) * nRowBytes + (x)*3]; pixel[4] = binrgb[(y + 1) * nRowBytes + (x)*3]; pixel[5] = binrgb[(y - 1) * nRowBytes + (x + 1) * 3]; pixel[6] = binrgb[(y)*nRowBytes + (x + 1) * 3]; pixel[7] = binrgb[(y + 1) * nRowBytes + (x + 1) * 3]; if (pixel[0] + pixel[1] + pixel[2] + pixel[3] + pixel[4] + pixel[5] + pixel[6] + pixel[7] == 0) { rgb[lineNum_24 + x * 3] = 255; rgb[lineNum_24 + x * 3 + 1] = 255; rgb[lineNum_24 + x * 3 + 2] = 255; } } } } return newImg; } QImage DImageHandler::binaryzation(const QImage &img) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { int gray = (rgb[i * 3] + rgb[i * 3 + 1] + rgb[i * 3 + 2]) / 3; int newGray = 0; if (gray > 128) newGray = 255; else newGray = 0; rgb[i * 3] = newGray; rgb[i * 3 + 1] = newGray; rgb[i * 3 + 2] = newGray; } return imgCopy; } QImage DImageHandler::grayScale(const QImage &img) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { int average = (rgb[i * 3] * 299 + rgb[i * 3 + 1] * 587 + rgb[i * 3 + 1] * 114 + 500) / 1000; rgb[i * 3] = average; rgb[i * 3 + 1] = average; rgb[i * 3 + 2] = average; } return imgCopy; } QImage DImageHandler::laplaceSharpen(const QImage &img) { QImage imgCopy; int width = img.width(); int height = img.height(); int window[3][3] = {0, -1, 0, -1, 4, -1, 0, -1, 0}; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(width, height, QImage::Format_RGB888); } else { imgCopy = QImage(img); } QImage imgCopyrgbImg = QImage(img).convertToFormat(QImage::Format_RGB888); uint8_t *rgbImg = imgCopyrgbImg.bits(); uint8_t *rgb = imgCopy.bits(); int nRowBytes = (width * 24 + 31) / 32 * 4; #pragma omp parallel for for (int x = 1; x < img.width(); x++) { for (int y = 1; y < img.height(); y++) { int sumR = 0; int sumG = 0; int sumB = 0; int lineNum_24 = 0; for (int m = x - 1; m <= x + 1; m++) for (int n = y - 1; n <= y + 1; n++) { if (m >= 0 && m < width && n < height) { lineNum_24 = n * nRowBytes; sumR += rgbImg[lineNum_24 + m * 3] * window[n - y + 1][m - x + 1]; sumG += rgbImg[lineNum_24 + m * 3 + 1] * window[n - y + 1][m - x + 1]; sumB += rgbImg[lineNum_24 + m * 3 + 2] * window[n - y + 1][m - x + 1]; } } int old_r = rgbImg[lineNum_24 + x * 3]; sumR += old_r; sumR = qBound(0, sumR, 255); int old_g = rgbImg[lineNum_24 + x * 3 + 1]; sumG += old_g; sumG = qBound(0, sumG, 255); int old_b = rgbImg[lineNum_24 + x * 3 + 2]; sumB += old_b; sumB = qBound(0, sumB, 255); lineNum_24 = y * nRowBytes; rgb[lineNum_24 + x * 3] = sumR; rgb[lineNum_24 + x * 3 + 1] = sumG; rgb[lineNum_24 + x * 3 + 2] = sumB; } } return imgCopy; } QImage DImageHandler::sobelEdgeDetector(const QImage &img) { double *Gx = new double[9]; double *Gy = new double[9]; /* Sobel */ Gx[0] = 1.0; Gx[1] = 0.0; Gx[2] = -1.0; Gx[3] = 2.0; Gx[4] = 0.0; Gx[5] = -2.0; Gx[6] = 1.0; Gx[7] = 0.0; Gx[8] = -1.0; Gy[0] = -1.0; Gy[1] = -2.0; Gy[2] = -1.0; Gy[3] = 0.0; Gy[4] = 0.0; Gy[5] = 0.0; Gy[6] = 1.0; Gy[7] = 2.0; Gy[8] = 1.0; QImage grayImage = grayScale(img); int height = grayImage.height(); int width = grayImage.width(); QImage imgCopy = QImage(width, height, QImage::Format_RGB888); uint8_t *rgbImg = grayImage.bits(); uint8_t *rgb = imgCopy.bits(); int nRowBytes = (width * 24 + 31) / 32 * 4; float *sobel_norm = new float[width * height]; float max = 0.0; QColor my_color; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { double value_gx = 0.0; double value_gy = 0.0; for (int k = 0; k < 3; k++) { for (int p = 0; p < 3; p++) { if ((x + 1 + 1 - k < width) && (y + 1 + 1 - p < height)) { int lineNum_24 = (y + 1 + 1 - p) * nRowBytes; value_gx += Gx[p * 3 + k] * rgbImg[lineNum_24 + (x + 1 + 1 - k) * 3]; value_gy += Gy[p * 3 + k] * rgbImg[lineNum_24 + (x + 1 + 1 - k) * 3]; } } sobel_norm[x + y * width] = abs(value_gx) + abs(value_gy); max = sobel_norm[x + y * width] > max ? sobel_norm[x + y * width] : max; } } } for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { my_color.setHsv(0, 0, 255 - int(255.0 * sobel_norm[i + j * width] / max)); int lineNum_24 = j * nRowBytes; rgb[lineNum_24 + i * 3] = my_color.red(); rgb[lineNum_24 + i * 3 + 1] = my_color.green(); rgb[lineNum_24 + i * 3 + 2] = my_color.blue(); } } delete[] sobel_norm; return imgCopy; } QImage DImageHandler::changeLightAndContrast(const QImage &img, int light, int contrast) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); if (nullptr == rgb) { return QImage(); } int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { int r; int g; int b; r = light * 0.01 * rgb[i * 3] - 150 + contrast; g = light * 0.01 * rgb[i * 3 + 1] - 150 + contrast; b = light * 0.01 * rgb[i * 3 + 2] - 150 + contrast; rgb[i * 3] = qBound(0, r, 255); rgb[i * 3 + 1] = qBound(0, g, 255); rgb[i * 3 + 2] = qBound(0, b, 255); } return imgCopy; } QImage DImageHandler::changeBrightness(const QImage &img, int brightness) { QImage imgCopy; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); int size = img.width() * img.height(); #pragma omp parallel for for (int i = 0; i < size; i++) { int r = rgb[i * 3] + brightness; int g = rgb[i * 3 + 1] + brightness; int b = rgb[i * 3 + 2] + brightness; r = qBound(0, r, 255); g = qBound(0, g, 255); b = qBound(0, b, 255); rgb[i * 3] = r; rgb[i * 3 + 1] = g; rgb[i * 3 + 2] = b; } return imgCopy; } QImage DImageHandler::changeTransparency(const QImage &img, int transparency) { QImage newImage(img.width(), img.height(), QImage::Format_ARGB32); QColor oldColor; int r, g, b; for (int x = 0; x < newImage.width(); x++) { for (int y = 0; y < newImage.height(); y++) { oldColor = QColor(img.pixel(x, y)); r = oldColor.red(); g = oldColor.green(); b = oldColor.blue(); newImage.setPixel(x, y, qRgba(r, g, b, transparency)); } } return newImage; } QImage DImageHandler::changeStauration(const QImage &img, int saturation) { int r, g, b, rgbMin, rgbMax; float k = saturation / 100.0f * 128; int alpha = 0; QImage newImage(img); QColor tmpColor; for (int x = 0; x < newImage.width(); x++) { for (int y = 0; y < newImage.height(); y++) { tmpColor = QColor(img.pixel(x, y)); r = tmpColor.red(); g = tmpColor.green(); b = tmpColor.blue(); rgbMin = qMin(qMin(r, g), b); rgbMax = qMax(qMax(r, g), b); int delta = (rgbMax - rgbMin); int value = (rgbMax + rgbMin); if (delta == 0) { continue; } int L = value >> 1; if (k >= 0) { int S = L < 128 ? (delta << 7) / value : (delta << 7) / (510 - value); alpha = k + S >= 128 ? S : 128 - k; alpha = 128 * 128 / alpha - 128; } else { alpha = k; } r = r + ((r - L) * alpha >> 7); g = g + ((g - L) * alpha >> 7); b = b + ((b - L) * alpha >> 7); r = qBound(0, r, 255); g = qBound(0, g, 255); b = qBound(0, b, 255); newImage.setPixel(x, y, qRgb(r, g, b)); } } return newImage; } QImage DImageHandler::replacePointColor(const QImage &img, QColor oldColor, QColor newColor) { QImage imgCopy = img; if (img.format() != QImage::Format_RGB888) { imgCopy = QImage(img).convertToFormat(QImage::Format_RGB888); } else { imgCopy = QImage(img); } uint8_t *rgb = imgCopy.bits(); if (nullptr == rgb) { return QImage(); } QColor frontColor; for (int x = 0; x < img.width(); ++x) { for (int y = 0; y < img.height(); ++y) { if (imgCopy.pixelColor(x, y) == oldColor) { imgCopy.setPixelColor(x, y, newColor); } } } return imgCopy; } QImage DImageHandler::flipHorizontal(const QImage &img) { return img.mirrored(true, false); } QImage DImageHandler::flipVertical(const QImage &img) { return img.mirrored(false, true); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/dimagehandlerlibs.cpp000066400000000000000000000445611476226661100210300ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "private/dimagehandlerlibs_p.h" #ifndef DTK_DISABLE_EX_IMAGE_FORMAT #include #include #include #include DLibFreeImage::DLibFreeImage() { freeImage = new QLibrary("freeimage", "3"); if (!freeImage->load()) { delete freeImage; freeImage = nullptr; return; } auto initFunctionError = [this]() { freeImage->unload(); delete freeImage; freeImage = nullptr; }; #define INIT_FUNCTION_FREEIMAGE(Name) \ Name = reinterpret_cast(freeImage->resolve(#Name)); \ if (!Name) { \ initFunctionError(); \ return; \ } INIT_FUNCTION_FREEIMAGE(FreeImage_Load); INIT_FUNCTION_FREEIMAGE(FreeImage_Unload); INIT_FUNCTION_FREEIMAGE(FreeImage_Save); INIT_FUNCTION_FREEIMAGE(FreeImage_FIFSupportsReading); INIT_FUNCTION_FREEIMAGE(FreeImage_GetFileType); INIT_FUNCTION_FREEIMAGE(FreeImage_GetFIFFromFilename); INIT_FUNCTION_FREEIMAGE(FreeImage_GetImageType); INIT_FUNCTION_FREEIMAGE(FreeImage_GetBPP); INIT_FUNCTION_FREEIMAGE(FreeImage_GetWidth); INIT_FUNCTION_FREEIMAGE(FreeImage_GetHeight); INIT_FUNCTION_FREEIMAGE(FreeImage_GetRedMask); INIT_FUNCTION_FREEIMAGE(FreeImage_GetGreenMask); INIT_FUNCTION_FREEIMAGE(FreeImage_GetBlueMask); INIT_FUNCTION_FREEIMAGE(FreeImage_GetThumbnail); INIT_FUNCTION_FREEIMAGE(FreeImage_SetThumbnail); INIT_FUNCTION_FREEIMAGE(FreeImage_ConvertToRawBits); INIT_FUNCTION_FREEIMAGE(FreeImage_GetMetadataCount); INIT_FUNCTION_FREEIMAGE(FreeImage_FindFirstMetadata); INIT_FUNCTION_FREEIMAGE(FreeImage_FindNextMetadata); INIT_FUNCTION_FREEIMAGE(FreeImage_FindCloseMetadata); INIT_FUNCTION_FREEIMAGE(FreeImage_GetTagKey); INIT_FUNCTION_FREEIMAGE(FreeImage_GetTagValue); INIT_FUNCTION_FREEIMAGE(FreeImage_TagToString); INIT_FUNCTION_FREEIMAGE(FreeImage_Rotate); } DLibFreeImage::~DLibFreeImage() { if (freeImage) { delete freeImage; } } bool DLibFreeImage::isValid() { return freeImage; } bool DLibFreeImage::findMetaData(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, QHash &data) { bool ret = false; if (freeImage) { if (FreeImage_GetMetadataCount(model, dib)) { FITAG *tag = nullptr; FIMETADATA *mdhandle = nullptr; mdhandle = FreeImage_FindFirstMetadata(model, dib, &tag); if (mdhandle) { do { QString value; // Warning: FreeImage_TagToString is not thread-safe, add mutex protection. apiMutex.lock(); value = QString(FreeImage_TagToString(model, tag, nullptr)); apiMutex.unlock(); data.insert(FreeImage_GetTagKey(tag), value); ret = true; } while (FreeImage_FindNextMetadata(mdhandle, &tag)); FreeImage_FindCloseMetadata(mdhandle); } } } return ret; } QHash DLibFreeImage::findAllMetaData(const QString &fileName) { FIBITMAP *dib = readFileToFIBITMAP(fileName, FIF_LOAD_NOPIXELS); QHash admMap; for (int i = FIMD_EXIF_MAIN; i <= FIMD_IPTC; ++i) { findMetaData(FREE_IMAGE_MDMODEL(i), dib, admMap); } QFileInfo info(fileName); if (admMap.contains("DateTime")) { // Get first DateTime. QDateTime time = QDateTime::fromString(admMap.value("DateTime"), "yyyy:MM:dd hh:mm:ss"); admMap.insert("DateTimeOriginal", time.toString("yyyy/MM/dd hh:mm")); } else { admMap.insert("DateTimeOriginal", info.lastModified().toString("yyyy/MM/dd HH:mm")); } admMap.insert("DateTimeDigitized", info.lastModified().toString("yyyy/MM/dd HH:mm")); // The value of width and height might incorrect QImageReader reader(fileName); int w = reader.size().width(); w = w > 0 ? w : static_cast(FreeImage_GetWidth(dib)); int h = reader.size().height(); h = h > 0 ? h : static_cast(FreeImage_GetHeight(dib)); admMap.insert("Dimension", QString::number(w) + "x" + QString::number(h)); admMap.insert("FileName", info.fileName()); admMap.insert("FileFormat", info.suffix()); static auto formatDataSize = [](qint64 size) -> QString { static const QStringList suffix = {"B", "KB", "MB", "GB", "TB", "PB"}; int level = 0; double bytes = size; while (bytes >= 1024 && level < (suffix.length() - 1)) { bytes /= 1024; ++level; } return QString("%1%2").arg(bytes, 0, 'f', 1).arg(suffix[level]); }; admMap.insert("FileSize", formatDataSize(info.size())); FreeImage_Unload(dib); return admMap; } FIBITMAP *DLibFreeImage::readFileToFIBITMAP(const QString &fileName, int flags, FREE_IMAGE_FORMAT fif) { QByteArray b = fileName.toUtf8(); const char *pc = b.data(); // Detect file format. if (FIF_UNKNOWN == fif) { fif = FreeImage_GetFileType(pc, 0); if (FIF_UNKNOWN == fif) { fif = FreeImage_GetFIFFromFilename(pc); } } if ((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) { FIBITMAP *dib = FreeImage_Load(fif, pc, flags); return dib; } return nullptr; } bool DLibFreeImage::writeFIBITMAPToFile(FIBITMAP *dib, const QString &fileName, int flags) { FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; bool bSuccess = false; const QByteArray ba = fileName.toUtf8(); const char *pc = ba.data(); // Try to guess the file format from the file extension fif = FreeImage_GetFIFFromFilename(pc); FREE_IMAGE_FORMAT realfif = FIF_UNKNOWN; if (fif == FIF_UNKNOWN) { realfif = FreeImage_GetFileType(pc, 0); } if (fif != FIF_UNKNOWN) { bSuccess = FreeImage_Save(fif, dib, pc, flags); } else if (realfif != FIF_UNKNOWN) { bSuccess = FreeImage_Save(realfif, dib, pc, flags); } return bSuccess; } QImage DLibFreeImage::FIBITMAPToQImage(FIBITMAP *dib) const { if (!dib || FreeImage_GetImageType(dib) == FIT_UNKNOWN) return QImage(0, 0, QImage::Format_Invalid); int width = static_cast(FreeImage_GetWidth(dib)); int height = static_cast(FreeImage_GetHeight(dib)); int depth = static_cast(FreeImage_GetBPP(dib)); switch (depth) { case 1: { QImage result(width, height, QImage::Format_Mono); FreeImage_ConvertToRawBits(result.scanLine(0), dib, result.bytesPerLine(), 1, 0, 0, 0, true); return result; } case 4: { // NOTE: QImage do not support 4-bit, convert it to 8-bit QImage result(width, height, QImage::Format_Indexed8); FreeImage_ConvertToRawBits(result.scanLine(0), dib, result.bytesPerLine(), 8, 0, 0, 0, true); return result; } case 8: { QImage result(width, height, QImage::Format_Indexed8); FreeImage_ConvertToRawBits(result.scanLine(0), dib, result.bytesPerLine(), 8, 0, 0, 0, true); return result; } case 16: if ((FreeImage_GetRedMask(dib) == FI16_555_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_555_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_555_BLUE_MASK)) { // 5-5-5 QImage result(width, height, QImage::Format_RGB555); FreeImage_ConvertToRawBits(result.scanLine(0), dib, result.bytesPerLine(), 16, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK, true); return result; } else { // 5-6-5 QImage result(width, height, QImage::Format_RGB16); FreeImage_ConvertToRawBits(result.scanLine(0), dib, result.bytesPerLine(), 16, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK, true); return result; } case 24: { QImage result(width, height, QImage::Format_RGB32); FreeImage_ConvertToRawBits(result.scanLine(0), dib, result.bytesPerLine(), 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, true); return result; } case 32: { QImage result(width, height, QImage::Format_ARGB32); FreeImage_ConvertToRawBits(result.scanLine(0), dib, result.bytesPerLine(), 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, true); return result; } case 48: case 64: case 96: case 128: default: break; } return QImage(0, 0, QImage::Format_Invalid); } ExifImageOrientation DLibFreeImage::imageOrientation(const QString &fileName) { ExifImageOrientation oreintation = Undefined; FIBITMAP *dib = readFileToFIBITMAP(fileName, FIF_LOAD_NOPIXELS); // Metadata may be null sometimes, check if metadata exist. if (0 == FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib)) { FreeImage_Unload(dib); return oreintation; } FITAG *tag = nullptr; FIMETADATA *mdhandle = nullptr; mdhandle = FreeImage_FindFirstMetadata(FIMD_EXIF_MAIN, dib, &tag); if (mdhandle) { do { if (qstrcmp(FreeImage_GetTagKey(tag), "Orientation") == 0) { oreintation = ExifImageOrientation(*static_cast(FreeImage_GetTagValue(tag))); break; } } while (FreeImage_FindNextMetadata(mdhandle, &tag)); FreeImage_FindCloseMetadata(mdhandle); } FreeImage_Unload(dib); return oreintation; } bool DLibFreeImage::rotateImageFile(const QString &fileName, int angle, QString &errorString) { FIBITMAP *dib = readFileToFIBITMAP(fileName); if (nullptr == dib) { errorString = "Unsupported format"; return false; } FIBITMAP *rotateRes = FreeImage_Rotate(dib, -angle, nullptr); if (rotateRes) { // Regenerate thumbnail if it's exits // Image formats that currently support thumbnail saving are // JPEG (JFIF formats), EXR, TGA and TIFF. if (FreeImage_GetThumbnail(dib)) { FIBITMAP *thumb = FreeImage_GetThumbnail(dib); FIBITMAP *rotateThumb = FreeImage_Rotate(thumb, -angle, nullptr); FreeImage_SetThumbnail(rotateRes, rotateThumb); FreeImage_Unload(rotateThumb); } } FREE_IMAGE_FORMAT f = FreeImage_GetFIFFromFilename(fileName.toUtf8().data()); if (f == FIF_UNKNOWN) { FreeImage_Unload(dib); FreeImage_Unload(rotateRes); errorString = "Rotate image format error"; return false; } if (!writeFIBITMAPToFile(rotateRes, fileName)) { FreeImage_Unload(dib); FreeImage_Unload(rotateRes); errorString = "Rotate image save failed, unknown format"; return false; } FreeImage_Unload(dib); FreeImage_Unload(rotateRes); return true; } DLibRaw::DLibRaw() { libraw = new QLibrary("libraw"); if (!libraw->load()) { delete libraw; libraw = nullptr; return; } auto initFunctionError = [this]() { libraw->unload(); delete libraw; libraw = nullptr; }; #define INIT_FUNCTION_LIBRAW(Name) \ Name = reinterpret_cast(libraw->resolve(#Name)); \ if (!Name) { \ initFunctionError(); \ return; \ } INIT_FUNCTION_LIBRAW(libraw_strerror); INIT_FUNCTION_LIBRAW(libraw_init); INIT_FUNCTION_LIBRAW(libraw_open_file); INIT_FUNCTION_LIBRAW(libraw_open_buffer); INIT_FUNCTION_LIBRAW(libraw_unpack); INIT_FUNCTION_LIBRAW(libraw_unpack_thumb); INIT_FUNCTION_LIBRAW(libraw_close); INIT_FUNCTION_LIBRAW(libraw_dcraw_process); INIT_FUNCTION_LIBRAW(libraw_dcraw_make_mem_image); INIT_FUNCTION_LIBRAW(libraw_dcraw_make_mem_thumb); INIT_FUNCTION_LIBRAW(libraw_dcraw_clear_mem); } DLibRaw::~DLibRaw() { if (libraw) { delete libraw; } } bool DLibRaw::isValid() { return libraw; } QImage DLibRaw::loadImage(const QString &fileName, QString &errString, QSize requestSize) { QImage image; libraw_data_t *rawData = libraw_init(0); if (!rawData) { errString = QStringLiteral("Create new libraw object failed!"); return image; } int ret = libraw_open_file(rawData, fileName.toUtf8().data()); if (LIBRAW_SUCCESS == ret) { ret = readImage(rawData, image, requestSize); } libraw_close(rawData); if (LIBRAW_SUCCESS != ret) { errString = errorString(ret); } return image; } QImage DLibRaw::loadImage(QByteArray &data, QString &errString, QSize requestSize) { QImage image; libraw_data_t *rawData = libraw_init(0); if (!rawData) { errString = QStringLiteral("Create new libraw object failed!"); return image; } int ret = libraw_open_buffer(rawData, reinterpret_cast(data.data()), static_cast(data.size())); if (LIBRAW_SUCCESS == ret) { ret = readImage(rawData, image, requestSize); } libraw_close(rawData); if (LIBRAW_SUCCESS != ret) { errString = errorString(ret); } return image; } int DLibRaw::readImage(libraw_data_t *rawData, QImage &image, QSize requestSize) { if (!rawData) { return LIBRAW_INPUT_CLOSED; } int ret = LIBRAW_UNSPECIFIED_ERROR; int errCode = LIBRAW_SUCCESS; libraw_processed_image_t *output = nullptr; // Try to read thumbnail image if possible. if (!requestSize.isEmpty() && (requestSize.width() < rawData->thumbnail.twidth || requestSize.height() < rawData->thumbnail.theight)) { ret = libraw_unpack_thumb(rawData); if (LIBRAW_SUCCESS == ret) { output = libraw_dcraw_make_mem_thumb(rawData, &errCode); if (LIBRAW_SUCCESS != errCode && output) { libraw_dcraw_clear_mem(output); } } } // Read default image if no thumbnail. if (!output) { ret = libraw_unpack(rawData); if (LIBRAW_SUCCESS != ret) { return ret; } ret = libraw_dcraw_process(rawData); if (LIBRAW_SUCCESS != ret) { return ret; } output = libraw_dcraw_make_mem_image(rawData, &errCode); if (LIBRAW_SUCCESS != errCode) { if (output) { libraw_dcraw_clear_mem(output); } // Can't read data, return. return errCode; } } if (LIBRAW_IMAGE_JPEG == output->type) { image.loadFromData(output->data, static_cast(output->data_size), "JPEG"); if (rawData->sizes.flip) { QTransform rotation; int angle = 0; // Image orientation (0 if does not require rotation; 3 if requires 180-deg rotation; // 5 if 90 deg counterclockwise, 6 if 90 deg clockwise). switch (rawData->sizes.flip) { case 3: angle = 180; break; case 5: angle = -90; break; case 6: angle = 90; break; default: break; } if (angle != 0) { rotation.rotate(angle); image = image.transformed(rotation); } } } else { int numPixels = output->width * output->height; int colorSize = output->bits / 8; int pixelSize = output->colors * colorSize; uchar *pixels = new uchar[numPixels * 4]; uchar *data = output->data; for (int i = 0; i < numPixels; i++, data += pixelSize) { if (output->colors == 3) { pixels[i * 4] = data[2 * colorSize]; pixels[i * 4 + 1] = data[1 * colorSize]; pixels[i * 4 + 2] = data[0]; } else { pixels[i * 4] = data[0]; pixels[i * 4 + 1] = data[0]; pixels[i * 4 + 2] = data[0]; } } // QImage::Format_RGB32 will cause window transparent image = QImage(pixels, output->width, output->height, QImage::Format_RGB32).convertToFormat(QImage::Format_ARGB32); delete[] pixels; } libraw_dcraw_clear_mem(output); return LIBRAW_SUCCESS; } QString DLibRaw::errorString(int errorCode) { return QString(libraw_strerror(errorCode)); } #endif dtkgui-5.7.12/src/util/dsvgrenderer.cpp000066400000000000000000000265721476226661100200660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DTK_DISABLE_LIBRSVG #include #else #include #endif #include "dsvgrenderer.h" #include "dobject_p.h" #include #include #include #include #include #include DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE #ifndef DTK_DISABLE_LIBRSVG class RSvg { public: RSvg() { // fix found lib was librsvg2-dev without version number rsvg = new QLibrary("rsvg-2", "2"); if (!rsvg->load()) { delete rsvg; rsvg = nullptr; return; } #define INIT_FUNCTION(Name) Name = reinterpret_cast(rsvg->resolve(#Name)); Q_ASSERT(Name) INIT_FUNCTION(cairo_image_surface_create_for_data); INIT_FUNCTION(cairo_create); INIT_FUNCTION(cairo_scale); INIT_FUNCTION(cairo_translate); INIT_FUNCTION(cairo_destroy); INIT_FUNCTION(cairo_surface_destroy); INIT_FUNCTION(g_object_unref); INIT_FUNCTION(rsvg_handle_render_cairo); INIT_FUNCTION(rsvg_handle_render_cairo_sub); INIT_FUNCTION(rsvg_handle_get_dimensions_sub); INIT_FUNCTION(rsvg_handle_get_position_sub); INIT_FUNCTION(rsvg_handle_has_sub); INIT_FUNCTION(rsvg_handle_new_from_data); INIT_FUNCTION(rsvg_handle_get_dimensions); } static RSvg *instance() { static RSvg *global = new RSvg(); return global; } bool isValid() const { return rsvg; } ~RSvg() { if (rsvg) delete rsvg; } cairo_surface_t *(*cairo_image_surface_create_for_data)(unsigned char *data, cairo_format_t format, int width, int height, int stride); cairo_t *(*cairo_create)(cairo_surface_t *target); void (*cairo_scale)(cairo_t *cr, double sx, double sy); void (*cairo_translate)(cairo_t *cr, double tx, double ty); void (*cairo_destroy)(cairo_t *cr); void (*cairo_surface_destroy)(cairo_surface_t *surface); void (*g_object_unref)(gpointer object); gboolean (*rsvg_handle_render_cairo)(RsvgHandle *handle, cairo_t *cr); gboolean (*rsvg_handle_render_cairo_sub)(RsvgHandle *handle, cairo_t *cr, const char *id); gboolean (*rsvg_handle_get_dimensions_sub)(RsvgHandle *handle, RsvgDimensionData *dimension_data, const char *id); gboolean (*rsvg_handle_get_position_sub)(RsvgHandle *handle, RsvgPositionData *position_data, const char *id); gboolean (*rsvg_handle_has_sub)(RsvgHandle *handle, const char *id); RsvgHandle *(*rsvg_handle_new_from_data)(const guint8 *data, gsize data_len, GError **error); void (*rsvg_handle_get_dimensions)(RsvgHandle *handle, RsvgDimensionData *dimension_data); private: QLibrary *rsvg = nullptr; }; #endif class DSvgRendererPrivate : public DObjectPrivate { public: explicit DSvgRendererPrivate(DSvgRenderer *qq); QImage getImage(const QSize &size, const QString &elementId) const; #ifndef DTK_DISABLE_LIBRSVG RsvgHandle *handle = nullptr; QSize defaultSize; mutable QRectF viewBox; #else QSvgRenderer *qRenderer = nullptr; #endif }; DSvgRendererPrivate::DSvgRendererPrivate(DSvgRenderer *qq) : DObjectPrivate(qq) // qq ==> DObject #ifdef DTK_DISABLE_LIBRSVG , qRenderer(new QSvgRenderer(qq)) // qq ==> QObject #endif { } QImage DSvgRendererPrivate::getImage(const QSize &size, const QString &elementId) const { #ifndef DTK_DISABLE_LIBRSVG if (!RSvg::instance()->isValid()) return QImage(); QImage image(size, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); cairo_surface_t *surface = RSvg::instance()->cairo_image_surface_create_for_data(image.bits(), CAIRO_FORMAT_ARGB32, image.width(), image.height(), image.bytesPerLine()); cairo_t *cairo = RSvg::instance()->cairo_create(surface); RSvg::instance()->cairo_scale(cairo, image.width() / viewBox.width(), image.height() / viewBox.height()); RSvg::instance()->cairo_translate(cairo, -viewBox.x(), -viewBox.y()); if (elementId.isEmpty()) RSvg::instance()->rsvg_handle_render_cairo(handle, cairo); else RSvg::instance()->rsvg_handle_render_cairo_sub(handle, cairo, elementId.toUtf8().constData()); RSvg::instance()->cairo_destroy(cairo); RSvg::instance()->cairo_surface_destroy(surface); return image; #else QImage image(size, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); QPainter pa(&image); if (elementId.isEmpty()) qRenderer->render(&pa); else qRenderer->render(&pa, elementId); return image; #endif } /*! \class Dtk::Gui::DSvgRenderer \inmodule dtkgui \brief 提供了将SVG文件的内容绘制到绘制设备上的方法. SVG图形可以在构造 DSvgRenderer 时加载,也可以稍后使用load()函数加载。 因为渲染是使用 QPainter 执行的,所以可以在 QPaintDevice 的任何子类上渲染SVG图形。 如果加载了有效文件,则无论是在构造时还是以后某个时间,isValid()都将返回true;否则将返回false。 DSvgRenderer提供render()插槽,用于使用给定的 QPainter 渲染当前文档或动画文档的当前帧 \note 使用 DSvgRenderer 需要 librsvg库 */ DSvgRenderer::DSvgRenderer(QObject *parent) : QObject(parent) , DObject(*new DSvgRendererPrivate(this)) { } DSvgRenderer::DSvgRenderer(const QString &filename, QObject *parent) : DSvgRenderer(parent) { load(filename); } DSvgRenderer::DSvgRenderer(const QByteArray &contents, QObject *parent) : DSvgRenderer(parent) { load(contents); } DSvgRenderer::~DSvgRenderer() { #ifndef DTK_DISABLE_LIBRSVG D_D(DSvgRenderer); if (d->handle) { Q_ASSERT(RSvg::instance()->isValid()); RSvg::instance()->g_object_unref(d->handle); } #endif } bool DSvgRenderer::isValid() const { D_DC(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG return d->handle; #else return d->qRenderer->isValid(); #endif } QSize DSvgRenderer::defaultSize() const { D_DC(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG return d->defaultSize; #else return d->qRenderer->defaultSize(); #endif } QRect DSvgRenderer::viewBox() const { D_DC(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG return d->handle ? d->viewBox.toRect() : QRect(); #else return d->qRenderer->viewBox(); #endif } QRectF DSvgRenderer::viewBoxF() const { D_DC(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG return d->handle ? d->viewBox : QRectF(); #else return d->qRenderer->viewBoxF(); #endif } void DSvgRenderer::setViewBox(const QRect &viewbox) { setViewBox(QRectF(viewbox)); } void DSvgRenderer::setViewBox(const QRectF &viewbox) { D_D(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG if (d->handle) d->viewBox = viewbox; #else return d->qRenderer->setViewBox(viewbox); #endif } QRectF DSvgRenderer::boundsOnElement(const QString &id) const { D_DC(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG if (!d->handle) return QRectF(); const QByteArray &id_data = id.toUtf8(); RsvgDimensionData dimension_data; if (!RSvg::instance()->rsvg_handle_get_dimensions_sub(d->handle, &dimension_data, id_data.constData())) return QRectF(); RsvgPositionData pos_data; if (!RSvg::instance()->rsvg_handle_get_position_sub(d->handle, &pos_data, id_data.constData())) return QRectF(); return QRectF(pos_data.x, pos_data.y, dimension_data.width, dimension_data.height); #else return d->qRenderer->boundsOnElement(id); #endif } bool DSvgRenderer::elementExists(const QString &id) const { D_DC(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG if (!d->handle) return false; return RSvg::instance()->rsvg_handle_has_sub(d->handle, id.toUtf8().constData()); #else return d->qRenderer->elementExists(id); #endif } QImage DSvgRenderer::toImage(const QSize sz, const QString &elementId) const { Q_D(const DSvgRenderer); return d->getImage(sz, elementId); } #ifndef DTK_DISABLE_LIBRSVG static QByteArray updateXmlAttribute(const QString &contents) { QByteArray data; QXmlStreamWriter writer(&data); QXmlStreamReader reader(contents); while(reader.readNext() != QXmlStreamReader::Invalid && !reader.atEnd()) { if (reader.tokenType() != QXmlStreamReader::StartElement || !reader.attributes().hasAttribute("href")) { writer.writeCurrentToken(reader); continue; } for (const auto &nd : reader.namespaceDeclarations()) writer.writeNamespace(nd.namespaceUri().toString(), nd.prefix().toString()); writer.writeStartElement(reader.namespaceUri().toString(), reader.name().toString()); for (const auto &attr : reader.attributes()) { if (attr.name() == QStringLiteral("href")) { writer.writeAttribute("xlink:href", attr.value().toString()); continue; } writer.writeAttribute(attr); } } return data; } static QByteArray format(const QByteArray &contents) { QXmlStreamReader reader(contents); while (reader.readNextStartElement()) { if (reader.attributes().hasAttribute("href")) return updateXmlAttribute(contents); } return contents; } #endif bool DSvgRenderer::load(const QString &filename) { #ifndef DTK_DISABLE_LIBRSVG QFile file(filename); if (file.open(QIODevice::ReadOnly)) { // TODO: if `href` attribute is adapted after librsvg upgrade revert me return load(format(file.readAll())); } return false; #else D_D(DSvgRenderer); return d->qRenderer->load(filename); #endif } bool DSvgRenderer::load(const QByteArray &contents) { D_D(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG if (!RSvg::instance()->isValid()) return false; if (d->handle) { RSvg::instance()->g_object_unref(d->handle); d->handle = nullptr; } GError *error = nullptr; d->handle = RSvg::instance()->rsvg_handle_new_from_data((const guint8*)contents.constData(), contents.length(), &error); if (error) { qWarning("DSvgRenderer::load: %s", error->message); g_error_free(error); return false; } RsvgDimensionData rsvg_data; RSvg::instance()->rsvg_handle_get_dimensions(d->handle, &rsvg_data); d->defaultSize.setWidth(rsvg_data.width); d->defaultSize.setHeight(rsvg_data.height); d->viewBox = QRectF(QPointF(0, 0), d->defaultSize); return true; #else return d->qRenderer->load(contents); #endif } void DSvgRenderer::render(QPainter *p) { #ifndef DTK_DISABLE_LIBRSVG render(p, QString(), QRectF()); #else D_D(DSvgRenderer); d->qRenderer->render(p); #endif } void DSvgRenderer::render(QPainter *p, const QRectF &bounds) { #ifndef DTK_DISABLE_LIBRSVG render(p, QString(), bounds); #else D_D(DSvgRenderer); d->qRenderer->render(p, bounds); #endif } void DSvgRenderer::render(QPainter *p, const QString &elementId, const QRectF &bounds) { D_D(DSvgRenderer); #ifndef DTK_DISABLE_LIBRSVG if (!d->handle) return; p->save(); const QImage image = d->getImage(QSize(p->device()->width(), p->device()->height()), elementId); if (bounds.isEmpty()) p->drawImage(0, 0, image); else p->drawImage(bounds, image); p->restore(); #else d->qRenderer->render(p, elementId, bounds); #endif } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/dtaskbarcontrol.cpp000066400000000000000000000104111476226661100205510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtaskbarcontrol.h" #include #include #include #include #include #include "private/dtaskbarcontrol_p.h" DCORE_USE_NAMESPACE DGUI_BEGIN_NAMESPACE DTaskbarControlPrivate::DTaskbarControlPrivate(DTaskbarControl *q) : DObjectPrivate(q) , m_counter(0) , m_counterVisible(true) , m_progress(0) , m_progressVisible(true) { } DTaskbarControlPrivate::~DTaskbarControlPrivate() { } /*! \class Dtk::Gui::DTaskbarControl \inmodule dtkgui \brief DTaskbarControl提供了一个Launcher API接口,用于方便应用程序控制taskbar进度条,设置当前任务数量. 如果想隐藏或者不使用进度条和任务数的显示,可以使用setProgress,setCounter 传递false隐藏相关显示. */ DTaskbarControl::DTaskbarControl(QObject *parent) : QObject(parent) , DObject(*new DTaskbarControlPrivate(this)) { } DTaskbarControl::~DTaskbarControl() { } /*! \brief DTaskbarControl::setProgress 设置当前进度和进度条是否可见 \a progressVisible true可见 false不可见 \a progress 当前进度值 0-1(换算成百分比) */ void DTaskbarControl::setProgress(bool progressVisible, double progress) { if (!qFuzzyCompare(d_func()->m_progress, progress)) { d_func()->m_progress = progress; Q_EMIT progressChanged(progress); } if (d_func()->m_progressVisible != progressVisible) { d_func()->m_progressVisible = progressVisible; Q_EMIT progressVisibleChanged(progressVisible); } QVariantMap properties; properties.insert("progress-visible", progressVisible); properties.insert("progress", progress); sendMessage(properties); } /*! \brief DTaskbarControl::setCounter 设置当前任务数量 \a counterVisible true任务数可见 false任务数不可见 \a counter */ void DTaskbarControl::setCounter(bool counterVisible, int counter) { if (counter != d_func()->m_counter) { d_func()->m_counter = counter; Q_EMIT counterChanged(counter); } if (d_func()->m_counterVisible != counterVisible) { d_func()->m_counterVisible = counterVisible; Q_EMIT counterVisibleChanged(counterVisible); } QVariantMap properties; properties.insert("count-visible", counterVisible); properties.insert("count", counter); sendMessage(properties); } /*! brief DTaskbarControl::counter 获取当前任务数 return 任务数量 */ int DTaskbarControl::counter() const { return d_func()->m_counter; } /*! \brief DTaskbarControl::setCounterVisible 设置任务数是否可见 \a counterVisible true可见 false不可见 如果需要隐藏,建议设置counter的值为0并且设置为false,只设置false,有可能会显示 */ void DTaskbarControl::setCounterVisible(bool counterVisible) { if (d_func()->m_counterVisible != counterVisible) { d_func()->m_counterVisible = counterVisible; Q_EMIT counterVisibleChanged(counterVisible); } QVariantMap properties; properties.insert("count-visible", counterVisible); sendMessage(properties); } /*! \brief DTaskbarControl::counterVisible 返回任务数是否可见 \return true可见 false不可见 */ bool DTaskbarControl::counterVisible() const { return d_func()->m_counterVisible; } /*! \brief DTaskbarControl::setUrgency 设置任务的紧急程度 \a val true 任务紧急 false普通任务 */ void DTaskbarControl::setUrgency(bool val) { QVariantMap properties; properties.insert("urgent", val); sendMessage(properties); } void DTaskbarControl::sendMessage(const QVariantMap ¶ms) { if (QGuiApplication::desktopFileName().isEmpty()) { qWarning() << "You need to set the desktop file name before you can use DTaskbarControl!"; return; } auto message = QDBusMessage::createSignal("/com/deepin/dtkgui/DTaskbarControl", "com.canonical.Unity.LauncherEntry", "Update"); message << "application://" + QGuiApplication::desktopFileName() << params; QDBusConnection::sessionBus().send(message); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/dthumbnailprovider.cpp000066400000000000000000000305001476226661100212600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dthumbnailprovider.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include DGUI_BEGIN_NAMESPACE #define FORMAT ".png" #define THUMBNAIL_PATH \ DCORE_NAMESPACE::DStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/thumbnails" #define THUMBNAIL_FAIL_PATH THUMBNAIL_PATH"/fail" #define THUMBNAIL_LARGE_PATH THUMBNAIL_PATH"/large" #define THUMBNAIL_NORMAL_PATH THUMBNAIL_PATH"/normal" #define THUMBNAIL_SMALL_PATH THUMBNAIL_PATH"/small" inline QByteArray dataToMd5Hex(const QByteArray &data) { return QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex(); } #ifndef UT_DThumbnailProviderPrivate class DThumbnailProviderPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate { public: explicit DThumbnailProviderPrivate(DThumbnailProvider *qq); void init(); QString sizeToFilePath(DThumbnailProvider::Size size) const; QString errorString; // MAX qint64 defaultSizeLimit = INT64_MAX; QHash sizeLimitHash; QMimeDatabase mimeDatabase; static QSet hasThumbnailMimeHash; struct ProduceInfo { QFileInfo fileInfo; DThumbnailProvider::Size size; DThumbnailProvider::CallBack callback; }; QQueue produceQueue; QSet> discardedProduceInfos; bool running = true; QWaitCondition waitCondition; QReadWriteLock dataReadWriteLock; D_DECLARE_PUBLIC(DThumbnailProvider) }; #endif QSet DThumbnailProviderPrivate::hasThumbnailMimeHash; DThumbnailProviderPrivate::DThumbnailProviderPrivate(DThumbnailProvider *qq) : DObjectPrivate(qq) { } void DThumbnailProviderPrivate::init() { } QString DThumbnailProviderPrivate::sizeToFilePath(DThumbnailProvider::Size size) const { switch (size) { case DThumbnailProvider::Small: return THUMBNAIL_SMALL_PATH; case DThumbnailProvider::Normal: return THUMBNAIL_NORMAL_PATH; case DThumbnailProvider::Large: return THUMBNAIL_LARGE_PATH; } return QString(); } class DFileThumbnailProviderPrivate : public DThumbnailProvider {}; Q_GLOBAL_STATIC(DFileThumbnailProviderPrivate, ftpGlobal) DThumbnailProvider *DThumbnailProvider::instance() { return ftpGlobal; } /*! \brief DThumbnailProvider::hasThumbnail缩略图是否存在 \a info 文件信息 \return true 存在 false 不存在 */ bool DThumbnailProvider::hasThumbnail(const QFileInfo &info) const { Q_D(const DThumbnailProvider); if (!info.isReadable() || !info.isFile()) { return false; } qint64 fileSize = info.size(); if (fileSize <= 0) { return false; } const QMimeType &mime = d->mimeDatabase.mimeTypeForFile(info); if (fileSize > sizeLimit(mime)) { return false; } return hasThumbnail(mime); } bool DThumbnailProvider::hasThumbnail(const QMimeType &mimeType) const { const QString &mime = mimeType.name(); if (DThumbnailProviderPrivate::hasThumbnailMimeHash.isEmpty()) { const QList &mimeTypes = QImageReader::supportedMimeTypes(); if (mimeTypes.isEmpty()) { DThumbnailProviderPrivate::hasThumbnailMimeHash.insert(""); return false; } DThumbnailProviderPrivate::hasThumbnailMimeHash.reserve(mimeTypes.size()); for (const QByteArray &t : mimeTypes) { DThumbnailProviderPrivate::hasThumbnailMimeHash.insert(QString::fromLocal8Bit(t)); } } return DThumbnailProviderPrivate::hasThumbnailMimeHash.contains(mime); } /*! \brief DThumbnailProvider::thumbnailFilePath返回文件缩略图文件路径 \a info 文件信息 \a size 图片大小 \return 路径信息 */ QString DThumbnailProvider::thumbnailFilePath(const QFileInfo &info, Size size) const { Q_D(const DThumbnailProvider); const QString &absolutePath = info.absolutePath(); const QString &absoluteFilePath = info.absoluteFilePath(); if (absolutePath == d->sizeToFilePath(Small) || absolutePath == d->sizeToFilePath(Normal) || absolutePath == d->sizeToFilePath(Large) || absolutePath == THUMBNAIL_FAIL_PATH) { return absoluteFilePath; } const QString thumbnailName = dataToMd5Hex(QUrl::fromLocalFile(absoluteFilePath).toString(QUrl::FullyEncoded).toLocal8Bit()) + FORMAT; QString thumbnail = d->sizeToFilePath(size) + QDir::separator() + thumbnailName; if (!QFile::exists(thumbnail)) { return QString(); } QImage image(thumbnail); if (image.text(QT_STRINGIFY(Thumb::MTime)) != info.lastModified().toString(Qt::ISODate)) { QFile::remove(thumbnail); Q_EMIT thumbnailChanged(absoluteFilePath, QString()); return QString(); } return thumbnail; } /*! \brief DThumbnailProvider::createThumbnail创建缩略图 \a info 文件信息 \a size 图片大小 \return 成功返回绝对路径信息,失败则返回空 */ QString DThumbnailProvider::createThumbnail(const QFileInfo &info, DThumbnailProvider::Size size) { Q_D(DThumbnailProvider); d->errorString.clear(); const QString &absolutePath = info.absolutePath(); const QString &absoluteFilePath = info.absoluteFilePath(); if (absolutePath == d->sizeToFilePath(Small) || absolutePath == d->sizeToFilePath(Normal) || absolutePath == d->sizeToFilePath(Large) || absolutePath == THUMBNAIL_FAIL_PATH) { return absoluteFilePath; } if (!hasThumbnail(info)) { d->errorString = QStringLiteral("This file has not support thumbnail: ") + absoluteFilePath; //!Warnning: Do not store thumbnails to the fail path return QString(); } const QString fileUrl = QUrl::fromLocalFile(absoluteFilePath).toString(QUrl::FullyEncoded); const QString thumbnailName = dataToMd5Hex(fileUrl.toLocal8Bit()) + FORMAT; // the file is in fail path QString thumbnail = THUMBNAIL_FAIL_PATH + QDir::separator() + thumbnailName; if (QFile::exists(thumbnail)) { QImage image(thumbnail); if (image.text(QT_STRINGIFY(Thumb::MTime)) != info.lastModified().toString(Qt::ISODate)) { QFile::remove(thumbnail); } else { return QString(); } }// end QScopedPointer image(new QImage(QSize(size, size), QImage::Format_ARGB32_Premultiplied)); QImageReader reader(absoluteFilePath); if (!reader.canRead()) { reader.setFormat(d->mimeDatabase.mimeTypeForFile(info).name().toLocal8Bit()); if (!reader.canRead()) { d->errorString = reader.errorString(); } } if (d->errorString.isEmpty()) { const QSize &imageSize = reader.size(); if (imageSize.isValid()) { if (imageSize.width() >= size || imageSize.height() >= size) { reader.setScaledSize(reader.size().scaled(size, size, Qt::KeepAspectRatio)); } if (!reader.read(image.data())) { d->errorString = reader.errorString(); } } else { d->errorString = "Fail to read image file attribute data:" + info.absoluteFilePath(); } } // successful if (d->errorString.isEmpty()) { thumbnail = d->sizeToFilePath(size) + QDir::separator() + thumbnailName; } else { //fail image.reset(new QImage(1, 1, QImage::Format_Mono)); } image->setText(QT_STRINGIFY(Thumb::URL), fileUrl); image->setText(QT_STRINGIFY(Thumb::MTime), info.lastModified().toString(Qt::ISODate)); // create path QFileInfo(thumbnail).absoluteDir().mkpath("."); if (!image->save(thumbnail, Q_NULLPTR, 80)) { d->errorString = QStringLiteral("Can not save image to ") + thumbnail; } if (d->errorString.isEmpty()) { Q_EMIT createThumbnailFinished(absoluteFilePath, thumbnail); Q_EMIT thumbnailChanged(absoluteFilePath, thumbnail); return thumbnail; } // fail Q_EMIT createThumbnailFailed(absoluteFilePath); return QString(); } void DThumbnailProvider::appendToProduceQueue(const QFileInfo &info, DThumbnailProvider::Size size, DThumbnailProvider::CallBack callback) { DThumbnailProviderPrivate::ProduceInfo produceInfo; produceInfo.fileInfo = info; produceInfo.size = size; produceInfo.callback = callback; Q_D(DThumbnailProvider); if (isRunning()) { QWriteLocker locker(&d->dataReadWriteLock); d->produceQueue.append(std::move(produceInfo)); locker.unlock(); d->waitCondition.wakeAll(); } else { d->produceQueue.append(std::move(produceInfo)); start(); } } /*! \brief DThumbnailProvider::removeInProduceQueue将缩略图从列表中删除 \a info 缩略图文件 \a size 缩略图大小 */ void DThumbnailProvider::removeInProduceQueue(const QFileInfo &info, DThumbnailProvider::Size size) { Q_D(DThumbnailProvider); if (isRunning()) { QWriteLocker locker(&d->dataReadWriteLock); Q_UNUSED(locker) } d->discardedProduceInfos.insert(qMakePair(info.absoluteFilePath(), size)); } /*! \brief DThumbnailProvider::errorString返回错误信息 \return 错误信息 */ QString DThumbnailProvider::errorString() const { Q_D(const DThumbnailProvider); return d->errorString; } /*! \brief DThumbnailProvider::defaultSizeLimit返回缩略图默认大小 \return 默认的大小 */ qint64 DThumbnailProvider::defaultSizeLimit() const { Q_D(const DThumbnailProvider); return d->defaultSizeLimit; } /*! \brief DThumbnailProvider::setDefaultSizeLimit设置缩略图的默认大小 \a size 大小 */ void DThumbnailProvider::setDefaultSizeLimit(qint64 size) { Q_D(DThumbnailProvider); d->defaultSizeLimit = size; } /*! \brief DThumbnailProvider::sizeLimit 返回文件大小 \a mimeType 由MIME类型字符串表示的文件或数据类型 \return */ qint64 DThumbnailProvider::sizeLimit(const QMimeType &mimeType) const { Q_D(const DThumbnailProvider); return d->sizeLimitHash.value(mimeType, d->defaultSizeLimit); } /*! \brief DThumbnailProvider::setSizeLimit 设置文件的大小 \a mimeType 由MIME类型字符串表示的文件或数据类型 \a size 范围 */ void DThumbnailProvider::setSizeLimit(const QMimeType &mimeType, qint64 size) { Q_D(DThumbnailProvider); d->sizeLimitHash[mimeType] = size; } /*! \class Dtk::Gui::DThumbnailProvider \inmodule dtkgui \brief 缩略图生成类.  \note 缩略图创建失败 该文件格式未知,无法由程序加载。 文件格式是已知的,但是文件已被损坏,因此无法读取。 由于文件很大,缩略图的生成将花费很长时间 */ DThumbnailProvider::DThumbnailProvider(QObject *parent) : QThread(parent) , DObject(*new DThumbnailProviderPrivate(this)) { d_func()->init(); } DThumbnailProvider::~DThumbnailProvider() { Q_D(DThumbnailProvider); d->running = false; d->waitCondition.wakeAll(); wait(); } void DThumbnailProvider::run() { Q_D(DThumbnailProvider); Q_FOREVER { QWriteLocker locker(&d->dataReadWriteLock); if (d->produceQueue.isEmpty()) { d->waitCondition.wait(&d->dataReadWriteLock); } if (!d->running) { return; } const DThumbnailProviderPrivate::ProduceInfo &task = d->produceQueue.dequeue(); const QPair &tmpKey = qMakePair(task.fileInfo.absoluteFilePath(), task.size); if (d->discardedProduceInfos.contains(tmpKey)) { d->discardedProduceInfos.remove(tmpKey); locker.unlock(); continue; } locker.unlock(); const QString &thumbnail = createThumbnail(task.fileInfo, task.size); if (task.callback) { task.callback(thumbnail); } } } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/icons/000077500000000000000000000000001476226661100157675ustar00rootroot00000000000000dtkgui-5.7.12/src/util/icons/actions/000077500000000000000000000000001476226661100174275ustar00rootroot00000000000000dtkgui-5.7.12/src/util/icons/actions/edit-copy_16px.svg000066400000000000000000000023571476226661100227320ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/actions/edit-cut_16px.svg000066400000000000000000000030221476226661100225410ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/actions/edit-delete_16px.svg000066400000000000000000000031551476226661100232170ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/actions/edit-paste_16px.svg000066400000000000000000000065451476226661100230770ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/actions/edit-redo_16px.svg000066400000000000000000000015641476226661100227100ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/actions/edit-select-all_16px.svg000066400000000000000000000027141476226661100240020ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/actions/edit-undo_16px.svg000066400000000000000000000007271476226661100227240ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/dci/000077500000000000000000000000001476226661100165265ustar00rootroot00000000000000dtkgui-5.7.12/src/util/icons/dci/sp_alert.dci000066400000000000000000000044201476226661100210200ustar00rootroot00000000000000DCI20normal.dark3f1.5p.webp../../normal.light/3/1.5p.webpnormal.light3:1.5p.webpRIFFWEBPVP8L/Y@M(h#I?7"?|EUMc61,-| w˃UYS2wJ6ҥ7ǶmYyfo5CYqe۶mוq]""#r!۶co/m۶mlնSڶmn1_lSsl*("₰|-_Ca| -WYw5Q#auDq]ͅ0zrqaGwt{M/T+e4p:G""0Atv-it:׻\vM/}0|a v;.ƘܙFfXP%"ӎ97<9mݕ+Xl y~ n1, (*j.؆ѬW+X!xŴc\"ثz !Kx`ƹ*tNu0QALS(EU ?P l >*fGGE7MJ0|"ԄcG'5ji>Ct*^ `ݙ Mw`; zj>$^1dOVn "*"l^-o$By= ب<:aÚ1gȴ3?AERe~> RYޑJd5EEɬ X%*R]&1 2Lӄ >Fhb\Zy@ڱ!D@ϥe غLV1:Gbʍ\b>O2#]200s-b~WD Z("iJe†hn)R &ZŒ܀ZTSQ+DUf-=qVr2890sݒYW:6-VaRfYAvҢn,39azn "vswb>_౎`M>CT\+(>-BkVzooc4& plọ}=ɩ}~IѩN"WxsKm}eYn-Y{~aEӲe->hM|qѥ_|:_f8b0U\*zIbGLᄄbiFҨZv5 QQᯫʗdeɆ0¦{l/͌ @Z%SE/Z=F\˥Govv&!;|;"ć<~kΞ X:.}@5J+dV}+vA I^ӯy&j:²t1r1۬srw]zaaI3Ae@f>g#PuuI:~5%7z{%ĤdB_q`as $`'Eqf&6KD#D U]4+bԣ~ t`U;AYE*`W&2j* ƃ#ݱpȨC#dtkgui-5.7.12/src/util/icons/dci/sp_ok.dci000066400000000000000000000146661476226661100203370ustar00rootroot00000000000000DCI20fnormal.dark3f1.5p.webp../../normal.light/3/1.5p.webpnormal.light(31.5p.webpRIFFWEBPVP8L/Y@ m9J{? !W-&Nh`4`.&YYb "J#u&mWY9_^W dm#If?.5Ŵ$IcO@0"C@Q6) =8ho-@F|CO<`;wԽ񙺷pB m[kOR"y#0!sϙɽjqU;X'YmӶm˵ue۾Bm_!ضml۶m:6מUM ^I?$= :@h ½UF;4r@8 |GhƪF64B-|ߏ]wn/oݣ .#Ѕ8]N7 B?58#{| "HMDꠖvFZf VpPB5Xڦ_Υǯyi[-? cQE!?S6oTO0@ P;bثK^c^uw GC8rH֚]>١[Ơ1e ꯡ)@``qߕ kyo^jC楇"ܟ(#y#RnȍF_;]zj% xzRˎ\q~dKs|}{Ŭ{Hޥ}XJGIA+䑵й | @_ٸm8D[OѬ:]] /SᶓF ܕ34`%j|];FT lܷ׃U/ OGurd5!I Ϟ[iw.ƸpiUsgbj$`طyb-&"pG%kf{gUtZ<^?ax,xvYʁq0`{$J+`P" laG(Tz,ݝ^SI:u;op9[>f 52*ĪH8h9k? X~uP!*Y jdX^+^eU9B; e=eKq^t#1`Ob8n`1W ncqೂ&Ǩ 1Q ].R_q6.G`;wy`r4Q1 L'#:Ʃ?`Pefk/Qc|gc+:z}c9#IU.r5zBj,qFg̈GH +$MK=y6g9`b)n u?N߲X;iA7]k혗#O^Hˡ#)y/wfj2Htqjiv1:{*>v)ep`dn wG_о Ҕo.Xbr Q( vM<+bE8U,ֽS p2g>g27=;ISQH:_,[QMnջ-2\:\Mwhu([/@n'7 k??1lQoa ,ltmqYjJSUEL.H*;gvV@@~ M[lo50¦NUQS?GFYOo~{¹O$4nA.Qr?SbU2uߜ|&F9\DoƱ)*:p{OrV峿Z̔(Qۇ]9#RmO|b{"|u*j}VY3m[AN쎬!aWݓeмKдw@c|Oewns4Y`5@ @l՗3WYSxŹq>`a+g? i泞cHF_lS{"S/E[FqbDZK}A\3~Yjf[\OHI%ߊw)m W}rNw2.WS.wMT0p6u{gD[ʾSA8* K^po#9̦ڹ'ul4wU.Hݕ& ClQ"6poߥqwׇ^rso:iDG{mbb 3n/WJIdZl!\wrI qAYϜWaBM5xxڷ 3[ak>`}vEb[aA@JGϽ9W,)aVIzE>(H3kv{-?Vh^\e'I/ԍOIϛD^""~fD5iU6Ȇ rvn@WWr݂QZo(b0"nMBtE>{/ۅ8|~@ ީ;!U.oLMHF`Rh? 2(^ ~yA^yc&h=Z]w2;'T!;b0/xhs>w)meo^{o51ZrRaI=4JG#`~oӰS1Dv$1UQ28h Y]J]2!npV9Mmv>au5,LްBi4fXD1J1c0"'@8R&R߿Ea5~ZGy`o}oH}F/e˭? x-[M0G0FUC 6E W2$Cemctȹ*,>! Ěfpڟ zFjk\-\$h|0\s\0j=F53 L.EtXnԈQO'1{sbA'{ SLJ3 ɤVVf16.F5/"嘆g XĴ&Q3/Eϣ[L@VdUoB <؜]n~pRN|Le}ɸ&ԍ +Z[=Jo>>~?Fd/S{5+YŲ֪XV2h.$ Tq#Y*ח.)ʔ;Ir\кխJpR_M#ʹf Iv(-T1qm?cbRǗͫZv'ZkȓFRBȓmEؤc_#!Fփ?Ul Ƌ#X-F]33k^,_~ϰC,!& 1DqMZ*lczJ8Dxm?זs08yZ4 3zA-*(Aj,hivӡjc[* @h7A4/1Wu-&$`Jkm?ZKsڀtp b$'^$EXE G1-t.@MѠaBոVƨĀ`ZИBUxאx\*[`sv؅z0 Fь)ҐWXė"Sd'MKt55پ&P/l@F4bkT 54`|*Tס#mA[Ѝ7-$K0>fLCL`MJ~:HQ[ 2g؁J  41 h5RsU8̄քx, 5<ӑ'3[:L$k**؆ۜ*#CSP֬l BЮ# 4!?؂Q2~+!2UeYqL\{N>{P5C-CjWӆ#Y"ΥӫTif[LJ)-|j;?,+obXm0囗ܐKz9?Eˡ@Y'Iꓖ \l@WupBk~OeI Qbt!zdtkgui-5.7.12/src/util/icons/dci/sp_waiting.dci000066400000000000000000000042521476226661100213560ustar00rootroot00000000000000DCI20Znormal.dark3f1.5p.webp../../normal.light/3/1.5p.webpnormal.light31.5p.webpRIFFWEBPVP8Lw/Y@M0l6d'r/F6[aR!yfˢV-h%#gV oxl VA&EٽMXzY, /' -ff&i2ϙZSGLڶMYm۶mwfֶ62m۶ QJCt`0a!)mjCa Bp쒔BSM!$|89Hihnq[L)N _wͻKQ3 !@#KΦKf:9v-%gF#iR ( A Z/͇]/:n#,;楦%gLEͤ@WthGZq(m; ?@v%37Bpdܵ&zŧ{@-D!"}qbtC $lxSC% Da&Zʞ}×` zvDVHx/IR:;*RNϏ"< G) &{!杊@} <,7BBȏﲅeyUЧ '#oHɀ ~Yb2D"3ut&A`,^m 래AY);er6@ rBW_7Id57(ّH3y)KBUphCP&] ɍw푙3.0Ʋ; {r]@c<ײ6z4Wb*׋@DW,(D3QEa~ZK} 9/deTOq*d1,>1`N#mi D5xYF9ߡ-4eg7ފ4~^œo(LVLhD.65?N7E i?<$7_i^VlY FDتjMOR7ܙ=Чu/355gGԭ{4og?$3Ձg~6c>j(?u~ni%&k5ɤ7%w-,4NqoA//]ei9%8 b]u**K9l(_4'qj#c^º` \J$@PJ4mNPd#Ir$Ije+K Ҷic^Yq<̐z133c۶m;*mvgWmmP]0 S$O=QêɾӮ gKN g4gEG¨+d1_3;(&iO)-R6@j!VG0)=/6:%s 3?j=) 5j_$qp1A+@2GR_g9Fܒ"4+eNXԴӮt]'M,p 2Ĝ]޴&v|egwF]@΃@#:cQԑ3T5c$Pc ߖK?>>ר1j 0 KhCfA^Ϩo /s\yǸ0te,AHa?'ٷ1?>p?ߵ{gc+G ILdNk s*uᢑŇլlVi@1$'TMM݇}`нTn,cmj$P -nž7k7ZdNE/#5Ā'@J t@?V1w5nA}y”DEmoS5Vz?138w`98.ˀ^]r h34fS`|xY79{ot7yq AhɃ!4VYVM TSr?sXmA F(7{^ y{͏j8t<;pUV޿+Rg\xdح(/T\ FW7 'ҺBƻH45,cm![V O',g\z71sԓ*'[7`$y/ֶʨ+2f gBo%-'HdyD N"wvҎ$!O[}JUdߵ:啬߿ R8֓@d@gb\'0D7NX}ŕGUĽSv]es@KcvM Bڦ.zkL~cʘaqL~٩b4zTz! $ar;B2;}tŏlIˇqKΘ5F 36A7a75a8zT q^cb NaXqܒ'*z9Gk$5VE cn]OCQ#BD޸e0`|F&``,lh]rwVSwm]Qc Z k>2/ $lhlUU^3tlǡRvyZSKd[D֥C; UU[]tA,X xZ~ciX1Uf,.Q갋< M+M)>*`FKAǦŴz7Ty8qX( \(ӡQǶZUӧ!֨ІvPЄod;+{a:i+=zoJʆ*4i@cT~ [o[Q `M-! ;>< }|b֓(+}>Qu=s~V mlDiw! j e̼I)Hih㧂;z) u?l\hLxL=n Z AJ+mUڐg 1[׽MF q0G@{`OX"fT Zu=އ_yŏSnLj4MIWeͰI *$[I3R[imtmW3y80iך2AԌ Y/<Ɵ0 b{uM­*~p{da|bIV?GLCڀ۵6Qd"5z+EPam(P)%vXHftA['[⋻FѨ7]5D#O8w|U y ҇U%̃IMl>~ T[DbEޠE66ZjH ")8d+BQb`$|?q0Ob"cV9BJo1HEs\02)[idI7QZB1~'3uG`?$ "RCD8jEUOw8. 2qkpڕ̰ +Uyqfӿ˸z5U ql[^CeܣN+ȁ\x/=O?`,\ҰkabDcVHu <>R G}C#]Q+ Ì 0p<=8s/3OvpAd]ѫ r=X5R@9 _^wNkѿgWns䩦n2I.g-yA@cW=}؏ţ֙,ꖋ}b-7T% U3fC| ?5[֣(Ԩ9>qͻ֓njSkM`D Jӫn(*sTgWp,^&6I c7$a5Mیb$FJsh R[f@`:vez(9Eͽc_ivaVP7I#ߠ"t%fESTzGЋ̂NErt9IFS ^t욆H4̣Gw.%N[jAjRFrPJ[x L6$P&m !5"ev: Rٵ"瑼Y.8 1:ͦG|"֊iJFHqޘpxNJI2uȂwZ.0>6^":}oLn5L6e2X pΝYk>7Ĭ8F[CF 4Gf{KT%[|绊㉘ fHB閱\4rحjoJ | f\ =/8?vō֒Ȅ!s<_CZ#R)['>'rRR(7?azcp74IVGTPh+`ϻ/{ŅQjS1(o*q<>w})qɷ޿=+Sn$,!ȅ:# 9"JҥsJw# dq @"5N$Z "J)mrH5k0KFNp_pC1R} JRh#pd^-RmFnnaKJ/[ݭ+.BRSD(APBJWÌ P#̹ (Wryo5{PGJq"taF.ZE2Ρ< !'紆 nF "P.+o6%+f#Жl uY;=hw{ᑗ0\3t1rܒeD /C;##ɘak9k/3 ϽPjIt.7)ɣp 9-Z&|/wQG^ O3/7͡',7q;qpvu9G6?J\`,(w`b! ֏puBJ5BJs8Xʏ3kH#<yox?#kJg.gy:qأdb7z%MخiiNUdtkgui-5.7.12/src/util/icons/deepin-theme-plugin-icons.qrc000066400000000000000000000123541476226661100234540ustar00rootroot00000000000000 texts/caps_lock_16px.svg texts/password_hide_24px.svg texts/password_show_24px.svg texts/edit_12px.svg icons/button_voice_active_30px.svg icons/button_voice_active_press_30px.svg icons/icon_fail_128px.svg icons/icon_success_128px.svg icons/icon_ok_32px.svg icons/icon_info_32px.svg icons/icon_warning_32px.svg texts/button_add_20px.svg texts/button_reduce_12px.svg texts/combobox_arrow_12px.svg texts/audio-volume-left_24px.svg texts/audio-volume-low_24px.svg texts/audio-volume-medium_24px.svg texts/audio-volume-muted_24px.svg texts/audio-volume-right_24px.svg texts/go-down_12px.svg texts/go-next_12px.svg texts/go-previous_12px.svg texts/go-up_12px.svg texts/media-playback-pause_24px.svg texts/media-playback-start_24px.svg texts/media-skip-backward_24px.svg texts/media-skip-forward_24px.svg texts/mark_indicator_12px.svg texts/fork_indicator_24px.svg texts/lock_indicator_24px.svg texts/selected_indicator_16px.svg texts/selected_checked_indicator_16px.svg texts/selected_indicator_16px.svg.background texts/unlock_indicator_24px.svg texts/unselected_indicator_16px.svg texts/window-close_round_30px.svg texts/unchecked_20px.svg texts/checked_20px.svg texts/next_indicator_24px.svg texts/prev_indicator_24px.svg actions/edit-select-all_16px.svg actions/edit-copy_16px.svg actions/edit-cut_16px.svg actions/edit-delete_16px.svg actions/edit-paste_16px.svg actions/edit-redo_16px.svg actions/edit-undo_16px.svg icons/light/edit-clear_30px.svg icons/light/edit-clear_active_30px.svg icons/light/edit-clear_press_30px.svg icons/light/button_voice_30px.svg icons/light/button_voice_press_30px.svg icons/light/list_delete_16px.svg icons/light/list_add_16px.svg icons/light/window-close_round_30px.svg icons/light/window-close_round_press_30px.svg icons/light/search_indicator_20px.svg icons/dark/edit-clear_30px.svg icons/dark/edit-clear_active_30px.svg icons/dark/edit-clear_press_30px.svg icons/dark/button_voice_30px.svg icons/dark/button_voice_press_30px.svg icons/dark/list_delete_16px.svg icons/dark/list_add_16px.svg icons/dark/window-close_round_30px.svg icons/dark/window-close_round_press_30px.svg icons/dark/search_indicator_20px.svg dci/sp_ok.dci dci/sp_alert.dci dci/sp_waiting.dci dci/sp_warning.dci dtkgui-5.7.12/src/util/icons/icons/000077500000000000000000000000001476226661100171025ustar00rootroot00000000000000dtkgui-5.7.12/src/util/icons/icons/button_voice_active_30px.svg000066400000000000000000000033151476226661100245320ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/button_voice_active_press_30px.svg000066400000000000000000000033531476226661100257500ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/000077500000000000000000000000001476226661100200235ustar00rootroot00000000000000dtkgui-5.7.12/src/util/icons/icons/dark/button_voice_30px.svg000066400000000000000000000041601476226661100241170ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/button_voice_press_30px.svg000066400000000000000000000042321476226661100253330ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/edit-clear_30px.svg000066400000000000000000000042261476226661100234330ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/edit-clear_active_30px.svg000066400000000000000000000043001476226661100247570ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/edit-clear_press_30px.svg000066400000000000000000000043001476226661100246400ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/list_add_16px.svg000066400000000000000000000005671476226661100232150ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/list_delete_16px.svg000066400000000000000000000003621476226661100237200ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/search_indicator_20px.svg000066400000000000000000000022001476226661100247100ustar00rootroot00000000000000 画板 dtkgui-5.7.12/src/util/icons/icons/dark/window-close_round_30px.svg000066400000000000000000000042261476226661100252430ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dark/window-close_round_press_30px.svg000066400000000000000000000043001476226661100264500ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dialog-right_30px.svg000066400000000000000000000021511476226661100230460ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/dialog-warning_30px.svg000066400000000000000000000024341476226661100234020ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/icon_fail_128px.svg000066400000000000000000000035001476226661100225060ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/icon_info_32px.svg000066400000000000000000000034421476226661100224450ustar00rootroot00000000000000 info dtkgui-5.7.12/src/util/icons/icons/icon_ok_32px.svg000066400000000000000000000031271476226661100221230ustar00rootroot00000000000000 ok dtkgui-5.7.12/src/util/icons/icons/icon_success_128px.svg000066400000000000000000000032641476226661100232520ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/icon_warning_32px.svg000066400000000000000000000033401476226661100231540ustar00rootroot00000000000000 warning dtkgui-5.7.12/src/util/icons/icons/light/000077500000000000000000000000001476226661100202115ustar00rootroot00000000000000dtkgui-5.7.12/src/util/icons/icons/light/button_voice_30px.svg000066400000000000000000000035761476226661100243170ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/light/button_voice_press_30px.svg000066400000000000000000000040521476226661100255210ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/light/edit-clear_30px.svg000066400000000000000000000036441476226661100236240ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/light/edit-clear_active_30px.svg000066400000000000000000000056411476226661100251560ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/light/edit-clear_press_30px.svg000066400000000000000000000056411476226661100250370ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/light/list_add_16px.svg000066400000000000000000000006551476226661100234010ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/light/list_delete_16px.svg000066400000000000000000000003621476226661100241060ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/light/search_indicator_20px.svg000066400000000000000000000021771476226661100251130ustar00rootroot00000000000000 画板 dtkgui-5.7.12/src/util/icons/icons/light/window-close_round_30px.svg000066400000000000000000000036441476226661100254340ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/icons/light/window-close_round_press_30px.svg000066400000000000000000000056411476226661100266470ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/000077500000000000000000000000001476226661100171365ustar00rootroot00000000000000dtkgui-5.7.12/src/util/icons/texts/audio-volume-left_24px.svg000066400000000000000000000014141476226661100240720ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/audio-volume-low_24px.svg000066400000000000000000000011521476226661100237400ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/audio-volume-medium_24px.svg000066400000000000000000000021401476226661100244150ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/audio-volume-muted_24px.svg000066400000000000000000000021161476226661100242560ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/audio-volume-right_24px.svg000066400000000000000000000022441476226661100242570ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/button_add_20px.svg000066400000000000000000000004051476226661100226520ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/button_reduce_12px.svg000066400000000000000000000003011476226661100233650ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/caps_lock_16px.svg000066400000000000000000000007061476226661100224760ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/checked_20px.svg000066400000000000000000000032101476226661100221120ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/combobox_arrow_12px.svg000066400000000000000000000002721476226661100235540ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/edit_12px.svg000066400000000000000000000010171476226661100214550ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/fork_indicator_24px.svg000066400000000000000000000005721476226661100235350ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/go-down_12px.svg000066400000000000000000000003371476226661100221060ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/go-next_12px.svg000066400000000000000000000002721476226661100221130ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/go-previous_12px.svg000066400000000000000000000002631476226661100230110ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/go-up_12px.svg000066400000000000000000000003261476226661100215610ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/lock_indicator_24px.svg000066400000000000000000000017351476226661100235260ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/mark_indicator_12px.svg000066400000000000000000000003301476226661100235130ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/media-playback-pause_24px.svg000066400000000000000000000004631476226661100245150ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/media-playback-start_24px.svg000066400000000000000000000005531476226661100245350ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/media-skip-backward_24px.svg000066400000000000000000000015551476226661100243410ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/media-skip-forward_24px.svg000066400000000000000000000015131476226661100242210ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/next_indicator_24px.svg000066400000000000000000000004741476226661100235530ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/password_hide_24px.svg000066400000000000000000000024271476226661100233740ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/password_show_24px.svg000066400000000000000000000014301476226661100234340ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/prev_indicator_24px.svg000066400000000000000000000005511476226661100235450ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/selected_checked_indicator_16px.svg000066400000000000000000000013071476226661100260300ustar00rootroot00000000000000 selected_foreground dtkgui-5.7.12/src/util/icons/texts/selected_indicator_16px.svg000066400000000000000000000013071476226661100243620ustar00rootroot00000000000000 selected_foreground dtkgui-5.7.12/src/util/icons/texts/selected_indicator_16px.svg.background000066400000000000000000000010241476226661100264740ustar00rootroot00000000000000 selected_background dtkgui-5.7.12/src/util/icons/texts/unchecked_20px.svg000066400000000000000000000013241476226661100224610ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/unlock_indicator_24px.svg000066400000000000000000000020201476226661100240550ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/unselected_indicator_16px.svg000066400000000000000000000007301476226661100247240ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/icons/texts/window-close_round_30px.svg000066400000000000000000000010251476226661100243500ustar00rootroot00000000000000 dtkgui-5.7.12/src/util/private/000077500000000000000000000000001476226661100163265ustar00rootroot00000000000000dtkgui-5.7.12/src/util/private/dbuiltiniconengine.cpp000066400000000000000000000346771476226661100227240ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dbuiltiniconengine_p.h" #include #include #include #include #include #include #include #include #include #include #define BUILTIN_ICON_PATH ":/icons/deepin/builtin" DGUI_BEGIN_NAMESPACE static qreal devicePixelRatio(QPainter *painter) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (qApp->testAttribute(Qt::AA_UseHighDpiPixmaps)) return (painter && painter->device()) ? painter->device()->devicePixelRatioF() : qApp->devicePixelRatio(); return 1.0; #else return (painter && painter->device()) ? painter->device()->devicePixelRatioF() : qApp->devicePixelRatio(); #endif } class Q_DECL_HIDDEN ImageEntry : public QIconLoaderEngineEntry { public: enum Type { TextType, // 完全跟随画笔前景色变化 ActionType, // 只在非normal状态下跟随画笔前景色 IconType // 任务状态都不跟随画笔颜色 }; ImageEntry(Type t) : type(t) { } QString pmcKey(const QSize &size, QIcon::Mode mode, QIcon::State state) { return QLatin1String("$qt_icon_") + filename + QLatin1String("_") + QString::number((((((qint64(size.width()) << 11) | size.height()) << 11) | mode) << 4) | state, 16); } void genIconTypeIcon(QPixmap &pm, QIcon::Mode mode) { if (type == IconType && qobject_cast(QCoreApplication::instance())) { const QPixmap generated = QGuiApplicationPrivate::instance()->applyQIconStyleHelper(mode, pm); if (!generated.isNull()) pm = generated; } } #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override { #else QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override { #endif Q_UNUSED(state) #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) const QSize pixmapSize = size * scale; #else const QSize pixmapSize(size); #endif QPixmap pm; QString pmckey(pmcKey(pixmapSize, mode, state)); if (QPixmapCache::find(pmckey, &pm)) { genIconTypeIcon(pm, mode); return pm; } // png 会读取前8个 bit 对比,需要关闭重新打开,否则同一个 icon 不同 state/mode 会再次读取时报错导致 pixmap 为空。 // 所以此处只对 DirImageEntry(isdir==true) 进行判断不再重新调用 setFileName if (Q_UNLIKELY(!reader.device()) || !QFileInfo(filename).isDir()) { reader.setFileName(filename); } if (dir.type == QIconDirInfo::Scalable) reader.setScaledSize(pixmapSize); pm = QPixmap::fromImageReader(&reader); if (!pm.isNull()) QPixmapCache::insert(pmckey, pm); genIconTypeIcon(pm, mode); return pm; } Type type; QImageReader reader; }; class Q_DECL_HIDDEN DirImageEntry : public ImageEntry { public: using ImageEntry::ImageEntry; static QString getIconFile(const QString &key, const QDir &dir, const QString &suffix) { if (dir.exists(key + "." + suffix)) { return dir.filePath(key + "." + suffix); } int _index = key.indexOf('_'); if (_index > 0) { const QString &mode = key.left(_index); if (dir.exists(mode + "." + suffix)) { return dir.filePath(mode + "." + suffix); } const QString &state = key.mid(_index); if (dir.exists("normal" + state + "." + suffix)) { return dir.filePath("normal" + state + "." + suffix); } } return dir.filePath("normal." + suffix); } #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override { #else QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override { #endif if (iconFileMap.isEmpty()) { const QString &suffix = QFileInfo(filename).suffix(); QDir dir(filename); iconFileMap[QIcon::Disabled << 8 | QIcon::On] = getIconFile("disabled_on", dir, suffix); iconFileMap[QIcon::Disabled << 8 | QIcon::Off] = getIconFile("disabled_off", dir, suffix); iconFileMap[QIcon::Active << 8 | QIcon::On] = getIconFile("active_on", dir, suffix); iconFileMap[QIcon::Active << 8 | QIcon::Off] = getIconFile("active_off", dir, suffix); iconFileMap[QIcon::Selected << 8 | QIcon::On] = getIconFile("selected_on", dir, suffix); iconFileMap[QIcon::Selected << 8 | QIcon::Off] = getIconFile("selected_off", dir, suffix); iconFileMap[QIcon::Normal << 8 | QIcon::On] = getIconFile("normal_on", dir, suffix); iconFileMap[QIcon::Normal << 8 | QIcon::Off] = getIconFile("normal_off", dir, suffix); } reader.setFileName(iconFileMap.value(mode << 8 | state)); #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) return ImageEntry::pixmap(size, mode, state, scale); #else return ImageEntry::pixmap(size, mode, state); #endif } QMap iconFileMap; }; DBuiltinIconEngine::DBuiltinIconEngine(const QString &iconName) : m_iconName(iconName) , m_initialized(false) // 当主题名称中包含'/'时, '/'前面的部分即为指定的图标类型, 此时不需要再 // 跟随系统中的主题类型改变 , m_followSystemTheme(iconName.indexOf('/') < 0) { // 初始化图标类型 m_key = iconName.startsWith("dark/") ? DGuiApplicationHelper::DarkType : DGuiApplicationHelper::LightType; } DBuiltinIconEngine::DBuiltinIconEngine(const DBuiltinIconEngine &other) : QIconEngine(other) , m_iconName(other.m_iconName) , m_key(other.m_key) , m_initialized(other.m_initialized) , m_followSystemTheme(other.m_initialized) { } DBuiltinIconEngine::~DBuiltinIconEngine() { #if QT_VERSION <= QT_VERSION_CHECK(6, 2, 4) if (hasIcon()) qDeleteAll(m_info.entries); #endif } QSize DBuiltinIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) { Q_UNUSED(mode); Q_UNUSED(state); ensureLoaded(); QIconLoaderEngineEntry *entry = QIconLoaderEngine::entryForSize(m_info, size); if (entry) { const QIconDirInfo &dir = entry->dir; if (dir.type == QIconDirInfo::Scalable) { return size; } else { int result = qMin(dir.size, qMin(size.width(), size.height())); return QSize(result, result); } } return QSize(0, 0); } QPixmap DBuiltinIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) { ensureLoaded(); QIconLoaderEngineEntry *entry = QIconLoaderEngine::entryForSize(m_info, size); if (entry) #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) return entry->pixmap(size, mode, state, devicePixelRatio(nullptr)); #else return entry->pixmap(size, mode, state); #endif return QPixmap(); } void DBuiltinIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) { ensureLoaded(); const qreal scale = devicePixelRatio(painter); QSize pixmapSize = rect.size() * scale; QIconLoaderEngineEntry *entry = QIconLoaderEngine::entryForSize(m_info, pixmapSize); if (!entry) return; // 如果有 background 则绘制背景图先 QString bgFileName = entry->filename + QStringLiteral(".background"); if (QFile::exists(bgFileName)) { QIcon(bgFileName).paint(painter, rect, Qt::AlignCenter, mode, state); } #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) QPixmap pm = entry->pixmap(pixmapSize, mode, state, 1.0); #else QPixmap pm = entry->pixmap(pixmapSize, mode, state); #endif ImageEntry::Type type = static_cast(entry)->type; if (type == ImageEntry::TextType || (type == ImageEntry::ActionType && mode != QIcon::Normal)) { QPainter pa(&pm); pa.setCompositionMode(QPainter::CompositionMode_SourceIn); pa.fillRect(pm.rect(), painter->pen().brush()); } pm.setDevicePixelRatio(scale); painter->drawPixmap(rect, pm); } QString DBuiltinIconEngine::key() const { return QLatin1String("DBuiltinIconEngine"); } QIconEngine *DBuiltinIconEngine::clone() const { return new DBuiltinIconEngine(*this); } bool DBuiltinIconEngine::read(QDataStream &in) { // QDataStream不支持位数据, 此处先将内容转为正常类型 uint key = m_key; bool followSystemTheme = m_followSystemTheme; in >> m_iconName >> key >> followSystemTheme; m_key = key; m_followSystemTheme = followSystemTheme; return true; } bool DBuiltinIconEngine::write(QDataStream &out) const { out << m_iconName << m_key << m_followSystemTheme; return true; } QString DBuiltinIconEngine::iconName() #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) const #endif { return m_iconName; } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QList DBuiltinIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) { ensureLoaded(); QList sizes; const int N = m_info.entries.size(); sizes.reserve(N); // Gets all sizes from the DirectoryInfo entries for (int i = 0; i < N; ++i) { const auto& entry = m_info.entries.at(i); int size = entry->dir.size; sizes.append(QSize(size, size)); } return sizes; } #endif QThemeIconInfo DBuiltinIconEngine::loadIcon(const QString &iconName, uint key) { QThemeIconInfo info; info.iconName = iconName; QString theme_name = (key == DGuiApplicationHelper::DarkType ? "dark" : "light"); QStringList iconDirList { QString("%1/%2/texts").arg(BUILTIN_ICON_PATH, theme_name), QString("%1/%2/actions").arg(BUILTIN_ICON_PATH, theme_name), QString("%1/%2/icons").arg(BUILTIN_ICON_PATH, theme_name), QString("%1/texts").arg(BUILTIN_ICON_PATH), QString("%1/actions").arg(BUILTIN_ICON_PATH), QString("%1/icons").arg(BUILTIN_ICON_PATH) }; QDir dir; dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); for (int i = 0; i < iconDirList.count(); ++i) { dir.setPath(iconDirList.at(i)); if (!dir.exists()) { continue; } ImageEntry::Type type = static_cast(i % 3); for (const QFileInfo &icon_file_info : dir.entryInfoList()) { const QString &file_name = icon_file_info.fileName(); // do not load background file if (!file_name.startsWith(iconName) || file_name.endsWith(QStringLiteral(".background"))) continue; // 先找到px所在位置 int size_str_pos = iconName.length() + 1; int px_str_pos = file_name.indexOf("px.", size_str_pos + 1); if (px_str_pos < 0) continue; bool ok = false; int size = file_name.mid(size_str_pos, px_str_pos - size_str_pos).toInt(&ok); if (Q_UNLIKELY(!ok || size <= 0)) { continue; } ImageEntry *entry = icon_file_info.isDir() ? new DirImageEntry(type) : new ImageEntry(type); entry->filename = icon_file_info.absoluteFilePath(); entry->dir.path = icon_file_info.absolutePath(); entry->dir.size = size; entry->dir.type = icon_file_info.suffix().startsWith("svg") ? QIconDirInfo::Scalable : QIconDirInfo::Fixed; #if QT_VERSION <= QT_VERSION_CHECK(6, 2, 4) info.entries.append(entry); #else info.entries.push_back(std::unique_ptr(entry)); #endif } // 已经找到图标时不再继续 if (info.entries.size() > 0) { break; } } return info; } bool DBuiltinIconEngine::hasIcon() const { return m_info.entries.size() > 0; } void DBuiltinIconEngine::virtual_hook(int id, void *data) { ensureLoaded(); switch (id) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) case QIconEngine::AvailableSizesHook: { QIconEngine::AvailableSizesArgument &arg = *reinterpret_cast(data); const int N = m_info.entries.size(); QList sizes; sizes.reserve(N); // Gets all sizes from the DirectoryInfo entries for (int i = 0; i < N; ++i) { const QIconLoaderEngineEntry *entry = m_info.entries.at(i); int size = entry->dir.size; sizes.append(QSize(size, size)); } arg.sizes.swap(sizes); // commit } break; case QIconEngine::IconNameHook: { QString &name = *reinterpret_cast(data); name = m_info.iconName; } break; #endif case QIconEngine::IsNullHook: { *reinterpret_cast(data) = !hasIcon(); } break; case QIconEngine::ScaledPixmapHook: { QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast(data); // QIcon::pixmap() multiplies size by the device pixel ratio. const int integerScale = qCeil(arg.scale); QIconLoaderEngineEntry *entry = QIconLoaderEngine::entryForSize(m_info, arg.size / integerScale, integerScale); #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state, arg.scale) : QPixmap(); #else arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state) : QPixmap(); #endif } break; default: QIconEngine::virtual_hook(id, data); } } void DBuiltinIconEngine::ensureLoaded() { if (Q_LIKELY(m_followSystemTheme) && Q_UNLIKELY(DGuiApplicationHelper::instance()->themeType() != m_key)) { m_initialized = false; // 记录当前使用的主题类型 m_key = DGuiApplicationHelper::instance()->themeType(); } if (Q_LIKELY(m_initialized)) { return; } // 标记为已初始化 m_initialized = true; #if QT_VERSION <= QT_VERSION_CHECK(6, 2, 4) qDeleteAll(m_info.entries); #endif m_info.entries.clear(); m_info.iconName.clear(); Q_ASSERT(m_info.entries.size() == 0); m_info = loadIcon(m_iconName, m_key); } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/private/dbuiltiniconengine_p.h000066400000000000000000000035411476226661100226720ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DBUILTINICONENGINE_H #define DBUILTINICONENGINE_H #include #include #include DGUI_BEGIN_NAMESPACE // 内置的主题引擎,会从Qt资源文件中查找图标 class DBuiltinIconEnginePrivate; class Q_DECL_HIDDEN DBuiltinIconEngine : public QIconEngine { public: explicit DBuiltinIconEngine(const QString &iconName); ~DBuiltinIconEngine() override; void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QString key() const override; QIconEngine *clone() const override; bool read(QDataStream &in) override; bool write(QDataStream &out) const override; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QString iconName() override; QList availableSizes(QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off) override; #else QString iconName() const override; #endif static QThemeIconInfo loadIcon(const QString &iconName, uint key); private: bool hasIcon() const; void ensureLoaded(); void virtual_hook(int id, void *data) override; DBuiltinIconEngine(const DBuiltinIconEngine &other); QThemeIconInfo m_info; QString m_iconName; // 图标的类型(Dark/Light) uint m_key:2; // 记录是否已经初始化 bool m_initialized:1; // 控制是否跟随系统级别的主题色来改变图标类型 bool m_followSystemTheme:1; friend class QIconLoader; }; DGUI_END_NAMESPACE #endif // DBUILTINICONENGINE_H dtkgui-5.7.12/src/util/private/dciiconengine.cpp000066400000000000000000000145151476226661100216360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dciiconengine_p.h" #include "dguiapplicationhelper.h" #include "dplatformtheme.h" #include #include #include #include DGUI_BEGIN_NAMESPACE static inline DDciIcon::Theme dciTheme() { auto theme = DGuiApplicationHelper::instance()->themeType(); return theme == DGuiApplicationHelper::DarkType ? DDciIcon::Dark : DDciIcon::Light; } static inline DDciIcon::Mode dciMode(QIcon::Mode mode) { // QIcon only support DDciIcon::Disabled and DDciIcon::Normal return mode == QIcon::Disabled ? DDciIcon::Disabled : DDciIcon::Normal; } static inline DDciIconPalette dciPalettle(QPaintDevice *paintDevice = nullptr) { QPalette pa; if (!paintDevice || paintDevice->devType() != QInternal::Widget) { pa = qApp->palette(); } else if (QObject *obj = dynamic_cast(paintDevice)) { pa = qvariant_cast(obj->property("palette")); } else { pa = qApp->palette(); } return DDciIconPalette(pa.windowText().color(), pa.window().color(), pa.highlight().color(), pa.highlightedText().color()); } static inline qreal deviceRadio(QPaintDevice *paintDevice = nullptr) { qreal scale = 1.0; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (qApp->testAttribute(Qt::AA_UseHighDpiPixmaps)) scale = paintDevice ? paintDevice->devicePixelRatioF() : qApp->devicePixelRatio(); #else scale = paintDevice ? paintDevice->devicePixelRatioF() : qApp->devicePixelRatio(); #endif return scale; } DDciIconEngine::DDciIconEngine(const QString &iconName) : m_iconName(iconName) , m_iconThemeName(DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName()) , m_dciIcon(DDciIcon::fromTheme(iconName)) { } DDciIconEngine::DDciIconEngine(const DDciIconEngine &other) : QIconEngine(other) , m_iconName(other.m_iconName) , m_iconThemeName(other.m_iconThemeName) , m_dciIcon(other.m_dciIcon) { } DDciIconEngine::~DDciIconEngine() { } QSize DDciIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) { Q_UNUSED(state); ensureIconTheme(); int s = m_dciIcon.actualSize(qMin(size.width(), size.height()), dciTheme(), dciMode(mode)); return QSize(s, s).boundedTo(size); } QPixmap DDciIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) { // QIcon::pixmap has already been multiplied by the screen scaling factor // so there is no need to do it again here. set radio 1.0 . return pixmap(size, mode, state, 1.0); } QPixmap DDciIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal radio) { Q_UNUSED(state); const int s = qMin(size.width(), size.height()); const DDciIcon::Theme theme = dciTheme(); const DDciIconPalette pa = dciPalettle(); QString key = QLatin1String("dci_") + m_iconName + m_iconThemeName + DDciIconPalette::convertToString(pa) % HexString(mode) % HexString(theme) % HexString(s) % HexString(uint(radio * 100)); QPixmap pix; if (QPixmapCache::find(key, &pix)) return pix; ensureIconTheme(); pix = m_dciIcon.pixmap(radio, s, theme, dciMode(mode), pa); if (!pix.isNull()) QPixmapCache::insert(key, pix); return pix; } void DDciIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) { Q_UNUSED(state); ensureIconTheme(); m_dciIcon.paint(painter, rect, deviceRadio(painter->device()), dciTheme(), dciMode(mode), Qt::AlignCenter, dciPalettle(painter->device())); } QString DDciIconEngine::key() const { return QLatin1String("DDciIconEngine"); } QIconEngine *DDciIconEngine::clone() const { return new DDciIconEngine(*this); } bool DDciIconEngine::read(QDataStream &in) { ensureIconTheme(); in >> m_iconThemeName >> m_iconName >> m_dciIcon; return true; } bool DDciIconEngine::write(QDataStream &out) const { const_cast(this)->ensureIconTheme(); out << m_iconThemeName << m_iconName << m_dciIcon; return true; } QString DDciIconEngine::iconName() #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) const #endif { return m_iconName; } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QList DDciIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) { ensureIconTheme(); const auto availableSizes = m_dciIcon.availableSizes(dciTheme(), DDciIcon::Normal); QList sizes; sizes.reserve(availableSizes.size()); for (int size : availableSizes) sizes.append(QSize(size, size)); return sizes; } #endif void DDciIconEngine::virtual_hook(int id, void *data) { ensureIconTheme(); switch (id) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) case QIconEngine::AvailableSizesHook: { auto &arg = *reinterpret_cast(data); auto availableSizes = m_dciIcon.availableSizes(dciTheme(), DDciIcon::Normal); QList sizes; sizes.reserve(availableSizes.size()); for (int size : availableSizes) sizes.append(QSize(size, size)); arg.sizes.swap(sizes); // commit } break; case QIconEngine::IconNameHook: { QString &name = *reinterpret_cast(data); name = iconName(); } break; #endif case QIconEngine::IsNullHook: { *reinterpret_cast(data) = m_dciIcon.isNull(); } break; case QIconEngine::ScaledPixmapHook: { QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast(data); arg.pixmap = pixmap(arg.size, arg.mode, arg.state); } break; default: QIconEngine::virtual_hook(id, data); } } void DDciIconEngine::ensureIconTheme() { QString iconThemeName = DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName(); if (m_iconThemeName != iconThemeName) { m_iconThemeName = iconThemeName; // update dci icon when icon theme name changed. m_dciIcon = DDciIcon::fromTheme(m_iconName); } } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/private/dciiconengine_p.h000066400000000000000000000027021476226661100216150ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DDCIICONENGINE_H #define DDCIICONENGINE_H #include #include "ddciicon.h" #include DGUI_BEGIN_NAMESPACE class Q_DECL_HIDDEN DDciIconEngine : public QIconEngine { public: explicit DDciIconEngine(const QString &iconName); virtual ~DDciIconEngine() override; void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal radio); QString key() const override; QIconEngine *clone() const override; bool read(QDataStream &in) override; bool write(QDataStream &out) const override; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QString iconName() override; QList availableSizes(QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off) override; #else QString iconName() const override; #endif private: void virtual_hook(int id, void *data) override; void ensureIconTheme(); DDciIconEngine(const DDciIconEngine &other); QString m_iconName; QString m_iconThemeName; DDciIcon m_dciIcon; }; DGUI_END_NAMESPACE #endif // DDCIICONENGINE_H dtkgui-5.7.12/src/util/private/diconproxyengine.cpp000066400000000000000000000166361476226661100224320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "diconproxyengine_p.h" #include "dciiconengine_p.h" #include "dbuiltiniconengine_p.h" #include "xdgiconproxyengine_p.h" #include #include #include #include #include #include #include #include #include #if (XDG_ICON_VERSION_MAR >= 3) #define private public #include #undef private #endif #include #include DGUI_BEGIN_NAMESPACE static inline QString iconThemeName() { return DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName(); } static inline QIconEngine *createBuiltinIconEngine(const QString &iconName) { QIconEngine *iconEngine = new DBuiltinIconEngine(iconName); if (iconEngine->isNull()) { delete iconEngine; return nullptr; } return iconEngine; } static inline QIconEngine *createDciIconEngine(const QString &iconName) { QIconEngine *iconEngine = new DDciIconEngine(iconName); if (iconEngine->isNull()) { delete iconEngine; return nullptr; } return iconEngine; } #ifndef DTK_DISABLE_LIBXDG static inline QIconEngine *createXdgProxyIconEngine(const QString &iconName) { QIconEngine *iconEngine = new XdgIconProxyEngine(new XdgIconLoaderEngine(iconName)); if (iconEngine->isNull()) { delete iconEngine; return nullptr; } return iconEngine; } #endif static inline QIconEngine *createDBuiltinIconEngine(const QString &iconName) { static QSet non_builtin_icon_cache; if (!non_builtin_icon_cache.contains(iconName)) { // 记录下来此种类型的icon为内置图标 // 因此,此处添加的缓存不考虑更新 // 优先使用内置图标 if (QIconEngine *engine = createBuiltinIconEngine(iconName)) { if (engine->isNull()) { delete engine; return nullptr; } return engine; } else { non_builtin_icon_cache.insert(iconName); } } return nullptr; } static bool hasDciIcon(const QString &iconName, const QString &iconThemeName) { QString iconPath; if (auto cached = DIconTheme::cached()) { iconPath = cached->findDciIconFile(iconName, iconThemeName); } else { iconPath = DIconTheme::findDciIconFile(iconName, iconThemeName); } return !iconPath.isEmpty(); } static inline bool isDciIconEngine(QIconEngine *engine) { return dynamic_cast(engine); } DIconProxyEngine::DIconProxyEngine(const QString &iconName, DIconTheme::Options options) : m_iconName(iconName) , m_option(options) { ensureEngine(); } DIconProxyEngine::DIconProxyEngine(const DIconProxyEngine &other) : QIconEngine(other) , m_iconName(other.m_iconName) , m_iconThemeName(other.m_iconThemeName) , m_iconEngine(other.m_iconEngine->clone()) { ensureEngine(); } DIconProxyEngine::~DIconProxyEngine() { if (m_iconEngine) delete m_iconEngine; } QSize DIconProxyEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) { ensureEngine(); return m_iconEngine ? m_iconEngine->actualSize(size, mode, state) :QSize(); } QPixmap DIconProxyEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) { ensureEngine(); return m_iconEngine ? m_iconEngine->pixmap(size, mode, state) : QPixmap(); } void DIconProxyEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) { ensureEngine(); if (m_iconEngine) m_iconEngine->paint(painter, rect, mode, state); } QString DIconProxyEngine::key() const { return QLatin1String("DIconProxyEngine"); } QIconEngine *DIconProxyEngine::clone() const { return new DIconProxyEngine(*this); } bool DIconProxyEngine::read(QDataStream &in) { in >> m_iconName >> m_iconThemeName; ensureEngine(); return m_iconEngine ? m_iconEngine->read(in) : false; } bool DIconProxyEngine::write(QDataStream &out) const { out << m_iconName << m_iconThemeName; return m_iconEngine ? m_iconEngine->write(out) : false; } QString DIconProxyEngine::iconName() #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) const #endif { return m_iconEngine ? m_iconEngine->iconName() : QString(); } QList DIconProxyEngine::availableSizes(QIcon::Mode mode, QIcon::State state) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) const #endif { return m_iconEngine ? m_iconEngine->availableSizes(mode, state) : QIconEngine::availableSizes(mode, state); } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) bool DIconProxyEngine::isNull() { return m_iconEngine ? m_iconEngine->isNull() : QIconEngine::isNull(); } #endif QString DIconProxyEngine::proxyKey() { ensureEngine(); return m_iconEngine ? m_iconEngine->key() : QString(); } void DIconProxyEngine::virtual_hook(int id, void *data) { ensureEngine(); if (m_iconEngine) { m_iconEngine->virtual_hook(id, data); return; } switch (id) { case QIconEngine::IsNullHook: { *reinterpret_cast(data) = true; } break; default: QIconEngine::virtual_hook(id, data); } } void DIconProxyEngine::ensureEngine() { if (m_iconName.isEmpty()) return; const QString &theme = iconThemeName(); if (theme == m_iconThemeName && m_iconEngine) return; static QMap> nonCache; if (Q_UNLIKELY(!m_option.testFlag(DIconTheme::IgnoreIconCache))) { const auto it = nonCache.find(theme); if (it != nonCache.end() && it->contains(m_iconName)) return; } if (m_iconEngine) { // dci => dci // xdg => xdg if (!(hasDciIcon(m_iconName, theme) ^ isDciIconEngine(m_iconEngine))) { m_iconThemeName = theme; return; } // delete old engine and create a new engine delete m_iconEngine; m_iconEngine = nullptr; } // null => dci // null => xdg // dci => xdg // xdg => dci // 1. try create dci iconengine // 2. try create builtin iconengine // 3. create xdgiconproxyengine if (!m_iconEngine && Q_UNLIKELY(!m_option.testFlag(DIconTheme::IgnoreDciIcons))) { m_iconEngine = createDciIconEngine(m_iconName); } if (!m_iconEngine && Q_UNLIKELY(!m_option.testFlag(DIconTheme::IgnoreBuiltinIcons)) ) { m_iconEngine = createDBuiltinIconEngine(m_iconName); } #ifdef DTK_DISABLE_LIBXDG if (!m_iconEngine) { QPlatformTheme * const platformTheme = QGuiApplicationPrivate::platformTheme(); if (platformTheme) { m_iconEngine = platformTheme->QPlatformTheme::createIconEngine(m_iconName); } else { qWarning() << "PlatformTheme not found!"; } } #else if (!m_iconEngine ) { m_iconEngine = createXdgProxyIconEngine(m_iconName); } #endif if (!m_iconEngine && !nonCache[theme].contains(m_iconName)) { qWarning("create icon [%s] engine failed.[theme:%s] nonCache[theme].size[%d]", m_iconName.toUtf8().data(), theme.toUtf8().data(), nonCache[theme].size()); nonCache[theme].insert(m_iconName); return; } m_iconThemeName = theme; } DGUI_END_NAMESPACE dtkgui-5.7.12/src/util/private/diconproxyengine_p.h000066400000000000000000000034301476226661100224020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DICONPROXYENGINE_H #define DICONPROXYENGINE_H #include #include #include "dicontheme.h" DGUI_BEGIN_NAMESPACE class Q_DECL_HIDDEN DIconProxyEngine : public QIconEngine { public: explicit DIconProxyEngine(const QString &iconName, DIconTheme::Options m_option); virtual ~DIconProxyEngine() override; void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QString key() const override; QIconEngine *clone() const override; bool read(QDataStream &in) override; bool write(QDataStream &out) const override; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QString iconName() override; #else QString iconName() const override; #endif #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QList availableSizes(QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off) override; #else QList availableSizes(QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off) const override; #endif #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) bool isNull() override; #endif inline QString themeName() const { return m_iconThemeName; } QString proxyKey(); private: void virtual_hook(int id, void *data) override; void ensureEngine(); DIconProxyEngine(const DIconProxyEngine &other); QString m_iconName; QString m_iconThemeName; QIconEngine *m_iconEngine = nullptr; DIconTheme::Options m_option; }; DGUI_END_NAMESPACE #endif // DICONPROXYENGINE_H dtkgui-5.7.12/src/util/private/dimagehandlerlibs_p.h000066400000000000000000000106301476226661100224540ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DIMAGEHANDLERLIBS_P_H #define DIMAGEHANDLERLIBS_P_H #ifndef DTK_DISABLE_EX_IMAGE_FORMAT #include #include #include #include #include class QLibrary; #endif enum ExifImageOrientation { Undefined, TopLeft, TopRight, BottomRight, BottomLeft, LeftTop, RightTop, RightBottom, LeftBottom, }; #ifndef DTK_DISABLE_EX_IMAGE_FORMAT class DLibFreeImage { public: DLibFreeImage(); ~DLibFreeImage(); bool isValid(); bool findMetaData(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, QHash &data); QHash findAllMetaData(const QString &fileName); FIBITMAP *readFileToFIBITMAP(const QString &fileName, int flags = 0, FREE_IMAGE_FORMAT fif = FIF_UNKNOWN); bool writeFIBITMAPToFile(FIBITMAP *dib, const QString &fileName, int flags = 0); QImage FIBITMAPToQImage(FIBITMAP *dib) const; ExifImageOrientation imageOrientation(const QString &fileName); bool rotateImageFile(const QString &fileName, int angle, QString &errorString); FIBITMAP *(*FreeImage_Load)(FREE_IMAGE_FORMAT fif, const char *filename, int flags); void (*FreeImage_Unload)(FIBITMAP *dib); bool (*FreeImage_Save)(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags); bool (*FreeImage_FIFSupportsReading)(FREE_IMAGE_FORMAT fif); FREE_IMAGE_FORMAT (*FreeImage_GetFileType)(const char *filename, int size); FREE_IMAGE_FORMAT (*FreeImage_GetFIFFromFilename)(const char *filename); FREE_IMAGE_TYPE (*FreeImage_GetImageType)(FIBITMAP *dib); unsigned (*FreeImage_GetBPP)(FIBITMAP *dib); unsigned (*FreeImage_GetWidth)(FIBITMAP *dib); unsigned (*FreeImage_GetHeight)(FIBITMAP *dib); unsigned (*FreeImage_GetRedMask)(FIBITMAP *dib); unsigned (*FreeImage_GetGreenMask)(FIBITMAP *dib); unsigned (*FreeImage_GetBlueMask)(FIBITMAP *dib); FIBITMAP *(*FreeImage_GetThumbnail)(FIBITMAP *dib); bool (*FreeImage_SetThumbnail)(FIBITMAP *dib, FIBITMAP *thumbnail); void (*FreeImage_ConvertToRawBits)(uint8_t *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, bool topdown); unsigned (*FreeImage_GetMetadataCount)(FREE_IMAGE_MDMODEL model, FIBITMAP *dib); FIMETADATA *(*FreeImage_FindFirstMetadata)(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag); bool (*FreeImage_FindNextMetadata)(FIMETADATA *mdhandle, FITAG **tag); void (*FreeImage_FindCloseMetadata)(FIMETADATA *mdhandle); const char *(*FreeImage_GetTagKey)(FITAG *tag); const void *(*FreeImage_GetTagValue)(FITAG *tag); const char *(*FreeImage_TagToString)(FREE_IMAGE_MDMODEL model, FITAG *tag, char *Make); FIBITMAP *(*FreeImage_Rotate)(FIBITMAP *dib, double angle, const void *bkcolor); private: QLibrary *freeImage = nullptr; QMutex apiMutex; Q_DISABLE_COPY(DLibFreeImage) }; class DLibRaw { public: DLibRaw(); ~DLibRaw(); bool isValid(); QImage loadImage(const QString &fileName, QString &errString, QSize requestSize = QSize()); QImage loadImage(QByteArray &data, QString &errString, QSize requestSize = QSize()); int readImage(libraw_data_t *rawData, QImage &image, QSize requestSize = QSize()); QString errorString(int errorCode); const char *(*libraw_strerror)(int errorcode); libraw_data_t *(*libraw_init)(unsigned int flags); int (*libraw_open_file)(libraw_data_t *, const char *); int (*libraw_open_buffer)(libraw_data_t *, void *buffer, size_t size); int (*libraw_unpack)(libraw_data_t *); int (*libraw_unpack_thumb)(libraw_data_t *); void (*libraw_close)(libraw_data_t *); int (*libraw_dcraw_process)(libraw_data_t *lr); libraw_processed_image_t *(*libraw_dcraw_make_mem_image)(libraw_data_t *lr, int *errc); libraw_processed_image_t *(*libraw_dcraw_make_mem_thumb)(libraw_data_t *lr, int *errc); void (*libraw_dcraw_clear_mem)(libraw_processed_image_t *); private: QLibrary *libraw = nullptr; Q_DISABLE_COPY(DLibRaw) }; #endif #endif // DIMAGEHANDLERLIBS_P_H dtkgui-5.7.12/src/util/private/xdgiconproxyengine.cpp000066400000000000000000000306221476226661100227600ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "xdgiconproxyengine_p.h" #include #include #include #include #include #include #include #include #include #include #if XDG_ICON_VERSION_MAR >= 3 #define private public #include #undef private static inline bool XdgIconFollowColorScheme() { return XdgIconLoader::instance()->followColorScheme(); } static inline QString rgba(const QColor &c) { // Hex-r-g-b-a return c.name(QColor::HexRgb).append(QString::number(c.alpha(), 16)); } static inline QPalette palette(QPaintDevice *paintDevice) { QPalette pa; if (QObject *obj = dynamic_cast(paintDevice)) { pa = qvariant_cast(obj->property("palette")); } else { pa = qApp->palette(); } return pa; } static inline QPixmap entryPixmap(ScalableEntry *color_entry, const QSize &size, QIcon::Mode mode, QIcon::State state) { if (!color_entry) return QPixmap(); // init svgIcon with svg absolute path // force to use svg iconengine if (color_entry->svgIcon.isNull()) color_entry->svgIcon = QIcon(color_entry->filename); if (auto d = color_entry->svgIcon.data_ptr()) if (d->engine) return d->engine->pixmap(size, mode, state); return color_entry->svgIcon.pixmap(size, mode, state); } static const QString STYLE = QStringLiteral(".ColorScheme-Text, .ColorScheme-NeutralText{color:%1;}\ \n.ColorScheme-Highlight{color:%2;}"); namespace DEEPIN_XDG_THEME { static QThreadStorage colorScheme; // } DGUI_BEGIN_NAMESPACE XdgIconProxyEngine::XdgIconProxyEngine(XdgIconLoaderEngine *proxy) : engine(proxy) , lastMode(QIcon::Normal) { } XdgIconProxyEngine::~XdgIconProxyEngine() { if (engine) delete engine; } quint64 XdgIconProxyEngine::entryCacheKey(const ScalableEntry *color_entry, const QIcon::Mode mode, const QIcon::State state) { return quint64(color_entry) ^ (quint64(mode) << 56) ^ (quint64(state) << 48); } QPixmap XdgIconProxyEngine::followColorPixmap(ScalableEntry *color_entry, const QSize &size, QIcon::Mode mode, QIcon::State state) { if (mode == QIcon::Selected && mode != lastMode) { // 由非选中状态切换至选中状态,如果颜色值不更新,会按照上一次的状态(非选中时的颜色值) // 从svg图标缓存中寻找异常图标,导致图标异常。 for (int each_mode = QIcon::Normal; each_mode <= QIcon::Selected; ++each_mode) { quint64 each_cache_key = entryCacheKey(color_entry, QIcon::Mode(each_mode), state); entryToColorScheme.remove(each_cache_key); } } lastMode = mode; quint64 cache_key = entryCacheKey(color_entry, mode, state); const DEEPIN_XDG_THEME::PALETTE_MAP &cache_color_scheme = entryToColorScheme.value(cache_key); // 当size为1时表示此svg文件不需要处理ColorScheme标签 if (!cache_color_scheme.isEmpty() && cache_color_scheme[DEEPIN_XDG_THEME::Text].size() == 1) return entryPixmap(color_entry, size, mode, state); const DEEPIN_XDG_THEME::PALETTE_MAP &color_scheme = DEEPIN_XDG_THEME::colorScheme.localData(); QPixmap pm = color_scheme == cache_color_scheme ? entryPixmap(color_entry, size, mode, state) : QPixmap(); // Note: not checking the QIcon::isNull(), because in Qt5.10 the isNull() is not reliable // for svg icons desierialized from stream (see https://codereview.qt-project.org/#/c/216086/) if (pm.isNull()) { // The following lines are adapted and updated from KDE's "kiconloader.cpp" -> // KIconLoaderPrivate::processSvg() and KIconLoaderPrivate::createIconImage(). // They read the SVG color scheme of SVG icons and give images based on the icon mode. QHash svg_buffers; bool invalidBuffers = true; QFile device {color_entry->filename}; if (device.open(QIODevice::ReadOnly)) { // Note: indexes are assembled as in qtsvg (QSvgIconEnginePrivate::hashKey()) QPair style_sheet; style_sheet = qMakePair((mode << 4) | state, STYLE.arg(color_scheme[DEEPIN_XDG_THEME::Text], color_scheme[DEEPIN_XDG_THEME::Highlight])); QSharedPointer writer(new QXmlStreamWriter {&svg_buffers[style_sheet.first]}); QXmlStreamReader xmlReader(&device); while (!xmlReader.atEnd()) { if (xmlReader.readNext() == QXmlStreamReader::StartElement && xmlReader.qualifiedName() == QLatin1String("style") && xmlReader.attributes().value(QLatin1String("id")) == QLatin1String("current-color-scheme")) { invalidBuffers = false; writer->writeStartElement(QLatin1String("style")); writer->writeAttributes(xmlReader.attributes()); writer->writeCharacters(style_sheet.second); writer->writeEndElement(); while (xmlReader.tokenType() != QXmlStreamReader::EndElement) xmlReader.readNext(); } else if (xmlReader.tokenType() != QXmlStreamReader::Invalid) { writer->writeCurrentToken(xmlReader); } } // duplicate the contents also for opposite state // svg_buffers[(QIcon::Normal<<4)|QIcon::On] = svg_buffers[(QIcon::Normal<<4)|QIcon::Off]; // svg_buffers[(QIcon::Selected<<4)|QIcon::On] = svg_buffers[(QIcon::Selected<<4)|QIcon::Off]; } if (invalidBuffers) { // 此svg图标无ColorScheme标签时不应该再下面的操作,且应该记录下来,避免后续再处理svg文件内容 entryToColorScheme[cache_key] = DEEPIN_XDG_THEME::PALETTE_MAP({ {DEEPIN_XDG_THEME::Text, "#"} }); return entryPixmap(color_entry, size, mode, state); } // use the QSvgIconEngine // - assemble the content as it is done by the operator <<(QDataStream &s, const QIcon &icon) // (the QSvgIconEngine::key() + QSvgIconEngine::write()) // - create the QIcon from the content by usage of the QIcon::operator >>(QDataStream &s, const QIcon &icon) // (icon with the (QSvgIconEngine) will be used) QByteArray icon_arr; QDataStream str {&icon_arr, QIODevice::WriteOnly}; str.setVersion(QDataStream::Qt_4_4); QHash filenames; filenames[0] = color_entry->filename; // Note: filenames are ignored in the QSvgIconEngine::read() filenames[-1] = color_scheme[DEEPIN_XDG_THEME::Text] + color_scheme[DEEPIN_XDG_THEME::Highlight]; // 在dsvg插件中会为svg图标做缓存,此处是为其添加额外的缓存文件key标识,避免不同color的svg图标会命中同一个缓存文件 str << QStringLiteral("svg") << filenames << static_cast(0) /*isCompressed*/ << svg_buffers << static_cast(0) /*hasAddedPimaps*/; QDataStream str_read {&icon_arr, QIODevice::ReadOnly}; str_read.setVersion(QDataStream::Qt_4_4); str_read >> color_entry->svgIcon; pm = entryPixmap(color_entry, size, mode, state); // load the icon directly from file, if still null if (pm.isNull()) { color_entry->svgIcon = QIcon(color_entry->filename); pm = entryPixmap(color_entry, size, mode, state); } entryToColorScheme[cache_key] = color_scheme; } return pm; } QPixmap XdgIconProxyEngine::pixmapByEntry(QIconLoaderEngineEntry *entry, const QSize &size, QIcon::Mode mode, QIcon::State state) { if (!XdgIconFollowColorScheme()) { DEEPIN_XDG_THEME::colorScheme.setLocalData(DEEPIN_XDG_THEME::PALETTE_MAP()); return entry->pixmap(size, mode, state); } QPixmap pixmap; char *type_name = abi::__cxa_demangle(typeid(*entry).name(), 0, 0, 0); if (type_name == QByteArrayLiteral("ScalableFollowsColorEntry")) { if (DEEPIN_XDG_THEME::colorScheme.localData().isEmpty()) { const QPalette &pal = palette(&pixmap); DEEPIN_XDG_THEME::colorScheme.setLocalData(DEEPIN_XDG_THEME::PALETTE_MAP({ { DEEPIN_XDG_THEME::Text, mode == QIcon::Selected ? rgba(pal.highlightedText().color()) : rgba(pal.windowText().color()) }, { DEEPIN_XDG_THEME::Highlight, rgba(pal.highlight().color()) } })); } pixmap = followColorPixmap(static_cast(entry), size, mode, state); } else { pixmap = entry->pixmap(size, mode, state); } free(type_name); DEEPIN_XDG_THEME::colorScheme.setLocalData(DEEPIN_XDG_THEME::PALETTE_MAP()); return pixmap; } void XdgIconProxyEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) { if (painter->device()->devType() == QInternal::Widget && XdgIconFollowColorScheme() && DEEPIN_XDG_THEME::colorScheme.localData().isEmpty()) { const QPalette &pal = palette(painter->device()); DEEPIN_XDG_THEME::colorScheme.setLocalData(DEEPIN_XDG_THEME::PALETTE_MAP({ { DEEPIN_XDG_THEME::Text, mode == QIcon::Selected ? rgba(pal.highlightedText().color()) : rgba(pal.windowText().color()) }, { DEEPIN_XDG_THEME::Highlight, rgba(pal.highlight().color()) } })); } qreal ratio = 1.0; if (qApp->testAttribute(Qt::AA_UseHighDpiPixmaps)) ratio = painter->device() ? painter->device()->devicePixelRatioF() : qApp->devicePixelRatio(); QPixmap pix = pixmap(rect.size() * ratio, mode, state); if (pix.isNull()) return; pix.setDevicePixelRatio(ratio); painter->drawPixmap(rect, pix); } QPixmap XdgIconProxyEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) { engine->ensureLoaded(); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QIconLoaderEngineEntry *entry = engine->entryForSize(size); #else QIconLoaderEngineEntry *entry = engine->entryForSize(engine->m_info ,size); #endif if (!entry) { DEEPIN_XDG_THEME::colorScheme.setLocalData(DEEPIN_XDG_THEME::PALETTE_MAP()); return QPixmap(); } return pixmapByEntry(entry, size, mode, state); } void XdgIconProxyEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) { return engine->addPixmap(pixmap, mode, state); } void XdgIconProxyEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) { return engine->addFile(fileName, size, mode, state); } QString XdgIconProxyEngine::key() const { return QLatin1String("XdgIconProxyEngine"); } QSize XdgIconProxyEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) { return engine->actualSize(size, mode, state); } QIconEngine *XdgIconProxyEngine::clone() const { return new XdgIconProxyEngine(static_cast(engine->clone())); } bool XdgIconProxyEngine::read(QDataStream &in) { return engine->read(in); } bool XdgIconProxyEngine::write(QDataStream &out) const { return engine->write(out); } void XdgIconProxyEngine::virtual_hook(int id, void *data) { #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) if (id == QIconEngine::ScaledPixmapHook) { engine->ensureLoaded(); QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast(data); // QIcon::pixmap() multiplies size by the device pixel ratio. const int integerScale = qCeil(arg.scale); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QIconLoaderEngineEntry *entry = engine->entryForSize(arg.size / integerScale, integerScale); #else QIconLoaderEngineEntry *entry = engine->entryForSize(engine->m_info, arg.size / integerScale, integerScale); #endif // 先禁用缩放,因为此size是已经缩放过的 bool useHighDpiPixmap = qGuiApp->testAttribute(Qt::AA_UseHighDpiPixmaps); qGuiApp->setAttribute(Qt::AA_UseHighDpiPixmaps, false); arg.pixmap = entry ? pixmapByEntry(entry, arg.size, arg.mode, arg.state) : QPixmap(); qGuiApp->setAttribute(Qt::AA_UseHighDpiPixmaps, useHighDpiPixmap); DEEPIN_XDG_THEME::colorScheme.setLocalData(DEEPIN_XDG_THEME::PALETTE_MAP()); return; } #endif return engine->virtual_hook(id, data); } DGUI_END_NAMESPACE #endif dtkgui-5.7.12/src/util/private/xdgiconproxyengine_p.h000066400000000000000000000036741476226661100227530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef XDGICONPROXYENGINE_H #define XDGICONPROXYENGINE_H #include #include #if XDG_ICON_VERSION_MAR >= 3 #include #endif namespace DEEPIN_XDG_THEME { enum PaletteType { Text, Background, Highlight, }; typedef QMap PALETTE_MAP; }; struct ScalableEntry; class QIconLoaderEngineEntry; class XdgIconLoaderEngine; DGUI_BEGIN_NAMESPACE #if (XDG_ICON_VERSION_MAR >= 3) class Q_DECL_HIDDEN XdgIconProxyEngine : public QIconEngine { public: XdgIconProxyEngine(XdgIconLoaderEngine *proxy); virtual ~XdgIconProxyEngine() override; static quint64 entryCacheKey(const ScalableEntry *color_entry, const QIcon::Mode mode, const QIcon::State state); QPixmap followColorPixmap(ScalableEntry *color_entry, const QSize &size, QIcon::Mode mode, QIcon::State state); QPixmap pixmapByEntry(QIconLoaderEngineEntry *entry, const QSize &size, QIcon::Mode mode, QIcon::State state); void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) override; void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) override; QString key() const override; QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QIconEngine *clone() const override; bool read(QDataStream &in) override; bool write(QDataStream &out) const override; void virtual_hook(int id, void *data) override; private: XdgIconLoaderEngine *engine; QHash entryToColorScheme; QIcon::Mode lastMode; }; #endif DGUI_END_NAMESPACE #endif // XDGICONPROXYENGINE_H dtkgui-5.7.12/src/util/util.cmake000066400000000000000000000037201476226661100166350ustar00rootroot00000000000000if(NOT DTK_DISABLE_LIBXDG) message("Enable libxdg!") find_package(qt${QT_VERSION_MAJOR}xdgiconloader) add_definitions(-DXDG_ICON_VERSION_MAR=${qt${QT_VERSION_MAJOR}xdgiconloader_VERSION_MAJOR}) set(UTIL_PRIVATE ${CMAKE_CURRENT_LIST_DIR}/private/xdgiconproxyengine_p.h ${CMAKE_CURRENT_LIST_DIR}/private/xdgiconproxyengine.cpp ${CMAKE_CURRENT_LIST_DIR}/private/dbuiltiniconengine_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dbuiltiniconengine.cpp ${CMAKE_CURRENT_LIST_DIR}/private/dimagehandlerlibs_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dciiconengine_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dciiconengine.cpp ${CMAKE_CURRENT_LIST_DIR}/private/diconproxyengine_p.h ${CMAKE_CURRENT_LIST_DIR}/private/diconproxyengine.cpp ) else() message("Disable libxdg!") add_definitions(-DDTK_DISABLE_LIBXDG) set(UTIL_PRIVATE ${CMAKE_CURRENT_LIST_DIR}/private/dbuiltiniconengine_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dbuiltiniconengine.cpp ${CMAKE_CURRENT_LIST_DIR}/private/dimagehandlerlibs_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dciiconengine_p.h ${CMAKE_CURRENT_LIST_DIR}/private/dciiconengine.cpp ${CMAKE_CURRENT_LIST_DIR}/private/diconproxyengine_p.h ${CMAKE_CURRENT_LIST_DIR}/private/diconproxyengine.cpp ) endif() if(DTK_DISABLE_EX_IMAGE_FORMAT OR NOT EX_IMAGE_FORMAT_LIBS_FOUND) add_definitions(-DDTK_DISABLE_EX_IMAGE_FORMAT) message("Disable extended image format!") else() message("Support extended image format!") endif() if(DTK_DISABLE_LIBRSVG) add_definitions(-DDTK_DISABLE_LIBRSVG) message("Disable librsvg!") else() message("Enable librsvg!") endif() file(GLOB UTIL_HEADER ${PROJECT_SOURCE_DIR}/include/util/*.h ) file(GLOB UTIL_SOURCE ${CMAKE_CURRENT_LIST_DIR}/*.cpp ) set(util_SRC ${UTIL_HEADER} ${UTIL_SOURCE} ${UTIL_PRIVATE} ${CMAKE_CURRENT_LIST_DIR}/icons/deepin-theme-plugin-icons.qrc ) dtkgui-5.7.12/tests/000077500000000000000000000000001476226661100142525ustar00rootroot00000000000000dtkgui-5.7.12/tests/CMakeLists.txt000066400000000000000000000034011476226661100170100ustar00rootroot00000000000000set(BIN_NAME ut-DtkGui) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Test) find_package(GTest REQUIRED) file(GLOB test_SRC res.qrc test.h main.cpp src/*.cpp ) if(DTK_DISABLE_LIBXDG) list(REMOVE_ITEM test_SRC "${CMAKE_CURRENT_LIST_DIR}/src/ut_xdgiconproxyengine.cpp") endif() set(test-plugin "minimal-plugin") add_subdirectory(platform-plugin-test) include(../src/util/util.cmake) add_executable(${BIN_NAME} ${test_SRC} ${UTIL_PRIVATE} ) add_dependencies(${BIN_NAME} ${test-plugin}) target_compile_options(${BIN_NAME} PRIVATE -fno-access-control -fsanitize=address) target_link_options(${BIN_NAME} PRIVATE -fsanitize=address) target_link_libraries(${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::GuiPrivate Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Test Dtk${DTK_VERSION_MAJOR}::Core PkgConfig::librsvg GTest::GTest ${LIB_NAME} gmock pthread m ) if(NOT DTK_DISABLE_EX_IMAGE_FORMAT AND EX_IMAGE_FORMAT_LIBS_FOUND) target_link_libraries(${BIN_NAME} PRIVATE PkgConfig::libraw FreeImage::FreeImage ) endif() if(NOT DTK_DISABLE_LIBXDG) target_link_libraries(${BIN_NAME} PRIVATE Qt${QT_VERSION_MAJOR}XdgIconLoader ) endif() target_include_directories(${BIN_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include/util ${PROJECT_SOURCE_DIR}/include/DtkGui ${PROJECT_SOURCE_DIR}/include/global ${PROJECT_SOURCE_DIR}/include/kernel ${PROJECT_SOURCE_DIR}/include/filedrag ${PROJECT_SOURCE_DIR}/src/private ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/src/dbus ${PROJECT_SOURCE_DIR}/src/util/private ) add_test(NAME ${BIN_NAME} COMMAND ${BIN_NAME}) dtkgui-5.7.12/tests/actions/000077500000000000000000000000001476226661100157125ustar00rootroot00000000000000dtkgui-5.7.12/tests/actions/icon_Layout_16px.svg000066400000000000000000000024241476226661100216000ustar00rootroot00000000000000 icon_Layout/normal dtkgui-5.7.12/tests/dcis/000077500000000000000000000000001476226661100151745ustar00rootroot00000000000000dtkgui-5.7.12/tests/dcis/selected_indicator.dci000066400000000000000000000220621476226661100215030ustar00rootroot00000000000000DCI16#hover.dark1k1.svg selected_background 2.3.svg selected_foreground hover.light1k1.svg selected_background 2.3.svg selected_foreground normal.dark1k1.svg selected_background 2.svg selected_foreground normal.light1k1.svg selected_background 2.svg selected_foreground pressed.dark1k1.3.svg selected_background 2.0_0_0_0_100_100_100_0.svg selected_foreground pressed.light1k1.3.svg selected_background 2.0_0_0_0_100_100_100_0.svg selected_foreground dtkgui-5.7.12/tests/images/000077500000000000000000000000001476226661100155175ustar00rootroot00000000000000dtkgui-5.7.12/tests/images/dci_heart_dci_hover.webp000066400000000000000000000753621476226661100223570ustar00rootroot00000000000000RIFFzWEBPVP8X ANIMANMFdwnCVP8LL/wGm#Q @=o"qB[!"RlQ"mv6vfm۶m۶m۶mn1i�=dߢbjp Xm8lW?bcO聹ijj<5wKL_*+* M/ذJ(&C7Q?V9~Sn({ .dVϟBq~GY c#4O?oW c. ؇q0M6 C-P;0JI)oq4>VSHQRfܢ` Av(yw+nY\]9Pt<ՓaBY 2XAd =.XrQ F5{aMHܢuUYSVuԨ܅ հW+úTCwW/,iaag*𿜏HX:G!T|o.^X;amW* 1zY,AV3vgTj c6p<*sqJ8I>:>!.#pa*SG 2x12pDi*P #5<> G_!/J%8 CQNZ8d-1oCR}p>2rש vӼp+ST#SՅ(8%#6S)x#c'p@S*їa8`ȕL}J>iy4*7y0*Je2l>JTfO%<'l'2芧PY [R TR*UҨlR*uJJm{S]@ ?a[e{A vrQƺRMuMT}`.-0ڰIDO3xhJCTշa: #9P.fB(tlN#) >QA=(|,+*QF;)W5u)ls#@ê) ma]wBz/X9X/ c( !)h`DJg2̧)M(] _4 DQX$JJ)MCi~V%US& p|‚|#>itD ؎|`rBrWeUnp/FX|RdءWJ `W== U@U %JqaU[yaAJ;<ұ̰{ ^)vf(* !%J`v~օR#Nc@9Ϛg{W#óP+3.P< u(}FI[솭{&`boؽ7^ /xnB8d@pNo׃ r?v(zSQxZ.^8+p8&gp- pP;)?mۆ)_ Gm66R(fK4eYJ|0(MRU0|a\00!::F?hk}S;?0,3m%Loq"oS5A4ANMF CVP8L/"mri DlwN۶m"y׶m۞Nq;iUzvDz O]~5 T nkm-{xC/C״lj<;SsS Cc( }( ETG@k PB0lhhQ:qо]~EfQR|(]*a] i)pUJNi:\I15JY J T C&>GiZax5bl:Ogl( aw ,6./`5i0~:URwPQ؞Ja4K!u%)0N QPXt'TPܐ70# E36cj@P;aP x `6 (G, Ga(t )DG `: $BF F>R8R60YNj2}BJJ! R1( Cߡtbg(D;q]J BR0pK)S((N!(IgPtaݣBKP[\U2<9+͠s/(u( $NP3!Ld5+Jrp7sZG }Ub?)[&*Մk5PnoLCT$p#YJT6Rq;\z*C<xeE98 R;kuyrt)4-L>h"2_DśIД*!TP Z_SQ0y !*3gRq$pT«RGKTa;~ /RS, Uo%۾]Tm[ Pu_"{lLEd%LGEx%soQd>!?D0!@ USwoĴ9KW`RTT=Öz2QY fSs?P?&RBsg()pu<`h;3A#)=HOƒ;lJlx$x7AC*<0P<l ;e΂[(\ vJ=wiJQ1/0lH~}7?(lB p2c0(\H!~?E(̤wt 9q0<.Bzk ` SxƿIafYM;NaJ `|# +R+QzB*Op,c Q8cq /NR{)$lP Ɨe 01oSQxkaT wu0ƿJO `! K\(0#(|G0 o'߃0PfD) [RG(,oS8{(KFQ5½0x&0JN4Jc`JQd7a# $:4 #Ӳ)Mҳ0J!Sϧt= ͔@lcS P[A^HT3ePTϡ {RN E)= e 2K^pv0CpTR`Hg(΃2S0x16Υt hC)?H a[yx#!s#n $ʣv[.uy7oF(O?VO+eR46sie9Ѿ a~OA|^Oy]')gO$A_LZ*Ag'ʑ{G>gg(lO7PGAT<Q*rB_*^z; !MŕA0/T.UT&U;K-Q.TY)먺2Ej[*L DbYC0p\>U[Quu̼1./ Sks`n XOth?eѿa~Of\Et\Gp͸=B|4~|({̂oANMF CVP8L/!G&m wOBD"wO¶$ضgwǶm۶mZ۶mm5]]ɟscpˁ,_pʰmE+NԢ<n)&VnPp5טi+Ǻ'#qP>jA ~{v%SJ\=v.v|_0Q^}Rq$lH9.GGց婔 [)oDZ[ô^ZQ~;):>ͻݡ#۔F;S"m]FIա @q=:E*A2EA5Fh,wq9PO9hr5 !C O_Szb|kŠW4.|BZMHQ(ΔކP!pc/-•aINA|َnQ K2F3BBdDl \*u)R) S+ Zpm,oD9^Up/&ȚFa ]Ca>PV2h Akb42QX cPh! Zao"h=@ K`"ZS(K/ K,R kSh!Fr<` 0: M5}XFi}eXA?0_Zc9Ga1ZcgayZc"aMZbX :(Te(tD% `p ULu KkZ ҏ2 >LdC"c0PhFa.C-2bh~Hk(25\J+dͤ.0Y#^ y U{ C`d #4 Df {$ ]a`o )`yŸ>˰֡4 WW(|-e0l=XFUL#䶔ޅI)J`JBD•|0&U 'G OioR!-#nєNNS;o))}{5R(D>*rJ7KRZ Q6G}O(nE)TR GR\'1SJ KW Ht<[p8qh(N('oQ|sOq<\PřLCK0`xnXR4-Jq)t^ jH:PB')ތgoR*3˨x;b_b5<4#BTkʑ4+@K)'cQj^:@9'wx@9+<p8!Dn xE*O㼰5*gMőYW*~.ǾJ͖U"儧;x4 6z'Pq O S)oird HG!z0U*NC(7rS,nRq">dRy>C[yEYCT_9_*w{{]a`գtt:|6ndkI0ڸʯFʑA<ߧp?%}lϔ7ANMFCVP8L/ m#Q B@P"IߜƔK7l4@CrMml۶mvm\R]mQضoD|g9 =y>~ s V潸 s{Ż#VHx{G0nүtRp]-yt۴i4.2׷Wt7wtV[3)J4v#u= f@HݱpY:)a[o.N G*?}K?:h~rJ/5ivrC"vىT]{; ,m/Dž7&rpX;9Sa\~" ͤ0Z(ǒEr)M9gQ.*MgR:.[EʯQ(Kuc:}VKD16^q:Q8CfK)4J4+F'N{:g6;͎Q7(i?tw)mQsu%!ʡ>CS-Bn]HIjAr Z !ȧ0CR9T ڧP(C A|z xOOm/^惬Yմxtx2bcZ mT jGn#UTgTI ]]u4nzF Tx9aJ)lL+L =Mj @?Eu& Aʧ6_uFpj]z^nN<_دTuTC<`bXH=>xF3kx*3A[%9CuBu_HW8N!|ݣBz 8Kj% JҎmx7M\HHnuEIir5(5p[t6aLJp]'՚]k@à(er) )z *c}AQ(~eASѝ 7o( C[I .U|axvɢ~> P[S, 3))fÃ)jSʯw)/፵< ^Yk)'Qs-xEI('a0x寂4HyGih/7!xL|24W:H<&P>WZ랥(l S^/O(^X"yi\.gbcB1WYQkBp\B9:>CbprxwUʙ67)_i M/Pwr(8BB#^Wp^>Ub&fsIW%͗k`m޳93@B9o ~r (>0iV }IaH-9͎0zڤ ýAwiU&=_]hit>5=Mg202`l:ȝ [0?Z>$rz  LANMFCVP8L/ m#Q B@P"Iq٤oz&`vjضo;mm۶m۶mtl۳6ƶmaܿG}yO&/s:u;H_]'Na^R$MޤU95ВkAZo-o yCw Doh3>8~ctcx*qlF&N9-CoLbL>C~7;5tzGK-Oxa?4Z^A[Sv,;1 @ Mq}Аj3{y_Z\_ %ujW!VCٺnv}&{=@UEŗ~isBW5O1uM2>Պef)!&m)-!zQm燍=N*&>KݭkV1MaB-V횧hbh2lCj9GMJX{FQ ><"Ɣ17 aM2l5)`[Q]{4mF)])>--"ieh)boXfEAnhs6w( JrC[Ǵ|ڲߥt CcxUs b;@kwCkX AIi47P )? <=RJu ( Q 0p /PIӋ\p{B|B38?DW3 )To]iL, ?zR·c `dY Mq6Ou>.zT;NTcO!' A!?R}cQm!T؃T`10v=Ju<Ou ~:P cRݍT[VT,0 ճ8H5mK0~v'vRcPk΁Ө$_-T'#+00ծ(M5.! Z)Tũ=`h_wq#C0'@,|Ga@(>zR=#PJ"si ` 5sjLf=ջ|1<D|!0,[4PPXPj9 qE`T&yQ"0=j )IŸK(,1K(Jb20lFXe~KFQx (c)20h >بp'H).#(]GC|vCwVxx 3.ps

HyЖ:)$((M%R> I#巍ʿ'|[)nqw᪰Ŵ D$Z &bGB`-f…CR +[EQWs_./׍`J$u(1j,#hq%;\wZI?@JܷwCw[߶P_I0m0|O9# )$h2~7 C%6{ER¨ٴi ӺF30~RFf>A'3ЄkhksB?q#`tx^g:Bh;ӏ ӽANMFCVP8L/!ǧm#i B@P"InIИ0_mۦ&IP:H۶m۶mmی.fJ+>QQq}wwDɣ6? ͻ\ &mzoO];w2QVP:UF*Nz GWWc_2na:9!TޛAwnwMwYp]>cs/e4svnVdL L5zƟ'a$*M^92M^2Ose!{_, @ :Iv꭫g<~ڻ>((.NRn_3k౳WݒE's - o(F>(rhV׽BO8zɉ|.tAQ|2vև{ӨN[]&oCz6ԤI\jgNR7UnR>E9| ܔ;|&$}Hp$]n;HRpp/J}2pGM1F;ct3"'AW-RdLM/BW(Ef07)LU)u`r&űtf7Rs fP= Jo`./a65PPȩqS,LWΤ_JJ`ܷT2HJP2'gEt^O]+PQfR= '`U4 AHiGi()\MEMSxbxB'')́5s(= Mr’*ԃn''`vA;Ѱb_D)*,M!NrE~8Ci-|RV%8NF[!ip"3Ui^yR(Հo8n]DA*+0]+ Z—.PngSy\_S ާ%Cxv!*3aE}/7?#`n9+aG`4(-O`6uʛ ߈2S7Q Wvx5~G xS$#.pߔ£m5Nh< =H91lFDx fqr0^ ʙ-u4_T*RhP>C?(g)#s`G>_k/U|} FO(G7Ȫ(O*O_\SV+1j^,-x5_քQsO>NvpOʱ=0Kc2ueMp ojJ jzɿQ^h˿Lɦw9?SEu= j.M8KG9 yJzŰ_>56Cq/974P44-`Sn惪+'-)就OOѳe`0X?!ޗjNK7d_'ANMF CVP8L/!mqA @RHsEK|hH<7l'nwߵm۶ve۶M*N>5yqD7},ڐsÓCn1rƲ-;_8o "v}_GԅƋ_b I?ȧȟw.UWB7NM޳E/:{K<W2]Sߧ3 p:Z>QpuY&B[Xvw DX? ޿S!vO{CP]j a\Rәu-3kl#tVߏdYtv\:G')BF}SFOp= ?2q:sRT U& PY޸8([̠2#\͢qa8kp!U{+ւǵOQqpB`QqF*J1{8[~\z{4u~wQi%O˔t,:n u? bVW0w8t$MyS|(=tt5X GxShN(6RL#hAq;5/SzZSSq=>N)'(})ި/)=m5{EitW;CJ(_Ca7.E:m[^gE, a|Zxg67)UA%Z E忢RZû,ڭz]06 qs#0)/p=:?`oDZ7 [`& pm=05 ̡m\O0=j-0x3E!40)T 1H N0 hоh?ӾiGh߁= iiOzڏ蓴obs`t&0H, >C)4 ( F2!0*}= Ki ?I{K )0EV\Ia-K? V#Zpc5[` p~0 徧0Fʯ;L FaW-0P\ g(q({GJ` J] |ED K:K+H(awP[ aT" ?BOR?(>4MT(c*P=1{(톺j7 UP:#R 'o(È'(}g)DFq 0Rf]J[4f/yweT._ϠxE)|BJU|J'kOQo )&Bq\D |zp%BCWÇ(^j -,Jnj5 R, -/Q_uϧbbxQ\?Bc#3[7m()Y5ORQJ.yO'M2(w3MNR,YO%(Ff“eO Uh峭i36( uʡ SD9) ' (?ǁt%Sby ڗX GziT=T<P:7iTmRq+|:BT+ʑ<&_RlR 󝠡%SAyFK Ç])˅//[ePh.wSq=|`/Wר8 a:|:YC'סG(x"'E`{rd+ OG!&JET<ZCh'=`HT\[L*71>*> Qv&H3Q0kY){C HEE*.ա0҇tqeN#`:* S0ڧT~U Ƈy K.NMs,WL]O/ô?>h \x'xiӀ \t:urXh(>=:pyM;]﯇([Js1Fep-(tιM_QG‚ojߠ+=/xȢcM Qu4Jϕ l-ҨzCoRw,D?GR8!:NDXޮR1j\u9gVn_Էz+[(b_zwR(-_zrRPO|ۢ킈TvV@7m'T[}H?m?š<(Lk4**>|RS1Up8¢؏h˼(.N EkUOx%ta\hrbj8o*BO't=S65?BW:x|Hq2)}F||D) ~+BTw>ADA hMʉF@B'tϠ;G( i:п ~hNi~/h0_S:B_0ύ p @9IMs>6ZpCfEåj!: Z .k(lD(4{N@>>>F]Ka, Marߣ=5Si91ɴ c_=%٭(L)BB `lU };06'!/h7i7~Y-'I[QB{܁BU4PWm)rڢ'0(B/08B?t(tF `py QBS\B0P Yh_ g_~{d_ / { 푒066uIamK;hJ KP߿zv!#ga) M{zYY:g? 0r۞½0hbŸ>fSH( PX{ 0nP )$Ua(T!Lr \ʤNI9s <3 wV C࡮IMUj6-@ L1y S<%b<΍Wwܒ#ANMFCVP8L/!mq@-{wzD_3qoضmmU۶m۶m{l۶vjԮjL1c]8#ΈtGVÿo聙* ]<ɶcgxoj?QF xh/{\A9=^ˣK/wHwr5Pn^˜[>勵++p'<^qO// θl;ʁl9:>Oӡ-}Vf&ɳc!;/Y0Pq~42o 7e+Lw_lzU0w?K/gV;lOH/OԺ׷@vg/ulinKf$uh/MDݹ(wӷԁzL xqKkMTjԜZQ^˭@͙V1ԍK^G*OG\'K'ol=vO)3ť09˥n)LΣRdav55#~@Oik ~Q}Ci )\ ӱ/)dVs2TEduOiw~)~vDPtp]O Hy@Pޣa Zb>ռTo8(9jAN{dwi4U9KPW nS-LB` a| CP|x:,MS ;۩B[iAa @HDXRj,Φo>%էaTEu,^OugŰx CTgT:z8 x"{΀3BXSo/g?kϥzс.EM0*v ;@TODa?TG| ]`iS Pܔðt (vS=WV8F5W0VN:() >g.9B/XחBQu\2],DM(m(e) B@fXu7.>5))fE:&B%)͂5)=Me SaIy S[BX~4VK] gRaAY Em1J_FwG(@7P)oC)vAȻQ R:Pg*Nik !.>إB %wBU7JAE~+/Q lyz;bNQJ(bV"BInHYD??L@bQܛ3 S|9E^x>Lȧ8P, sS(߃8Rtʷ $7SSވP4 Gߣ!XK(LFw`7#M *gRA:PG43Q} W 7b$*d?)JO9&vJ0^[ٵtM(CyjCڟO(pK}aʿ߄TF`2 ͧ' )ew-,w)Sa*65O%wAj/pE Y}j^J@؜[ |@}Bȥ|-|4>L]pɧ(xwr$Q<mvWKCQjNFfR3/]sj[Ap/5*#챧oAy$,XRsO:N1|ʾNMx5jLjNw=~@_aSqRE"E}QX7!>r'vGX{ؙw֒OK`|j G9n= ǶSfYϺ9aANMFCVP8L/!ϧmy@Dmf&¬Um;#IoRQ{l۶mm6Ƕm^{ǶO=¿SËæ.ڰ{)C_XfR]^>uцORǒ]X\yqu>[ x_z2]CQitYE?˺G#f^Á;ޝF{;hu4)B)B&ґB$ҹja2sGLLKB 0|ULW D1(( S/PDͦx&̵ˤ8EH"S)fts(s w,ŜaMʣFBy¸;H#(ta>z1.uGS^ <)#c)oȃ`o<3EOJEyQOywKCyM~oI2i a3Rlʿ"?R NM9 >q`q;/(oG8.~7NyM>%f.`lK 5Ӣ&w5 w,j* [{>lur| ʗ#S3, ܏9Q-+5!lj,0'C;f5gA85svY/C|8r,7)yD &a,5{J5Ԝk[A 5U=Ix ܠfK*lAݘMefW拰Y86+;x꾓M9yj/~*ls ~米TN?'WbGANMFCVP8L/!mw@D*Exj۶86wl۶ms=mFk۶{5m4ɛ9 ]ɇ틷׎jF5/?p`W׼|_C݃"0úuk;oͷߦk;kݫV#c[\>zd.M8Eg&D2~L>D3MhQ9:ƊJsg4N p&/f52hzG9_-1x-PJibV0ݤcwH dvn$h!,~49^^*UmcZ#dսB}1H6+Lur5F;RRUSwm]m-ՄRI[[n J|2ǩ\ys.w52'SNl+/%wQw^ E|_xvg(* Eާ {O)/}OEa"%!ltPrftLf+%g̍uu&$An&vL΢4k0ayJ?BK)9̆yfsLiA wt t[D Or%Hi((|.2[FoޜB!|i,g4| ^|+N oG5-/Px=Ba8ޥEÿyҩKAf' ` S Vt.EWT)TF,&Xjjv=)%(B2,DuV_n˰%|Cu%,^I$s`\$,Dui`8S'P=a${~:ϢgT7T~oz,մ=Gjr:L!*L$2_z5 KC' :&"mt-Z[yaeKT#k9r4ȪOaw()t])D~})FiúBR°,s(eRpB} @hPX6SpBz½ Ay¯aXIp䭔&Iu ’2(\+ >(=m$HX1oa>p,,p½zpҷa>3p Jr]7J: p҅t˔vuӔ~́Nt wv(DpC/QJtu#)x Jqx|ҝdTJ*k/ ` >"\@AF0LG80S27#P5+T ;CLxŌ607̡A m(C@Q)B R )@R~# O(+(RGD zB)_n.R](+;=`-)E|_S?Fߣs'ׇ, @h5AbPB Rf o櫂cjEOef[C3~Gu۔3"RvV*4=Af'Ij mԜ J&EfwY;GԜmMc|]Al&c,lA /v('fÎ|S KM@ 5' ~j7=Í]6~g:>zrVaTzH럤S ag5atj>L ^+iTRF̼<$ANMFCVP8L/!m#aA B@P"IӘcԜŘh6HQHٶm۶mնm۶Smۿs߻o~s% }F`TY_LZK2- zf+Ȧ>95`3ykU x;:.dj\&L?.ߟEwօ&]`A=Pa0fo\_;2i&p,Lu~hmh0uC1M @ɒۣ'4ajWi9fGi|wKoްpʰ#/Kt\oݺd~æ.t?nFP|cy#m6}RBmH*!7\Z!p>SkIWԝ\Njl9A]hRsqI$nH&wTj.g )M[)_!nbRNk 'U|#>Ft۶?P>Z 8{hS,Z 3Jt-, R\ ]J055H`jDV#s-s# (}q>i092WBi v:jn-Tҋ0}7W0CPkQ8_#ߤӕNSȯea0Lb}TJ*]wr(ģb 9uIlN'53),G_)G#6x-xeO:|?-_Dó.2z2,}B0NeSKT_@EW^BS `: SkSjn$̥~ɰ8R}@ÿo+`J3΅sQ'S QSS GQ QP-Fu,C5$-x5sTŷPEotXLyTI6>Duy ` T;գ{? ai0{P6AXXP=+P͍ÿR+GPx(|+ߡ0qYT`a0xwWa[Bva)`[3 _BOi ,Bi<Fê @Di3Ii:/r ,z(PkfPzE$W(@w`cn ᑰbOt,q8y-J/Q,Ju2 J]AJ0)Iu3> iJFQSiK(Fq ܼL)<KJ:G?|:0H\5lF)nWS<^>y: ]w#ߍbާx$&^lxF0ӷ 0óan.;aAʛ͔(( _Q V)~IP kO)7 OԅSO7Q޴Ly?HߢۚpUsjPs=\4;J]r})Qp:vuFr8Zʤ(8ss|m+\ MX[hB͟ķqP 5U#tw"jJy9bd3lMQ[j&gIר6M9v>Mú-%tQ6Τ㬱Q:<V}>HJ  gQ= maGTJNBSX~ANMFCVP8L/@!m#aA @=_$BJ؝{1&ރڶm3I6m۶m۶m+NdFyުw?G?;{?uIwozE* ftqL} zf!V>.kjHEQ_Ua~3%>sB/=YBGo M8C϶ẏ֊X(ǟnỶ5iy99w6LuAs@a #$hlmbUQtʄ!T] i~W3(v7[_v^y{D\=;_qޝzr+[P>~F!7Zaaؿ7gԅ\mڋF'(uVTRWɮE^Q^*,L]l Rgj^Ӗ{ۓ왙 ĝć[SK֦OMQʧS..~RS>^} >~mݻR?az~4#7@b Y"\Jqt-K) Qe S( 07"Jml4*Gb`rbwLRZ)0`v1!Bi ?B.(΁ț~΂AB'gLߚ05FN\{~^v<\©i^@ SXK kP(/A@)¥e L>P脋QED\pQ-\W~ɎPj #`0 k| X~;pQ} ־@ӊBXB `mr`s'~TRz/ka5T:ϦzxXu8I8R>A?IT]lɄ7(۟u> ATW?jh(0 6IpGXCkAh :Gyo#csadFS啕сo*j~pe@ 85"liSue)5g |{>lBޥ|? ?g˂p5M4cquOTR$_wBtsQ}=߲$%H/Lܵ)[I=j;gׁh(:#j#;ׇ\{OajtK[U Njn΢~6 Q2TXBnp5fiԄ׾IMڴ8AͣVpV>rxC"ܔ|BpSxsg[mtq6?AXa8xtQ!'Y#Q:ʙ 33GAW>Rx8L N09P%ȁ(ܐ09)E(uSarXH)mٹlٕ$@M B jR0caDPPT+|({b=j /ަ|C)< Og^`xR!w.G(UTWS>J̦yv-%"H x,FU)KP ()CTŞR} kze(, Ftֶu2է 6)ŧn귰_ oz<ٰxsiT'TSRGPSMTO>Mu,A5* x'.s+Mu,;fSTPPݘ`XۍBT_+>NWa1#w 水&Ha,]D3r㲨fʘ+TCu ae2דŸrȋM5,lMvҥDk?ٔ7 ^8_x4KDO:Ey<^@L)xQ2t1+Mû)Ut/Q`;ZncI̛3˺qP͠Fn:I0\r?̆N*U`ʩW)6z7(_T:G9 ޡ|2R('acʧ?QΙ #S#&OwR#-BW'|_PY*75o+.\f9)B~_8E9grdNxFPjވMԄ:ϵ/Q[IhzC\nM+!vo DW S-+&=ۢWmjSaK5"aj=u/R=Psl*%9+ ^˷aݴt dqV7Y$ [ FG_jsV`u,jBa{c׀_P o/ ^/ԁdtkgui-5.7.12/tests/images/dci_heart_dci_normal.webp000066400000000000000000000032041476226661100225060ustar00rootroot00000000000000RIFF|WEBPVP8X ANIMANMFPwndVP8L7/wWm#Q @=;(Bܹ؈[q΅؋P0D*+d۶mH.m۶m۶m۶m۶mrE#ɈO8.};~$xu؂Ca r'՝ z };̽;r^̦JT{g,m2Kߨ^kݒ_xsdg_Η>j[^T'5C=7!vzͯ`7dL,-%$ں N=!;r+o,u*ǂr.-O5aprERH 3g D즌 e;YLusL] YG^ O\JY e+J~iFjBy ֪a. Z5aG2࿄0 K #`;,ٰS>Ey$P<ߒotPrxMQ &PLSLŸE'I=xQa) )*th O>"'Fr1el(>SO @% >ҕܤՅ+k(CN&\e D.@~3|u;P,EvvSMWM2<7|R vPi ״Q7(#%('_(?+rN&P>d|@FPOy88Ft8-Aph^*g#<}*;BmTESf3 ZIwyKeW(Jl]k@eW(JbK裲; C6R} =0jǒhԆj` # cYoS 4/ yJm 5ڻ0R-\D*k@T|}Tbq(*]&1T|_"Vt_ԖALjLISZ n(̰XQdtkgui-5.7.12/tests/images/dci_heart_dci_pressed.webp000066400000000000000000000375301476226661100226740ustar00rootroot00000000000000RIFFP?WEBPVP8X ANIMANMF&CVP8L /ANMF^WCVP8L/^'sY.& Uv6/[_ M\@㥁'Buj.h_Vx[ zlT6.6g3 v -{`;ÃwgžL܂`oT~Rf:\N!.p3pJ JaJ {P}N1b8œS\SlN9S\OF-t`Sj؝҂ F%Πo S8 To SVPSJ)BcpJ ZACtV: sp= ,H9 `rAڙ| Lp F \5ag0l.8 7*X-9 A< YANMF" CVP8L /" H~ EmS/3Tz̄CmfCFgUNM muf p9Օ"q9O}O2/?eRhѫGZ գ,<㴋<ѡ/<8u)<Ψ k3GUIU<ZEP/fgIPIcS-v3_;-Ml*m2%Z' ڶWi`AZSFF{G]; GjSn<]dek2G!U|WNܗ+8TG{dKߺ9qmk '9qоzm-TTjz.6+,H=s\tκʞκ(aA:0bf5m랑^,a;|##l$]&̦pU0Q5p͈tud4'8V#1 WF%p{FkXoSna y(b~+:]1+C! 5B"!!,9B,7/U#D{frg TY!\C/^Sˁ1d=9w$':5 Q?tx@\{:{Cl-tgQ.6kĩ\xX!w.js9p-wqf{r? 92OR\8iȡh?WE/̻F(ANMF{rCVP8Lm/{jN#@"#0pCX’û$?I1iI!UY>y&E `dI4bhEqd*u6lC >g`s s @6jK ֶIcLl^H/f\{E?Z;Odmep9c ԑ钅L-1mQFZ+`ZoozΪHU%: 5jH,ݵ}*$,T2N bSQL {a* 7PKiF^]FGK]EG_oKy$(I.EEU (1!ACq~@/F6v)|"} Boeǔjӥ |^R,bC(Y`E|N1_,;\Sm\ ^u(ņ< |.S2> l|]R )tV"~v(>Kaإhu;Oa~(3E=#a"8)ĂG1Z^hh{*j h`4U1-BK\ܤa;P[QunР7it4i4it5i5ܧ:nQtԸ15atZ91SC8 S69*($JleQ~SY&1at xц)3[0|va\)cQȰoֆ\h C>F!pwnANMF:kcCVP8L"/k' m&exp\۶2gNTA=,'wx_ ADa6Lv{ *$ɈE''LD.p#/򖴢勒9Jz(")?1b@1OrB!B>‡mVfjLaff,3 Ǭ#]][zBwpeO{1C.{:war%C/_ A{UW/`FרY[Z;Snjp2sF8A7F8PdDYh2rsmFn.C[=7 =[yr " ]M!gP4N!_(#.#KA(s=DQGQMQX;]RKa5mֶ)A ;Aa֘)ʷHQ^dSdSId"7DAC_[סK13Yb!|BYuW(*"y uN!mU;4&bI=n!˧^'ܧ(3Ic'l$kݦ[-Hz^Dw4 18@vƭ@m. s4+84.tAFc~@GC3҈1J'hT)tVL3 譚fs]5T章j)T!I6UtJGX)r^a i/6ҵR+:{0OmeqlNuj9uS0_QfoΆq*w`-&: 3WpV 0Pͼb61ƻ3r̯bH5$d Omi{9e_!ANMF8wnCVP8L/w'FmSncVwwrB dBw}@_m6bGwg$3jg(; s3M%M!o>%/vtI% bHI">xE(9Mw/Qգzg m.Jò,3q"!EnBhEE(;SAKIxBq]EqkFaو~G\~'E kuT  (zZ(gfgpKe'삧74M h= ^?sE}1 hp}!Thl`ԖePnr)y6ꙷiL(zE^BOu3 k:iT7Ωδh= i=i~,w{)og{ mW{.G3n3iO'S_> a ȽD`J1j=s7QD0mz΁y_4RCXʏ+`f9*ρ[;^GcX^Vp"SLnc ȩ|@Utj}5 ANMF{rCVP8L/{1M/9 ȑ$Vzzf@p!'CְoG8p6s6]I[8m0SyPrS9lj\r#yO8}iǎ#oinkKe@gc^seR9♥-`oi{ýlR*OhxV}i#0k3%_=rBXXËZ~O1PP^jcalصii:V#`9em>nnŽg(܈KhUog `+4|o\K>7,1ӡ:5fkKf΂ڌ 7cFΞ q4߰vjϚFmm:aޫ)tϮ'RܩR@qCw#ފQu01QW@uO)stjP4:.žH)ŖGS){)($ Nn`5Spk"'ONAΡ^.VF2ž( t iP:ߡѵB7g&EFybFUS`HB#nl-ՌC w=SXMaG!K(_t'BgRLuPyB^wS=P3ԧ)YFA":}!4W Ǧ0N/]k`n0ѧs&;gѱaj:uLBnq/Jg/JG/J'M/JH-6Z6k` ZjS`[- pcM - Wdx23{\%~3 n} ׼ki.L#ps .LvR;kj8.}Z޹mTn4ίbHXH䅐1c*|1RzлzBЦ*l2%6)1 p%'NEANMF{qCVP8L/{@qH8٧j 8"`E,[9o5@&б:x眙fض#¹/O.Dmft*,Oxg< ^q/n,LveaBܸ{Q7Ó,Kfag?'ξΟӗ_6NHiy r觟́ )ժ4>>J|(A L @ݔr5wS%~9.Ai>J.QXA(:"E[. )2hz.oSȥ("l/5{(ido]^S nډ;(xX >` >d9u)RfdߧϐO=bODŶEn9!$N@~ D:ܜ@A|EmJ(=(}Aq!d vPf.BdkG>R*(^(e2PP@wQPN|F?C6:%tt{ nӷ@Atonj dyO920uns`l<:ȇ=Ca: y) 7țiHA'N :N/K=G&a3VaןLs}#18p=-7N.+xQpg61.uXI[[o؇ ^b6 -J SFn .Zu_ƫz{|ǕQw%)?`M '8#$!2 i]e]!/yUVtjANMFwnCVP8L/wЖ$IEe_0LOM{qyW/3A$I* =Y "8i϶mm۶m۶m{7Icx XJUJ򐘖G.sPX<`kߍiXnAlv{`PCc,[^{vxȚ\=h;Up5:tF^4E 6zU' 5x{M#^x (j\a}&W"_}AnYa$]8@L~6zws/f#'utxޑȑk[/qogԂ_[QNԍ4:b|`?>^9XIh g{ם]0R'63ۭR;wo~̑1 >(DǏ>a{/1xݷf?= Z ySx_Ln6{>'x'G@`czpH)ԱJ ~E cGVPG×:)LuqOG L8<&aJ֠_$ozl 7ccw>extLB?χfH=ѵ .{pX/?h\WJ*9dΟ,yG] QANMFvnCVP8L/vЖ$I$G'7TfVғ/3=]3F$72nte SzWl@sm۶m۶m[mg 7I 阱w_KڢV+s,6 Wpsep7^ 7So"qa-(d3t9%(hHfKGJiCUʬF8j}v`z|ZQzD1/' |UdZTb1wHBA.V;gl'jDxb blk(uOY 9D!5޾H:dۼq $#Gs鿆rm %p~_/(d)IS;JG 'vj8.ǟ86R9Ê/d|vV"QviN%KU_Nw%' e[h}7ymfG Ƞm|o2&Sã[)6^)a o*:Pct8j)EՂs?<ə±x9Q9G՛s?{3N6Ĭ<7c/ȴMdDJKӥl|;oSv|;9Trd_P~˕E F>)Ϡe}D,'p 60K /:޶H9_YDgc  Cp ?&-܍BcGs+ⓟG3 )@Oy$L@=k73CN<ϙQݘ >c A <v%3nx9yaD{ȟm$Ä[Ӹ)H<4ޡ3w(`xǃo;,Wc,or AkG_;gx5l5c~DulxPZ:A =q2 'y >::$(c1bi`O*4CORNEJ h r+A*lن)LM@O[ȟӢÞ)xb܅C"/i%%@~N+n"]*G/x@88&yz8a$ŊqANMFwnCVP8L/wЖ$I]EvK'fZ /ٶ6\=s=) X6}m۶m۶m۶m۶}+ HJoHnjw\a(:sJ؎s✄M#!|% "~K 8>x]bVkQ: .6H݉˨jq\#\l!~C},R-}T&7CI40MdQqMK:UX5~gqȝQ}nrʸ%-&vء:~Q]SG3DN]Cig@}7H˄8ՙrTpOOC3[m'EgcꟙwmJKLȗJ3!Z%1)6">"xQNdB3Sa*oh>:ھZe.gbeBHj'WiЅ,EYi=!M?hߥf9,3ToQmջzl[m'Tܷ_qo؋ gI`d5lXsb=6>¨z#Um덒XTh@d+b%*.S_). R R} 'VI=6SU[v *$ju!ײF4jq5zE:/Dvnjwbh7X|CutG{aAOݏt~3%&y5Chv}gJlj?z^o?^%;YgL`t^-U;|U1e^n/ma\11}'v'הbZɟ}c)Kj]ܙ\N%*Uo5*5[eϥNr)_1HsK*y.EI݁>tjH|fZ̳s| |qP*Ra!"g&ki0]NQNoNMMT9x6I:SoV'/u:y^Xb M rM*GdcwpOrsD9%2}Y85 ^Onׁ{j1Ój]ퟹ-3_ub&7,uI Y.Ȯ$7KյXsM{ɭ!rƻFR3%O`%%m j` z8In6xM$߮6xM&߬-x%L>$S$W{Z&;DjoIUO5{˲><e gdirqV2 %#Ts SÒ 46L]=:{Y1H{.$*ׁKcvmrltM+ɛY PÓqflڒ Khl7&g'{{7p璼,s~$Ȇ=I>L̄/ip)d`: ANMFzpCVP8L/zЖ$I$rCUfT>l-33_@n#ɑtBFtEdO㴾= #)bm۶ml۶m۶m6϶o@p#Iސvf &LQˮT!d D bp ,4eHJ iCFC]n*AB#fz%otԡ]tk9"u]T sCÃ2ꖟ:S]\A0[0bp#k$E>*'),};{A F抿TK:f/>Yb2*T~ğ0zTgE;Xc/ .v׻3`hwggc\0o [~M)Wg&9Fj߆3≺%řK msbofs;' Gg6qxy gf>1t|bFU"[ؼfLnLiY܁EER1Q ךN+sv)j8¢rHy/ůztg fA$li׫,,H9L?<9qd4W5%F(4=009Xu8d[U& 5o_ԝX/Gk!Nd< ;B |p:(GG 8o1bLkWΩ|#S7:2? q"FzhC4ԧ[hBDn)}lCVAmq>x`%'0LO#xTP[\g<{0LS[qbp((̊1FΑpCzL]b zyXLWb0n6]PE(Q7Y=ʡqg^bkx?o| _{K;tv{<"J\ ꕵW>׮+`|*ˀ4>5>WC\^]X(GN~VtLk]=ؽ])D[?W&1\muSEtH תea*}<*Zv}cp'&gwsUJsWl泌%܏k_+pe5Λ螯,͝y*&zTބ=CtQ)aW,v[ݶ]2EVa_<џq1a_}DW_LغND_nW1kb浖֞60Rtv1a;a{"zFYIL Cig=w{|+n/Aak?+r(jX0jr? #ߏU=ONq藼qXE?k\O>,\%HW)0ҙ%ʵ02E%? ac Ck/ C90>Ϸ04&*04и&4 ֯͝0^{Gjv5) 53ڄ# Cad} #aףHRF3a WE?9 tuMTނDk 㜥?&[aX^YEW7a30*ܢWׇQl=1%(z0v@>1Z'LњW{MNWcˆDZt #.+9pFt'iNoi+pn]n^+D׭N_t1xh!fj8t{-¡r{Hy 7=hAC Ԙp\bhU!$j%.(pTh'I1E{ͰpJ #Eu\8Čg|8™,z4{L511t@<`;=轴=)vVnN[ Dr5&YYtȯ=!>ΰul{d╲rߏ4s쀵$:7akޢW7cDić I4-E'ڥn'̔d<7 ;Tps^Ƅ1,r{6c ctS&åb {VFokօf!^A9Z.Ó(dS?ND\U^b9UDodtkgui-5.7.12/tests/images/deepin/000077500000000000000000000000001476226661100167635ustar00rootroot00000000000000dtkgui-5.7.12/tests/images/deepin/cs_rect_64.svg000066400000000000000000000007451476226661100214450ustar00rootroot00000000000000 dtkgui-5.7.12/tests/images/deepin/index.theme000066400000000000000000000003031476226661100211120ustar00rootroot00000000000000[Icon Theme] Name=deepin Inherits= Papirus Example=x-directory-normal FollowsColorScheme=true Directories=actions/64 [actions/64] Size=64 Context=Actions Type=Scalable MinSize=32 MaxSize=128 dtkgui-5.7.12/tests/images/logo_icon.png000066400000000000000000000015031476226661100201740ustar00rootroot00000000000000PNG  IHDR szz pHYs+IDATXŗKTQ?g8#qD i#eQS`OfiӮ2ZM/hJE !0C͂쁡=)Lǜs3>ߜ~{νG`o*q Vb_Z&>f|e!KK+ Wj6&TܨFF@N5d(uP *U1#s1=36 "Yi [Mn[̰k2cA.w,/CWeh(@8J |Re&@ԁ+`p+Xec0^K5"^VFS.JOf @*LW, |_nKOab%=?ZL#%pt?绊Ȫ>%(Ę logo icon dtkgui-5.7.12/tests/main.cpp000066400000000000000000000025041476226661100157030ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include #include #include #ifdef QT_DEBUG #include #endif #include #include DGUI_USE_NAMESPACE int main(int argc, char *argv[]) { // gerrit编译时没有显示器,需要指定环境变量 if (!qEnvironmentVariableIsSet("DISPLAY")) qputenv("QT_QPA_PLATFORM", "offscreen"); qputenv("QT_QPA_PLATFORM", "minimal"); QString paths(QFileInfo(QString::fromUtf8(argv[0])).path() + "/plugins"); qputenv("QT_QPA_PLATFORM_PLUGIN_PATH", paths.toLocal8Bit().data()); // for ut_dicon.cpp 测试指定缩放时 dicon 的 ut // 如果需要删除,请一起删除 ut_dicon.cpp 中 ASSERT_FLOAT_EQ(devicePixelRatio, 1.25); qputenv("D_DXCB_DISABLE_OVERRIDE_HIDPI","1"); qputenv("QT_SCALE_FACTOR","1.25"); // Testing `setPaletteType` called before QApplication constructed. DGuiApplicationHelper::instance()->setPaletteType(DGuiApplicationHelper::LightType); QApplication app(argc, argv); ::testing::InitGoogleTest(&argc, argv); int ret = RUN_ALL_TESTS(); #ifdef QT_DEBUG __sanitizer_set_report_path("asan.log"); #endif return ret; } dtkgui-5.7.12/tests/platform-plugin-test/000077500000000000000000000000001476226661100203475ustar00rootroot00000000000000dtkgui-5.7.12/tests/platform-plugin-test/CMakeLists.txt000066400000000000000000000021131476226661100231040ustar00rootroot00000000000000set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui) if("${QT_VERSION_MAJOR}" STRLESS "6") find_package(Qt${QT_VERSION_MAJOR} REQUIRED EventDispatcherSupport ServiceSupport) endif() find_package(Dtk${DTK_VERSION_MAJOR}Core REQUIRED) file(GLOB plugin_SRC minimal.json *.h *.cpp ) add_library(${test-plugin} SHARED ${plugin_SRC}) target_link_libraries(${test-plugin} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::CorePrivate Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::GuiPrivate Dtk${DTK_VERSION_MAJOR}::Core) if("${QT_VERSION_MAJOR}" STRLESS "6") target_link_libraries(${test-plugin} PRIVATE Qt${QT_VERSION_MAJOR}::EventDispatcherSupportPrivate Qt${QT_VERSION_MAJOR}::ServiceSupportPrivate) endif() target_include_directories(${test-plugin} PUBLIC ${PROJECT_SOURCE_DIR}/include/global ${PROJECT_SOURCE_DIR}/include/kernel ${PROJECT_SOURCE_DIR}/include/filedrag ) set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/../plugins/platforms) dtkgui-5.7.12/tests/platform-plugin-test/ddynamicmetaobject.cpp000066400000000000000000000370531476226661100247110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "ddynamicmetaobject.h" #include "dplatformsettings.h" #include #include #include #define VALID_PROPERTIES "validProperties" #define ALL_KEYS "allKeys" DGUI_BEGIN_NAMESPACE QHash DDynamicMetaObject::mapped; /* * 将 base 对象的 metaobject 替换成 this,会跟随 base 对象一起销毁。 * 通过覆盖 QObject 的 qt_metacall 虚函数,检测 base object 中自定义的属性列表 * 将 settings 对应的 setting/setSetting 和 object 对象中的属性绑定到一起使用 * 将 base 对象通过 property/setProperty 调用对属性的读写操作转为对 setting 的 setting/setSetting 调用 */ DDynamicMetaObject::DDynamicMetaObject(QObject *base, DPlatformSettings *settings, bool global_settings) : m_base(base) , m_settings(settings) , m_isGlobalSettings(global_settings) { if (mapped.value(base)) { qCritical() << "DDynamicMetaObject: Native settings are already initialized for object:" << base; std::abort(); } mapped[base] = this; const QMetaObject *meta_object; if (qintptr ptr = qvariant_cast(m_base->property("_d_metaObject"))) { meta_object = reinterpret_cast(ptr); } else { meta_object = m_base->metaObject(); } if (m_settings->initialized()) { init(meta_object); } } DDynamicMetaObject::~DDynamicMetaObject() { if (!m_isGlobalSettings) { delete m_settings; } else if (m_settings->initialized()) { // 移除注册的callback m_settings->removeCallbackForHandle(this); m_settings->removeSignalCallback(this); } mapped.remove(m_base); if (m_metaObject) { free(m_metaObject); } } bool DDynamicMetaObject::isValid() const { return m_settings->initialized(); } void DDynamicMetaObject::init(const QMetaObject *metaObject) { m_objectBuilder.addMetaObject(metaObject); m_firstProperty = metaObject->propertyOffset(); m_propertyCount = m_objectBuilder.propertyCount(); // 用于记录属性是否有效的属性, 属性类型为64位整数,最多可用于记录64个属性的状态 m_flagPropertyIndex = metaObject->indexOfProperty(VALID_PROPERTIES); qint64 validProperties = 0; // 用于记录所有属性的key m_allKeysPropertyIndex = metaObject->indexOfProperty(ALL_KEYS); int allKeyPropertyType = 0; QMetaObjectBuilder &ob = m_objectBuilder; #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) ob.setFlags(ob.flags() | DynamicMetaObject); #else ob.setFlags(ob.flags() | QMetaObjectBuilder::DynamicMetaObject); #endif // 先删除所有的属性,等待重构 while (ob.propertyCount() > 0) { ob.removeProperty(0); } QVector propertySignalIndex; propertySignalIndex.reserve(m_propertyCount); // QMetaObjectBuilder对象中的属性、信号、方法均从0开始,但是m_base对象的QMetaObject则包含offset // 因此往QMetaObjectBuilder对象中添加属性时要将其对应的信号的index减去偏移量 int signal_offset = metaObject->methodOffset(); for (int i = 0; i < m_propertyCount; ++i) { int index = i + m_firstProperty; const QMetaProperty &mp = metaObject->property(index); if (mp.hasNotifySignal()) { propertySignalIndex << mp.notifySignalIndex(); } // 跳过特殊属性 if (index == m_flagPropertyIndex) { ob.addProperty(mp); continue; } if (index == m_allKeysPropertyIndex) { ob.addProperty(mp); allKeyPropertyType = mp.userType(); continue; } if (m_settings->setting(mp.name()).isValid()) { validProperties |= (1 << i); } QMetaPropertyBuilder op; switch (mp.type()) { case QVariant::Type::ByteArray: case QVariant::Type::String: case QVariant::Type::Color: case QVariant::Type::Int: case QVariant::Type::Double: case QVariant::Type::Bool: op = ob.addProperty(mp); break; default: // 重设属性的类型,只支持Int double color string bytearray op = ob.addProperty(mp.name(), "QByteArray", mp.notifySignalIndex()); break; } if (op.isWritable()) { // 声明支持属性reset op.setResettable(true); } // 重置属性对应的信号 if (op.hasNotifySignal()) { op.setNotifySignal(ob.method(op.notifySignal().index() - signal_offset)); } } { // 通过class info确定是否应该关联对象的信号 int index = metaObject->indexOfClassInfo("SignalType"); if (index >= 0) { const QByteArray signals_value(metaObject->classInfo(index).value()); // 如果base对象声明为信号的生产者,则应该将其产生的信号转发到native settings if (signals_value == "producer") { // 创建一个槽用于接收所有信号 m_relaySlotIndex = ob.addMethod("relaySlot(QByteArray,qint32,qint32)").index() + metaObject->methodOffset(); } } } // 将属性状态设置给对象 m_base->setProperty(VALID_PROPERTIES, validProperties); // 将所有属性名称设置给对象 if (allKeyPropertyType == qMetaTypeId>()) { QSet set(m_settings->settingKeys().begin(), m_settings->settingKeys().end()); m_base->setProperty(ALL_KEYS, QVariant::fromValue(set)); } else { m_base->setProperty(ALL_KEYS, QVariant::fromValue(m_settings->settingKeys())); } m_propertySignalIndex = metaObject->indexOfMethod(QMetaObject::normalizedSignature("propertyChanged(const QByteArray&, const QVariant&)")); // 监听native setting变化 m_settings->registerCallback(reinterpret_cast(onPropertyChanged), this); // 监听信号. 如果base对象声明了要转发其信号,则此对象不应该关心来自于native settings的信号 // 即信号的生产者和消费者只能选其一 if (!isRelaySignal()) { m_settings->registerSignalCallback(reinterpret_cast(onSignal), this); } // 支持在base对象中直接使用property/setProperty读写native属性 QObjectPrivate *op = QObjectPrivate::get(m_base); op->metaObject = this; m_metaObject = ob.toMetaObject(); *static_cast(this) = *m_metaObject; if (isRelaySignal()) { // 把 static_metacall 置为nullptr,迫使对base对象调用QMetaObject::invodeMethod时使用DDynamicMetaObject::metaCall d.static_metacall = nullptr; // 链接 base 对象的所有信号 int first_method = methodOffset(); int method_count = methodCount(); for (int i = 0; i < method_count; ++i) { int index = i + first_method; // 排除属性对应的信号 if (propertySignalIndex.contains(index)) { continue; } QMetaMethod method = this->method(index); if (method.methodType() != QMetaMethod::Signal) { continue; } QMetaObject::connect(m_base, index, m_base, m_relaySlotIndex, Qt::DirectConnection); } } } QByteArray DDynamicMetaObject::getSettingsProperty(QObject *base) { const QMetaObject *meta_object; if (qintptr ptr = qvariant_cast(base->property("_d_metaObject"))) { meta_object = reinterpret_cast(ptr); } else { meta_object = base->metaObject(); } QByteArray settings_property; { // 获取base对象是否指定了native settings的域 // 默认情况下,native settings的值保存在窗口的_XSETTINGS_SETTINGS属性上 // 指定域后,会将native settings的值保存到指定的窗口属性。 // 将域的值转换成窗口属性时,会把 "/" 替换为 "_",如域:"/xxx/xxx" 转成窗口属性为:"_xxx_xxx" // 且所有字母转换为大写 settings_property = base->property("_d_domain").toByteArray(); if (settings_property.isEmpty()) { int index = meta_object->indexOfClassInfo("Domain"); if (index >= 0) { settings_property = QByteArray(meta_object->classInfo(index).value()); } } if (!settings_property.isEmpty()) { settings_property = settings_property.toUpper(); settings_property.replace('/', '_'); } } return settings_property; } int DDynamicMetaObject::createProperty(const char *name, const char *) { // 不处理空字符串 if (strlen(name) == 0) { return -1; } // 不创建特殊属性(以'_'开头的属性认为是私有的,不自动关联到native Settings) if (QByteArrayLiteral(VALID_PROPERTIES) == name || QByteArrayLiteral(ALL_KEYS) == name || name[0] == '_') { return -1; } // 清理旧数据 free(m_metaObject); // 添加新属性 auto property = m_objectBuilder.addProperty(name, "QVariant"); property.setReadable(true); property.setWritable(true); property.setResettable(true); m_metaObject = m_objectBuilder.toMetaObject(); *static_cast(this) = *m_metaObject; return m_firstProperty + property.index(); } void DDynamicMetaObject::onPropertyChanged(const QByteArray &name, const QVariant &property, DDynamicMetaObject *handle) { if (handle->m_propertySignalIndex >= 0) { handle->method(handle->m_propertySignalIndex).invoke(handle->m_base, Q_ARG(QByteArray, name), Q_ARG(QVariant, property)); } // 重设对象的 ALL_KEYS 属性 { const QVariant &old_property = handle->m_base->property(ALL_KEYS); if (old_property.canConvert>()) { QSet keys = qvariant_cast>(old_property); int old_count = keys.count(); if (property.isValid()) { keys << name; } else if (keys.contains(name)) { keys.remove(name); } // 数量无变化时说明值无变化 if (old_count != keys.count()) { handle->m_base->setProperty(ALL_KEYS, QVariant::fromValue(keys)); } } else { bool changed = false; QByteArrayList keys = qvariant_cast(old_property); if (property.isValid()) { if (!keys.contains(name)) { keys << name; changed = true; } } else if (keys.contains(name)) { keys.removeOne(name); changed = true; } if (changed) { handle->m_base->setProperty(ALL_KEYS, QVariant::fromValue(keys)); } } } // 不要直接调用自己的indexOfProperty函数,属性不存在时会导致调用createProperty函数 int property_index = handle->m_objectBuilder.indexOfProperty(name.constData()); if (Q_UNLIKELY(property_index < 0)) { return; } { bool ok = false; qint64 flags = handle->m_base->property(VALID_PROPERTIES).toLongLong(&ok); // 更新有效属性的标志位 if (ok) { qint64 flag = (1 << property_index); flags = property.isValid() ? flags | flag : flags & ~flag; handle->m_base->setProperty(VALID_PROPERTIES, flags); } } const QMetaProperty &p = handle->property(handle->m_firstProperty + property_index); if (p.hasNotifySignal()) { // 通知属性改变 p.notifySignal().invoke(handle->m_base); } } // 处理native settings发过来的信号 void DDynamicMetaObject::onSignal(const QByteArray &signal, qint32 data1, qint32 data2, DDynamicMetaObject *handle) { // 根据不同的参数寻找对应的信号 static QByteArrayList signal_suffixs { QByteArrayLiteral("()"), QByteArrayLiteral("(qint32)"), QByteArrayLiteral("(qint32,qint32)") }; int signal_index = -1; for (const QByteArray &suffix : signal_suffixs) { signal_index = handle->indexOfMethod(signal + suffix); if (signal_index >= 0) break; } QMetaMethod signal_method = handle->method(signal_index); // 调用base对象对应的信号 signal_method.invoke(handle->m_base, Qt::DirectConnection, Q_ARG(qint32, data1), Q_ARG(qint32, data2)); } int DDynamicMetaObject::metaCall(QMetaObject::Call _c, int _id, void ** _a) { enum CallFlag { ReadProperty = 1 << QMetaObject::ReadProperty, WriteProperty = 1 << QMetaObject::WriteProperty, ResetProperty = 1 << QMetaObject::ResetProperty, AllCall = ReadProperty | WriteProperty | ResetProperty }; if (AllCall & (1 << _c)) { const QMetaProperty &p = property(_id); const int index = p.propertyIndex(); // 对于本地属性,此处应该从m_settings中读写 if (Q_LIKELY(index != m_flagPropertyIndex && index != m_allKeysPropertyIndex && index >= m_firstProperty)) { switch (_c) { case QMetaObject::ReadProperty: *reinterpret_cast(_a[1]) = m_settings->setting(p.name()); _a[0] = reinterpret_cast(_a[1])->data(); break; case QMetaObject::WriteProperty: m_settings->setSetting(p.name(), *reinterpret_cast(_a[1])); break; case QMetaObject::ResetProperty: m_settings->setSetting(p.name(), QVariant()); break; default: break; } return -1; } } do { if (!isRelaySignal()) break; if (Q_LIKELY(_c != QMetaObject::InvokeMetaMethod || _id != m_relaySlotIndex)) { break; } int signal = m_base->senderSignalIndex(); QByteArray signal_name; qint32 data1 = 0, data2 = 0; // 不是通过信号触发的槽调用,可能是使用QMetaObject::invoke if (signal < 0) { signal_name = *reinterpret_cast(_a[1]); data1 = *reinterpret_cast(_a[2]); data2 = *reinterpret_cast(_a[3]); } else { const auto &signal_method = method(signal); signal_name = signal_method.name(); // 0为return type, 因此参数值下标从1开始 if (signal_method.parameterCount() > 0) { #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QVariant arg(signal_method.parameterMetaType(0), _a[1]); #else QVariant arg(signal_method.parameterType(0), _a[1]); #endif // 获取参数1,获取参数2 data1 = arg.toInt(); } if (signal_method.parameterCount() > 1) { #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QVariant arg(signal_method.parameterMetaType(1), _a[2]); #else QVariant arg(signal_method.parameterType(1), _a[2]); #endif data2 = arg.toInt(); } } m_settings->emitSignal(signal_name, data1, data2); return -1; } while (false); return m_base->qt_metacall(_c, _id, _a); } bool DDynamicMetaObject::isRelaySignal() const { return m_relaySlotIndex > 0; } DGUI_END_NAMESPACE dtkgui-5.7.12/tests/platform-plugin-test/ddynamicmetaobject.h000066400000000000000000000035111476226661100243460ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2017 - 2022 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DDYNAMICMETAOBJECT_H #define DDYNAMICMETAOBJECT_H #include "dtkgui_global.h" #define protected public #include #undef protected #include #include DGUI_BEGIN_NAMESPACE class DPlatformSettings; class DDynamicMetaObject : public QAbstractDynamicMetaObject { public: explicit DDynamicMetaObject(QObject *base, DPlatformSettings *settings, bool global_settings); ~DDynamicMetaObject() override; static QByteArray getSettingsProperty(QObject *base); bool isValid() const; private: void init(const QMetaObject *meta_object); int createProperty(const char *, const char *) override; int metaCall(QMetaObject::Call, int _id, void **) override; bool isRelaySignal() const; static void onPropertyChanged(const QByteArray &name, const QVariant &property, DDynamicMetaObject *handle); static void onSignal(const QByteArray &signal, qint32 data1, qint32 data2, DDynamicMetaObject *handle); QObject *m_base; QMetaObject *m_metaObject = nullptr; QMetaObjectBuilder m_objectBuilder; int m_firstProperty; int m_propertyCount; // propertyChanged信号的index int m_propertySignalIndex; // VALID_PROPERTIES属性的index int m_flagPropertyIndex; // ALL_KEYS属性的index int m_allKeysPropertyIndex; // 用于转发base对象产生的信号的槽,使用native settings的接口将其发送出去. 值为0时表示不转发base对象的所有信号 int m_relaySlotIndex = 0; DPlatformSettings *m_settings = nullptr; bool m_isGlobalSettings = false; static QHash mapped; }; DGUI_END_NAMESPACE #endif // DDYNAMICMETAOBJECT_H dtkgui-5.7.12/tests/platform-plugin-test/dplatformnativeinterface.cpp000066400000000000000000000027601476226661100261400ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dtkgui_global.h" #include "dplatformnativeinterface.h" #include "dummysettings.h" #include "ddynamicmetaobject.h" #include #include #include DGUI_USE_NAMESPACE static bool buildNativeSettings(QObject *object, quint32 /*settingWindow*/) { if (!qApp) return false; static QPair kvs[] = { {"Net/ThemeName", "deepin"}, {"Qt/ActiveColor", QColor(Qt::red)}, {"Net/IconThemeName", "bloom"}, {"DTK/WindowRadius", 18} }; QString domain = object->property("_d_domain").toByteArray(); domain.replace("/", "_"); auto settings = new DummySettings(domain); for (auto pair : kvs) { settings->setSetting(pair.first, pair.second); } // set object.metaobject to this, destroyed with object destroyed... DDynamicMetaObject *mj = new DDynamicMetaObject(object, settings, false); if (!mj->isValid()) { delete mj; return false; } return true; } DPlatformNativeInterface::DPlatformNativeInterface() :QPlatformNativeInterface() { } QFunctionPointer DPlatformNativeInterface::platformFunction(const QByteArray &function) const { if (!function.compare("_d_buildNativeSettings")) return reinterpret_cast(buildNativeSettings); return QPlatformNativeInterface::platformFunction(function); } dtkgui-5.7.12/tests/platform-plugin-test/dplatformnativeinterface.h000066400000000000000000000007441476226661100256050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPLATFORMNATIVEINTERFACE_H #define DPLATFORMNATIVEINTERFACE_H #include #include class DPlatformNativeInterface : public QPlatformNativeInterface { public: DPlatformNativeInterface(); virtual QFunctionPointer platformFunction(const QByteArray &function) const; }; #endif // DPLATFORMNATIVEINTERFACE_H dtkgui-5.7.12/tests/platform-plugin-test/dplatformsettings.cpp000066400000000000000000000030311476226661100246210ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dplatformsettings.h" DGUI_BEGIN_NAMESPACE void DPlatformSettings::registerCallback(DPlatformSettings::PropertyChangeFunc func, void *handle) { Callback callback = { func, handle }; callback_links.push_back(callback); } void DPlatformSettings::removeCallbackForHandle(void *handle) { auto isCallbackForHandle = [handle](const Callback &cb) { return cb.handle == handle; }; callback_links.erase(std::remove_if(callback_links.begin(), callback_links.end(), isCallbackForHandle)); } void DPlatformSettings::registerSignalCallback(DPlatformSettings::SignalFunc func, void *handle) { SignalCallback callback = { func, handle }; signal_callback_links.push_back(callback); } void DPlatformSettings::removeSignalCallback(void *handle) { auto isCallbackForHandle = [handle](const SignalCallback &cb) { return cb.handle == handle; }; signal_callback_links.erase(std::remove_if(signal_callback_links.begin(), signal_callback_links.end(), isCallbackForHandle)); } void DPlatformSettings::handlePropertyChanged(const QByteArray &property, const QVariant &value) { for (auto callback : callback_links) { callback.func(property, value, callback.handle); } } void DPlatformSettings::handleNotify(const QByteArray &signal, qint32 data1, qint32 data2) { for (auto callback : signal_callback_links) { callback.func(signal, data1, data2, callback.handle); } } DGUI_END_NAMESPACE dtkgui-5.7.12/tests/platform-plugin-test/dplatformsettings.h000066400000000000000000000034021476226661100242700ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DPLATFORMSETTINGS_H #define DPLATFORMSETTINGS_H #include "dtkgui_global.h" #include QT_BEGIN_NAMESPACE class QByteArray; QT_END_NAMESPACE DGUI_BEGIN_NAMESPACE class DPlatformSettings { public: virtual ~DPlatformSettings() {} virtual bool initialized() const { return true; } virtual bool isEmpty() const { return false; } virtual bool contains(const QByteArray &property) const = 0; virtual QVariant setting(const QByteArray &property) const = 0; virtual void setSetting(const QByteArray &property, const QVariant &value) = 0; virtual QByteArrayList settingKeys() const = 0; virtual void emitSignal(const QByteArray &signal, qint32 data1, qint32 data2) = 0; typedef void (*PropertyChangeFunc)(const QByteArray &name, const QVariant &property, void *handle); void registerCallback(PropertyChangeFunc func, void *handle); void removeCallbackForHandle(void *handle); typedef void (*SignalFunc)(const QByteArray &signal, qint32 data1, qint32 data2, void *handle); void registerSignalCallback(SignalFunc func, void *handle); void removeSignalCallback(void *handle); protected: void handlePropertyChanged(const QByteArray &property, const QVariant &value); void handleNotify(const QByteArray &signal, qint32 data1, qint32 data2); struct Q_DECL_HIDDEN Callback { PropertyChangeFunc func; void *handle; }; struct Q_DECL_HIDDEN SignalCallback { SignalFunc func; void *handle; }; std::vector callback_links; std::vector signal_callback_links; }; DGUI_END_NAMESPACE #endif // DPLATFORMSETTINGS_H dtkgui-5.7.12/tests/platform-plugin-test/dummysettings.cpp000066400000000000000000000037021476226661100237710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dummysettings.h" #include class DummySettingsPrivate : public QObject { public: DummySettingsPrivate(DummySettings *q, const QString &domain, QObject *parent = nullptr); ~DummySettingsPrivate(); protected: QString domain; QByteArrayList keys; DummySettings *q_ptr = nullptr; bool initialized = true; Q_DECLARE_PUBLIC(DummySettings) }; DummySettingsPrivate::DummySettingsPrivate(DummySettings *q, const QString &domain, QObject *parent) : QObject(parent) , domain(domain) , q_ptr(q) { } DummySettingsPrivate::~DummySettingsPrivate() { } DummySettings::DummySettings(const QString &domain) :d_ptr(new DummySettingsPrivate(this, domain)) { } DummySettings::~DummySettings() { } bool DummySettings::initialized() const { Q_D(const DummySettings); return d->initialized; } bool DummySettings::isEmpty() const { Q_D(const DummySettings); return d->keys.isEmpty(); } bool DummySettings::contains(const QByteArray &property) const { Q_D(const DummySettings); return d->property(property.data()).isValid(); } QVariant DummySettings::setting(const QByteArray &property) const { Q_D(const DummySettings); return d->property(property.data()); } void DummySettings::setSetting(const QByteArray &property, const QVariant &value) { if (setting(property) == value) return; Q_D(DummySettings); if (!d->keys.contains(property)) d->keys << property; d->setProperty(property.data(), value); // call baseobject's propertychanged handlePropertyChanged(property, value); } QByteArrayList DummySettings::settingKeys() const { Q_D(const DummySettings); return d->keys; } void DummySettings::emitSignal(const QByteArray &signal, qint32 data1, qint32 data2) { qInfo() << "emitSignal[" << signal << "] "<< data1 << data2; } dtkgui-5.7.12/tests/platform-plugin-test/dummysettings.h000066400000000000000000000016721476226661100234420ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DUMMYSETTINGS_H #define DUMMYSETTINGS_H #include #include "dplatformsettings.h" DGUI_USE_NAMESPACE class DummySettingsPrivate; class DummySettings : public DPlatformSettings { public: explicit DummySettings(const QString &domain = QString()); virtual ~DummySettings(); virtual bool initialized() const; virtual bool isEmpty() const; virtual bool contains(const QByteArray &property) const; virtual QVariant setting(const QByteArray &property) const; virtual void setSetting(const QByteArray &property, const QVariant &value); virtual QByteArrayList settingKeys() const; virtual void emitSignal(const QByteArray &signal, qint32 data1, qint32 data2); private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(DummySettings) }; #endif // DUMMYSETTINGS_H dtkgui-5.7.12/tests/platform-plugin-test/main.cpp000066400000000000000000000013211476226661100217740ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include "qminimalintegration.h" class MinimalIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "minimal.json") public: QPlatformIntegration *create(const QString&, const QStringList&) override; }; QPlatformIntegration *MinimalIntegrationPlugin::create(const QString& system, const QStringList& paramList) { if (!system.compare("minimal", Qt::CaseInsensitive)) return new MinimalIntegration(paramList); return nullptr; } #include "main.moc" dtkgui-5.7.12/tests/platform-plugin-test/minimal.json000066400000000000000000000000361476226661100226670ustar00rootroot00000000000000{ "Keys": [ "minimal" ] } dtkgui-5.7.12/tests/platform-plugin-test/qminimalbackingstore.cpp000066400000000000000000000015051476226661100252570ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "qminimalbackingstore.h" #include "qminimalintegration.h" #include "qscreen.h" #include #include #include MinimalBackingStore::MinimalBackingStore(QWindow *window) : QPlatformBackingStore(window) { } MinimalBackingStore::~MinimalBackingStore() { } QPaintDevice *MinimalBackingStore::paintDevice() { return &mImage; } void MinimalBackingStore::flush(QWindow *, const QRegion &, const QPoint &) { } void MinimalBackingStore::resize(const QSize &size, const QRegion &) { QImage::Format format = QGuiApplication::primaryScreen()->handle()->format(); if (mImage.size() != size) mImage = QImage(size, format); } dtkgui-5.7.12/tests/platform-plugin-test/qminimalbackingstore.h000066400000000000000000000012431476226661100247230ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef QBACKINGSTORE_MINIMAL_H #define QBACKINGSTORE_MINIMAL_H #include #include #include class MinimalBackingStore : public QPlatformBackingStore { public: MinimalBackingStore(QWindow *window); ~MinimalBackingStore() override; QPaintDevice *paintDevice() override; void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override; void resize(const QSize &size, const QRegion &staticContents) override; private: QImage mImage; }; #endif dtkgui-5.7.12/tests/platform-plugin-test/qminimalintegration.cpp000066400000000000000000000044121476226661100251270ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "qminimalintegration.h" #include "qminimalbackingstore.h" #include "dplatformnativeinterface.h" #include #include #include #include #include #include #include #include MinimalIntegration::MinimalIntegration(const QStringList ¶meters) { m_primaryScreen = new MinimalScreen(); m_primaryScreen->mGeometry = QRect(0, 0, 240, 320); m_primaryScreen->mDepth = 32; m_primaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied; QWindowSystemInterface::handleScreenAdded(m_primaryScreen); } MinimalIntegration::~MinimalIntegration() { QWindowSystemInterface::handleScreenRemoved(m_primaryScreen); } QPlatformWindow *MinimalIntegration::createPlatformWindow(QWindow *window) const { Q_UNUSED(window); QPlatformWindow *w = new QPlatformWindow(window); w->requestActivateWindow(); return w; } QPlatformBackingStore *MinimalIntegration::createPlatformBackingStore(QWindow *window) const { return new MinimalBackingStore(window); } QAbstractEventDispatcher *MinimalIntegration::createEventDispatcher() const { return createUnixEventDispatcher(); } QPlatformServices *MinimalIntegration::services() const { if (!m_services) m_services.reset(new QGenericUnixServices); return m_services.get(); } QPlatformNativeInterface *MinimalIntegration::nativeInterface() const { if (!m_nativeInterface) m_nativeInterface.reset(new DPlatformNativeInterface); return m_nativeInterface.get(); } QStringList MinimalIntegration::themeNames() const { QStringList list = QPlatformIntegration::themeNames(); const QByteArray desktop_session = qgetenv("DESKTOP_SESSION"); if (desktop_session.isEmpty() || desktop_session.startsWith("deepin")) list.prepend("deepin"); return list; } MinimalIntegration *MinimalIntegration::instance() { return static_cast(QGuiApplicationPrivate::platformIntegration()); } dtkgui-5.7.12/tests/platform-plugin-test/qminimalintegration.h000066400000000000000000000027461476226661100246040ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 Uniontech Software Technology Co.,Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef QPLATFORMINTEGRATION_MINIMAL_H #define QPLATFORMINTEGRATION_MINIMAL_H #include #include #include class MinimalScreen : public QPlatformScreen { public: MinimalScreen() : mDepth(32), mFormat(QImage::Format_ARGB32_Premultiplied) {} QRect geometry() const override { return mGeometry; } int depth() const override { return mDepth; } QImage::Format format() const override { return mFormat; } public: QRect mGeometry; int mDepth; QImage::Format mFormat; QSize mPhysicalSize; }; class MinimalIntegration : public QPlatformIntegration { public: explicit MinimalIntegration(const QStringList ¶meters); ~MinimalIntegration() override; QPlatformWindow *createPlatformWindow(QWindow *window) const override; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; QAbstractEventDispatcher *createEventDispatcher() const override; QPlatformServices *services() const override; QPlatformNativeInterface *nativeInterface() const override; QStringList themeNames() const override; static MinimalIntegration *instance(); private: mutable QScopedPointer m_nativeInterface; mutable QScopedPointer m_services; MinimalScreen *m_primaryScreen; }; #endif dtkgui-5.7.12/tests/res.qrc000066400000000000000000000016251476226661100155560ustar00rootroot00000000000000 images/logo_icon.png images/logo_icon.svg images/dci_heart_dci_hover.webp images/dci_heart_dci_normal.webp images/dci_heart_dci_pressed.webp ../examples/animation-dci/dci_heart.dci ../examples/animation-dci/3depict.dci images/deepin/index.theme images/deepin/cs_rect_64.svg actions/icon_Layout_16px.svg dcis/selected_indicator.dci dtkgui-5.7.12/tests/src/000077500000000000000000000000001476226661100150415ustar00rootroot00000000000000dtkgui-5.7.12/tests/src/ut_builtinengine.cpp000066400000000000000000000135331476226661100211160ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #define private public #include "dbuiltiniconengine_p.h" #undef private DGUI_USE_NAMESPACE #define ICONNAME "icon_Layout" #define ICONSIZE 16 class ut_DBuiltinIconEngine : public testing::Test { protected: void SetUp() override; void TearDown() override; DBuiltinIconEngine *mIconEngine; }; void ut_DBuiltinIconEngine::SetUp() { mIconEngine = new DBuiltinIconEngine(ICONNAME); } void ut_DBuiltinIconEngine::TearDown() { delete mIconEngine; } QIconLoaderEngineEntry *firstEntry(const QThemeIconEntries &entries) { #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) QIconLoaderEngineEntry *entry = entries.first(); #else QIconLoaderEngineEntry *entry = entries.begin()->get(); #endif return entry; } TEST_F(ut_DBuiltinIconEngine, loadIcon) { const QThemeIconInfo &themeInfo = mIconEngine->loadIcon(ICONNAME, DGuiApplicationHelper::instance()->themeType()); ASSERT_EQ(themeInfo.iconName, ICONNAME); QIconLoaderEngineEntry *entry = firstEntry(themeInfo.entries); QString builtinActionPath = ":/icons/deepin/builtin/actions"; ASSERT_TRUE(entry->filename.contains(ICONNAME)); ASSERT_EQ(entry->dir.path, builtinActionPath); ASSERT_EQ(entry->dir.size, ICONSIZE); ASSERT_EQ(entry->dir.type, QIconDirInfo::Scalable); #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) ASSERT_FALSE(entry->pixmap(QSize(ICONSIZE, ICONSIZE), QIcon::Normal, QIcon::On, 1.0).isNull()); #else ASSERT_FALSE(entry->pixmap(QSize(ICONSIZE, ICONSIZE), QIcon::Normal, QIcon::On).isNull()); #endif #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) for (auto item : themeInfo.entries) { delete item; } #endif } TEST_F(ut_DBuiltinIconEngine, actualSize) { QSize size(ICONSIZE, ICONSIZE); QSize iconSize = mIconEngine->actualSize(size, QIcon::Normal, QIcon::On); ASSERT_FALSE(iconSize.isEmpty()); QIconLoaderEngineEntry *entry = firstEntry(mIconEngine->m_info.entries); if (entry->dir.type == QIconDirInfo::Scalable) { ASSERT_EQ(iconSize, size); } else { bool isTrue = (iconSize.width() <= qMin(iconSize.width(), iconSize.height())) && (iconSize.height() <= qMin(iconSize.width(), iconSize.height())); ASSERT_TRUE(isTrue); } } TEST_F(ut_DBuiltinIconEngine, pixmap) { QPixmap iconenginePixmap = mIconEngine->pixmap(QSize(ICONSIZE, ICONSIZE), QIcon::Normal, QIcon::On); ASSERT_FALSE(iconenginePixmap.isNull()); } TEST_F(ut_DBuiltinIconEngine, paint) { QImage iconImage(QSize(ICONSIZE, ICONSIZE), QImage::Format_ARGB32); QPainter iconPainter(&iconImage); mIconEngine->paint(&iconPainter, QRect({0, 0}, iconImage.size()), QIcon::Normal, QIcon::On); ASSERT_FALSE(iconImage.isNull()); } TEST_F(ut_DBuiltinIconEngine, key) { ASSERT_EQ(mIconEngine->key(), "DBuiltinIconEngine"); } TEST_F(ut_DBuiltinIconEngine, clone) { auto clone = mIconEngine->clone(); ASSERT_FALSE(!clone); delete clone; } TEST_F(ut_DBuiltinIconEngine, read) { QByteArray data; uint key = 1; bool followSystemTheme = true; QString iconName = ICONNAME; QDataStream out(&data, QIODevice::WriteOnly); out << iconName << key << followSystemTheme; QDataStream in(&data, QIODevice::ReadOnly); mIconEngine->read(in); ASSERT_EQ(mIconEngine->m_iconName, iconName); ASSERT_EQ(mIconEngine->m_key, key); ASSERT_EQ(mIconEngine->m_followSystemTheme, followSystemTheme); } TEST_F(ut_DBuiltinIconEngine, write) { QByteArray data; QDataStream out(&data, QIODevice::WriteOnly); mIconEngine->write(out); uint key = 0; bool followSystemTheme = false; QString iconName; QDataStream in(&data, QIODevice::ReadOnly); in >> iconName >> key >> followSystemTheme; ASSERT_EQ(mIconEngine->m_iconName, iconName); ASSERT_EQ(mIconEngine->m_key, key); ASSERT_EQ(mIconEngine->m_followSystemTheme, followSystemTheme); } TEST_F(ut_DBuiltinIconEngine, iconName) { ASSERT_EQ(mIconEngine->iconName(), ICONNAME); } TEST_F(ut_DBuiltinIconEngine, ensureLoaded) { mIconEngine->ensureLoaded(); ASSERT_EQ(mIconEngine->m_key, DGuiApplicationHelper::instance()->themeType()); ASSERT_TRUE(mIconEngine->m_initialized); ASSERT_EQ(mIconEngine->m_info.iconName, ICONNAME); QIconLoaderEngineEntry *entry = firstEntry(mIconEngine->m_info.entries); QString builtinActionPath = ":/icons/deepin/builtin/actions"; ASSERT_TRUE(entry->filename.contains(ICONNAME)); ASSERT_EQ(entry->dir.path, builtinActionPath); ASSERT_EQ(entry->dir.size, ICONSIZE); ASSERT_EQ(entry->dir.type, QIconDirInfo::Scalable); } TEST_F(ut_DBuiltinIconEngine, hasIcon) { mIconEngine->ensureLoaded(); ASSERT_TRUE(mIconEngine->hasIcon()); } TEST_F(ut_DBuiltinIconEngine, virtual_hook) { void *arg; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QIconEngine::AvailableSizesArgument data; arg = reinterpret_cast(&data); mIconEngine->virtual_hook(QIconEngine::AvailableSizesHook, arg); ASSERT_FALSE(data.sizes.isEmpty()); QString icon_name; arg = reinterpret_cast(&icon_name); mIconEngine->virtual_hook(QIconEngine::IconNameHook, arg); ASSERT_EQ(icon_name, ICONNAME); #endif bool isNull = true; arg = reinterpret_cast(&isNull); mIconEngine->virtual_hook(QIconEngine::IsNullHook, arg); ASSERT_FALSE(isNull); QIconEngine::ScaledPixmapArgument pixmapData; // 参数值会在函数内部进行判断,需要初始化后传入 并判断函数是否执行成功 pixmapData.size = QSize(ICONSIZE, ICONSIZE); pixmapData.scale = 1; arg = reinterpret_cast(&pixmapData); mIconEngine->virtual_hook(QIconEngine::ScaledPixmapHook, arg); ASSERT_FALSE(pixmapData.pixmap.isNull()); } dtkgui-5.7.12/tests/src/ut_dciiconengine.cpp000066400000000000000000000047471476226661100210670ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include "dciiconengine_p.h" DGUI_USE_NAMESPACE class ut_DDciIconEngine : public testing::Test { protected: void SetUp() override; void TearDown() override; DDciIconEngine *mIconEngine = nullptr; }; void ut_DDciIconEngine::SetUp() { mIconEngine = new DDciIconEngine("test_selected_indicator"); } void ut_DDciIconEngine::TearDown() { delete mIconEngine; } TEST_F(ut_DDciIconEngine, actualSize) { QSize size(32, 32); QSize iconSize = mIconEngine->actualSize(size, QIcon::Normal, QIcon::On); ASSERT_FALSE(iconSize.isEmpty()); ASSERT_EQ(iconSize, QSize(16, 16)); // 该图标只有16这个大小。。 } TEST_F(ut_DDciIconEngine, pixmap) { QPixmap iconenginePixmap = mIconEngine->pixmap(QSize(32, 32), QIcon::Normal, QIcon::On); ASSERT_FALSE(iconenginePixmap.isNull()); } TEST_F(ut_DDciIconEngine, paint) { QImage iconImage(QSize(32, 32), QImage::Format_ARGB32); QPainter iconPainter(&iconImage); mIconEngine->paint(&iconPainter, QRect({0, 0}, iconImage.size()), QIcon::Normal, QIcon::On); ASSERT_FALSE(iconImage.isNull()); } TEST_F(ut_DDciIconEngine, key) { QIcon icon(new DDciIconEngine("test_selected_indicator")); ASSERT_EQ(icon.data_ptr()->engine->key(), "DDciIconEngine"); } TEST_F(ut_DDciIconEngine, clone) { auto clone = mIconEngine->clone(); ASSERT_FALSE(!clone); delete clone; } TEST_F(ut_DDciIconEngine, read) { QByteArray data; QString iconName = "test_selected_indicator"; QString iconThemeName = DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName(); QDataStream out(&data, QIODevice::WriteOnly); out << iconThemeName << iconName; QDataStream in(&data, QIODevice::ReadOnly); mIconEngine->read(in); ASSERT_EQ(mIconEngine->iconName(), iconName); } TEST_F(ut_DDciIconEngine, write) { QByteArray data; QDataStream out(&data, QIODevice::WriteOnly); mIconEngine->write(out); QString iconName, iconThemeName; QDataStream in(&data, QIODevice::ReadOnly); in >> iconThemeName >> iconName ; ASSERT_EQ(mIconEngine->iconName(), iconName); } TEST_F(ut_DDciIconEngine, iconName) { ASSERT_EQ(mIconEngine->iconName(), "test_selected_indicator"); } dtkgui-5.7.12/tests/src/ut_ddciicon.cpp000066400000000000000000000020441476226661100200310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "ddciicon.h" #include DGUI_USE_NAMESPACE class ut_DDciIcon : public DTest { public: ut_DDciIcon() : icon(QStringLiteral(":/images/dci_heart.dci")) {} ~ut_DDciIcon() override {} DDciIcon icon; }; TEST_F(ut_DDciIcon, isNull) { ASSERT_FALSE(icon.isNull()); } TEST_F(ut_DDciIcon, actualSize) { DDciIconMatchResult res = icon.matchIcon(64, DDciIcon::Light, DDciIcon::Normal); int size = icon.actualSize(res); ASSERT_EQ(size, 100); } TEST_F(ut_DDciIcon, pixmap) { EXPECT_EQ(icon.pixmap(1, 0, DDciIcon::Light).size().height(), 100); // invalid size 0 EXPECT_EQ(icon.pixmap(1, 64, DDciIcon::Light).size().height(), 64); EXPECT_EQ(icon.pixmap(1.25, 64, DDciIcon::Light).size().height(), 80); // 64 * 1.25 EXPECT_EQ(icon.pixmap(1, 100, DDciIcon::Light).size().height(), 100); EXPECT_EQ(icon.pixmap(1, 256, DDciIcon::Light).size().height(), 256); } dtkgui-5.7.12/tests/src/ut_ddciiconpalette.cpp000066400000000000000000000055701476226661100214170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "ddciiconpalette.h" #include #include #include DGUI_USE_NAMESPACE static QVariant property(const DDciIconPalette &pa, const char *name) { const QMetaObject *meta = &pa.staticMetaObject; int id = meta->indexOfProperty(name); if (id < 0) return QVariant(); QMetaProperty p = meta->property(id); if (!p.isReadable()) qWarning("%s::property: Property \"%s\" invalid or does not exist", meta->className(), name); return p.readOnGadget(&pa); } static bool setProperty(DDciIconPalette &pa, const char *name, const QVariant &var) { const QMetaObject *meta = &pa.staticMetaObject; int id = meta->indexOfProperty(name); if (id < 0) { qWarning("%s::setProperty: Property \"%s\" invalid," "not support dynamic property..", meta->className(), name); return false; } QMetaProperty p = meta->property(id); if (!p.isWritable()) qWarning("%s::setProperty: Property \"%s\" invalid," " read-only or does not exist", meta->className(), name); return p.writeOnGadget(&pa, var); } TEST(ut_DDciIconPalette, color) { DDciIconPalette pa(Qt::red, Qt::green, Qt::black, Qt::white); #define testColor(role, setFunc,color1, color2) do { \ Q_ASSERT(color1!=color2); \ ASSERT_EQ(pa.role(), color1); \ ASSERT_EQ(property(pa, QT_STRINGIFY(role)), color1); \ pa.setFunc(color2); \ ASSERT_EQ(pa.role(), color2); \ ASSERT_EQ(property(pa, QT_STRINGIFY(role)), color2); \ setProperty(pa, #role, QColor(color1)); \ ASSERT_EQ(pa.role(), color1); \ ASSERT_EQ(property(pa, QT_STRINGIFY(role)), color1); \ } while(false); testColor(foreground, setForeground, QColor(Qt::red), QColor(Qt::green)); testColor(background, setBackground, QColor(Qt::green), QColor(Qt::red)); testColor(highlight, setHighlight,QColor(Qt::black), QColor(Qt::white)); testColor(highlightForeground, setHighlightForeground, QColor(Qt::white), QColor(Qt::black)); } TEST(ut_DDciIconPalette, convertToString_convertFromString_operator) { DDciIconPalette pa(Qt::red, Qt::green, Qt::black, Qt::white); // convertToString QString str = DDciIconPalette::convertToString(pa); // convertFromString auto ap = DDciIconPalette::convertFromString(str); // operator != && == ASSERT_FALSE(pa != ap); } TEST(ut_DDciIconPalette, fromQPalette) { DDciIconPalette pa(Qt::red, Qt::green, Qt::black, Qt::white); QPalette qpa; qpa.setColor(QPalette::WindowText, Qt::red); qpa.setColor(QPalette::Window, Qt::green); qpa.setColor(QPalette::Highlight, Qt::black); qpa.setColor(QPalette::HighlightedText, Qt::white); ASSERT_EQ(pa, DDciIconPalette::fromQPalette(qpa)); } dtkgui-5.7.12/tests/src/ut_ddciiconplayer.cpp000066400000000000000000000273741476226661100212630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "ddciicon.h" #include "ddciiconplayer.h" #include #include #include #include #include #include DGUI_USE_NAMESPACE static void image_dye(QImage &image, const QColor &color) { QPainter pa(&image); pa.setCompositionMode(QPainter::CompositionMode_SourceIn); pa.fillRect(image.rect(), color); } TEST(ut_DDciIconImage, render) { DDciIcon icon(QStringLiteral(":/images/dci_heart.dci")); ASSERT_FALSE(icon.isNull()); { // normal auto result = icon.matchIcon(-1, DDciIcon::Light, DDciIcon::Normal); QImageReader reader(":/images/dci_heart_dci_normal.webp"); DDciIconImage image = icon.image(result, reader.size().width(), 1.0); ASSERT_FALSE(image.isNull()); ASSERT_TRUE(image.hasPalette()); QImage image1 = image.toImage(DDciIconPalette(Qt::red)); QImage image2 = reader.read().convertToFormat(image1.format()); image2.setDevicePixelRatio(1.0); image_dye(image2, Qt::red); ASSERT_EQ(image1, image2); } { // hover auto result = icon.matchIcon(-1, DDciIcon::Light, DDciIcon::Hover); QImageReader reader(":/images/dci_heart_dci_hover.webp"); DDciIconImage image = icon.image(result, reader.size().width(), 1.0); ASSERT_FALSE(image.isNull()); ASSERT_TRUE(reader.canRead()); ASSERT_TRUE(image.supportsAnimation()); ASSERT_TRUE(reader.supportsAnimation()); ASSERT_TRUE(image.atBegin()); ASSERT_EQ(image.loopCount(), reader.loopCount()); ASSERT_EQ(image.maxImageCount(), reader.imageCount()); while (!image.atEnd()) { QImage image1 = image.toImage(); QImage image2 = reader.read().convertToFormat(image1.format()); ASSERT_EQ(image1, image2); ASSERT_EQ(image.currentImageDuration(), reader.nextImageDelay()); ASSERT_TRUE(image.jumpToNextImage()); } } { // pressed auto result = icon.matchIcon(-1, DDciIcon::Light, DDciIcon::Pressed); QImageReader reader(":/images/dci_heart_dci_pressed.webp"); DDciIconImage image = icon.image(result, reader.size().width(), 1.0); ASSERT_FALSE(image.isNull()); ASSERT_TRUE(reader.canRead()); ASSERT_TRUE(image.supportsAnimation()); ASSERT_TRUE(reader.supportsAnimation()); ASSERT_TRUE(image.atBegin()); ASSERT_EQ(image.loopCount(), reader.loopCount()); ASSERT_EQ(image.maxImageCount(), reader.imageCount()); while (!image.atEnd()) { QImage image1 = image.toImage(); QImage image2 = reader.read().convertToFormat(image1.format()); ASSERT_EQ(image1, image2); ASSERT_EQ(image.currentImageDuration(), reader.nextImageDelay()); ASSERT_TRUE(image.jumpToNextImage()); } } } class ut_DDciIconPlayer : public DTest { protected: ut_DDciIconPlayer() : update_signal_spy(&player, &DDciIconPlayer::updated) {} void SetUp() override; void TearDown() override; DDciIconPlayer player; QSignalSpy update_signal_spy; }; void ut_DDciIconPlayer::SetUp() { DDciIcon icon(QStringLiteral(":/images/dci_heart.dci")); ASSERT_FALSE(icon.isNull()); player.setIcon(icon); player.setTheme(DDciIcon::Light); player.setIconSize(200); player.setDevicePixelRatio(1.0); player.setPalette(DDciIconPalette(Qt::red)); qputenv("D_DTK_DCI_PLAYER_IGNORE_ANIMATION_LOOP", "1"); } void ut_DDciIconPlayer::TearDown() { qunsetenv("D_DTK_DCI_PLAYER_IGNORE_ANIMATION_LOOP"); } TEST_F(ut_DDciIconPlayer, play) { QImageReader reader(":/images/dci_heart_dci_hover.webp"); update_signal_spy.clear(); player.play(DDciIcon::Hover); while (update_signal_spy.wait(100)); ASSERT_EQ(update_signal_spy.count(), reader.imageCount()); } TEST_F(ut_DDciIconPlayer, state) { player.abort(); ASSERT_EQ(player.state(), DDciIconPlayer::Idle); QSignalSpy state_changed_signal_spy(&player, &DDciIconPlayer::stateChanged); player.play(DDciIcon::Hover); ASSERT_EQ(player.state(), DDciIconPlayer::Busy); ASSERT_TRUE(state_changed_signal_spy.wait(2000)); ASSERT_EQ(player.state(), DDciIconPlayer::Idle); ASSERT_EQ(state_changed_signal_spy.count(), 2); player.play(DDciIcon::Pressed); ASSERT_EQ(player.state(), DDciIconPlayer::Busy); player.stop(); ASSERT_EQ(player.state(), DDciIconPlayer::Idle); ASSERT_EQ(state_changed_signal_spy.count(), 4); player.setMode(DDciIcon::Normal); player.setMode(DDciIcon::Pressed); ASSERT_TRUE(update_signal_spy.wait(100)); ASSERT_EQ(player.state(), DDciIconPlayer::Busy); player.abort(); ASSERT_FALSE(update_signal_spy.wait(100)); ASSERT_EQ(player.state(), DDciIconPlayer::Idle); ASSERT_EQ(state_changed_signal_spy.count(), 6); player.setMode(DDciIcon::Normal); int idle_count = 0; while (update_signal_spy.wait(100)) if (player.state() == DDciIconPlayer::Idle) ++idle_count; ASSERT_EQ(idle_count, 1); ASSERT_EQ(state_changed_signal_spy.count(), 8); } TEST_F(ut_DDciIconPlayer, setMode) { QImageReader hover(":/images/dci_heart_dci_hover.webp"); QImageReader pressed(":/images/dci_heart_dci_pressed.webp"); player.setMode(DDciIcon::Normal); player.abort(); ASSERT_EQ(player.state(), DDciIconPlayer::Idle); { // normal -> hover update_signal_spy.clear(); player.setMode(DDciIcon::Hover); while (update_signal_spy.wait(100)); ASSERT_EQ(update_signal_spy.count(), hover.imageCount()); } { // hover -> pressed update_signal_spy.clear(); player.setMode(DDciIcon::Pressed); while (update_signal_spy.wait(100)); ASSERT_EQ(update_signal_spy.count(), pressed.imageCount()); } { // pressed -> hover update_signal_spy.clear(); player.setMode(DDciIcon::Hover); while (update_signal_spy.wait(100)); // the animation is stop in the hover's last image, so needs +1 ASSERT_EQ(update_signal_spy.count(), pressed.imageCount() + 1); } { // hover -> normal update_signal_spy.clear(); player.setMode(DDciIcon::Normal); while (update_signal_spy.wait(100)); // the animation is stop in the normal state, so needs +1 ASSERT_EQ(update_signal_spy.count(), hover.imageCount() + 1); } { // normal -> pressed update_signal_spy.clear(); player.setMode(DDciIcon::Pressed); while (update_signal_spy.wait(100)); ASSERT_EQ(update_signal_spy.count(), hover.imageCount() + pressed.imageCount()); } { // pressed -> normal update_signal_spy.clear(); player.setMode(DDciIcon::Normal); while (update_signal_spy.wait(100)); // the animation is stop in the normal state, so needs +1 ASSERT_EQ(update_signal_spy.count(), hover.imageCount() + pressed.imageCount() + 1); } { player.setMode(DDciIcon::Normal); player.abort(); // hover -> disabled update_signal_spy.clear(); player.setMode(DDciIcon::Hover); while (update_signal_spy.wait(100)) { player.setMode(DDciIcon::Disabled); } ASSERT_EQ(update_signal_spy.count(), 2); QImageReader normal(":/images/dci_heart_dci_normal.webp"); QImage image1 = player.currentImage(); QImage image2 = normal.read().convertToFormat(image1.format()); image2.setDevicePixelRatio(1.0); image_dye(image2, Qt::red); ASSERT_EQ(image1, image2); } { update_signal_spy.clear(); // disable -> pressed player.setMode(DDciIcon::Pressed); update_signal_spy.wait(100); ASSERT_EQ(update_signal_spy.count(), 1); QImageReader normal(":/images/dci_heart_dci_normal.webp"); QImage image1 = player.currentImage(); QImage image2 = normal.read().convertToFormat(image1.format()); image2.setDevicePixelRatio(1.0); image_dye(image2, Qt::red); ASSERT_EQ(image1, image2); } } TEST_F(ut_DDciIconPlayer, animationInvertedOrderAndContinue) { QImageReader hover(":/images/dci_heart_dci_hover.webp"); QImageReader pressed(":/images/dci_heart_dci_pressed.webp"); player.setMode(DDciIcon::Normal); player.abort(); ASSERT_EQ(player.state(), DDciIconPlayer::Idle); QVector> images; while (hover.canRead()) { const QImage &img = hover.read(); images.append({img, hover.nextImageDelay()}); } while (pressed.canRead()) { const QImage &img = pressed.read(); images.append({img, pressed.nextImageDelay()}); } update_signal_spy.clear(); player.setMode(DDciIcon::Hover); int lastImageIndex = -1; while (update_signal_spy.count() < hover.imageCount() / 2 && update_signal_spy.wait(100)) { QImage image1 = player.currentImage(); auto i = images[++lastImageIndex]; QImage image2 = i.first.convertToFormat(image1.format()); image2.setDevicePixelRatio(1.0); image_dye(image2, Qt::red); ASSERT_EQ(image1, image2); } player.setMode(DDciIcon::Normal); ASSERT_TRUE(update_signal_spy.wait(0)); do { ASSERT_TRUE(lastImageIndex > -2); // the last image is normal if (lastImageIndex < 0) { QImageReader normal(":/images/dci_heart_dci_normal.webp"); QImage image1 = player.currentImage(); QImage image2 = normal.read().convertToFormat(image1.format()); image2.setDevicePixelRatio(1.0); image_dye(image2, Qt::red); ASSERT_EQ(image1, image2); break; } ASSERT_TRUE(lastImageIndex < images.count()); QImage image1 = player.currentImage(); auto i = images[lastImageIndex]; QImage image2 = i.first.convertToFormat(image1.format()); image2.setDevicePixelRatio(1.0); image_dye(image2, Qt::red); ASSERT_EQ(image1, image2); } while (update_signal_spy.wait(images[lastImageIndex--].second + 1)); ASSERT_EQ(lastImageIndex, -1); } TEST_F(ut_DDciIconPlayer, animationSequentially) { QImageReader hover(":/images/dci_heart_dci_hover.webp"); QImageReader pressed(":/images/dci_heart_dci_pressed.webp"); player.setMode(DDciIcon::Normal); player.abort(); ASSERT_EQ(player.state(), DDciIconPlayer::Idle); QVector> images; while (hover.canRead()) { const QImage &img = hover.read(); images.append({img, hover.nextImageDelay()}); } while (pressed.canRead()) { const QImage &img = pressed.read(); images.append({img, pressed.nextImageDelay()}); } update_signal_spy.clear(); player.setMode(DDciIcon::Hover); player.setMode(DDciIcon::Pressed); int lastImageIndex = 0; while (update_signal_spy.wait(100)) { ASSERT_TRUE(lastImageIndex < images.count()); QImage image1 = player.currentImage(); auto i = images[lastImageIndex++]; QImage image2 = i.first.convertToFormat(image1.format()); image2.setDevicePixelRatio(1.0); if (lastImageIndex <= hover.imageCount()) // the pressed image is not have palette image_dye(image2, Qt::red); ASSERT_EQ(image1, image2); } ASSERT_EQ(lastImageIndex, images.count()); } TEST_F(ut_DDciIconPlayer, nonAnimationImage) { DDciIcon icon(QStringLiteral(":/images/3depict.dci")); ASSERT_FALSE(icon.isNull()); DDciIconPlayer player; update_signal_spy.clear(); player.setIcon(icon); update_signal_spy.wait(1000); ASSERT_EQ(update_signal_spy.count(), 1); ASSERT_FALSE(player.currentImage().isNull()); } dtkgui-5.7.12/tests/src/ut_dfiledrag.cpp000066400000000000000000000044031476226661100201770ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "dfiledragcommon_p.h" #include "dfiledrag.h" #include "dfiledragserver.h" #include "dfiledragclient.h" #include #include #include #include #include DGUI_USE_NAMESPACE TEST(ut_DFileDrag, filedrag) { qRegisterMetaType("DFileDragState"); QObject source; QScopedPointer s(new DFileDragServer()); QMimeData *m = new QMimeData(); // QMimeData will delete on ~DFileDrag~QDrag QScopedPointer drag(new DFileDrag(&source, s.data())); drag->setMimeData(m); ASSERT_TRUE(DFileDragClient::checkMimeData(m)); { QSignalSpy spy(s.data(), &DFileDragServer::targetDataChanged); DFileDragClient::setTargetData(m, "Key0", "Value0"); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() > 0; }, 1000)); ASSERT_EQ(s->targetData("Key0"), QVariant("Value0")); } { QUrl url = QUrl::fromLocalFile("/tmp/xxx"); QSignalSpy spy(drag.data(), &DFileDrag::targetUrlChanged); DFileDragClient::setTargetUrl(m, url); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() > 0; }, 1000)); ASSERT_EQ(drag->targetUrl(), url); } // client will delete on serverDestroyed DFileDragClient *c = new DFileDragClient(m); { ASSERT_EQ(c->progress(), 0); QSignalSpy spy(c, &DFileDragClient::progressChanged); s->setProgress(30); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() > 0; }, 1000)); ASSERT_EQ(c->progress(), 30); } { ASSERT_EQ(c->state(), 0); QSignalSpy spy(c, &DFileDragClient::stateChanged); s->setState(DFileDragState::Running); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() > 0; }, 1000)); ASSERT_EQ(c->state(), DFileDragState::Running); } { QSignalSpy spy(c, &DFileDragClient::serverDestroyed); // destroy server to emit serverDestroyed s.reset(); waitforSpy(spy, 1000); ASSERT_TRUE(spy.count() > 0); } } dtkgui-5.7.12/tests/src/ut_dfontmanager.cpp000066400000000000000000000047371476226661100207350ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "dfontmanager.h" #include DGUI_USE_NAMESPACE TEST(ut_DFontManager, StaticFunction) { enum { FontSize = 18 }; QFont tF = DFontManager::get(FontSize, qApp->font()); ASSERT_EQ(tF.pixelSize(), FontSize); ASSERT_EQ(DFontManager::fontPixelSize(tF), FontSize); tF.setPointSizeF(FontSize); ASSERT_TRUE(DFontManager::fontPixelSize(tF) > 0); } class TDFontManager : public DTestWithParam { protected: void SetUp(); void TearDown(); DFontManager *manager; }; INSTANTIATE_TEST_CASE_P(DFontManager, TDFontManager, testing::Range(int(DFontManager::T1), int(DFontManager::NSizeTypes))); void TDFontManager::SetUp() { manager = new DFontManager; } void TDFontManager::TearDown() { delete manager; } TEST_P(TDFontManager, testGetFont) { int param = GetParam(); QFont font = manager->get(DFontManager::SizeType(param), qApp->font()); ASSERT_EQ(font.pixelSize(), manager->fontPixelSize(DFontManager::SizeType(param))); manager->setBaseFont(qApp->font()); ASSERT_EQ(manager->baseFont(), qApp->font()); font = manager->get(DFontManager::SizeType(param)); ASSERT_EQ(font.pixelSize(), manager->fontPixelSize(DFontManager::SizeType(param))); manager->resetBaseFont(); ASSERT_NE(manager->baseFont(), qApp->font()); manager->setFontPixelSize(DFontManager::SizeType(param), param); ASSERT_EQ(manager->fontPixelSize(DFontManager::SizeType(param)), param); } TEST_F(TDFontManager, testFontSize) { manager->setBaseFont(qApp->font()); ASSERT_EQ(manager->t1().pixelSize(), manager->fontPixelSize(DFontManager::T1)); ASSERT_EQ(manager->t2().pixelSize(), manager->fontPixelSize(DFontManager::T2)); ASSERT_EQ(manager->t3().pixelSize(), manager->fontPixelSize(DFontManager::T3)); ASSERT_EQ(manager->t4().pixelSize(), manager->fontPixelSize(DFontManager::T4)); ASSERT_EQ(manager->t5().pixelSize(), manager->fontPixelSize(DFontManager::T5)); ASSERT_EQ(manager->t6().pixelSize(), manager->fontPixelSize(DFontManager::T6)); ASSERT_EQ(manager->t7().pixelSize(), manager->fontPixelSize(DFontManager::T7)); ASSERT_EQ(manager->t8().pixelSize(), manager->fontPixelSize(DFontManager::T8)); ASSERT_EQ(manager->t9().pixelSize(), manager->fontPixelSize(DFontManager::T9)); ASSERT_EQ(manager->t10().pixelSize(), manager->fontPixelSize(DFontManager::T10)); } dtkgui-5.7.12/tests/src/ut_dforeignwindow.cpp000066400000000000000000000032231476226661100213020ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "dforeignwindow.h" #include #include #include DGUI_BEGIN_NAMESPACE #define WmClass "_d_WmClass" #define ProcessId "_d_ProcessId" class TDForeignWindow : public DTest { protected: virtual void SetUp() { const QVector ¤tIdList = DWindowManagerHelper::instance()->currentWorkspaceWindowIdList(); foreignWindows.clear(); for (quint32 currentId : qAsConst(currentIdList)) { foreignWindows.append(DForeignWindow::fromWinId(currentId)); } } virtual void TearDown() { qDeleteAll(foreignWindows); foreignWindows.clear(); } QList foreignWindows; }; TEST_F(TDForeignWindow, wmClass) { for (auto foreignWindow : qAsConst(foreignWindows)) ASSERT_NE(foreignWindow->wmClass(), QString()); } TEST_F(TDForeignWindow, pid) { for (auto foreignWindow : qAsConst(foreignWindows)) ASSERT_NE(foreignWindow->pid(), 0); } TEST_F(TDForeignWindow, event) { QDynamicPropertyChangeEvent wmevent(WmClass); QDynamicPropertyChangeEvent pidevent(ProcessId); for (auto foreignWindow : qAsConst(foreignWindows)) { QSignalSpy wmspy(foreignWindow, SIGNAL(wmClassChanged())); ASSERT_TRUE(foreignWindow->event(&wmevent)); ASSERT_EQ(wmspy.count(), 1); QSignalSpy pidspy(foreignWindow, SIGNAL(pidChanged())); ASSERT_TRUE(foreignWindow->event(&pidevent)); ASSERT_EQ(pidspy.count(), 1); } } DGUI_END_NAMESPACE dtkgui-5.7.12/tests/src/ut_dguiapplicationhelper.cpp000066400000000000000000000116571476226661100226430ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #define private public #include "dguiapplicationhelper_p.h" #include "dguiapplicationhelper.h" #undef private #include #include DGUI_BEGIN_NAMESPACE class TDGuiApplicationHelper : public DTest { protected: virtual void SetUp() { helper = DGuiApplicationHelper::instance(); helper_d = helper->d_func(); /* read write */ readWriteDatas << DGuiApplicationHelper::Attribute::UseInactiveColorGroup << DGuiApplicationHelper::Attribute::ColorCompositing; /* read only */ readOnlyDatas << DGuiApplicationHelper::Attribute::IsDeepinPlatformTheme << DGuiApplicationHelper::Attribute::IsDXcbPlatform << DGuiApplicationHelper::Attribute::IsXWindowPlatform << DGuiApplicationHelper::Attribute::IsTableEnvironment << DGuiApplicationHelper::Attribute::IsDeepinEnvironment; } DGuiApplicationHelper *helper = nullptr; DGuiApplicationHelperPrivate *helper_d = nullptr; QList readWriteDatas; QList readOnlyDatas; }; TEST_F(TDGuiApplicationHelper, testFunction) { QColor testColor(Qt::red); QColor adjustedColor = helper->adjustColor(testColor, 0, 0, 0, 0, 0, 0, -20); ASSERT_NE(testColor, adjustedColor); ASSERT_TRUE(adjustedColor.isValid()); QColor disBlendColor = Qt::black; QColor blendedColor = helper->blendColor(testColor, disBlendColor); ASSERT_NE(testColor, blendedColor); ASSERT_TRUE(blendedColor.isValid()); DPalette tPalette; helper->generatePaletteColor(tPalette, QPalette::Window, DGuiApplicationHelper::ColorType::LightType); ASSERT_EQ(tPalette.brush(QPalette::Disabled, QPalette::Window), tPalette.brush(QPalette::Normal, QPalette::Window)); tPalette.setColor(DPalette::Window, Qt::black); helper->generatePaletteColor(tPalette, QPalette::Highlight, DGuiApplicationHelper::ColorType::DarkType); ASSERT_TRUE(tPalette.highlight().color().isValid()); // 初始化调色板为默认值 helper->generatePalette(tPalette); ASSERT_EQ(helper->isXWindowPlatform(), DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsXWindowPlatform)); ASSERT_EQ(helper->isTabletEnvironment(), DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsTableEnvironment)); ASSERT_TRUE(helper->applicationTheme()); ASSERT_TRUE(helper->systemTheme()); ASSERT_NE(helper->applicationPalette(), tPalette); qGuiApp->setAttribute(Qt::AA_SetPalette, false); helper->setPaletteType(DGuiApplicationHelper::DarkType); ASSERT_NE(helper->applicationPalette(), tPalette); helper->setApplicationPalette(tPalette); ASSERT_EQ(helper->applicationPalette(), tPalette); ASSERT_TRUE(helper->fontManager()); ASSERT_EQ(helper->toColorType(QColor(Qt::white)), DGuiApplicationHelper::LightType); ASSERT_EQ(helper->toColorType(QColor(Qt::black)), DGuiApplicationHelper::DarkType); ASSERT_EQ(helper->themeType(), DGuiApplicationHelper::DarkType); ASSERT_EQ(helper->paletteType(), DGuiApplicationHelper::DarkType); } TEST_F(TDGuiApplicationHelper, adjustColor_NoChange) { QColor testColor(Qt::red); QColor adjustedColor = helper->adjustColor(testColor, 0, 0, 0, 0, 0, 0, 0); ASSERT_EQ(testColor, adjustedColor); testColor = QColor::fromHsl(100, 100, 100, 100); adjustedColor = helper->adjustColor(testColor, 0, 0, 0, 0, 0, 0, 0); ASSERT_EQ(testColor, adjustedColor); } TEST_F(TDGuiApplicationHelper, AttributeReadWrite) { QMap oldData; for (const DGuiApplicationHelper::Attribute attribute : readWriteDatas) { oldData[attribute] = helper->testAttribute(attribute); } for (const DGuiApplicationHelper::Attribute attribute : readWriteDatas) { helper->setAttribute(attribute, !oldData[attribute]); EXPECT_EQ(helper->testAttribute(attribute), !oldData[attribute]); } } TEST_F(TDGuiApplicationHelper, AttributeReadOnly) { QMap oldData; for (const DGuiApplicationHelper::Attribute attribute : readOnlyDatas) { oldData[attribute] = helper->testAttribute(attribute); } for (const DGuiApplicationHelper::Attribute attribute : readOnlyDatas) { helper->setAttribute(attribute, !oldData[attribute]); EXPECT_EQ(helper->testAttribute(attribute), oldData[attribute]); } } TEST_F(TDGuiApplicationHelper, loadTranslator) { EXPECT_EQ(QProcess::tr("No program defined"), "No program defined"); DGuiApplicationHelper::loadTranslator({QLocale("zh_CN")}); EXPECT_EQ(QProcess::tr("No program defined"), "没有定义程序"); qInfo() << QCoreApplication::translate("TDGuiApplicationHelper", "test-translation"); } DGUI_END_NAMESPACE dtkgui-5.7.12/tests/src/ut_dicon.cpp000066400000000000000000000032521476226661100173530ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include #include DGUI_USE_NAMESPACE TEST(ut_DIcon, pixmap) { QIcon icon = QIcon::fromTheme("dde", QIcon(":/images/logo_icon.png")); ASSERT_FALSE(icon.isNull()); DIcon dicon(icon); QSize size(32, 32); qreal devicePixelRatio = qApp->devicePixelRatio(); // D_DXCB_DISABLE_OVERRIDE_HIDPI=1 QT_SCALE_FACTOR=1.25 ASSERT_FLOAT_EQ(devicePixelRatio, 1.25); // 默认单元测试未开启 AA_UseHighDpiPixmaps, 这时 pixmap 获取的 devicePixelRatio 为 1.0 // 图片大小也就是设置大小 32x32 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) ASSERT_FALSE(QGuiApplication::testAttribute(Qt::AA_UseHighDpiPixmaps)); #endif ASSERT_EQ(icon.pixmap(size).size(), size); // 开启 AA_UseHighDpiPixmaps 之后 pixmap 的大小和 qApp 缩放有关 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); ASSERT_EQ(icon.pixmap(size).size(), size * devicePixelRatio); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, false); ASSERT_EQ(dicon.pixmap(size, -1).size(), size * devicePixelRatio); ASSERT_EQ(dicon.pixmap(size, 1.0).size(), size); ASSERT_EQ(dicon.pixmap(size, 1.75).size(), size * 1.75); #else // DIcon 在 Qt6 下行为应和 QIcon 这个接口一致 ASSERT_EQ(dicon.pixmap(size, -1).size(), icon.pixmap(size, -1).size()); ASSERT_EQ(dicon.pixmap(size, 1.0).size(), icon.pixmap(size, 1.0).size()); ASSERT_EQ(dicon.pixmap(size, 1.75).size(), icon.pixmap(size, 1.75).size()); #endif } dtkgui-5.7.12/tests/src/ut_diconproxyengine.cpp000066400000000000000000000076301476226661100216470ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #define private public #include "diconproxyengine_p.h" #undef private DGUI_USE_NAMESPACE /* bool read(QDataStream &in) override; bool write(QDataStream &out) const override; private: void virtual_hook(int id, void *data) override; */ class ut_DIconProxyEngine : public testing::Test { protected: void SetUp() override; void TearDown() override; DIconProxyEngine *mIconEngine = nullptr; QSize s64 = QSize(64, 64); }; void ut_DIconProxyEngine::SetUp() { mIconEngine = new DIconProxyEngine("selected_indicator" ,DIconTheme::DontFallbackToQIconFromTheme); } void ut_DIconProxyEngine::TearDown() { delete mIconEngine; } TEST_F(ut_DIconProxyEngine, key_proxyKey) { EXPECT_EQ(mIconEngine->key(), QLatin1String("DIconProxyEngine")); EXPECT_EQ(mIconEngine->proxyKey(), QLatin1String("DBuiltinIconEngine")); } TEST_F(ut_DIconProxyEngine, themeName) { QString themeName = DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName(); EXPECT_EQ(mIconEngine->themeName(), themeName); } TEST_F(ut_DIconProxyEngine, iconName) { EXPECT_EQ(mIconEngine->iconName(), "selected_indicator"); } TEST_F(ut_DIconProxyEngine, paint) { QImage img(s64, QImage::Format_ARGB32_Premultiplied); { img.fill(Qt::transparent); QPainter p(&img); mIconEngine->paint(&p, QRect({0, 0}, s64), QIcon::Normal, QIcon::On); } QImage img1(s64, QImage::Format_ARGB32_Premultiplied); { img1.fill(Qt::transparent); QPainter p(&img1); ASSERT_TRUE(mIconEngine->m_iconEngine); mIconEngine->m_iconEngine->paint(&p, QRect({0, 0}, s64), QIcon::Normal, QIcon::On); } ASSERT_TRUE(img == img1); } TEST_F(ut_DIconProxyEngine, actualSize) { ASSERT_TRUE(mIconEngine->m_iconEngine); QSize s1 = mIconEngine->actualSize(s64, QIcon::Normal, QIcon::On); QSize s2 = mIconEngine->m_iconEngine->actualSize(s64, QIcon::Normal, QIcon::On); ASSERT_TRUE(s1 == s2); } TEST_F(ut_DIconProxyEngine, pixmap) { ASSERT_TRUE(mIconEngine->m_iconEngine); ASSERT_EQ(mIconEngine->pixmap(s64, QIcon::Normal, QIcon::On).toImage(), mIconEngine->m_iconEngine->pixmap(s64, QIcon::Normal, QIcon::On).toImage()); } TEST_F(ut_DIconProxyEngine, clone) { QScopedPointer clone(mIconEngine->clone()); ASSERT_EQ(clone->key(), mIconEngine->key()); ASSERT_EQ(clone->iconName(), mIconEngine->iconName()); } TEST_F(ut_DIconProxyEngine, read_write) { QByteArray data; { QDataStream out(&data, QIODevice::WriteOnly); mIconEngine->write(out); } QString iconName, themeName; { QDataStream in(&data, QIODevice::ReadOnly); in >> iconName >> themeName; ASSERT_EQ(themeName, mIconEngine->themeName()); ASSERT_EQ(iconName, mIconEngine->iconName()); } { auto engine = new DIconProxyEngine("selected_indicator" ,DIconTheme::DontFallbackToQIconFromTheme); QIcon icon_write(engine); QDataStream out(&data, QIODevice::WriteOnly); out << icon_write; QIcon icon_read; QDataStream in(&data, QIODevice::ReadOnly); in >> icon_read; ASSERT_TRUE(icon_read.data_ptr()->engine); EXPECT_EQ(icon_read.data_ptr()->engine->key(), engine->key()); EXPECT_EQ(icon_read.data_ptr()->engine->iconName(), engine->iconName()); } } TEST_F(ut_DIconProxyEngine, virtual_hook) { ASSERT_TRUE(mIconEngine->m_iconEngine); bool data1 = false, data2 = false; mIconEngine->virtual_hook(QIconEngine::IsNullHook, &data1); mIconEngine->m_iconEngine->virtual_hook(QIconEngine::IsNullHook, &data2); ASSERT_EQ(data1, data2); } dtkgui-5.7.12/tests/src/ut_dicontheme.cpp000066400000000000000000000031701476226661100203750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "DIconTheme" #include DGUI_USE_NAMESPACE TEST(ut_DIconTheme, builtinIcon) { const QIcon icon1 = DIconTheme::findQIcon("edit"); // 内置的图标主题中必然存在 edit 这个图标 ASSERT_FALSE(icon1.isNull()); ASSERT_TRUE(DIconTheme::isBuiltinIcon(icon1)); const QIcon icon2 = DIconTheme::findQIcon("edit", DIconTheme::IgnoreBuiltinIcons); // icon2 只可能是从外部找到的图标,不会与 icon1 相同 ASSERT_TRUE(icon1.cacheKey() != icon2.cacheKey()); #ifndef DTK_DISABLE_LIBXDG if (!icon2.isNull()) ASSERT_TRUE(DIconTheme::isXdgIcon(icon2)); #endif } TEST(ut_DIconTheme, cachedTheme) { const QIcon icon1 = DIconTheme::cached()->findQIcon("edit"); // 内置的图标主题中必然存在 edit 这个图标 ASSERT_FALSE(icon1.isNull()); ASSERT_TRUE(DIconTheme::isBuiltinIcon(icon1)); const QIcon icon2 = DIconTheme::cached()->findQIcon("edit", DIconTheme::IgnoreBuiltinIcons); // icon2 只可能是从外部找到的图标,不会与 icon1 相同 ASSERT_TRUE(icon1.cacheKey() != icon2.cacheKey()); #ifndef DTK_DISABLE_LIBXDG if (!icon2.isNull()) ASSERT_TRUE(DIconTheme::isXdgIcon(icon2)); #endif const QIcon icon1_cached1 = DIconTheme::cached()->findQIcon("edit"); ASSERT_EQ(icon1_cached1.cacheKey(), icon1.cacheKey()); DIconTheme::cached()->clear(); const QIcon icon1_cached2 = DIconTheme::cached()->findQIcon("edit"); ASSERT_NE(icon1_cached2.cacheKey(), icon1.cacheKey()); } dtkgui-5.7.12/tests/src/ut_dimagehandler.cpp000066400000000000000000000231761476226661100210520ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "dimagehandler.h" #include #include #include #include #include DGUI_USE_NAMESPACE class TDImageHandler : public DTest { public: static void SetUpTestCase(); static void TearDownTestCase(); static bool canLoadFreeImage; static bool canLoadLibRaw; static int tmpImageWidth; static int tmpImageHeight; static QString tmpFileName; protected: void SetUp(); void TearDown(); DImageHandler *handler; }; bool TDImageHandler::canLoadFreeImage = false; bool TDImageHandler::canLoadLibRaw = false; int TDImageHandler::tmpImageWidth = 300; int TDImageHandler::tmpImageHeight = 200; QString TDImageHandler::tmpFileName = QString("/tmp/TDImageHandler_shared_test.png"); void TDImageHandler::SetUpTestCase() { // Always false if build without libfreeimage and libraw. #ifndef DTK_DISABLE_EX_IMAGE_FORMAT QLibrary freeImage("freeimage", "3"); if (!freeImage.isLoaded()) { canLoadFreeImage = freeImage.load(); if (canLoadFreeImage) { freeImage.unload(); } } QLibrary libraw("libraw"); if (!libraw.isLoaded()) { canLoadLibRaw = libraw.load(); if (canLoadLibRaw) { freeImage.unload(); } } #endif QImage image(tmpImageWidth, tmpImageHeight, QImage::Format_ARGB32); image.fill(Qt::red); image.save(tmpFileName); } void TDImageHandler::TearDownTestCase() { if (QFile::exists(tmpFileName)) { QFile::remove(tmpFileName); } } void TDImageHandler::SetUp() { handler = new DImageHandler; } void TDImageHandler::TearDown() { delete handler; } TEST_F(TDImageHandler, testSetFileName) { handler->setFileName(tmpFileName); ASSERT_EQ(tmpFileName, handler->fileName()); } TEST_F(TDImageHandler, testReadImage) { handler->setFileName(tmpFileName); QImage image = handler->readImage(); ASSERT_EQ(QSize(tmpImageWidth, tmpImageHeight), image.size()); } TEST_F(TDImageHandler, testThumbnail) { handler->setFileName(tmpFileName); QImage image = handler->thumbnail(QSize(20, 20), Qt::IgnoreAspectRatio); ASSERT_EQ(QSize(20, 20), image.size()); } TEST_F(TDImageHandler, testImageFormat) { handler->setFileName(tmpFileName); ASSERT_EQ(handler->imageFormat(), QString("PNG")); handler->setFileName("/tmp/ut_parsefilesuffix.bmp"); ASSERT_EQ(handler->imageFormat(), QString("BMP")); } TEST_F(TDImageHandler, testImageSize) { ASSERT_EQ(QSize(0, 0), handler->imageSize()); handler->setFileName(tmpFileName); ASSERT_EQ(QSize(tmpImageWidth, tmpImageHeight), handler->imageSize()); } TEST_F(TDImageHandler, testImageSizeWithSVG) { QByteArray svgCode(" "); QString tmpFilePath("/tmp/TDImageHandler_testImageSizeWithSVG.svg"); QFile tmpFile(tmpFilePath); ASSERT_TRUE(tmpFile.open(QFile::WriteOnly)); tmpFile.write(svgCode); tmpFile.close(); handler->setFileName(tmpFilePath); EXPECT_EQ(QSize(300, 300), handler->imageSize()); tmpFile.remove(); } TEST_F(TDImageHandler, testFindAllMetaData) { handler->setFileName(tmpFileName); if (canLoadFreeImage) { ASSERT_FALSE(handler->findAllMetaData().isEmpty()); } else { ASSERT_TRUE(handler->findAllMetaData().isEmpty()); } } TEST_F(TDImageHandler, testClearCache) { ASSERT_TRUE(handler->readImage().isNull()); ASSERT_FALSE(handler->lastError().isEmpty()); handler->clearCache(); ASSERT_TRUE(handler->lastError().isEmpty()); } TEST_F(TDImageHandler, testSaveImage) { QString tmpSaveFileName("/tmp/TDImageHandler_testSaveImage.jpg"); handler->setFileName(tmpFileName); ASSERT_TRUE(handler->saveImage(tmpSaveFileName, "JPG")); ASSERT_TRUE(QFile::exists(tmpSaveFileName)); QFile::remove(tmpSaveFileName); } TEST_F(TDImageHandler, testRotateImage) { QImage image(300, 200, QImage::Format_ARGB32); image.fill(Qt::red); ASSERT_TRUE(handler->rotateImage(image, 90)); ASSERT_EQ(QSize(200, 300), image.size()); } TEST_F(TDImageHandler, testRotateImageFile) { ASSERT_TRUE(handler->rotateImageFile(tmpFileName, 90)); handler->setFileName(tmpFileName); ASSERT_EQ(QSize(tmpImageHeight, tmpImageWidth), handler->imageSize()); ASSERT_TRUE(handler->rotateImageFile(tmpFileName, -90)); handler->clearCache(); ASSERT_EQ(QSize(tmpImageWidth, tmpImageHeight), handler->imageSize()); } TEST_F(TDImageHandler, testIsReadable) { ASSERT_FALSE(handler->isReadable()); handler->setFileName(tmpFileName); ASSERT_TRUE(handler->isReadable()); handler->setFileName("/tmp/ut_testIsReadable.error_suffix"); ASSERT_FALSE(handler->isReadable()); } TEST_F(TDImageHandler, testIsWriteable) { ASSERT_FALSE(handler->isWriteable()); handler->setFileName(tmpFileName); ASSERT_TRUE(handler->isWriteable()); handler->setFileName("/tmp/ut_testIsWriteable.error_suffix"); ASSERT_FALSE(handler->isWriteable()); } TEST_F(TDImageHandler, testIsRotatable) { ASSERT_FALSE(handler->isRotatable()); handler->setFileName(tmpFileName); ASSERT_TRUE(handler->isRotatable()); } TEST_F(TDImageHandler, testSupportFormats) { QStringList supportFormats = DImageHandler::supportFormats(); QByteArrayList qtSupport = QImageReader::supportedImageFormats(); for (const QByteArray &support : qtSupport) { ASSERT_TRUE(supportFormats.contains(QString::fromUtf8(support).toUpper())); } if (canLoadFreeImage) { ASSERT_TRUE(supportFormats.contains("TIF")); ASSERT_TRUE(supportFormats.contains("PBMRAW")); } if (canLoadLibRaw) { ASSERT_TRUE(supportFormats.contains("RAW")); ASSERT_TRUE(supportFormats.contains("MRW")); } } TEST_F(TDImageHandler, testDetectImageFormat) { QString suffix = DImageHandler::detectImageFormat(tmpFileName); ASSERT_EQ(suffix, QString("PNG")); } TEST_F(TDImageHandler, testColorFilter) { QImage image(300, 300, QImage::Format_ARGB32); image.fill(Qt::red); ASSERT_NE(image, DImageHandler::oldColorFilter(image)); ASSERT_NE(image, DImageHandler::warmColorFilter(image)); ASSERT_NE(image, DImageHandler::coolColorFilter(image)); ASSERT_NE(image, DImageHandler::grayScaleColorFilter(image)); ASSERT_NE(image, DImageHandler::antiColorFilter(image)); ASSERT_NE(image, DImageHandler::metalColorFilter(image)); } TEST_F(TDImageHandler, testBilateralFilter) { QImage image(300, 300, QImage::Format_ARGB32); image.fill(Qt::white); QPainter painter(&image); painter.setPen(QPen(QColor(Qt::black))); painter.drawLine(0, 150, 300, 150); painter.end(); image.setPixelColor(150, 155, QColor(Qt::black)); // The color at point 150,155 will be smoother. image = DImageHandler::bilateralFilter(image, 0.02, 100); ASSERT_NE(image.pixelColor(150, 155), QColor(Qt::black)); } TEST_F(TDImageHandler, testBinaryzation) { QImage image(300, 300, QImage::Format_ARGB32); image.fill(QColor(0xEEEEEE)); QImage scaleImage = DImageHandler::binaryzation(image); ASSERT_EQ(scaleImage.pixelColor(0, 0), QColor(Qt::white)); image.fill(QColor(0x0E0E0E)); scaleImage = DImageHandler::binaryzation(image); ASSERT_EQ(scaleImage.pixelColor(0, 0), QColor(Qt::black)); } TEST_F(TDImageHandler, testGrayScale) { QImage image(300, 300, QImage::Format_ARGB32); image.fill(Qt::red); QImage scaleImage = DImageHandler::grayScale(image); QColor color = scaleImage.pixelColor(0, 0); ASSERT_EQ(color.red(), color.blue()); ASSERT_EQ(color.red(), color.green()); } TEST_F(TDImageHandler, testChangeLightAndContrast) { QImage image(300, 300, QImage::Format_ARGB32); image.fill(Qt::red); QImage scaleImage = DImageHandler::changeLightAndContrast(image, 0, 0); ASSERT_EQ(scaleImage.pixelColor(0, 0), QColor(Qt::black)); } TEST_F(TDImageHandler, testChangeBrightness) { QImage image(300, 300, QImage::Format_ARGB32); image.fill(Qt::gray); QImage scaleImage = DImageHandler::changeBrightness(image, 100); ASSERT_GT(scaleImage.pixel(0, 0), image.pixel(0, 0)); } TEST_F(TDImageHandler, testChangeTransparency) { QImage image(300, 300, QImage::Format_ARGB32); image.fill(Qt::gray); QImage scaleImage = DImageHandler::changeTransparency(image, 100); ASSERT_EQ(scaleImage.pixelColor(0, 0).alpha(), 100); } TEST_F(TDImageHandler, testChangeStauration) { QImage image(300, 300, QImage::Format_ARGB32); image.fill(Qt::gray); int oldSaturatuin = image.pixelColor(0, 0).saturation(); QImage scaleImage = DImageHandler::changeStauration(image, oldSaturatuin + 100); ASSERT_GT(scaleImage.pixelColor(0, 0).saturation(), oldSaturatuin); } TEST_F(TDImageHandler, testFlip) { QColor oldColor(Qt::red); QColor newColor(Qt::blue); QImage image(300, 300, QImage::Format_ARGB32); image.fill(oldColor); image.setPixelColor(0, 0, newColor); QImage horizontalImage = DImageHandler::flipHorizontal(image); ASSERT_NE(image, horizontalImage); ASSERT_EQ(image, horizontalImage.mirrored(true, false)); QImage verticalImage = DImageHandler::flipVertical(image); ASSERT_NE(image, verticalImage); ASSERT_EQ(image, verticalImage.mirrored(false, true)); } TEST_F(TDImageHandler, testReplacePointColor) { QColor oldColor(Qt::red); QColor newColor(Qt::blue); QImage image(300, 300, QImage::Format_ARGB32); image.fill(oldColor); QImage replaceImage = DImageHandler::replacePointColor(image, oldColor, newColor); ASSERT_FALSE(replaceImage.isNull()); ASSERT_EQ(replaceImage.pixelColor(0, 0), newColor); }dtkgui-5.7.12/tests/src/ut_dnativesettings.cpp000066400000000000000000000035761476226661100215030ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #define private public #include "dnativesettings.h" #undef private #include #include #include #include DGUI_USE_NAMESPACE DCORE_USE_NAMESPACE class ut_DNativeSettings : public testing::Test { public: static void SetUpTestSuite(); static void TearDownTestSuite(); static DNativeSettings *settings; }; DNativeSettings *ut_DNativeSettings::settings = nullptr; void ut_DNativeSettings::SetUpTestSuite() { settings = new DNativeSettings(0, "ut_dnativesettings"); } void ut_DNativeSettings::TearDownTestSuite() { delete settings; } TEST_F(ut_DNativeSettings, allKeys) { ASSERT_EQ(settings->allKeys(), QByteArrayList({"Net/ThemeName", "Qt/ActiveColor", "Net/IconThemeName", "DTK/WindowRadius"})); } TEST_F(ut_DNativeSettings, valid) { ASSERT_TRUE(settings->isValid()); } TEST_F(ut_DNativeSettings, get_set) { ASSERT_EQ(settings->getSetting("Net/ThemeName").toString(), "deepin"); settings->setSetting("Net/ThemeName", "deepin-themeName"); ASSERT_EQ(settings->getSetting("Net/ThemeName").toString(), "deepin-themeName"); } TEST_F(ut_DNativeSettings, signal) { { QSignalSpy spy(settings, &DNativeSettings::propertyChanged); settings->setSetting("Qt/ActiveColor", QColor(Qt::green)); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() > 0; }, 1000)); } { QSignalSpy spy(settings, &DNativeSettings::allKeysChanged); settings->__setAllKeys({"Net/ThemeName", "Qt/ActiveColor"}); ASSERT_TRUE(QTest::qWaitFor([&spy](){ return spy.count() > 0; }, 1000)); } } dtkgui-5.7.12/tests/src/ut_dpalette.cpp000066400000000000000000000073141476226661100200640ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include "test.h" #include "dpalette.h" DGUI_USE_NAMESPACE class TDPalette : public DTestWithParam { protected: void SetUp(); void testAttribute(int cgCount, int ctCount); DPalette palette; }; INSTANTIATE_TEST_CASE_P(DPalette, TDPalette, ::testing::Range(0, 12)); void TDPalette::SetUp() { DGuiApplicationHelper::instance()->generatePalette(palette, DGuiApplicationHelper::LightType); } TEST_P(TDPalette, testFunction) { // 测试属性设置和属性获取函数能够正常调用且返回正确数值 enum {ColorGroupCount = 6}; int ctGroup = GetParam(); for (int i = 0; i < ColorGroupCount; ++i) { QColor color = palette.color(DPalette::ColorGroup(i), DPalette::ColorType(ctGroup)); ASSERT_TRUE(color.isValid()); QBrush brush = palette.brush(DPalette::ColorGroup(i), DPalette::ColorType(ctGroup)); ASSERT_TRUE(brush.color().isValid()); color = palette.color(DPalette::ColorType(ctGroup)); ASSERT_TRUE(color.isValid()); palette.setColor(DPalette::ColorGroup(i), DPalette::ColorType(ctGroup), Qt::black); color = palette.color(DPalette::ColorGroup(i), DPalette::ColorType(ctGroup)); ASSERT_EQ(color, Qt::black); palette.setBrush(DPalette::ColorGroup(i), DPalette::ColorType(ctGroup), QBrush(Qt::blue)); brush = palette.brush(DPalette::ColorGroup(i), DPalette::ColorType(ctGroup)); ASSERT_EQ(brush.color(), Qt::blue); } palette.setColor(DPalette::ColorType(ctGroup), Qt::white); QColor color = palette.color(DPalette::ColorType(ctGroup)); ASSERT_EQ(color, Qt::white); palette.setBrush(DPalette::ColorType(ctGroup), QBrush(Qt::blue)); QBrush brush = palette.brush(DPalette::ColorType(ctGroup)); ASSERT_EQ(brush.color(), Qt::blue); } TEST_F(TDPalette, testColorFunction) { // 测试默认的调色板颜色有效 QBrush brush = palette.itemBackground(); ASSERT_TRUE(brush.color().isValid()); brush = palette.textTitle(); ASSERT_TRUE(brush.color().isValid()); brush = palette.textTips(); ASSERT_TRUE(brush.color().isValid()); brush = palette.textWarning(); ASSERT_TRUE(brush.color().isValid()); brush = palette.textLively(); ASSERT_TRUE(brush.color().isValid()); brush = palette.lightLively(); ASSERT_TRUE(brush.color().isValid()); brush = palette.darkLively(); ASSERT_TRUE(brush.color().isValid()); brush = palette.frameBorder(); ASSERT_TRUE(brush.color().isValid()); brush = palette.placeholderText(); ASSERT_TRUE(brush.color().isValid()); brush = palette.frameShadowBorder(); ASSERT_TRUE(brush.color().isValid()); #ifndef QT_NO_DATASTREAM QByteArray inArray; QDataStream in(&inArray, QIODevice::WriteOnly); // in.setVersion(QDataStream::Qt_5_11); // 直接调用左移运算符会出现二异性 先直接执行一次生成结果 in << static_cast(palette); for (int i = 0; i < DPalette::NColorGroups; ++i) { for (int j = 0; j < DPalette::NColorTypes; ++j) { in << palette.brush(DPalette::ColorGroup(i), DPalette::ColorType(j)); } } ASSERT_FALSE(inArray.isEmpty()); DPalette tp; QDataStream out(&inArray, QIODevice::ReadOnly); out >> tp; ASSERT_EQ(palette, tp); #endif #ifndef QT_NO_DEBUG_STREAM QByteArray debugData; QBuffer debugBuffer(&debugData); ASSERT_TRUE(debugBuffer.open(QIODevice::WriteOnly)); QDebug(&debugBuffer) << palette; debugBuffer.close(); EXPECT_FALSE(debugData.isEmpty()); #endif } dtkgui-5.7.12/tests/src/ut_dplatformhandle.cpp000066400000000000000000000226351476226661100214310ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include "dplatformhandle.h" #include "dwindowmanagerhelper.h" #define DXCB_PLUGIN_KEY "dxcb" #define DXCB_PLUGIN_SYMBOLIC_PROPERTY "_d_isDxcb" #define SETWMWALLPAPERPARAMETER "_d_setWmWallpaperParameter" #define CLIENTLEADER "_d_clientLeader" #define WINDOWRADIUS "_d_windowRadius" #define BORDERWIDTH "_d_borderWidth" #define BORDRCOLOR "_d_borderColor" #define SHADOWRADIUS "_d_shadowRadius" #define SHADOWOFFSET "_d_shadowOffset" #define SHADOWCOLOR "_d_shadowColor" #define CLIPPATH "_d_clipPath" #define FRAMEMASK "_d_frameMask" #define FRAMEMARGINS "_d_frameMargins" #define TRANSLUCENTBACKGROUND "_d_translucentBackground" #define ENABLESYSTEMRESIZE "_d_enableSystemResize" #define ENABLESYSTEMMOVE "_d_enableSystemMove" #define ENABLEBLURWINDOW "_d_enableBlurWindow" #define AUTOINPUTMASKBYCLIPPATH "_d_autoINPUTMASKBYCLIPPATH" #define REALWINDOWID "_d_real_content_window" DGUI_USE_NAMESPACE class TDPlatformHandle : public testing::Test { protected: void SetUp(); void TearDown(); QWindow *window; DPlatformHandle *pHandle; }; void TDPlatformHandle::SetUp() { window = new QWindow; window->create(); pHandle = new DPlatformHandle(window); ASSERT_TRUE(pHandle); } void TDPlatformHandle::TearDown() { delete window; delete pHandle; } TEST_F(TDPlatformHandle, testFunction) { if (!pHandle || qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; qDebug() << "pluginVersion is " << DPlatformHandle::pluginVersion(); EXPECT_EQ(DPlatformHandle::isDXcbPlatform(), (qApp->platformName() == DXCB_PLUGIN_KEY || qApp->property(DXCB_PLUGIN_SYMBOLIC_PROPERTY).toBool())); (DPlatformHandle::enableDXcbForWindow(window)); (DPlatformHandle::enableDXcbForWindow(window, true)); qInfo() << "TDPlatformHandle(isEnabledDXcb):" << DPlatformHandle::isEnabledDXcb(window); if (DPlatformHandle::isEnabledDXcb(window)) { EXPECT_TRUE(DPlatformHandle::setEnabledNoTitlebarForWindow(window, true)); EXPECT_TRUE(DPlatformHandle::setEnabledNoTitlebarForWindow(window, false)); } QVector wmAreaVector; wmAreaVector << dMakeWMBlurArea(0, 0, 20, 20, 4, 4); if (DWindowManagerHelper::instance()->hasBlurWindow()) { EXPECT_TRUE(pHandle->setWindowBlurAreaByWM(window, wmAreaVector)); QPainterPath pPath; pPath.addRect({0, 0, 20, 20}); EXPECT_TRUE(pHandle->setWindowBlurAreaByWM(window, {pPath})); EXPECT_TRUE(pHandle->setWindowBlurAreaByWM(wmAreaVector)); EXPECT_TRUE(pHandle->setWindowBlurAreaByWM({pPath})); } if (qApp->platformFunction(SETWMWALLPAPERPARAMETER)) { EXPECT_TRUE(pHandle->setWindowWallpaperParaByWM(window, {0, 0, 20, 20}, DPlatformHandle::FollowScreen, DPlatformHandle::PreserveAspectFit)); } else { EXPECT_FALSE(pHandle->setWindowWallpaperParaByWM(window, {0, 0, 20, 20}, DPlatformHandle::FollowScreen, DPlatformHandle::PreserveAspectFit)); } if (qApp->platformFunction(CLIENTLEADER)) { ASSERT_TRUE(DPlatformHandle::windowLeader()); } else { ASSERT_FALSE(DPlatformHandle::windowLeader()); } DPlatformHandle::setDisableWindowOverrideCursor(window, true); QVariant windowRadius = window->property(WINDOWRADIUS); if (windowRadius.isValid() && windowRadius.canConvert(QVariant::Int)) { ASSERT_EQ(pHandle->windowRadius(), windowRadius.toInt()); } QVariant borderWidth = window->property(BORDERWIDTH); if (borderWidth.isValid() && borderWidth.canConvert(QVariant::Int)) { ASSERT_EQ(pHandle->borderWidth(), borderWidth.toInt()); } else { ASSERT_EQ(pHandle->borderWidth(), 0); } QVariant borderColor = window->property(BORDRCOLOR); if (borderColor.isValid() && borderColor.canConvert(QVariant::Color)) { ASSERT_EQ(pHandle->borderColor(), borderColor.value()); } else { ASSERT_FALSE(pHandle->borderColor().isValid()); } QVariant shadowRadius = window->property(SHADOWRADIUS); if (shadowRadius.isValid() && shadowRadius.canConvert(QVariant::Int)) { ASSERT_EQ(pHandle->shadowRadius(), shadowRadius.toInt()); } else { ASSERT_FALSE(pHandle->borderColor().isValid()); } QVariant shadowOffset = window->property(SHADOWOFFSET); if (shadowOffset.isValid() && shadowOffset.canConvert(QVariant::Point)) { ASSERT_EQ(pHandle->shadowOffset(), shadowOffset.value()); } else { ASSERT_TRUE(pHandle->shadowOffset().isNull()); } QVariant shadowColor = window->property(SHADOWCOLOR); if (shadowColor.isValid() && shadowColor.canConvert(QVariant::Color)) { ASSERT_EQ(pHandle->shadowColor(), shadowColor.value()); } else { ASSERT_FALSE(pHandle->shadowColor().isValid()); } QVariant clipPath = window->property(CLIPPATH); if (clipPath.isValid() && !clipPath.value().isEmpty()) { ASSERT_EQ(pHandle->clipPath(), clipPath.value()); } else { ASSERT_TRUE(pHandle->clipPath().isEmpty()); } QVariant frameMask = window->property(FRAMEMASK); if (frameMask.isValid() && frameMask.canConvert(QVariant::Region)) { ASSERT_EQ(pHandle->frameMask(), frameMask.value()); } else { ASSERT_TRUE(pHandle->frameMask().isEmpty()); } QVariant frameMargins = window->property(FRAMEMARGINS); if (frameMargins.isValid() && !frameMargins.value().isNull()) { ASSERT_EQ(pHandle->frameMargins(), frameMargins.value()); } else { ASSERT_TRUE(pHandle->frameMargins().isNull()); } QVariant translucentBackground = window->property(TRANSLUCENTBACKGROUND); if (translucentBackground.isValid() && translucentBackground.canConvert(QVariant::Bool)) { ASSERT_EQ(pHandle->translucentBackground(), translucentBackground.toBool()); } else { ASSERT_FALSE(pHandle->translucentBackground()); } QVariant enableSystemResize = window->property(ENABLESYSTEMRESIZE); if (enableSystemResize.isValid() && enableSystemResize.canConvert(QVariant::Bool)) { ASSERT_EQ(pHandle->enableSystemResize(), enableSystemResize.toBool()); } else { ASSERT_FALSE(pHandle->enableSystemResize()); } QVariant enableSystemMove = window->property(ENABLESYSTEMMOVE); if (enableSystemMove.isValid() && enableSystemMove.canConvert(QVariant::Bool)) { ASSERT_EQ(pHandle->enableSystemMove(), enableSystemMove.toBool()); } else { ASSERT_FALSE(pHandle->enableSystemMove()); } QVariant enableBlurWindow = window->property(ENABLEBLURWINDOW); if (enableBlurWindow.isValid() && enableBlurWindow.canConvert(QVariant::Bool)) { ASSERT_EQ(pHandle->enableBlurWindow(), enableBlurWindow.toBool()); } else { ASSERT_FALSE(pHandle->enableBlurWindow()); } QVariant autoInputMaskByClipPath = window->property(AUTOINPUTMASKBYCLIPPATH); if (autoInputMaskByClipPath.isValid() && autoInputMaskByClipPath.canConvert(QVariant::Bool)) { ASSERT_EQ(pHandle->autoInputMaskByClipPath(), autoInputMaskByClipPath.toBool()); } else { ASSERT_FALSE(pHandle->autoInputMaskByClipPath()); } QVariant realWindowId = window->property(REALWINDOWID); if (enableBlurWindow.isValid() && enableBlurWindow.value() != 0) { ASSERT_EQ(pHandle->realWindowId(), enableBlurWindow.value()); } else { ASSERT_FALSE(pHandle->realWindowId()); } } TEST_F(TDPlatformHandle, testSlots) { enum { TESTBORDERWIDTH = 4, TESTOFFSET = 6, TESTRADIUS = 8 }; if (pHandle) { pHandle->setWindowRadius(TESTRADIUS); ASSERT_EQ(pHandle->windowRadius(), TESTRADIUS); pHandle->setBorderWidth(TESTBORDERWIDTH); ASSERT_EQ(pHandle->borderWidth(), TESTBORDERWIDTH); pHandle->setBorderColor(Qt::black); ASSERT_EQ(pHandle->borderColor(), Qt::black); pHandle->setShadowRadius(TESTRADIUS); ASSERT_EQ(pHandle->shadowRadius(), TESTRADIUS); pHandle->setShadowOffset({TESTOFFSET, TESTOFFSET}); ASSERT_EQ(pHandle->shadowOffset(), QPoint(TESTOFFSET, TESTOFFSET)); pHandle->setShadowColor(Qt::blue); ASSERT_EQ(pHandle->shadowColor(), Qt::blue); QPainterPath pPath; pPath.addRect({0, 0, 20, 20}); pHandle->setClipPath(pPath); ASSERT_EQ(pHandle->clipPath(), pPath); pHandle->setFrameMask(QRegion(0, 0, 10, 10)); ASSERT_EQ(pHandle->frameMask(), QRegion(0, 0, 10, 10)); pHandle->setTranslucentBackground(true); ASSERT_TRUE(pHandle->translucentBackground()); pHandle->setEnableSystemResize(true); ASSERT_TRUE(pHandle->enableSystemResize()); pHandle->setEnableSystemMove(true); ASSERT_TRUE(pHandle->enableSystemMove()); pHandle->setEnableBlurWindow(true); ASSERT_TRUE(pHandle->enableBlurWindow()); pHandle->setAutoInputMaskByClipPath(true); ASSERT_TRUE(pHandle->autoInputMaskByClipPath()); } } TEST_F(TDPlatformHandle, wmAreaDebug) { DPlatformHandle::WMBlurArea area = dMakeWMBlurArea(0, 0, 20, 20); QByteArray data; QBuffer buf(&data); ASSERT_TRUE(buf.open(QIODevice::WriteOnly)); QDebug tDebug(&buf); tDebug << area; buf.close(); ASSERT_FALSE(data.isEmpty()); } dtkgui-5.7.12/tests/src/ut_dplatformtheme.cpp000066400000000000000000000140731476226661100212750ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include "dguiapplicationhelper.h" #define private public #include "dplatformtheme.h" #include "dplatformtheme_p.h" #undef private DGUI_USE_NAMESPACE class TDPlatformTheme : public testing::Test { protected: void SetUp(); void TearDown(); QWidget *widget; DPlatformTheme *theme; DPlatformThemePrivate *theme_d; }; void TDPlatformTheme::SetUp() { widget = new QWidget; widget->createWinId(); //widget->show(); ASSERT_TRUE(widget->windowHandle()); theme = new DPlatformTheme(quint32(widget->windowHandle()->winId()), widget); theme_d = theme->d_func(); } void TDPlatformTheme::TearDown() { delete widget; } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) TEST_F(TDPlatformTheme, testFunction) { ASSERT_TRUE(theme_d->theme); ASSERT_EQ(theme->parentTheme(), theme_d->parent); ASSERT_TRUE(theme->isValid()); DPalette tPalette = theme->palette(); ASSERT_EQ(theme->fetchPalette(tPalette), tPalette); } #endif #define TEST_THEME_NAME(TYPE) \ QByteArrayLiteral("Test_Name_About_").append(TYPE) #define ASSERT_EQ_BY_VALUE(SetFunc,Func,Param) \ theme->SetFunc(Param); \ ASSERT_EQ(theme->Func(),Param); \ #define ASSERT_EQ_COLOR(SetFunc,Func,Param) \ ASSERT_EQ_BY_VALUE(SetFunc,Func,Param); \ #define ASSERT_EQ_BY_NAME(SetFunc,Func,Param) \ theme->SetFunc(TEST_THEME_NAME(Param)); \ ASSERT_EQ(theme->Func(),TEST_THEME_NAME(Param)); TEST_F(TDPlatformTheme, testSetFunction) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; if (!theme->isValid()) { qDebug() << "PlatformTheme is not valid"; return; } enum { TEST_COLOR = Qt::blue, TEST_DATA = 50 }; ASSERT_EQ_BY_VALUE(setCursorBlinkTime, cursorBlinkTime, TEST_DATA); ASSERT_EQ_BY_VALUE(setCursorBlinkTimeout, cursorBlinkTimeout, TEST_DATA); ASSERT_EQ_BY_VALUE(setCursorBlink, cursorBlink, true) ASSERT_EQ_BY_VALUE(setDoubleClickDistance, doubleClickDistance, TEST_DATA); ASSERT_EQ_BY_VALUE(setDoubleClickTime, doubleClickTime, TEST_DATA) ASSERT_EQ_BY_VALUE(setDndDragThreshold, dndDragThreshold, TEST_DATA); ASSERT_EQ_BY_NAME(setThemeName, themeName, "Theme"); ASSERT_EQ_BY_NAME(setIconThemeName, iconThemeName, "Icon"); ASSERT_EQ_BY_NAME(setSoundThemeName, soundThemeName, "Sound"); ASSERT_EQ_BY_NAME(setFontName, fontName, "Font"); ASSERT_EQ_BY_NAME(setMonoFontName, monoFontName, "MonoFont"); ASSERT_EQ_BY_NAME(setGtkFontName, gtkFontName, "GtkFont"); ASSERT_EQ_BY_VALUE(setFontPointSize, fontPointSize, TEST_DATA); ASSERT_EQ_BY_VALUE(setActiveColor, activeColor, TEST_COLOR); #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) ASSERT_EQ_COLOR(setWindow, window, TEST_COLOR); ASSERT_EQ_BY_VALUE(setWindowText, windowText, TEST_COLOR); ASSERT_EQ_BY_VALUE(setBase, base, TEST_COLOR); ASSERT_EQ_BY_VALUE(setAlternateBase, alternateBase, TEST_COLOR); ASSERT_EQ_BY_VALUE(setToolTipBase, toolTipBase, TEST_COLOR); ASSERT_EQ_BY_VALUE(setToolTipText, toolTipText, TEST_COLOR); ASSERT_EQ_BY_VALUE(setText, text, TEST_COLOR); ASSERT_EQ_BY_VALUE(setButton, button, TEST_COLOR); ASSERT_EQ_BY_VALUE(setButtonText, buttonText, TEST_COLOR); ASSERT_EQ_BY_VALUE(setBrightText, brightText, TEST_COLOR); ASSERT_EQ_BY_VALUE(setLight, light, TEST_COLOR); ASSERT_EQ_BY_VALUE(setMidlight, midlight, TEST_COLOR); ASSERT_EQ_BY_VALUE(setDark, dark, TEST_COLOR); ASSERT_EQ_BY_VALUE(setMid, mid, TEST_COLOR); ASSERT_EQ_BY_VALUE(setShadow, shadow, TEST_COLOR); ASSERT_EQ_BY_VALUE(setHighlight, highlight, TEST_COLOR); ASSERT_EQ_BY_VALUE(setLink, link, TEST_COLOR); ASSERT_EQ_BY_VALUE(setLinkVisited, linkVisited, TEST_COLOR); ASSERT_EQ_BY_VALUE(setItemBackground, itemBackground, TEST_COLOR); ASSERT_EQ_BY_VALUE(setTextTitle, textTitle, TEST_COLOR); ASSERT_EQ_BY_VALUE(setTextTips, textTips, TEST_COLOR); ASSERT_EQ_BY_VALUE(setTextWarning, textWarning, TEST_COLOR); ASSERT_EQ_BY_VALUE(setTextLively, textLively, TEST_COLOR); ASSERT_EQ_BY_VALUE(setLightLively, lightLively, TEST_COLOR); ASSERT_EQ_BY_VALUE(setDarkLively, darkLively, TEST_COLOR); ASSERT_EQ_BY_VALUE(setFrameBorder, frameBorder, TEST_COLOR); ASSERT_EQ_BY_VALUE(setWindowRadius, windowRadius, TEST_DATA / 10); #endif } #if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) TEST_F(TDPlatformTheme, palette) { DPalette pa = theme->palette(); ASSERT_EQ(theme->window(), pa.window().color()); ASSERT_EQ(theme->windowText(), pa.windowText().color()); ASSERT_EQ(theme->base(), pa.base().color()); ASSERT_EQ(theme->alternateBase(), pa.alternateBase().color()); ASSERT_EQ(theme->toolTipBase(), pa.toolTipBase().color()); ASSERT_EQ(theme->toolTipText(), pa.toolTipText().color()); ASSERT_EQ(theme->text(), pa.text().color()); ASSERT_EQ(theme->button(), pa.button().color()); ASSERT_EQ(theme->buttonText(), pa.buttonText().color()); ASSERT_EQ(theme->brightText(), pa.brightText().color()); ASSERT_EQ(theme->light(), pa.light().color()); ASSERT_EQ(theme->midlight(), pa.midlight().color()); ASSERT_EQ(theme->dark(), pa.dark().color()); ASSERT_EQ(theme->mid(), pa.mid().color()); ASSERT_EQ(theme->shadow(), pa.shadow().color()); ASSERT_EQ(theme->highlight(), pa.highlight().color()); ASSERT_EQ(theme->highlightedText(), pa.highlightedText().color()); ASSERT_EQ(theme->link(), pa.link().color()); ASSERT_EQ(theme->linkVisited(), pa.linkVisited().color()); ASSERT_EQ(theme->itemBackground(), pa.itemBackground().color()); ASSERT_EQ(theme->textTitle(), pa.textTitle().color()); ASSERT_EQ(theme->textTips(), pa.textTips().color()); ASSERT_EQ(theme->textWarning(), pa.textWarning().color()); ASSERT_EQ(theme->textLively(), pa.textLively().color()); ASSERT_EQ(theme->lightLively(), pa.lightLively().color()); ASSERT_EQ(theme->darkLively(), pa.darkLively().color()); ASSERT_EQ(theme->frameBorder(), pa.frameBorder().color()); } #endif dtkgui-5.7.12/tests/src/ut_dregionmonitor.cpp000066400000000000000000000141251476226661100213170ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "dregionmonitor.h" #include "private/dregionmonitor_p.h" #include #include #include DGUI_BEGIN_NAMESPACE class TDRegionMonitor : public DTest { protected: virtual void SetUp() { regionMonitor = new DRegionMonitor(nullptr); } virtual void TearDown() { delete regionMonitor; } DRegionMonitor *regionMonitor = nullptr; }; TEST_F(TDRegionMonitor, registerRegion) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; regionMonitor->registerRegion(); ASSERT_TRUE(regionMonitor->registered()); } TEST_F(TDRegionMonitor, registered) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; ASSERT_FALSE(regionMonitor->registered()); } TEST_F(TDRegionMonitor, watchedRegion) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; ASSERT_EQ(regionMonitor->watchedRegion(), QRegion()); } TEST_F(TDRegionMonitor, coordinateType) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; ASSERT_EQ(regionMonitor->coordinateType(), DRegionMonitor::ScaleRatio); } TEST_F(TDRegionMonitor, registerRegionArg) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; ASSERT_EQ(regionMonitor->watchedRegion(), QRegion()); QRegion r(0, 0, 600, 400); regionMonitor->registerRegion(r); ASSERT_EQ(regionMonitor->watchedRegion(), r); } TEST_F(TDRegionMonitor, unregisterRegion) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; regionMonitor->registerRegion(); ASSERT_TRUE(regionMonitor->registered()); regionMonitor->unregisterRegion(); ASSERT_FALSE(regionMonitor->registered()); } TEST_F(TDRegionMonitor, setWatchedRegion) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; ASSERT_EQ(regionMonitor->watchedRegion(), QRegion()); QRegion r(0, 0, 600, 400); regionMonitor->setWatchedRegion(r); ASSERT_EQ(regionMonitor->watchedRegion(), r); } TEST_F(TDRegionMonitor, setCoordinateType) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; ASSERT_EQ(regionMonitor->coordinateType(), DRegionMonitor::ScaleRatio); regionMonitor->setCoordinateType(DRegionMonitor::Original); ASSERT_EQ(regionMonitor->coordinateType(), DRegionMonitor::Original); } TEST_F(TDRegionMonitor, registerFlags) { #ifndef QT_NO_DEBUG_STREAM enum { TestRegionFlag = (DRegionMonitor::Motion | DRegionMonitor::Button) }; regionMonitor->setRegisterFlags(DRegionMonitor::RegisterdFlag(TestRegionFlag)); ASSERT_EQ(regionMonitor->registerFlags(), TestRegionFlag); #endif } TEST_F(TDRegionMonitor, privateFunctions) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; DRegionMonitorPrivate *region_d = regionMonitor->d_func(); ASSERT_TRUE(region_d); regionMonitor->registerRegion(); ASSERT_TRUE(region_d->registered()); region_d->registerMonitorRegion(); ASSERT_FALSE(region_d->registerKey.isEmpty()); region_d->watchedRegion = {0, 0, 30, 30}; region_d->registerMonitorRegion(); ASSERT_FALSE(region_d->registerKey.isEmpty()); region_d->unregisterMonitorRegion(); ASSERT_TRUE(region_d->registerKey.isEmpty()); enum { TestFlag = 1 | 2, TestPos = 20 }; const QString testKey = "Key_Enter"; QSignalSpy btnPressSpy(regionMonitor, SIGNAL(buttonPress(const QPoint &, const int))); region_d->_q_ButtonPress(TestFlag, TestPos, TestPos, region_d->registerKey); ASSERT_EQ(btnPressSpy.count(), 1); auto pressArguments = btnPressSpy.takeFirst(); ASSERT_EQ(pressArguments.at(0).toPoint(), region_d->deviceScaledCoordinate({TestPos, TestPos}, qApp->devicePixelRatio())); ASSERT_EQ(pressArguments.at(1).toInt(), TestFlag); QSignalSpy btnreleaseSpy(regionMonitor, SIGNAL(buttonRelease(const QPoint &, const int))); region_d->_q_ButtonRelease(TestFlag, TestPos, TestPos, region_d->registerKey); ASSERT_EQ(btnreleaseSpy.count(), 1); auto releaseArguments = btnreleaseSpy.takeFirst(); ASSERT_EQ(releaseArguments.at(0).toPoint(), region_d->deviceScaledCoordinate({TestPos, TestPos}, qApp->devicePixelRatio())); ASSERT_EQ(releaseArguments.at(1).toInt(), TestFlag); QSignalSpy cursorMoveSpy(regionMonitor, SIGNAL(cursorMove(const QPoint &))); region_d->_q_CursorMove(TestPos, TestPos, region_d->registerKey); ASSERT_EQ(cursorMoveSpy.count(), 1); auto curMoveArguments = cursorMoveSpy.takeFirst(); ASSERT_EQ(curMoveArguments.at(0).toPoint(), region_d->deviceScaledCoordinate({TestPos, TestPos}, qApp->devicePixelRatio())); QSignalSpy cursorEnterSpy(regionMonitor, SIGNAL(cursorEnter(const QPoint &))); region_d->_q_CursorEnter(TestPos, TestPos, region_d->registerKey); ASSERT_EQ(cursorEnterSpy.count(), 1); auto curEnterArguments = cursorEnterSpy.takeFirst(); ASSERT_EQ(curEnterArguments.at(0).toPoint(), region_d->deviceScaledCoordinate({TestPos, TestPos}, qApp->devicePixelRatio())); QSignalSpy cursorLeaveSpy(regionMonitor, SIGNAL(cursorLeave(const QPoint &))); region_d->_q_CursorLeave(TestPos, TestPos, region_d->registerKey); ASSERT_EQ(cursorLeaveSpy.count(), 1); auto curLeaveArguments = cursorLeaveSpy.takeFirst(); ASSERT_EQ(curLeaveArguments.at(0).toPoint(), region_d->deviceScaledCoordinate({TestPos, TestPos}, qApp->devicePixelRatio())); QSignalSpy keyPressSpy(regionMonitor, SIGNAL(keyPress(const QString &))); region_d->_q_KeyPress(testKey, TestPos, TestPos, region_d->registerKey); ASSERT_EQ(keyPressSpy.count(), 1); auto keyPressArguments = keyPressSpy.takeFirst(); ASSERT_EQ(keyPressArguments.at(0).toString(), testKey); QSignalSpy keyReleaseSpy(regionMonitor, SIGNAL(keyRelease(const QString &))); region_d->_q_KeyRelease(testKey, TestPos, TestPos, region_d->registerKey); ASSERT_EQ(keyReleaseSpy.count(), 1); auto keyReleaseArguments = keyReleaseSpy.takeFirst(); ASSERT_EQ(keyReleaseArguments.at(0).toString(), testKey); } DGUI_END_NAMESPACE dtkgui-5.7.12/tests/src/ut_dsvgrenderer.cpp000066400000000000000000000062001476226661100207450ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsvgrenderer.h" #include "test.h" #include #include #include #include #include DGUI_USE_NAMESPACE TEST(ut_DSvgRenderer, testInit) { DSvgRenderer svg_1; DSvgRenderer svg_2(QStringLiteral(":/images/logo_icon.svg")); ASSERT_FALSE(svg_1.isValid()); ASSERT_TRUE(svg_2.isValid()); QFile file(":/images/logo_icon.svg"); if (!file.open(QFile::ReadOnly)) return; QByteArray data = file.readAll(); DSvgRenderer svg_3(data); ASSERT_TRUE(svg_3.isValid()); } class TDSvgRenderer : public DTest { protected: void SetUp(); void TearDown(); DSvgRenderer *renderer; bool canLoad; }; void TDSvgRenderer::SetUp() { QLibrary rsvg("rsvg-2", "2"); if (!rsvg.isLoaded()) { canLoad = rsvg.load(); if (canLoad) { rsvg.unload(); } } renderer = new DSvgRenderer; } void TDSvgRenderer::TearDown() { delete renderer; } TEST_F(TDSvgRenderer, testLoad) { if (!canLoad) return; ASSERT_TRUE(renderer->load(QStringLiteral(":/images/logo_icon.svg"))); ASSERT_TRUE(renderer->isValid()); ASSERT_FALSE(renderer->defaultSize().isEmpty()); ASSERT_FALSE(renderer->viewBox().isEmpty()); ASSERT_FALSE(renderer->viewBoxF().isEmpty()); } static bool testPixmapHasData(const QPixmap &pixmap) { QImage image = pixmap.toImage(); image.reinterpretAsFormat(QImage::Format_RGB32); const QRgb *bits = reinterpret_cast(image.constBits()); const QRgb *end = bits + qulonglong(image.sizeInBytes()) / sizeof(QRgb); return !std::all_of(bits, end, [](QRgb r) { return r == QColor(Qt::green).rgb(); }); } #define TestRenderID QStringLiteral("#tittlebar") #define TestRenderID_NotExist QStringLiteral("#TestRsvg_notexist") TEST_F(TDSvgRenderer, testRender) { if (!canLoad) return; enum { TestPixmapSize = 16 }; ASSERT_TRUE(renderer->load(QString(":/images/logo_icon.svg"))); QPixmap tPixmap(QSize(TestPixmapSize, TestPixmapSize)); tPixmap.fill(Qt::green); QPainter tPainter(&tPixmap); renderer->render(&tPainter); ASSERT_TRUE(testPixmapHasData(tPixmap)); tPixmap.fill(Qt::green); ASSERT_FALSE(testPixmapHasData(tPixmap)); renderer->render(&tPainter, TestRenderID); ASSERT_TRUE(testPixmapHasData(tPixmap)); tPixmap.fill(Qt::green); ASSERT_FALSE(testPixmapHasData(tPixmap)); ASSERT_TRUE(renderer->elementExists(TestRenderID)); ASSERT_FALSE(renderer->elementExists(TestRenderID_NotExist)); ASSERT_FALSE(renderer->boundsOnElement(TestRenderID).isEmpty()); ASSERT_TRUE(renderer->boundsOnElement(TestRenderID_NotExist).isEmpty()); renderer->render(&tPainter, {0, 0, TestPixmapSize, TestPixmapSize}); ASSERT_TRUE(testPixmapHasData(tPixmap)); tPixmap.fill(Qt::green); ASSERT_FALSE(testPixmapHasData(tPixmap)); ASSERT_FALSE(renderer->toImage({TestPixmapSize, TestPixmapSize}).isNull()); ASSERT_FALSE(renderer->toImage({TestPixmapSize, TestPixmapSize}, TestRenderID).isNull()); } dtkgui-5.7.12/tests/src/ut_dtaskbarcontrol.cpp000066400000000000000000000032411476226661100214510ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "dtaskbarcontrol.h" #include #include DGUI_USE_NAMESPACE // 由于需要发送dbus接口 使用打桩类进行 class MockDTaskbarControl : public DTaskbarControl { public: using DTaskbarControl::DTaskbarControl; MOCK_METHOD1(sendMessage, void(const QVariantMap &)); }; class TDTaskbarControl : public DTest { protected: void SetUp(); void TearDown(); MockDTaskbarControl *control; }; void TDTaskbarControl::SetUp() { control = new MockDTaskbarControl; } void TDTaskbarControl::TearDown() { delete control; } TEST_F(TDTaskbarControl, testFunction) { enum { ProgressTestValue = 1 }; EXPECT_CALL(*control, sendMessage(testing::_)).Times(testing::AtLeast(1)); QSignalSpy valueChangedSpy(control, SIGNAL(progressChanged(double))); control->setProgress(true, ProgressTestValue); ASSERT_EQ(valueChangedSpy.count(), 1); QSignalSpy visibleChangedSpy(control, SIGNAL(progressVisibleChanged(bool))); control->setProgress(false, ProgressTestValue); ASSERT_EQ(visibleChangedSpy.count(), 1); QSignalSpy counterChangedSpy(control, SIGNAL(counterChanged(int))); control->setCounter(true, 1); ASSERT_EQ(control->counter(), 1); ASSERT_EQ(counterChangedSpy.count(), 1); QSignalSpy counterVisibleSpy(control, SIGNAL(counterVisibleChanged(bool))); control->setCounter(false, 1); ASSERT_EQ(counterVisibleSpy.count(), 1); control->setUrgency(true); control->setCounterVisible(true); ASSERT_EQ(control->counterVisible(), true); } dtkgui-5.7.12/tests/src/ut_dthumbnailprovider.cpp000066400000000000000000000076251476226661100221710ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "dthumbnailprovider.h" #include #include #include #include #include #include #include #include #include DGUI_BEGIN_NAMESPACE #ifndef UT_DThumbnailProviderPrivate #define UT_DThumbnailProviderPrivate class DThumbnailProviderPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate { public: DThumbnailProviderPrivate(DThumbnailProvider *qq); void init(); QString sizeToFilePath(DThumbnailProvider::Size size) const; QString errorString; // MAX qint64 defaultSizeLimit = INT64_MAX; QHash sizeLimitHash; QMimeDatabase mimeDatabase; static QSet hasThumbnailMimeHash; struct ProduceInfo { QFileInfo fileInfo; DThumbnailProvider::Size size; DThumbnailProvider::CallBack callback; }; QQueue produceQueue; QSet> discardedProduceInfos; bool running = true; QWaitCondition waitCondition; QReadWriteLock dataReadWriteLock; D_DECLARE_PUBLIC(DThumbnailProvider) }; #endif DGUI_END_NAMESPACE DGUI_USE_NAMESPACE class TDThumbnailProvider : public DTest { protected: void SetUp(); void TearDown(); DThumbnailProvider *provider; DThumbnailProviderPrivate *provider_d; }; void TDThumbnailProvider::SetUp() { provider = DThumbnailProvider::instance(); provider_d = provider->d_func(); } void TDThumbnailProvider::TearDown() { // gtest会释放静态部分数据 导致双重释放程序崩溃这里手动将数据清空防止崩溃事情发生 provider_d->hasThumbnailMimeHash.clear(); } #define TESTRES_PATH ":/images/logo_icon.svg" #define TESTRES_PATH_1 "no_exist" TEST_F(TDThumbnailProvider, TestCreate) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; QFileInfo fi(TESTRES_PATH); QSignalSpy finishedSpy(provider, SIGNAL(createThumbnailFinished(const QString &, const QString &))); QString ret = provider->createThumbnail(fi, DThumbnailProvider::Normal); ASSERT_FALSE(ret.isEmpty()); ASSERT_EQ(finishedSpy.count(), 1); ASSERT_FALSE(provider->thumbnailFilePath(fi, DThumbnailProvider::Normal).isEmpty()); QFileInfo fi_notexisted(TESTRES_PATH_1); QSignalSpy failedSpy(provider, SIGNAL(createThumbnailFailed(const QString &))); ret = provider->createThumbnail(fi_notexisted, DThumbnailProvider::Normal); ASSERT_TRUE(ret.isEmpty()); ASSERT_EQ(finishedSpy.count(), 1); ASSERT_FALSE(provider->errorString().isEmpty()); ASSERT_TRUE(provider->thumbnailFilePath(fi_notexisted, DThumbnailProvider::Normal).isEmpty()); } TEST_F(TDThumbnailProvider, testAttribute) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; ASSERT_TRUE(provider->hasThumbnail(QFileInfo(TESTRES_PATH))); enum { TEST_DEFALUTSIZELIMIT = 25 }; provider->setDefaultSizeLimit(TEST_DEFALUTSIZELIMIT); ASSERT_EQ(provider->defaultSizeLimit(), TEST_DEFALUTSIZELIMIT); QMimeDatabase base; auto type = base.mimeTypeForFile(TESTRES_PATH); provider->setSizeLimit(type, TEST_DEFALUTSIZELIMIT); ASSERT_EQ(provider->sizeLimit(type), TEST_DEFALUTSIZELIMIT); } void testCallBack(const QString &) { return; } TEST_F(TDThumbnailProvider, TestProducrQueue) { provider_d->running = true; provider->appendToProduceQueue(QFileInfo(TESTRES_PATH), DThumbnailProvider::Small); provider->appendToProduceQueue(QFileInfo(TESTRES_PATH), DThumbnailProvider::Large, &testCallBack); ASSERT_FALSE(provider_d->produceQueue.isEmpty()); provider->removeInProduceQueue(QFileInfo(TESTRES_PATH), DThumbnailProvider::Small); ASSERT_FALSE(provider_d->discardedProduceInfos.isEmpty()); provider_d->running = false; } dtkgui-5.7.12/tests/src/ut_dwindowgroupleader.cpp000066400000000000000000000030171476226661100221630ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include "dwindowgroupleader.h" #include #include #include DGUI_USE_NAMESPACE class TDWindowGroupLeader : public DTest { protected: void SetUp(); void TearDown(); DWindowGroupLeader *groupLeader; QWindow *window1; QWindow *window2; }; void TDWindowGroupLeader::SetUp() { groupLeader = new DWindowGroupLeader; window1 = new QWindow; window2 = new QWindow; window1->create(); window2->create(); } void TDWindowGroupLeader::TearDown() { delete groupLeader; delete window1; delete window2; } TEST_F(TDWindowGroupLeader, testFunctions) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; // 测试多种情况添加window时数据是否正常 groupLeader->addWindow(window1); groupLeader->addWindow(window2); qDebug() << "addWindow 1 & 2"; qDebug() << "groupLeaderId" << groupLeader->groupLeaderId(); qDebug() << "groupLeaderId" << groupLeader->clientLeaderId(); groupLeader->removeWindow(window1); qDebug() << "removeWindow 1"; qDebug() << "groupLeaderId" << groupLeader->groupLeaderId(); qDebug() << "groupLeaderId" << groupLeader->clientLeaderId(); groupLeader->removeWindow(window2); qDebug() << "removeWindow 2"; qDebug() << "groupLeaderId" << groupLeader->groupLeaderId(); qDebug() << "groupLeaderId" << groupLeader->clientLeaderId(); } dtkgui-5.7.12/tests/src/ut_dwindowmanagerhelper.cpp000066400000000000000000000104751476226661100224720ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "test.h" #include #include "dwindowmanagerhelper.h" #include "dforeignwindow.h" DGUI_USE_NAMESPACE class TDWindowMangerHelper : public DTest { protected: void SetUp(); DWindowManagerHelper *wm_helper; }; void TDWindowMangerHelper::SetUp() { wm_helper = DWindowManagerHelper::instance(); } TEST_F(TDWindowMangerHelper, testStaticFunction) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; QWidget *w = new QWidget; w->createWinId(); //w->show(); ASSERT_TRUE(w->windowHandle()); enum { TestMotifFunction = DWindowManagerHelper::FUNC_RESIZE | DWindowManagerHelper::FUNC_MOVE, TestAllMotifFunction = DWindowManagerHelper::FUNC_ALL}; enum { TestDecorations = DWindowManagerHelper::DECOR_BORDER | DWindowManagerHelper::DECOR_RESIZEH, TestAllDecorations = DWindowManagerHelper::DECOR_ALL }; // 测试静态函数测试是否正常 DWindowManagerHelper::setMotifFunctions(w->windowHandle(), DWindowManagerHelper::MotifFunctions(TestMotifFunction)); DWindowManagerHelper::MotifFunctions mFuncs = DWindowManagerHelper::getMotifFunctions(w->windowHandle()); if (wm_helper->windowManagerName() == DWindowManagerHelper::KWinWM) { ASSERT_EQ(mFuncs, TestMotifFunction); } else { qDebug() << "not support other wm"; } mFuncs = DWindowManagerHelper::setMotifFunctions(w->windowHandle(), DWindowManagerHelper::MotifFunctions(TestAllMotifFunction), true); ASSERT_EQ(mFuncs, TestAllMotifFunction); DWindowManagerHelper::setMotifDecorations(w->windowHandle(), DWindowManagerHelper::MotifDecorations(TestDecorations)); DWindowManagerHelper::MotifDecorations mDecos = DWindowManagerHelper::getMotifDecorations(w->windowHandle()); if (wm_helper->windowManagerName() == DWindowManagerHelper::KWinWM) ASSERT_EQ(mDecos, TestDecorations); mDecos = DWindowManagerHelper::setMotifDecorations(w->windowHandle(), DWindowManagerHelper::MotifDecorations(TestAllDecorations), true); if (wm_helper->windowManagerName() == DWindowManagerHelper::KWinWM) ASSERT_EQ(mDecos, TestAllDecorations); // 没有崩溃则测试成功 enum { TestWindowType = DWindowManagerHelper::DesktopType | DWindowManagerHelper::MenuType }; DWindowManagerHelper::setWmWindowTypes(w->windowHandle(), DWindowManagerHelper::WmWindowTypes(TestWindowType)); DWindowManagerHelper::setWmClassName(QByteArrayLiteral("TestWmClass")); DWindowManagerHelper::popupSystemWindowMenu(w->windowHandle()); delete w; } TEST_F(TDWindowMangerHelper, testFunctions) { if (qgetenv("QT_QPA_PLATFORM").contains("offscreen")) return; qDebug() << wm_helper->windowManagerNameString() << "\nhas blur window:" << wm_helper->hasBlurWindow() << "\nhas composite:" << wm_helper->hasComposite() << "\nhas not titlebar:" << wm_helper->hasNoTitlebar(); // ASSERT_TRUE(wm_helper->hasWallpaperEffect()); // ASSERT_FALSE(wm_helper->windowManagerNameString().isEmpty()); if (wm_helper->windowManagerNameString().contains(QStringLiteral("DeepinGala"))) { ASSERT_EQ(wm_helper->windowManagerName(), DWindowManagerHelper::DeepinWM); } else if (wm_helper->windowManagerNameString().contains(QStringLiteral("KWin"))) { ASSERT_EQ(wm_helper->windowManagerName(), DWindowManagerHelper::KWinWM); } else { ASSERT_EQ(wm_helper->windowManagerName(), DWindowManagerHelper::OtherWM); } if (wm_helper->windowManagerName() == DWindowManagerHelper::KWinWM) { ASSERT_FALSE(wm_helper->allWindowIdList().isEmpty()); ASSERT_FALSE(wm_helper->currentWorkspaceWindowIdList().isEmpty()); ASSERT_FALSE(wm_helper->currentWorkspaceWindows().isEmpty()); ASSERT_TRUE(wm_helper->windowFromPoint(wm_helper->currentWorkspaceWindows().first()->position())); } else { qDebug() << "allWindowIdList count:" << wm_helper->allWindowIdList().count() << "\ncurrentWorkspaceWindowIdList count:" << wm_helper->currentWorkspaceWindowIdList().count() << "\ncurrentWorkspaceWindows count:" << wm_helper->currentWorkspaceWindows().count() << "\nwindowFromPoint:" << wm_helper->windowFromPoint(QPoint()); } } dtkgui-5.7.12/tests/src/ut_xdgiconproxyengine.cpp000066400000000000000000000135461476226661100222110ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #define private public #include "xdgiconproxyengine_p.h" #include #undef private DGUI_USE_NAMESPACE class ut_XdgIconProxyEngine : public testing::Test { protected: void SetUp() override; void TearDown() override; XdgIconProxyEngine *mIconEngine = nullptr; QSize s64 = QSize(64, 64); }; void ut_XdgIconProxyEngine::SetUp() { // :/icons/deepin/xxx.svg QIconLoader::instance()->setThemeName("deepin"); mIconEngine = new XdgIconProxyEngine(new XdgIconLoaderEngine("cs_rect_64")); } void ut_XdgIconProxyEngine::TearDown() { delete mIconEngine; } TEST_F(ut_XdgIconProxyEngine, entryCacheKey) { ScalableEntry *entry = reinterpret_cast(QRandomGenerator::global()->generate()); QSet keySet; for (int i = QIcon::Normal; i <= QIcon::Selected; ++i) { for (int j = QIcon::On; j <= QIcon::Off; ++j) { quint64 key = XdgIconProxyEngine::entryCacheKey(entry, QIcon::Mode(i), QIcon::State(j)); quint64 calKey = quint64(entry) ^ (quint64(i) << 56) ^ (quint64(j) << 48); EXPECT_EQ(key, calKey); // conflict check EXPECT_FALSE(keySet.contains(key)); keySet.insert(key); } } } /* cs_rect_64.svg * +-------------+-------------+ * | | | * | Highlight | Text | * | | | * +-------------+-------------+ */ void testHighlightColor(const QPalette &pa, const QImage &img) { EXPECT_FALSE(img.isNull()); // QColor(AHSL) && QColor(ARGB) ? EXPECT_EQ(pa.highlight().color().toRgb(), img.pixelColor(QPoint(16, 16)).name()); } void testWindowTextColor(const QPalette &pa, const QImage &img) { EXPECT_FALSE(img.isNull()); EXPECT_EQ(pa.windowText().color(), img.pixelColor(QPoint(48, 16))); } void testHighlightedTextColor(const QPalette &pa, const QImage &img) { EXPECT_FALSE(img.isNull()); EXPECT_EQ(pa.highlightedText().color(), img.pixelColor(QPoint(48, 16))); } TEST_F(ut_XdgIconProxyEngine, pixmapByEntry) { QPalette pa = qApp->palette(); // ensureLoaded EXPECT_EQ(s64, mIconEngine->actualSize(s64, QIcon::Normal, QIcon::On)); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QIconLoaderEngineEntry *entry = mIconEngine->engine->entryForSize(s64); #else QIconLoaderEngineEntry *entry = mIconEngine->engine->entryForSize(mIconEngine->engine->m_info, s64); #endif ASSERT_TRUE(entry); QPixmap normalPix = mIconEngine->pixmapByEntry(entry, s64, QIcon::Normal, QIcon::On); testWindowTextColor(pa, normalPix.toImage()); QPixmap selectPix = mIconEngine->pixmapByEntry(entry, s64, QIcon::Selected, QIcon::On); testHighlightedTextColor(pa, selectPix.toImage()); testHighlightColor(pa, normalPix.toImage()); } TEST_F(ut_XdgIconProxyEngine, paint) { QPalette pa = qApp->palette(); QImage img(s64, QImage::Format_ARGB32_Premultiplied); { img.fill(Qt::transparent); QPainter p(&img); mIconEngine->paint(&p, QRect(QPoint(0, 0), s64),QIcon::Normal, QIcon::On); testHighlightColor(pa, img); testWindowTextColor(pa, img); } { img.fill(Qt::transparent); QPainter p(&img); mIconEngine->paint(&p, QRect(QPoint(0, 0), s64),QIcon::Selected, QIcon::On); testHighlightColor(pa, img); testHighlightedTextColor(pa, img); } } TEST_F(ut_XdgIconProxyEngine, pixmap) { QPalette pa = qApp->palette(); QPixmap normalPix = mIconEngine->pixmap(s64, QIcon::Normal, QIcon::On); testWindowTextColor(pa, normalPix.toImage()); QPixmap selectPix = mIconEngine->pixmap(s64, QIcon::Selected, QIcon::On); testHighlightColor(pa, selectPix.toImage()); testHighlightedTextColor(pa, selectPix.toImage()); } TEST_F(ut_XdgIconProxyEngine, addPixmap_addFile) { QString fileName(":/icons/deepin/actions/64/cs_rect_64.svg"); // XdgIconLoaderEngine did not implement these methods mIconEngine->addPixmap(QPixmap(fileName), QIcon::Normal, QIcon::On); mIconEngine->addFile(fileName, s64, QIcon::Normal, QIcon::On); } TEST_F(ut_XdgIconProxyEngine, key) { ASSERT_EQ(mIconEngine->key(), QLatin1String("XdgIconProxyEngine")); } TEST_F(ut_XdgIconProxyEngine, actualSize) { EXPECT_EQ(s64, mIconEngine->actualSize(s64, QIcon::Normal, QIcon::On)); } TEST_F(ut_XdgIconProxyEngine, clone) { QScopedPointer clone(mIconEngine->clone()); ASSERT_EQ(clone->key(), mIconEngine->key()); ASSERT_EQ(clone->iconName(), mIconEngine->iconName()); } TEST_F(ut_XdgIconProxyEngine, read_write) { QByteArray data; { QDataStream out(&data, QIODevice::WriteOnly); mIconEngine->write(out); } QString iconName; { QDataStream in(&data, QIODevice::ReadOnly); in >> iconName; ASSERT_EQ("cs_rect_64", iconName); } iconName = "test_icon_name"; { QDataStream out(&data, QIODevice::WriteOnly); out << iconName; } { QDataStream in(&data, QIODevice::ReadOnly); mIconEngine->read(in); ASSERT_EQ(mIconEngine->engine->m_iconName, iconName); // iconName() not implement ASSERT_EQ(mIconEngine->iconName(), ""); ASSERT_EQ(mIconEngine->engine->iconName(), ""); } } TEST_F(ut_XdgIconProxyEngine, virtual_hook) { #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) { QIconEngine::ScaledPixmapArgument scalePixmapArg = { s64, QIcon::Normal, QIcon::On, 1.25, QPixmap() }; mIconEngine->virtual_hook(QIconEngine::ScaledPixmapHook, &scalePixmapArg); ASSERT_EQ(scalePixmapArg.pixmap.size(), s64); } #endif } dtkgui-5.7.12/tests/test-recoverage.sh000077500000000000000000000016221476226661100177110ustar00rootroot00000000000000#!/bin/bash # SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later set -ex BUILD_DIR=`pwd`/../build/tests/ HTML_DIR=${BUILD_DIR}/html XML_DIR=${BUILD_DIR}/report export ASAN_OPTIONS="halt_on_error=0" # back to project directroy cd .. cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DBUILD_EXAMPLE=OFF -DBUILD_DOCS=OFF -DEnableCov=ON cmake --build build --target ut-DtkGui -j$(nproc) cd $BUILD_DIR ./ut-DtkGui --gtest_output=xml:${XML_DIR}/report_dtkgui.xml lcov -d ../ -c -o coverage_all.info lcov --remove coverage_all.info "*/tests/*" "*/usr/include*" "*build-ut/src*" --output-file coverage.info cd .. genhtml -o $HTML_DIR $BUILD_DIR/coverage.info && mv ${BUILD_DIR}/html/index.html ${BUILD_DIR}/html/cov_dtkgui.html test -e ${BUILD_DIR}/asan.log* && mv ${BUILD_DIR}/asan.log* ${BUILD_DIR}/asan_dtkgui.log || touch ${BUILD_DIR}/asan_dtkgui.log dtkgui-5.7.12/tests/test.h000066400000000000000000000010201476226661100153730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef TEST_H #define TEST_H #include class DTest : public ::testing::Test { }; template class DTestWithParam : public ::testing::TestWithParam { }; template bool waitforSpy(T &spy, int timeout = 5000) { int times = timeout / 10 + 1; while(!spy.wait(10)) { if (--times <= 1) break; } return times > 1; } #endif // TEST_H dtkgui-5.7.12/toolGenerate/000077500000000000000000000000001476226661100155405ustar00rootroot00000000000000dtkgui-5.7.12/toolGenerate/dconfig2cpp/000077500000000000000000000000001476226661100177365ustar00rootroot00000000000000dtkgui-5.7.12/toolGenerate/dconfig2cpp/org_deepin_dtk_ui_preference.hpp000066400000000000000000000203141476226661100263170ustar00rootroot00000000000000/** * This file is generated by dconfig2cpp. * Command line arguments: ./dconfig2cpp -p ./dtkgui/toolGenerate/dconfig2cpp ./dtkgui/misc/org.deepin.dtk.ui.preference.json * Generation time: 2025-01-14T10:54:59 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. * If you need to change the content, please modify the dconfig2cpp tool. */ #ifndef ORG_DEEPIN_DTK_UI_PREFERENCE_H #define ORG_DEEPIN_DTK_UI_PREFERENCE_H #include #include #include #include #include #include class org_deepin_dtk_ui_preference : public QObject { Q_OBJECT Q_PROPERTY(double themeType READ themeType WRITE setThemeType NOTIFY themeTypeChanged) Q_PROPERTY(double titlebarHeight READ titlebarHeight WRITE setTitlebarHeight NOTIFY titlebarHeightChanged) public: explicit org_deepin_dtk_ui_preference(QThread *thread, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(appId, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit org_deepin_dtk_ui_preference(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, appId, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit org_deepin_dtk_ui_preference(QThread *thread, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } explicit org_deepin_dtk_ui_preference(QThread *thread, DTK_CORE_NAMESPACE::DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent = nullptr) : QObject(parent) { if (!thread->isRunning()) { qWarning() << QStringLiteral("Warning: The provided thread is not running."); } Q_ASSERT(QThread::currentThread() != thread); auto worker = new QObject(); worker->moveToThread(thread); QMetaObject::invokeMethod(worker, [=]() { auto config = DTK_CORE_NAMESPACE::DConfig::create(backend, name, subpath, nullptr); if (!config) { qWarning() << QStringLiteral("Failed to create DConfig instance."); worker->deleteLater(); return; } config->moveToThread(QThread::currentThread()); initialize(config); worker->deleteLater(); }); } ~org_deepin_dtk_ui_preference() { if (m_config.loadRelaxed()) { m_config.loadRelaxed()->deleteLater(); } } double themeType() const { return p_themeType; } void setThemeType(const double &value) { auto oldValue = p_themeType; p_themeType = value; markPropertySet(0); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("themeType"), value); }); } if (p_themeType != oldValue) { Q_EMIT themeTypeChanged(); } } double titlebarHeight() const { return p_titlebarHeight; } void setTitlebarHeight(const double &value) { auto oldValue = p_titlebarHeight; p_titlebarHeight = value; markPropertySet(1); if (auto config = m_config.loadRelaxed()) { QMetaObject::invokeMethod(config, [this, value]() { m_config.loadRelaxed()->setValue(QStringLiteral("titlebarHeight"), value); }); } if (p_titlebarHeight != oldValue) { Q_EMIT titlebarHeightChanged(); } } Q_SIGNALS: void themeTypeChanged(); void titlebarHeightChanged(); private: void initialize(DTK_CORE_NAMESPACE::DConfig *config) { Q_ASSERT(!m_config.loadRelaxed()); m_config.storeRelaxed(config); if (testPropertySet(0)) { config->setValue(QStringLiteral("themeType"), QVariant::fromValue(p_themeType)); } else { updateValue(QStringLiteral("themeType"), QVariant::fromValue(p_themeType)); } if (testPropertySet(1)) { config->setValue(QStringLiteral("titlebarHeight"), QVariant::fromValue(p_titlebarHeight)); } else { updateValue(QStringLiteral("titlebarHeight"), QVariant::fromValue(p_titlebarHeight)); } connect(config, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, [this](const QString &key) { updateValue(key); }, Qt::DirectConnection); } void updateValue(const QString &key, const QVariant &fallback = QVariant()) { Q_ASSERT(QThread::currentThread() == m_config.loadRelaxed()->thread()); const QVariant &value = m_config.loadRelaxed()->value(key, fallback); if (key == QStringLiteral("themeType")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_themeType != newValue) { p_themeType = newValue; Q_EMIT themeTypeChanged(); } }); return; } if (key == QStringLiteral("titlebarHeight")) { auto newValue = qvariant_cast(value); QMetaObject::invokeMethod(this, [this, newValue]() { if (p_titlebarHeight != newValue) { p_titlebarHeight = newValue; Q_EMIT titlebarHeightChanged(); } }); return; } } inline void markPropertySet(const int index) { if (index < 32) { m_propertySetStatus0.fetchAndOrOrdered(1 << (index - 0)); return; } Q_UNREACHABLE(); } inline bool testPropertySet(const int index) const { if (index < 32) { return (m_propertySetStatus0.loadRelaxed() & (1 << (index - 0))); } Q_UNREACHABLE(); } QAtomicPointer m_config = nullptr; double p_themeType { 0 }; double p_titlebarHeight { -1 }; QAtomicInteger m_propertySetStatus0 = 0; }; #endif // ORG_DEEPIN_DTK_UI_PREFERENCE_H dtkgui-5.7.12/tools/000077500000000000000000000000001476226661100142505ustar00rootroot00000000000000dtkgui-5.7.12/tools/CMakeLists.txt000066400000000000000000000002561476226661100170130ustar00rootroot00000000000000add_subdirectory(deepin-gui-settings) add_subdirectory(dci-image-converter) add_subdirectory(dci-icon-theme) add_subdirectory(dde-kwin-debug) add_subdirectory(image-handler) dtkgui-5.7.12/tools/dci-icon-theme/000077500000000000000000000000001476226661100170355ustar00rootroot00000000000000dtkgui-5.7.12/tools/dci-icon-theme/CMakeLists.txt000066400000000000000000000005471476226661100216030ustar00rootroot00000000000000set(BIN_NAME dci-icon-theme) set(TARGET_NAME ${BIN_NAME}${DTK_VERSION_MAJOR}) add_executable(${TARGET_NAME} main.cpp ) target_link_libraries(${TARGET_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Gui ${LIB_NAME} ) set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${BIN_NAME}) install(TARGETS ${TARGET_NAME} DESTINATION "${TOOL_INSTALL_DIR}") dtkgui-5.7.12/tools/dci-icon-theme/README.md000066400000000000000000000066461476226661100203300ustar00rootroot00000000000000# dci-icon-theme ```` Usage: dci-icon-theme [options] ~/dci-png-icons dci-icon-theme tool is a command tool that generate dci icons from common icons. For example, the tool is used in the following ways: dci-icon-theme /usr/share/icons/hicolor/256x256/apps -o ~/Desktop/hicolor -O 3=95 dci-icon-theme -m *.png /usr/share/icons/hicolor/256x256/apps -o ~/Desktop/hicolor -O 3=95 dci-icon-theme --fix-dark-theme -o dci-icon-theme --find dci-icon-theme --find -t bloom dci-icon-theme -o -s -O Options: -m, --match Give wildcard rules on search icon files, Each eligible icon will be packaged to a dci file, If the icon have the dark mode, it needs to store the dark icon file at "dark/" directory relative to current icon file, and the file name should be consistent. -o, --output Save the *.dci files to the given directory. -s, --symlink Give a csv file to create symlinks for the output icon file. The content of symlink.csv like: sublime-text, com.sublimetext.2 deb, " application-vnd.debian.binary-package application-x-deb gnome-mime-application-x-deb " --fix-dark-theme Create symlinks from light theme for dark theme files. --find Find dci icon file path -t, --theme Give a theme name to find dci icon file path -O, --scale-quality Quility of dci scaled icon image The value may like = e.g. 2=98:3=95 The quality factor must be in the range 0 to 100 or -1. Specify 0 to obtain small compressed files, 100 for large uncompressed files and -1 to use the image handler default settings. The higher the quality, the larger the dci icon file size -h, --help Displays help on commandline options. --help-all Displays help including Qt specific options. -v, --version Displays version information. Arguments: source Search the given directory and it's subdirectories, get the files conform to rules of --match. ```` dtkgui-5.7.12/tools/dci-icon-theme/main.cpp000066400000000000000000000410471476226661100204730ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include #include DCORE_USE_NAMESPACE DGUI_USE_NAMESPACE #define MAX_SCALE 10 #define INVALIDE_QUALITY -2 static int quality4Scaled[MAX_SCALE] = {}; static inline void initQuality() { for (int i = 0; i < MAX_SCALE; ++i) quality4Scaled[i] = INVALIDE_QUALITY; } static inline void dciChecker(bool result, std::function cb) { if (!result) { qWarning() << "Failed on writing dci file" << cb(); exit(-6); } } static inline QByteArray webpImageData(const QImage &image, int quality) { QByteArray data; QBuffer buffer(&data); bool ok = buffer.open(QIODevice::WriteOnly); Q_ASSERT(ok); dciChecker(image.save(&buffer, "webp", quality), []{return "failed to save webp image";}); return data; } static bool writeScaledImage(DDciFile &dci, const QString &imageFile, const QString &targetDir, int scale/* = 2*/) { QString sizeDir = targetDir.mid(1, targetDir.indexOf("/", 1) - 1); bool ok = false; int baseSize = sizeDir.toInt(&ok); if (!ok) baseSize = 256; int size = scale * baseSize; QImageReader image(imageFile); if (!image.canRead()) { qWarning() << "Ignore the null image file:" << imageFile; return false; } if (image.supportsOption(QImageIOHandler::ScaledSize)) { image.setScaledSize(QSize(size, size)); } dciChecker(dci.mkdir(targetDir + QString("/%1").arg(scale)), [&]{return dci.lastErrorString();}); const QImage &img = image.read().scaledToWidth(size, Qt::SmoothTransformation); int quality = quality4Scaled[scale - 1]; const QByteArray &data = webpImageData(img, quality); dciChecker(dci.writeFile(targetDir + QString("/%1/1.webp").arg(scale), data), [&]{return dci.lastErrorString();}); return true; } static bool writeImage(DDciFile &dci, const QString &imageFile, const QString &targetDir) { for (int i = 0; i < MAX_SCALE; ++i) { if (quality4Scaled[i] == INVALIDE_QUALITY) continue; if (!writeScaledImage(dci, imageFile, targetDir, i + 1)) return false; } return true; } static bool recursionLink(DDciFile &dci, const QString &fromDir, const QString &targetDir) { for (const auto &i : dci.list(fromDir, true)) { const QString file(fromDir + "/" + i); const QString targetFile(targetDir + "/" + i); if (dci.type(file) == DDciFile::Directory) { if (!dci.mkdir(targetFile)) return false; if (!recursionLink(dci, file, targetFile)) return false; } else { if (!dci.link(file, targetFile)) return false; } } return true; } static QByteArray readNextSection(QIODevice *io) { QByteArray section; char ch; bool oneLine = true; while (io->getChar(&ch)) { if (!oneLine && ch == '"') { // ["] end if (io->peek(1) == ",") io->skip(1); // skip [,] break; } else if (ch == ',') { break; } else if (ch == '"') { // ["] begin oneLine = false; continue; } section.append(ch); if(oneLine && io->peek(1) == "\n") break; } return section.trimmed(); } QMultiHash parseIconFileSymlinkMap(const QString &csvFile) { QFile file(csvFile); if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Failed on open symlink map file:" << csvFile; exit(-7); } QMultiHash map; while (!file.atEnd()) { QByteArray key = readNextSection(&file); QByteArray value = readNextSection(&file); for (const auto &i : value.split('\n')) { map.insert(QString::fromLocal8Bit(key), QString::fromLocal8Bit(i)); } char ch = 0; while (file.getChar(&ch) && ch != '\n'); } qInfo() << "Got symlinks:" << map.size(); return map; } void makeLink(const QFileInfo &file, const QDir &outputDir, const QString &dciFilePath, const QMultiHash &symlinksMap) { if (symlinksMap.contains(file.completeBaseName())) { const QString symlinkKey = QFileInfo(dciFilePath).fileName(); for (const auto &symTarget : symlinksMap.values(file.completeBaseName())) { const QString newSymlink = outputDir.absoluteFilePath(symTarget + ".dci"); qInfo() << "Create symlink from" << symlinkKey << "to" << newSymlink; if (!QFile::link(symlinkKey, newSymlink)) { qWarning() << "Failed on create symlink from" << symlinkKey << "to" << newSymlink; } } } } void doFixDarkTheme(const QFileInfo &file, const QDir &outputDir, const QMultiHash &symlinksMap) { const QString &newFile = outputDir.absoluteFilePath(file.fileName()); DDciFile dciFile(file.absoluteFilePath()); if (!dciFile.isValid()) { qWarning() << "Skip invalid dci file:" << file.absoluteFilePath(); return; } for (const auto &i : dciFile.list("/")) { if (dciFile.type(i) != DDciFile::Directory) continue; for (const auto &j : dciFile.list(i)) { if (dciFile.type(j) != DDciFile::Directory || !j.endsWith(".light")) continue; const QString darkDir(j.left(j.size() - 5) + "dark"); Q_ASSERT(darkDir.endsWith(".dark")); if (!dciFile.exists(darkDir)) { dciChecker(dciFile.mkdir(darkDir), [&]{return dciFile.lastErrorString();}); dciChecker(recursionLink(dciFile, j, darkDir), [&]{return dciFile.lastErrorString();}); } } } dciChecker(dciFile.writeToFile(newFile), [&]{return dciFile.lastErrorString();}); makeLink(file, outputDir, newFile, symlinksMap); } int main(int argc, char *argv[]) { QCommandLineOption fileFilter({"m", "match"}, "Give wildcard rules on search icon files, " "Each eligible icon will be packaged to a dci file, " "If the icon have the dark mode, it needs to store " "the dark icon file at \"dark/\" directory relative " "to current icon file, and the file name should be " "consistent.", "wildcard palette"); QCommandLineOption outputDirectory({"o", "output"}, "Save the *.dci files to the given directory.", "directory"); QCommandLineOption symlinkMap({"s", "symlink"}, "Give a csv file to create symlinks for the output icon file." "\nThe content of symlink.csv like:\n" "\t\t sublime-text, com.sublimetext.2\n" "\t\t deb, \"\n" "\t\t application-vnd.debian.binary-package\n" "\t\t application-x-deb\n" "\t\t gnome-mime-application-x-deb\n" "\t\t \"\n" , "csv file"); QCommandLineOption fixDarkTheme("fix-dark-theme", "Create symlinks from light theme for dark theme files."); QCommandLineOption iconFinder("find", "Find dci icon file path"); QCommandLineOption themeOpt({"t","theme"}, "Give a theme name to find dci icon file path", "theme name"); QCommandLineOption scaleQuality({"O","scale-quality"}, "Quility of dci scaled icon image\n" "The value may like = e.g. 2=98:3=95\n" "The quality factor must be in the range 0 to 100 or -1.\n" "Specify 0 to obtain small compressed files, 100 for large uncompressed files " "and -1 to use the image handler default settings.\n" "The higher the quality, the larger the dci icon file size", "scale quality"); QGuiApplication a(argc, argv); a.setApplicationName("dci-icon-theme"); a.setApplicationVersion("0.0.6"); QCommandLineParser cp; cp.setApplicationDescription("dci-icon-theme tool is a command tool that generate dci icons from common icons.\n" "For example, the tool is used in the following ways: \n" "\t dci-icon-theme /usr/share/icons/hicolor/256x256/apps -o ~/Desktop/hicolor -O 3=95\n" "\t dci-icon-theme -m *.png /usr/share/icons/hicolor/256x256/apps -o ~/Desktop/hicolor -O 3=95\n" "\t dci-icon-theme --fix-dark-theme -o \n" "\t dci-icon-theme --find \n" "\t dci-icon-theme --find -t bloom\n" "\t dci-icon-theme -o -s -O \n""" ); cp.addOptions({fileFilter, outputDirectory, symlinkMap, fixDarkTheme, iconFinder, themeOpt, scaleQuality}); cp.addPositionalArgument("source", "Search the given directory and it's subdirectories, " "get the files conform to rules of --match.", "~/dci-png-icons"); cp.addHelpOption(); cp.addVersionOption(); cp.process(a); if (a.arguments().size() == 1) cp.showHelp(-1); bool isIconFinder = cp.isSet(iconFinder); if (cp.positionalArguments().isEmpty()) { qWarning() << "Not give a" << (isIconFinder ? "icon name." : "source directory."); cp.showHelp(-2); } QString iconThemeName; if (cp.isSet(themeOpt)) { iconThemeName = cp.value(themeOpt); } else { iconThemeName = DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName(); } if (isIconFinder) { QString iconName = cp.positionalArguments().value(0); QString iconPath = DIconTheme::findDciIconFile(iconName, iconThemeName); qInfo() << iconName << "[" << iconThemeName << "]:" << iconPath; return 0; } if (!cp.isSet(outputDirectory)) { qWarning() << "Not give -o argument"; cp.showHelp(-4); } if (!cp.isSet(scaleQuality) && !cp.isSet(fixDarkTheme)) { qWarning() << "Not give -O argument"; scaleQuality.flags(); cp.showHelp(-5); } initQuality(); QString surfix; if (cp.isSet(scaleQuality)) { #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) auto behavior = Qt::SkipEmptyParts; #else auto behavior = QString::SkipEmptyParts; #endif QStringList qualityList = cp.value(scaleQuality).split(":", behavior); #ifdef QT_DEBUG surfix = cp.value(scaleQuality).prepend("-"); #endif for (const QString &kv : qualityList) { auto sq = kv.split("="); if (sq.size() != 2) { qWarning() << "Invalid quality value:" << kv; continue; } int scaleSize = sq.value(0).toInt(); if (scaleSize < 1 || scaleSize > MAX_SCALE) { qWarning() << "Invalid scale size:" << kv; continue; } int validQuality = qMax(qMin(sq.value(1).toInt(), 100), -1); // -1, 0~100 quality4Scaled[scaleSize - 1] = validQuality; } } QDir outputDir(cp.value(outputDirectory)); if (!outputDir.exists()) { if (!QDir::current().mkpath(outputDir.absolutePath())) { qWarning() << "Can't create the" << outputDir.absolutePath() << "directory"; cp.showHelp(-5); } } else { qErrnoWarning("The output directory have been exists."); #ifndef QT_DEBUG return -1; #endif } QMultiHash symlinksMap; if (cp.isSet(symlinkMap)) { symlinksMap = parseIconFileSymlinkMap(cp.value(symlinkMap)); } const QStringList nameFilter = cp.isSet(fileFilter) ? cp.values(fileFilter) : QStringList(); const auto sourceDirectory = cp.positionalArguments(); for (const auto &sd : qAsConst(sourceDirectory)) { QDir sourceDir(sd); if (!sourceDir.exists()) { qWarning() << "Ignore the non-exists directory:" << sourceDir; continue; } // read all links first { QDirIterator di(sourceDir.absolutePath(), nameFilter, QDir::NoDotAndDotDot | QDir::Files, QDirIterator::Subdirectories); while (di.hasNext()) { di.next(); QFileInfo file = di.fileInfo(); if (!file.isSymLink()) continue; #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) auto link = file.symLinkTarget(); #else auto link = file.readLink(); #endif const QString &linkTarget = QFileInfo(link).completeBaseName(); if (!symlinksMap.values(linkTarget).contains(file.completeBaseName())) { symlinksMap.insert(linkTarget, file.completeBaseName()); qInfo() << "Add link" << file.completeBaseName() << "->" << linkTarget; } else { // qDebug() << "** link already existed in symlinksMap **"; } } } QDirIterator di(sourceDir.absolutePath(), nameFilter, QDir::NoDotAndDotDot | QDir::Files, QDirIterator::Subdirectories); while (di.hasNext()) { di.next(); QFileInfo file = di.fileInfo(); if (file.isSymLink()) continue; if (cp.isSet(fixDarkTheme)) { doFixDarkTheme(file, outputDir, symlinksMap); continue; } if (file.path().endsWith(QStringLiteral("/dark"))) { qInfo() << "Ignore the dark icon file:" << file; continue; } QString dirName = file.absoluteDir().dirName(); bool isNum = false; dirName.toInt(&isNum); dirName.prepend("/"); QScopedPointer dciFile; const QString dciFilePath(outputDir.absoluteFilePath(file.completeBaseName()) + surfix + ".dci"); if (QFileInfo::exists(dciFilePath)) { dciFile.reset(new DDciFile(dciFilePath)); if (dciFile->isValid() && dciFile->exists(dirName)) { qWarning() << "Skip exists dci file:" << dciFilePath << dirName << dciFile->list(dirName); continue; } } qInfo() << "Writing to dci file:" << file.absoluteFilePath() << "==>" << dciFilePath; if (dciFile.isNull() || !dciFile->isValid()) dciFile.reset(new DDciFile); QString sizeDir = isNum ? dirName : "/256"; // "/256" QString normalLight = sizeDir + "/normal.light"; // "/256/normal.light" QString normalDark = sizeDir + "/normal.dark"; // "/256/normal.dark" dciChecker(dciFile->mkdir(sizeDir), [&]{return dciFile->lastErrorString();}); dciChecker(dciFile->mkdir(normalLight), [&]{return dciFile->lastErrorString();}); if (!writeImage(*dciFile, file.filePath(), normalLight)) continue; dciChecker(dciFile->mkdir(normalDark), [&]{return dciFile->lastErrorString();}); QFileInfo darkIcon(file.dir().absoluteFilePath("dark/" + file.fileName())); if (darkIcon.exists()) { writeImage(*dciFile, darkIcon.filePath(), normalDark); } else { dciChecker(recursionLink(*dciFile, normalLight, normalDark), [&]{return dciFile->lastErrorString();}); } dciChecker(dciFile->writeToFile(dciFilePath), [&]{return dciFile->lastErrorString();}); makeLink(file, outputDir, dciFilePath, symlinksMap); } } return 0; } dtkgui-5.7.12/tools/dci-image-converter/000077500000000000000000000000001476226661100200745ustar00rootroot00000000000000dtkgui-5.7.12/tools/dci-image-converter/CMakeLists.txt000066400000000000000000000004711476226661100226360ustar00rootroot00000000000000set(BIN_NAME dci-image-converter) set(TARGET_NAME ${BIN_NAME}${DTK_VERSION_MAJOR}) add_executable(${TARGET_NAME} main.cpp ) target_link_libraries(${TARGET_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui ) set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${BIN_NAME}) dtkgui-5.7.12/tools/dci-image-converter/main.cpp000066400000000000000000000060771476226661100215360ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #define ALPHA8STRING QLatin1String("alpha8") static bool convertImageTo(const QString &originPath, const QString &targetPath) { QImage originImage(originPath); if (originImage.isNull()) return false; const auto fi = QFileInfo(originPath); const QString &suffix = fi.suffix(); // ###(Chen bin): The tool only determines whether the image is suitable // for conversion,and does not judge the palette. if ((originImage.width() % 2) || (originImage.height() % 2)) return false; auto tmp = originImage.convertToFormat(QImage::Format_Alpha8); QImage alpha(tmp.constBits(), tmp.width(), tmp.height(), tmp.bytesPerLine(), QImage::Format_Grayscale8); return alpha.save(targetPath, suffix.toLocal8Bit()); } static bool convertImageFrom(const QString &originPath, const QString &targetPath) { QString path(originPath); auto fi = QFileInfo(originPath); QString suffix = fi.suffix(); if (suffix.compare(ALPHA8STRING, Qt::CaseInsensitive)) return false; // No convert to alpha8. path.remove(QLatin1Char('.') + fi.suffix()); QImage originImage(originPath); if (originPath.isNull() || originImage.format() != QImage::Format_Grayscale8) return false; suffix = QFileInfo(path).suffix(); QImage targetImage(originImage.bits(), originImage.width(), originImage.height(), originImage.bytesPerLine(), QImage::Format_Alpha8); return targetImage.save(targetPath, suffix.toLocal8Bit()); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); a.setApplicationName("dci-image-converter"); a.setApplicationVersion("0.0.1"); QCommandLineParser commandParser; auto options = QList { QCommandLineOption("toAlpha8", "Convert image format to alpha8.", "targetPath"), QCommandLineOption("fromAlpha8", "Convert image format from alpha8.", "targetPath"), }; commandParser.addOptions(options); commandParser.addPositionalArgument("sourcesPath", "The file path of the original image to be converted.", "[dir1 dir2...]/[file1 file2...]"); commandParser.addHelpOption(); commandParser.addVersionOption(); commandParser.process(a); auto arguments = commandParser.positionalArguments(); if (arguments.isEmpty()) commandParser.showHelp(-1); if (commandParser.isSet(options.at(0))) { if (!convertImageTo(arguments.first(), commandParser.value(options.at(0)))) { printf("Convert image failed.\n"); return 1; } } else if (commandParser.isSet(options.at(1))) { if (!convertImageFrom(arguments.first(), commandParser.value(options.at(1)))) { printf("Convert image failed.\n"); return 1; } } else { commandParser.showHelp(-1); } return 0; } dtkgui-5.7.12/tools/dde-kwin-debug/000077500000000000000000000000001476226661100170365ustar00rootroot00000000000000dtkgui-5.7.12/tools/dde-kwin-debug/CMakeLists.txt000066400000000000000000000006111476226661100215740ustar00rootroot00000000000000set(BIN_NAME dde-kwin-bug) set(TARGET_NAME ${BIN_NAME}${DTK_VERSION_MAJOR}) pkg_check_modules(X11 IMPORTED_TARGET REQUIRED x11) add_executable(${TARGET_NAME} main.cpp ) target_link_libraries(${TARGET_NAME} PRIVATE PkgConfig::X11 pthread ) set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${BIN_NAME}) install(TARGETS ${TARGET_NAME} DESTINATION "${TOOL_INSTALL_DIR}") dtkgui-5.7.12/tools/dde-kwin-debug/main.cpp000066400000000000000000000302701476226661100204700ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include #include #include // 记录日志打印的格式 char *outputFormat = nullptr; // 完成启动参数测试后是否自动推出进程 bool killWindow = false; // 监听所有窗口 bool watchAll = false; bool noCache = false; int repeatTime = 1; // 启动时间的偏移值 int time_offset = 0; const std::string timer_interval_env = "_D_CHECKER_TIMER_INTERVAL"; const std::string ping_time_env = "_D_CHECKER_PING_TIME"; const std::string valid_count_env = "_D_CHECKER_VALID_COUNT"; const std::string damage_count_env = "_D_CHECKER_DAMAGE_COUNT"; std::map checkArgMap { {"--ci", ""}, {"--cpt", ""}, {"--cvc", ""}, {"--cdc", ""} }; std::map checkEnvMap { {"--cil", timer_interval_env}, {"--cpt", ping_time_env}, {"--cvc", valid_count_env}, {"--cdc", damage_count_env} }; uint64_t timeSinceEpochMillisec() { using namespace std::chrono; return duration_cast(system_clock::now().time_since_epoch()).count(); } bool checkCommand(int argc, char *argv[], const char *arg) { for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], arg) == 0) return true; } return false; } int xerrorHandler(Display* /* display */, XErrorEvent* /* error_event */) { return 0; } int exec(const char *process) { // 准备环境变量 char env[100] = {}; auto time = timeSinceEpochMillisec(); sprintf(env, "D_KWIN_DEBUG_APP_START_TIME=%lu", time); putenv(env); char *displayname = getenv("DISPLAY"); Display *dpy = XOpenDisplay(displayname); if (dpy) { XSetErrorHandler(xerrorHandler); } // deepin-trubo 启动的程序无法对外暴露环境变量,因此通过root窗口设置启动时间 XChangeProperty(dpy, XDefaultRootWindow(dpy), XInternAtom(dpy, "D_KWIN_DEBUG_APP_START_TIME", false), XA_CARDINAL, 32, PropModeReplace, reinterpret_cast(&time), 2); XFlush(dpy); for (auto it = checkArgMap.cbegin(); it != checkArgMap.cend(); ++it) { if (!it->second.empty()) { setenv(checkEnvMap[it->first].data(), it->second.data(), 0); } } if (noCache) { std::string clearCache = "sync && sudo bash -c \"echo 3 > /proc/sys/vm/drop_caches\""; system(clearCache.c_str()); } // 启动进程,并等待其退出 int code = system(process); // 清理窗口属性 XDeleteProperty(dpy, XDefaultRootWindow(dpy), XInternAtom(dpy, "D_KWIN_DEBUG_APP_START_TIME", true)); XFlush(dpy); XFree(dpy); return code; } // 检测这个进程是不是自己的子进程 bool checkPid(__pid_t pid) { auto self = getpid(); while (true) { char status[100] = {0}; sprintf(status, "/proc/%d/exe", pid); // 检测是不是deepin-turbo-booster进程 char exe_path[100]; readlink(status, exe_path, 100); // 对于deepin-turbo的进程无法检测是否为子进程,因此默认认为是被dde-kwin-debug启动的 if (strstr(exe_path, "/usr/lib/deepin-turbo") == exe_path) return true; __pid_t ppid = 1; sprintf(status, "/proc/%d/status", pid); auto file = fopen(status, "ro"); if (!file) return false; char data[1024] = {}; fread(data, sizeof(char), 1024, file); // 查找父进程id if (const char *i = strstr(data, "\nPPid:")) { i += 6; // 移除空白 while (i[0] == ' ' || i[0] == '\t') { ++i; } const char *ppid_begin = i; char ppid_string[100] = {}; // 查找ppid的结尾 while (i[0] <= '9' && i[0] >= '0') { ppid_string[i - ppid_begin] = i[0]; ++i; } ppid = atoi(ppid_string); } fclose(file); if (ppid == self) return true; // 继续向上查找 pid = ppid; if (ppid == 1) break; } return false; } __pid_t getWindowPid(Display *dpy, Window window) { Atom actual_type; int actual_format; unsigned long nitems; unsigned long bytes_after; static unsigned char *prop = NULL; int status; status = XGetWindowProperty(dpy, window, XInternAtom(dpy, "_NET_WM_PID", false), 0, 1024, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); if (status == Success && prop) { // 获取pid return *(uint32_t*)(prop); } return 0; } bool event_queue_done = false; Display *dpy = nullptr; void processXEvent() { if (!dpy) { char *displayname = getenv("DISPLAY"); dpy = XOpenDisplay(displayname); if (!dpy) { fprintf(stderr, "%s: unable to open display '%s'\n", "dde-kwin-startup-debug", XDisplayName (displayname)); exit(1); } } int screen = DefaultScreen(dpy); Window root = RootWindow(dpy, screen); XSelectInput(dpy, root, SubstructureNotifyMask); // 事件队列 for (; !event_queue_done; ) { XEvent event; XNextEvent(dpy, &event); switch (event.type) { case PropertyNotify: { XPropertyEvent *pe = (XPropertyEvent*)&event; static Atom atom_D_APP_STARTUP_TIME = XInternAtom(dpy, "_D_APP_STARTUP_TIME", false); if (pe->atom == atom_D_APP_STARTUP_TIME) { auto pid = getWindowPid(dpy, pe->window); // 检测这个窗口是否属于我们启动的应用程序 if (!watchAll) { // 不是监听的窗口则退出 if (!pid || !checkPid(pid)) break; } Atom actual_type; int actual_format; unsigned long nitems; unsigned long bytes_after; static unsigned char *prop = NULL; int status; status = XGetWindowProperty(dpy, pe->window, atom_D_APP_STARTUP_TIME, 0, 1024, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); if (status == Success && prop) { uint32_t time = *(uint32_t*)prop - time_offset; // 打印数据 if (!outputFormat) { std::cout << time << std::endl; } else { int count = strlen(outputFormat); for (int i = 0; i < count; ++i) { if (outputFormat[i] == '%') { switch (outputFormat[i + 1]) { case 'p': std::cout << pid; break; case 't': std::cout << time; break; case 'n': { char command[100] = {}; sprintf(command, "/proc/%u/cmdline", pid); auto file = fopen(command, "ro"); if (file) { char data[1024] = {}; if (fread(data, sizeof(char), 1024, file)) std::cout << data; } break; } default: break; } ++i; } else { std::cout << outputFormat[i]; } } std::cout << std::endl; } if (killWindow) { // 退出对应的程序 char command[100]; sprintf(command, "xkill -id %lu > /dev/null", pe->window); system(command); } } } break; } case CreateNotify: { XCreateWindowEvent *e = (XCreateWindowEvent*)&event; Window new_window = e->window; // 监听这个窗口的属性变化事件 XSelectInput(dpy, new_window, PropertyChangeMask); } default: break; } } XCloseDisplay(dpy); } void signal_handle(int sig) { (void)sig; exit(0); } int main(int argc, char *argv[]) { if (argc ==1 || checkCommand(argc, argv, "--help")) { auto help_message = R"help( Eg: dde-kwin-debug -k --format "%p %t %n" qtcreator --help Show the help message. -k Auto kill the application on test finished. -L Disable outputs of applications. (redirect standard outputs to /dev/null) -a Watch all windows. --format Log formats: %p: application pid %t: startup time(unit: ms) %n: application name -no--cache Disable cache --r Repeat time --ci Set check interval, default 100 ms --cpt Set window ping reply time, default 50 ms --cvc Set check valid count, default 10 --cdc Set check damage count, default 20 Arguments: The applications. Eg: dde-kwin-debug -k --format "%t %n" "app1" "app2" "app3" )help"; std::cout << help_message << std::endl; return 0; } // 初始化环境 killWindow = checkCommand(argc, argv, "-k"); watchAll = checkCommand(argc, argv, "-a"); noCache = checkCommand(argc, argv, "-no-cache"); for (int i = 1; i < argc; ++i) { const std::string currentArg = argv[i]; if (currentArg == "--r") { repeatTime = atoi(argv[++i]); continue; } if (currentArg == "--format") { outputFormat = argv[++i]; continue; } if (checkArgMap.count(currentArg) > 0) { checkArgMap[currentArg] = argv[++i]; continue; } } signal(SIGINT, signal_handle); signal(SIGABRT, signal_handle); signal(SIGTERM, signal_handle); signal(SIGHUP, signal_handle); signal(SIGQUIT, signal_handle); signal(SIGKILL, signal_handle); signal(SIGBUS, signal_handle); signal(SIGSYS, signal_handle); signal(SIGPIPE, signal_handle); signal(SIGKILL, signal_handle); // 获取全局启动时间的环境变量 auto time_env = getenv("D_KWIN_DEBUG_APP_START_TIME"); int64_t kwin_start_time = 0; if (time_env && strlen(time_env)) sscanf(time_env, "%ld", &kwin_start_time); if (kwin_start_time) { struct timeval time; gettimeofday(&time, nullptr); time_offset = time.tv_sec * 1000 + (1.0 * time.tv_usec) / 1000 - kwin_start_time; } // 监听X11事件 std::thread x11_thread(processXEvent); x11_thread.detach(); bool disable_outpus = checkCommand(argc, argv, "-L"); for (int i = 1; i < argc; ++i) { const char *arg = argv[i]; if (arg[0] == '-') { if (arg[1] == '-') ++i; // 跳过参数携带的值 continue; } for (int i = 0; i < repeatTime; ++i) { // 不以'-'开头的参数认为三要启动的应用程序名称 if (disable_outpus) { char command[1024] = {}; sprintf(command, "%s 2>/dev/null 1> /dev/null", arg); exec(command); } else { exec(arg); } } } if (watchAll) { sleep(INT32_MAX); } event_queue_done = false; return 0; } dtkgui-5.7.12/tools/deepin-gui-settings/000077500000000000000000000000001476226661100201345ustar00rootroot00000000000000dtkgui-5.7.12/tools/deepin-gui-settings/CMakeLists.txt000066400000000000000000000006451476226661100227010ustar00rootroot00000000000000set(BIN_NAME deepin-gui-settings) set(TARGET_NAME ${BIN_NAME}${DTK_VERSION_MAJOR}) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) add_executable(${TARGET_NAME} main.cpp ) target_link_libraries(${TARGET_NAME} Qt${QT_VERSION_MAJOR}::Widgets ${LIB_NAME} ) set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${BIN_NAME}) install(TARGETS ${TARGET_NAME} DESTINATION "${TOOL_INSTALL_DIR}") dtkgui-5.7.12/tools/deepin-gui-settings/main.cpp000066400000000000000000000137231476226661100215720ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include #include DGUI_USE_NAMESPACE int main(int argc, char *argv[]) { // 禁用输入法,防止输入法插件乱输出内容 qunsetenv("QT_IM_MODULE"); qputenv("QT_QPA_PLATFORM", "dxcb"); QGuiApplication app(argc, argv); qunsetenv("QT_QPA_PLATFORM"); QCommandLineParser parser; QCommandLineOption option_window({"w", "window"}, "resource id of window to examine"); QCommandLineOption option_window_leader("window-leader", "use leader window of the window"); QCommandLineOption option_select_window("select", "auto select a window on screen"); QCommandLineOption option_domain({"p", "domain"}, "domain of settings property"); QCommandLineOption option_set("set", "set a settings item to a given value. Can only and must specify a value(eg: [-s|-i|-c])"); QCommandLineOption option_string({"s", "string"}, "set a string value of a settings item"); QCommandLineOption option_int({"i", "int"}, "set a int value of a settings item"); QCommandLineOption option_color({"c", "color"}, "set a color value of a settings item"); QCommandLineOption option_remove({"r", "remove"}, "remove a settings item"); option_window.setValueName("id"); option_window.setDefaultValue("0"); option_domain.setValueName("domain"); option_domain.setDefaultValue(QString()); option_set.setValueName("key"); option_string.setValueName("value"); option_int.setValueName("value"); option_color.setValueName("value"); option_remove.setValueName("key"); parser.addOption(option_window); parser.addOption(option_window_leader); parser.addOption(option_select_window); parser.addOption(option_domain); parser.addOption(option_set); parser.addOption(option_string); parser.addOption(option_int); parser.addOption(option_color); parser.addOption(option_remove); parser.addPositionalArgument("keys", "key of get settings value", "[keys...]"); parser.addHelpOption(); parser.addVersionOption(); parser.process(app); quint32 window_id = 0; if (parser.isSet(option_select_window)) { QProcess xdotool; xdotool.start("xdotool", {"selectwindow"}, QIODevice::ReadOnly); if (!xdotool.waitForFinished()) { parser.showHelp(1); } bool ok = false; window_id = xdotool.readAllStandardOutput().trimmed().toInt(&ok); if (!ok) { parser.showHelp(1); } } else { const QString &window_id_value = parser.value(option_window); bool ok = false; if (window_id_value.startsWith("0x")) { window_id = window_id_value.toInt(&ok, 16); } else { window_id = window_id_value.toInt(&ok); } if (!ok) { parser.showHelp(-1); } } if (parser.isSet(option_window_leader)) { QProcess xprop; xprop.start("xprop", {"-id", QString::number(window_id), "WM_CLIENT_LEADER"}, QIODevice::ReadOnly); if (!xprop.waitForFinished()) { qFatal("%s\n", xprop.errorString().toLocal8Bit().constData()); return -1; } const QByteArrayList &list = xprop.readAllStandardOutput().split(' '); bool ok = false; if (!list.isEmpty()) { quint32 id = list.last().trimmed().toInt(&ok, 16); if (ok) { window_id = id; } } if (!ok) { qFatal("%s\n", "not found WM_CLIENT_LEADER"); return -1; } } DNativeSettings settings(window_id, parser.value(option_domain).toLatin1()); if (!settings.isValid()) { qWarning() << "Settings is invalid, platform plugin is:" << qApp->platformName(); return -1; } if (parser.isSet(option_set)) { QVariant value; if (parser.isSet(option_string)) { // string if (parser.isSet(option_int) || parser.isSet(option_color)) { parser.showHelp(-1); } value = parser.value(option_string).toLocal8Bit(); } else if (parser.isSet(option_int)) { // int if (parser.isSet(option_string) || parser.isSet(option_color)) { parser.showHelp(-1); } bool ok = false; int integer = parser.value(option_int).toInt(&ok); if (!ok) { parser.showHelp(-1); } value = QVariant(integer); } else if (parser.isSet(option_color)) { // color if (parser.isSet(option_string) || parser.isSet(option_int)) { parser.showHelp(-1); } QColor color(parser.value(option_color)); if (!color.isValid()) { parser.showHelp(-1); } value = QVariant(color); } else { parser.showHelp(-1); } // 设置一个属性的值 const QByteArray &name = parser.value(option_set).toLatin1(); if (name.isEmpty()) { parser.showHelp(-1); } settings.setSetting(name, value); qDebug() << name << settings.getSetting(name); } else if (parser.isSet(option_remove)) { const QByteArray &name = parser.value(option_remove).toLatin1(); if (name.isEmpty()) { parser.showHelp(-1); } settings.setSetting(name, QVariant()); qDebug() << name << settings.getSetting(name); } else { const QStringList &keys = parser.positionalArguments(); if (keys.isEmpty()) { // 打印所有设置项 qDebug() << settings; } else { for (const QString &key : keys) { qDebug() << key << settings.getSetting(key.toLatin1()); } } } return 0; } dtkgui-5.7.12/tools/image-handler/000077500000000000000000000000001476226661100167455ustar00rootroot00000000000000dtkgui-5.7.12/tools/image-handler/CMakeLists.txt000066400000000000000000000004241476226661100215050ustar00rootroot00000000000000set(BIN image-handler) set(TARGET_NAME ${BIN}${DTK_VERSION_MAJOR}) add_executable(${TARGET_NAME} main.cpp ) target_link_libraries(${TARGET_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Gui ${LIB_NAME} ) set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${BIN}) dtkgui-5.7.12/tools/image-handler/main.cpp000066400000000000000000000131671476226661100204050ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include DGUI_USE_NAMESPACE bool rotateImage(DImageHandler &handler, QImage &image, const QString ¶m) { int degresses = param.toInt(); if (!handler.rotateImage(image, degresses)) { qWarning().noquote() << "Rotate image failed" << handler.lastError(); return false; } return true; } bool applyImageFilter(QImage &image, const QString ¶m) { enum FilterType { Old, Warm, Cool, Gray, AntiColor, Metal }; static const QHash colorFilters{ {"old", Old}, {"warm", Warm}, {"cool", Cool}, {"gray", Gray}, {"anticolor", AntiColor}, {"metal", Metal}}; QString filter = param.toLower(); if (!colorFilters.contains(filter)) { qWarning().noquote() << QString("There is no color filter named %1.").arg(filter); return false; } FilterType type = colorFilters.value(filter); switch (type) { case Old: image = DImageHandler::oldColorFilter(image); break; case Warm: image = DImageHandler::warmColorFilter(image); break; case Cool: image = DImageHandler::coolColorFilter(image); break; case Gray: image = DImageHandler::grayScaleColorFilter(image); break; case AntiColor: image = DImageHandler::antiColorFilter(image); break; case Metal: image = DImageHandler::metalColorFilter(image); break; default: break; } return true; } void printMultipleImage(const QStringList &imageFiles, bool extra) { if (imageFiles.isEmpty()) { return; } DImageHandler handler; QStringList notSupportList; QStringList errorList; for (const QString &imageFile : imageFiles) { handler.setFileName(imageFile); if (!handler.isReadable()) { notSupportList << imageFile; } else { // Load image internal. QSize size = handler.imageSize(); QString errorString = handler.lastError(); if (errorString.isEmpty()) { qInfo().noquote() << imageFile << handler.imageFormat() << size; if (extra) { qInfo().noquote() << handler.findAllMetaData(); } } else { errorList << QString("%1 %2").arg(imageFile).arg(errorString); } } } if (!notSupportList.isEmpty()) { qInfo().noquote() << "\nNot support image format:"; for (const QString ¬Support : notSupportList) { qInfo().noquote() << notSupport; } } if (!errorList.isEmpty()) { qInfo().noquote() << "\nLoad image error:"; for (const QString &error : errorList) { qInfo().noquote() << error; } } } int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QCoreApplication::setApplicationName("Image handler"); QCommandLineOption rotateOption({"r", "rotate"}, "Rotate image with geven degresses.", "degresses"); QCommandLineOption saveOption({"o", "output"}, "Save image with file path.", "file"); QCommandLineOption filterOption("f", "Apply filters to pictures.\n" "Contains old, warm, cool, gray, anticolor and metal.", "filter"); QCommandLineOption extraOption("e", "Show extra image info."); QCommandLineOption supportOption({"l", "list"}, "List all support image formats"); QCommandLineParser parser; parser.setApplicationDescription("Image handler"); parser.addHelpOption(); parser.addOption(rotateOption); parser.addOption(saveOption); parser.addOption(filterOption); parser.addOption(extraOption); parser.addOption(supportOption); parser.addPositionalArgument("file", "Open file. More than one file will only display file info.", "[file...]"); parser.process(app); if (parser.isSet(supportOption)) { qInfo().noquote() << "Support image formats:"; qInfo().noquote() << DImageHandler::supportFormats().join(','); return 0; } const QStringList fileArgs = parser.positionalArguments(); if (fileArgs.isEmpty()) { parser.showHelp(); return 0; } bool needRotate = parser.isSet(rotateOption); bool needFilter = parser.isSet(filterOption); if (needRotate || needFilter) { QString fileName = fileArgs.first(); QString saveFileName = parser.isSet(saveOption) ? parser.value(saveOption) : fileName; DImageHandler handler; handler.setFileName(fileName); QImage image = handler.readImage(); if (image.isNull()) { qWarning().noquote() << "Can't read image." << handler.lastError(); return 0; } if (needRotate) { if (!rotateImage(handler, image, parser.value(rotateOption))) { return 0; } } if (needFilter) { if (!applyImageFilter(image, parser.value(filterOption))) { return 0; } } if (!handler.saveImage(image, saveFileName)) { qWarning().noquote() << QString("Save file %1 failed.").arg(saveFileName) << handler.lastError(); return 0; } } else { printMultipleImage(fileArgs, parser.isSet(extraOption)); } return 0; }