forked from github_mirror/framelesshelper
Compare commits
80 Commits
wip/snap-l
...
main
Author | SHA1 | Date |
---|---|---|
|
10580baf54 | |
|
e72257bb34 | |
|
43f632f261 | |
|
9dce992112 | |
|
d1b4aadb76 | |
|
6b09aa9e91 | |
|
617a015b97 | |
|
7c0d8c4b11 | |
|
fa5389a0fc | |
|
2a49e9fcaf | |
|
6ccb25db0a | |
|
8f321e2e54 | |
|
f15412cf5b | |
|
a5ec49d0a2 | |
|
86a9b85d04 | |
|
b7556d467e | |
|
074664afc2 | |
|
6229a0db3c | |
|
6c27125d69 | |
|
fdd6640d5c | |
|
10b661f541 | |
|
c1370c4897 | |
|
af200adf63 | |
|
85be988760 | |
|
273e3e204c | |
|
00b67ead0e | |
|
907fdeae67 | |
|
5a344f3e23 | |
|
b28b6e8d27 | |
|
1e754c1612 | |
|
f7f8fc3dd0 | |
|
e1cf95f208 | |
|
9778582d9b | |
|
0424d0ee1b | |
|
13e93cfed5 | |
|
9376e4d6e7 | |
|
59fb61d981 | |
|
e090359d9a | |
|
e7da37d06a | |
|
3a18f36d3f | |
|
9df1e9d7b5 | |
|
e48fc7e01f | |
|
2b1623fbd6 | |
|
e67a91d668 | |
|
ec93740bd7 | |
|
e4fdb9c260 | |
|
de2cad679b | |
|
1ba9c9c918 | |
|
721f46307b | |
|
32b055a7ab | |
|
8b7ee7a24d | |
|
951dd5f931 | |
|
2c1164b834 | |
|
0be45565dc | |
|
2fa3140b0f | |
|
8d5ea49d52 | |
|
66c2c60a09 | |
|
82e29f37bb | |
|
84745db4d9 | |
|
84a9a76021 | |
|
901aaee7e3 | |
|
a9ee1c5fff | |
|
76453b123e | |
|
cfcf9f4178 | |
|
8ece315390 | |
|
92d850c2a9 | |
|
224302500d | |
|
cf568b6e7a | |
|
a3cfa59d1d | |
|
250aff0faf | |
|
b039a9130a | |
|
4d063369fa | |
|
41e91bb39a | |
|
30d2261baf | |
|
fe724271da | |
|
b2561c16ba | |
|
a203e2c3ca | |
|
8930ea128f | |
|
3b8571401f | |
|
99417bf916 |
|
@ -18,19 +18,25 @@ jobs:
|
|||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
qt-version: [5.15.2, 6.5.0]
|
||||
qt-version: [5.15.2, 6.5.1]
|
||||
library-type: [shared, static]
|
||||
platform: [windows-latest, ubuntu-latest, macos-latest]
|
||||
include:
|
||||
- platform: windows-latest
|
||||
CC: cl
|
||||
CXX: cl
|
||||
LD: link
|
||||
EXTRA_FLAGS: -DFRAMELESSHELPER_ENABLE_SPECTRE=ON -DFRAMELESSHELPER_ENABLE_EHCONTGUARD=ON -DFRAMELESSHELPER_ENABLE_INTELCET=ON -DFRAMELESSHELPER_ENABLE_CFGUARD=ON
|
||||
- platform: ubuntu-latest
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
LD: ld
|
||||
EXTRA_FLAGS: -DFRAMELESSHELPER_ENABLE_SPECTRE=ON -DFRAMELESSHELPER_ENABLE_INTELCET=ON -DFRAMELESSHELPER_ENABLE_CFGUARD=ON
|
||||
- platform: macos-latest
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
CC: /usr/local/opt/llvm/bin/clang
|
||||
CXX: /usr/local/opt/llvm/bin/clang++
|
||||
LD: /usr/local/opt/llvm/bin/ld64.lld
|
||||
EXTRA_FLAGS: -DFRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD=OFF
|
||||
- library-type: shared
|
||||
lib_type_flag: -DFRAMELESSHELPER_BUILD_STATIC=OFF
|
||||
- library-type: static
|
||||
|
@ -64,10 +70,16 @@ jobs:
|
|||
run: |
|
||||
sudo apt install -y libgl1-mesa-dev libxcb1-dev libgtk-3-dev
|
||||
|
||||
- name: Install macOS dependencies
|
||||
if: ${{ matrix.platform == 'macos-latest' }}
|
||||
run: |
|
||||
brew install llvm
|
||||
export PATH="/usr/local/opt/llvm/bin:$PATH"
|
||||
|
||||
- name: Build library with CMake
|
||||
run: |
|
||||
mkdir ci
|
||||
cd ci
|
||||
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_C_COMPILER=${{ matrix.CC }} -DCMAKE_CXX_COMPILER=${{ matrix.CXX }} -DCMAKE_INSTALL_PREFIX=../../install -DCMAKE_BUILD_TYPE=Release -DFRAMELESSHELPER_BUILD_EXAMPLES=ON ${{ matrix.lib_type_flag }} -DFRAMELESSHELPER_ENABLE_SPECTRE=ON -DFRAMELESSHELPER_ENABLE_INTELCET=ON -DFRAMELESSHELPER_ENABLE_INTELJCC=ON -DFRAMELESSHELPER_ENABLE_CFGUARD=ON -GNinja ..
|
||||
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_C_COMPILER=${{ matrix.CC }} -DCMAKE_CXX_COMPILER=${{ matrix.CXX }} -DCMAKE_LINKER=${{ matrix.LD }} -DCMAKE_INSTALL_PREFIX=../../install -DCMAKE_BUILD_TYPE=Release -DFRAMELESSHELPER_BUILD_EXAMPLES=ON -DFRAMELESSHELPER_NO_SUMMARY=OFF ${{ matrix.lib_type_flag }} ${{ matrix.EXTRA_FLAGS }} -GNinja ..
|
||||
cmake --build . --target all --config Release --parallel
|
||||
cmake --install . --config Release --strip
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "cmake"]
|
||||
path = cmake
|
||||
url = https://github.com/wangwenx190/cmake-utils.git
|
||||
url = https://git.ourdocs.cn/github_mirror/cmake-utils.git
|
||||
|
|
101
CMakeLists.txt
101
CMakeLists.txt
|
@ -25,11 +25,14 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(FramelessHelper
|
||||
VERSION "2.3.6"
|
||||
VERSION "2.4.0"
|
||||
DESCRIPTION "Cross-platform window customization framework for Qt Widgets and Qt Quick."
|
||||
HOMEPAGE_URL "https://github.com/wangwenx190/framelesshelper/"
|
||||
)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
|
||||
# TODO: Use add_feature_info() for every option below? Is it worth doing?
|
||||
option(FRAMELESSHELPER_BUILD_STATIC "Build FramelessHelper as a static library." OFF)
|
||||
option(FRAMELESSHELPER_BUILD_WIDGETS "Build FramelessHelper's Widgets module." ON)
|
||||
option(FRAMELESSHELPER_BUILD_QUICK "Build FramelessHelper's Quick module." ON)
|
||||
|
@ -45,10 +48,29 @@ option(FRAMELESSHELPER_NO_INSTALL "Don't install any files." OFF)
|
|||
option(FRAMELESSHELPER_NO_SUMMARY "Don't show CMake configure summary." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_SPECTRE "Mitigate Spectre security vulnerabilities." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_EHCONTGUARD "MSVC only: Enable EH Continuation (EHCONT) Metadata." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_INTELCET "Enable Intel CET." ON)
|
||||
option(FRAMELESSHELPER_ENABLE_INTELJCC "Enable Intel JCC." ON)
|
||||
option(FRAMELESSHELPER_ENABLE_CFGUARD "Enable Control Flow Guard (CFG)." ON)
|
||||
option(FRAMELESSHELPER_ENABLE_INTELCET "Enable Intel CET." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_INTELJCC "Enable Intel JCC." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_CFGUARD "Enable Control Flow Guard (CFG)." OFF)
|
||||
option(FRAMELESSHELPER_EXAMPLES_STANDALONE "Build the demo projects as standalone CMake projects." OFF)
|
||||
cmake_dependent_option(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD "macOS only: build universal library/example for Mac." ON APPLE OFF)
|
||||
option(FRAMELESSHELPER_FORCE_LTO "Force enable LTO/LTCG even when building static libraries." OFF)
|
||||
option(FRAMELESSHELPER_REPRODUCIBLE_OUTPUT "Don't update the build commit and date dynamically." OFF)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 QUIET COMPONENTS Widgets Quick)
|
||||
find_package(Qt${QT_VERSION_MAJOR} QUIET COMPONENTS Widgets Quick)
|
||||
|
||||
include(cmake/utils.cmake)
|
||||
|
||||
if(NOT APPLE AND FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
message(WARNING "Current OS is not macOS, universal build will be disabled.")
|
||||
set(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD OFF)
|
||||
elseif(APPLE AND ((QT_VERSION VERSION_LESS "6.2" AND QT_VERSION VERSION_GREATER_EQUAL "6.0") OR (QT_VERSION VERSION_LESS "5.15.9")))
|
||||
message(WARNING "Your Qt version ${QT_VERSION} doesn't support universal build, it will be disabled.")
|
||||
set(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD OFF)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_BUNDLE_RESOURCE)
|
||||
message(WARNING "Nothing will be embeded into the FramelessHelper library, the chrome buttons will have no icon.")
|
||||
|
@ -58,8 +80,6 @@ if(FRAMELESSHELPER_ENABLE_VCLTL AND NOT MSVC)
|
|||
message(WARNING "VC-LTL is only available for the MSVC toolchain.")
|
||||
endif()
|
||||
|
||||
include(cmake/utils.cmake)
|
||||
|
||||
set(__extra_flags)
|
||||
if(NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
list(APPEND __extra_flags ENABLE_LTO)
|
||||
|
@ -76,14 +96,13 @@ setup_project(
|
|||
unset(__extra_flags)
|
||||
|
||||
set(PROJECT_VERSION_COMMIT "UNKNOWN")
|
||||
get_commit_hash(RESULT PROJECT_VERSION_COMMIT)
|
||||
|
||||
set(PROJECT_COMPILE_DATETIME "UNKNOWN")
|
||||
string(TIMESTAMP PROJECT_COMPILE_DATETIME UTC)
|
||||
if(NOT FRAMELESSHELPER_REPRODUCIBLE_OUTPUT)
|
||||
get_commit_hash(RESULT PROJECT_VERSION_COMMIT)
|
||||
string(TIMESTAMP PROJECT_COMPILE_DATETIME UTC)
|
||||
endif()
|
||||
|
||||
if(MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
message(WARNING "Your current toolchain is not officially supported by FramelessHelper.\n"
|
||||
"Only LLVM-MinGW (https://github.com/mstorsjo/llvm-mingw) has partial support.")
|
||||
set(FRAMELESSHELPER_ENABLE_SPECTRE OFF)
|
||||
set(FRAMELESSHELPER_ENABLE_EHCONTGUARD OFF)
|
||||
set(FRAMELESSHELPER_ENABLE_INTELCET OFF)
|
||||
|
@ -95,10 +114,17 @@ if(MSVC)
|
|||
if(FRAMELESSHELPER_ENABLE_VCLTL)
|
||||
include(cmake/VC-LTL.cmake)
|
||||
if("x${SupportLTL}" STREQUAL "xtrue")
|
||||
# Make sure we will always overwrite the previous settings.
|
||||
unset(CMAKE_MSVC_RUNTIME_LIBRARY)
|
||||
unset(CMAKE_MSVC_RUNTIME_LIBRARY CACHE)
|
||||
#unset(CMAKE_MSVC_RUNTIME_LIBRARY PARENT_SCOPE)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
if(FRAMELESSHELPER_ENABLE_YYTHUNKS)
|
||||
unset(YYTHUNKS_TARGET_OS)
|
||||
unset(YYTHUNKS_TARGET_OS CACHE)
|
||||
#unset(YYTHUNKS_TARGET_OS PARENT_SCOPE)
|
||||
set(YYTHUNKS_TARGET_OS "WinXP" CACHE STRING "" FORCE)
|
||||
include(cmake/YY-Thunks.cmake)
|
||||
endif()
|
||||
|
@ -115,12 +141,6 @@ prepare_package_export(
|
|||
)
|
||||
unset(__extra_flags)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 QUIET COMPONENTS Widgets Quick)
|
||||
find_package(Qt${QT_VERSION_MAJOR} QUIET COMPONENTS Widgets Quick)
|
||||
|
||||
if(FRAMELESSHELPER_BUILD_QUICK AND NOT TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
message(WARNING "Can't find the QtQuick module. FramelessHelper's QtQuick implementation and the QtQuick demo won't be built.")
|
||||
set(FRAMELESSHELPER_BUILD_QUICK OFF)
|
||||
|
@ -147,11 +167,31 @@ if(NOT FRAMELESSHELPER_NO_SUMMARY)
|
|||
message("CMake version: ${CMAKE_VERSION} (${CMAKE_COMMAND})")
|
||||
message("Host system: ${CMAKE_HOST_SYSTEM}")
|
||||
message("Host processor: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||
#message("C compiler: ${CMAKE_C_COMPILER_ID} (${CMAKE_C_COMPILER})") # Currently we are not using any C compilers.
|
||||
#message("C compiler version: ${CMAKE_C_COMPILER_VERSION}")
|
||||
#[[message("C compiler: ${CMAKE_C_COMPILER_ID} (${CMAKE_C_COMPILER})") # Currently we are not using any C compilers.
|
||||
message("C compiler version: ${CMAKE_C_COMPILER_VERSION}")
|
||||
message("C common flags: ${CMAKE_C_FLAGS}")
|
||||
message("C debug flags: ${CMAKE_C_FLAGS_DEBUG}")
|
||||
message("C release flags: ${CMAKE_C_FLAGS_RELEASE}")
|
||||
message("C minsizerel flags: ${CMAKE_C_FLAGS_MINSIZEREL}")
|
||||
message("C relwithdebinfo flags: ${CMAKE_C_FLAGS_RELWITHDEBINFO}")]]
|
||||
message("C++ compiler: ${CMAKE_CXX_COMPILER_ID} (${CMAKE_CXX_COMPILER})")
|
||||
message("C++ compiler version: ${CMAKE_CXX_COMPILER_VERSION}")
|
||||
message("C++ common flags: ${CMAKE_CXX_FLAGS}")
|
||||
message("C++ debug flags: ${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
message("C++ release flags: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
message("C++ minsizerel flags: ${CMAKE_CXX_FLAGS_MINSIZEREL}")
|
||||
message("C++ relwithdebinfo flags: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
message("Linker: ${CMAKE_LINKER}")
|
||||
message("Linker exe common flags: ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
message("Linker exe debug flags: ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
|
||||
message("Linker exe release flags: ${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
|
||||
message("Linker exe minsizerel flags: ${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}")
|
||||
message("Linker exe relwithdebinfo flags: ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
message("Linker dll common flags: ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
message("Linker dll debug flags: ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
|
||||
message("Linker dll release flags: ${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
|
||||
message("Linker dll minsizerel flags: ${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL}")
|
||||
message("Linker dll relwithdebinfo flags: ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
message("Make program: ${CMAKE_MAKE_PROGRAM}")
|
||||
message("Generator: ${CMAKE_GENERATOR}")
|
||||
message("Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
@ -160,25 +200,15 @@ if(NOT FRAMELESSHELPER_NO_SUMMARY)
|
|||
message("Prefix paths: ${CMAKE_PREFIX_PATH}")
|
||||
message("Toolchain file: ${CMAKE_TOOLCHAIN_FILE}")
|
||||
message("------------------------------ Qt -------------------------------")
|
||||
set(__qt_inst_dir)
|
||||
if(DEFINED Qt6_DIR)
|
||||
set(__qt_inst_dir "${Qt6_DIR}")
|
||||
else()
|
||||
set(__qt_inst_dir "${Qt5_DIR}")
|
||||
endif()
|
||||
# /whatever/Qt/6.4.0/gcc_64/lib/cmake/Qt6
|
||||
cmake_path(GET __qt_inst_dir PARENT_PATH __qt_inst_dir)
|
||||
cmake_path(GET __qt_inst_dir PARENT_PATH __qt_inst_dir)
|
||||
cmake_path(GET __qt_inst_dir PARENT_PATH __qt_inst_dir)
|
||||
query_qt_paths(SDK_DIR __qt_inst_dir)
|
||||
query_qt_library_info(STATIC __qt_static_lib)
|
||||
message("Qt SDK installation directory: ${__qt_inst_dir}")
|
||||
message("Qt SDK version: ${QT_VERSION}")
|
||||
get_target_property(__qt_type Qt${QT_VERSION_MAJOR}::Core TYPE)
|
||||
if(__qt_type STREQUAL "STATIC_LIBRARY")
|
||||
set(__qt_type static)
|
||||
if(__qt_static_lib)
|
||||
message("Qt SDK library type: static")
|
||||
else()
|
||||
set(__qt_type shared)
|
||||
message("Qt SDK library type: shared")
|
||||
endif()
|
||||
message("Qt SDK library type: ${__qt_type}")
|
||||
message("------------------------ FramelessHelper ------------------------")
|
||||
message("FramelessHelper version: ${PROJECT_VERSION}")
|
||||
message("FramelessHelper commit hash: ${PROJECT_VERSION_COMMIT}")
|
||||
|
@ -201,5 +231,8 @@ if(NOT FRAMELESSHELPER_NO_SUMMARY)
|
|||
message("Enable Intel JCC: ${FRAMELESSHELPER_ENABLE_INTELJCC}")
|
||||
message("Enable Control Flow Guard (CFG): ${FRAMELESSHELPER_ENABLE_CFGUARD}")
|
||||
message("Build standalone demo projects: ${FRAMELESSHELPER_EXAMPLES_STANDALONE}")
|
||||
message("[macOS]: Build universal library/example: ${FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD}")
|
||||
message("Force enable LTO: ${FRAMELESSHELPER_FORCE_LTO}")
|
||||
message("Make output reproducible: ${FRAMELESSHELPER_REPRODUCIBLE_OUTPUT}")
|
||||
message("-----------------------------------------------------------------")
|
||||
endif()
|
||||
|
|
|
@ -28,12 +28,7 @@ set(_@PROJECT_NAME@_supported_components Core Widgets Quick)
|
|||
|
||||
foreach(_comp ${@PROJECT_NAME@_FIND_COMPONENTS})
|
||||
if(_comp IN_LIST _@PROJECT_NAME@_supported_components)
|
||||
set(__proj_name "@PROJECT_NAME@${_comp}")
|
||||
cmake_path(GET CMAKE_CURRENT_LIST_FILE PARENT_PATH __imp_prefix)
|
||||
cmake_path(GET __imp_prefix PARENT_PATH __imp_prefix)
|
||||
include("${__imp_prefix}/${__proj_name}/${__proj_name}Config.cmake")
|
||||
unset(__imp_prefix)
|
||||
unset(__proj_name)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@${_comp}Config.cmake")
|
||||
else()
|
||||
set(@PROJECT_NAME@_FOUND FALSE)
|
||||
set(@PROJECT_NAME@_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")
|
||||
|
@ -52,3 +47,9 @@ if(NOT DEFINED @PROJECT_NAME@_FOUND)
|
|||
set(@PROJECT_NAME@_COMMIT "@PROJECT_VERSION_COMMIT@")
|
||||
set(@PROJECT_NAME@_COMPILE_DATETIME "@PROJECT_COMPILE_DATETIME@")
|
||||
endif()
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(@PROJECT_NAME@ PROPERTIES
|
||||
DESCRIPTION "@PROJECT_DESCRIPTION@"
|
||||
URL "@PROJECT_HOMEPAGE_URL@"
|
||||
)
|
|
@ -1,59 +0,0 @@
|
|||
#[[
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2021-2023 by wangwenx190 (Yuhang Zhao)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
|
||||
if(NOT DEFINED @SUB_PROJ_NAME@_FOUND)
|
||||
set(@SUB_PROJ_NAME@_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
if(@SUB_PROJ_NAME@_FOUND)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@SUB_PROJ_NAME@Targets.cmake")
|
||||
endif()
|
||||
|
||||
if(TARGET @PROJECT_NAME@::@SUB_MOD_NAME@)
|
||||
set(@SUB_PROJ_NAME@_LIBRARIES @PROJECT_NAME@::@SUB_MOD_NAME@)
|
||||
get_target_property(@SUB_PROJ_NAME@_VERSION @PROJECT_NAME@::@SUB_MOD_NAME@ VERSION)
|
||||
if(NOT @SUB_PROJ_NAME@_VERSION)
|
||||
set(@SUB_PROJ_NAME@_VERSION "")
|
||||
endif()
|
||||
get_target_property(@SUB_PROJ_NAME@_INCLUDE_DIRS @PROJECT_NAME@::@SUB_MOD_NAME@ INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if(NOT @SUB_PROJ_NAME@_INCLUDE_DIRS)
|
||||
set(@SUB_PROJ_NAME@_INCLUDE_DIRS "")
|
||||
endif()
|
||||
get_target_property(@SUB_PROJ_NAME@_DEFINITIONS @PROJECT_NAME@::@SUB_MOD_NAME@ INTERFACE_COMPILE_DEFINITIONS)
|
||||
if(NOT @SUB_PROJ_NAME@_DEFINITIONS)
|
||||
set(@SUB_PROJ_NAME@_DEFINITIONS "")
|
||||
else()
|
||||
list(TRANSFORM @SUB_PROJ_NAME@_DEFINITIONS PREPEND "-D")
|
||||
endif()
|
||||
get_target_property(@SUB_PROJ_NAME@_COMPILE_DEFINITIONS @PROJECT_NAME@::@SUB_MOD_NAME@ INTERFACE_COMPILE_DEFINITIONS)
|
||||
if(NOT @SUB_PROJ_NAME@_COMPILE_DEFINITIONS)
|
||||
set(@SUB_PROJ_NAME@_COMPILE_DEFINITIONS "")
|
||||
endif()
|
||||
list(REMOVE_DUPLICATES @SUB_PROJ_NAME@_INCLUDE_DIRS)
|
||||
list(REMOVE_DUPLICATES @SUB_PROJ_NAME@_DEFINITIONS)
|
||||
list(REMOVE_DUPLICATES @SUB_PROJ_NAME@_COMPILE_DEFINITIONS)
|
||||
else()
|
||||
set(@SUB_PROJ_NAME@_FOUND FALSE)
|
||||
set(@SUB_PROJ_NAME@_NOT_FOUND_MESSAGE "Target \"@PROJECT_NAME@::@SUB_MOD_NAME@\" was not found.")
|
||||
endif()
|
|
@ -1,47 +0,0 @@
|
|||
#[[
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2021-2023 by wangwenx190 (Yuhang Zhao)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
|
||||
if(NOT TARGET @PROJECT_NAME@::@SUB_MOD_NAME@)
|
||||
cmake_path(GET CMAKE_CURRENT_LIST_FILE PARENT_PATH __import_prefix)
|
||||
cmake_path(GET __import_prefix PARENT_PATH __import_prefix)
|
||||
cmake_path(GET __import_prefix PARENT_PATH __import_prefix)
|
||||
cmake_path(GET __import_prefix PARENT_PATH __import_prefix)
|
||||
if(__import_prefix STREQUAL "/")
|
||||
set(__import_prefix "")
|
||||
endif()
|
||||
add_library(@SUB_PROJ_NAME@ @SUB_MOD_LIB_TYPE@ IMPORTED)
|
||||
add_library(@PROJECT_NAME@::@SUB_MOD_NAME@ ALIAS @SUB_PROJ_NAME@)
|
||||
set_target_properties(@SUB_PROJ_NAME@ PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${__import_prefix}/include;${__import_prefix}/include/@PROJECT_NAME@;${__import_prefix}/include/@SUB_PROJ_PATH@;${__import_prefix}/include/@SUB_PROJ_PATH@/private"
|
||||
INTERFACE_COMPILE_DEFINITIONS "@SUB_MOD_DEFS@"
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${__import_prefix}/@SUB_MOD_LIB_DIR@/@SUB_MOD_FILE_NAME@"
|
||||
IMPORTED_IMPLIB "${__import_prefix}/lib/@SUB_MOD_FILE_BASENAME@.lib"
|
||||
VERSION "@PROJECT_VERSION@"
|
||||
SOVERSION "@PROJECT_VERSION_MAJOR@"
|
||||
__COMMIT "@PROJECT_VERSION_COMMIT@"
|
||||
__COMPILE_DATETIME "@PROJECT_COMPILE_DATETIME@"
|
||||
)
|
||||
unset(__import_prefix)
|
||||
endif()
|
65
README.md
65
README.md
|
@ -28,6 +28,11 @@ You can join our [Discord channel](https://discord.gg/grrM4Tmesy) to communicate
|
|||
- Widgets: Nested frameless windows are supported now!
|
||||
- Linux: There have been many improvements to the Linux/X11 implementation! Most of them won't be directly visible to the user, but the code quality has been greatly improved.
|
||||
- macOS: The frameless windows will now use native window frame and buttons, only the title bar itself is hidden, which also means the window will have round corners as all other native windows on macOS.
|
||||
- Mica Material: It is now possible to load wallpaper images with very large file size or resolution, for example, 4K pictures. However, if the images have larger resolution than 1920x1080, they will be shrinked to reduce memory usage, and this process will also lower the image quality and break the aspect ratio of them.
|
||||
- Mica Material: FramelessHelper will now use a seperate thread to load and apply special effects to the wallpaper image, to speed up application startup performance and avoid such process block the main thread.
|
||||
- Window management: It is now possible to close the window (the dtor is executed) and show it again without breaking the frameless functionalities.
|
||||
- Theme: It is now possible to force a desired theme instead of always respecting the system theme.
|
||||
- Build system: The [**Ninja Multi-Config**](https://cmake.org/cmake/help/latest/generator/Ninja%20Multi-Config.html) generator is fully supported now, finally!
|
||||
- Routine bug fixes and internal refactorings.
|
||||
|
||||
## Highlights v2.3
|
||||
|
@ -126,28 +131,70 @@ There are some additional restrictions for each platform, please refer to the _P
|
|||
## Build
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/wangwenx190/framelesshelper.git
|
||||
mkdir A_TEMP_DIR
|
||||
cd A_TEMP_DIR
|
||||
git clone --recursive https://github.com/wangwenx190/framelesshelper.git # "--recursive" is necessary to clone the submodules.
|
||||
mkdir build # Please change to your own build directory!
|
||||
cd build
|
||||
cmake -DCMAKE_PREFIX_PATH=<YOUR_QT_SDK_DIR_PATH> -DCMAKE_INSTALL_PREFIX=<WHERE_YOU_WANT_TO_INSTALL> -DCMAKE_BUILD_TYPE=Release -GNinja <PATH_TO_THE_REPOSITORY>
|
||||
cmake --build . --config Release --target all --parallel
|
||||
cmake --install . --config Release --strip
|
||||
cmake --install . --config Release --strip # Don't add "--strip" for MSVC/Clang-CL/Intel-CL toolchains!
|
||||
# YOUR_QT_SDK_DIR_PATH: the Qt SDK directory, something like "C:/Qt/6.5.1/msvc2019_64" or "/opt/Qt/6.5.1/gcc_64". Please change to your own path!
|
||||
# WHERE_YOU_WANT_TO_INSTALL: the install directory of FramelessHelper, something like "../install". You can ignore this setting if you don't need to install the CMake package. Please change to your own path!
|
||||
# PATH_TO_THE_REPOSITORY: the source code directory of FramelessHelper, something like "../framelesshelper". Please change to your own path!
|
||||
```
|
||||
|
||||
You can also use `Qt6_DIR` or `Qt5_DIR` to replace `CMAKE_PREFIX_PATH`:
|
||||
|
||||
```bash
|
||||
cmake -DQt6_DIR=C:/Qt/6.5.1/msvc2019_64/lib/cmake/Qt6 [other parameters ...]
|
||||
# Or
|
||||
cmake -DQt5_DIR=C:/Qt/5.15.2/msvc2019_64/lib/cmake/Qt5 [other parameters ...]
|
||||
```
|
||||
|
||||
If there are any errors when cloning the submodules, try run `git submodule update --init --recursive --remote` in the project directory, that command will download & update all the submodules. If it fails again, try execute it multiple times until it finally succeeds.
|
||||
|
||||
Once the compilation and installation is done, you will be able to use the `find_package(FramelessHelper REQUIRED COMPONENTS Core Widgets Quick)` command to find and link to the FramelessHelper library. But before doing that, please make sure CMake knows where to find FramelessHelper, by passing the `CMAKE_PREFIX_PATH` variable to it. For example: `-DCMAKE_PREFIX_PATH=C:/my-cmake-packages;C:/my-toolchain;etc...`. Build FramelessHelper as a sub-directory of your CMake project is of course also supported. The supported FramelessHelper target names are `FramelessHelper::Core`, `FramelessHelper::Widgets` and `FramelessHelper::Quick`.
|
||||
Once the compilation and installation is done, you will be able to use the `find_package(FramelessHelper REQUIRED COMPONENTS Core Widgets Quick)` command to find and link to the FramelessHelper library. But before doing that, please make sure CMake knows where to find FramelessHelper, by passing the `CMAKE_PREFIX_PATH` or `FramelessHelper_DIR` variable to it. For example: `-DCMAKE_PREFIX_PATH=C:/my-cmake-packages;C:/my-toolchain;etc...` or `-DFramelessHelper_DIR=C:/Projects/FramelessHelper/lib64/cmake/FramelessHelper`. Build FramelessHelper as a sub-directory of your CMake project is of course also supported. The supported FramelessHelper target names are `FramelessHelper::Core`, `FramelessHelper::Widgets` and `FramelessHelper::Quick`. Example code:
|
||||
|
||||
**IMPORTANT NOTE**: Currently *Ninja Multi-Config* is known to be **NOT** supported, you can only build one single configuration at a time, however, I'm planning to support it as soon as possible, in a future version.
|
||||
```cmake
|
||||
# Find Qt:
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
|
||||
# Find FramelessHelper:
|
||||
find_package(FramelessHelper REQUIRED COMPONENTS Core Widgets)
|
||||
# Create your target:
|
||||
add_executable(demo)
|
||||
# Add your source code:
|
||||
target_sources(demo PRIVATE main.cpp)
|
||||
# Link to Qt and FramelessHelper:
|
||||
target_link_libraries(demo PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
FramelessHelper::Core
|
||||
FramelessHelper::Widgets
|
||||
)
|
||||
```
|
||||
|
||||
If you need the syntax highlighting of FramelessHelper's Quick module, please set up the `QML_IMPORT_PATH` variable. Example code:
|
||||
|
||||
```cmake
|
||||
# This is the path where you want FramelessHelper's Quick plugin (it only contains the QML meta
|
||||
# info and an optional dummy library, for QtCreator's QML tooling purpose, it's not the Quick
|
||||
# module) to place. Please change to your own path!
|
||||
# If you are using add_subdirectory() to include FramelessHelper directly, you can change it to
|
||||
# "${PROJECT_BINARY_DIR}/imports" instead of the install location.
|
||||
set(FRAMELESSHELPER_IMPORT_DIR "C:/packages/FramelessHelper/qml")
|
||||
list(APPEND QML_IMPORT_PATH "${FRAMELESSHELPER_IMPORT_DIR}")
|
||||
list(REMOVE_DUPLICATES QML_IMPORT_PATH)
|
||||
# Force cache refresh:
|
||||
set(QML_IMPORT_PATH ${QML_IMPORT_PATH} CACHE STRING "Qt Creator extra QML import paths" FORCE)
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
### Qt Widgets
|
||||
|
||||
To customize the window frame of a QWidget, you need to instantiate a `FramelessWidgetsHelper` object and then attach it to the widget's top level widget, and then `FramelessWidgetsHelper` will do all the rest work for you: the window frame will be removed automatically once it has been attached to the top level widget successfully. In theory you can instantiate multiple `FramelessWidgetsHelper` objects for a same widget, in this case there will be only one object that keeps functional, all other objects will become a wrapper of that one. But to make sure everything goes smoothly and normally, you should not do that in any case. The simplest way to instantiate a `FramelessWidgetsHelper`
|
||||
object is to call the static method `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)`. It will return the handle of the previously instantiated object if any, or it will instantiate a new object if it can't find one. It's safe to call this method multiple times for a same widget, it won't instantiate any new objects if there is one already. It also does not matter when and where you call that function as long as the top level widget is the same. The internally created objects will always be parented to the top level widget. Once you get the handle of the `FramelessWidgetsHelper` object, you can call `void FramelessWidgetsHelper::setContentExtendedIntoTitleBar(true)` to let it hide the default title bar provided by the operating system. In order to make sure `FramelessWidgetsHelper` can find the correct top level widget, you should call the `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)` function on a widget which has a complete parent-chain whose root parent is the top level widget. To make the frameless window draggable, you should provide a homemade title bar widget yourself, the title bar widget doesn't need to be in rectangular shape, it also doesn't need to be placed on the first row of the window. Call `void FramelessWidgetsHelper::setTitleBarWidget(QWidget *)` to let `FramelessHelper` know what's your title bar widget. By default, all the widgets in the title bar area won't be responsible to any mouse and keyboard events due to they have been intercepted by FramelessHelper. To make them recover the responsible state, you should make them visible to hit test. Call `void FramelessWidgetsHelper::setHitTestVisible(QWidget* )` to do that. You can of course call it on a widget that is not inside the title bar at all, it won't have any effect though. Due to Qt's own limitations, you need to make sure your widget has a complete parent-chain whose root parent is the top level widget. Do not ever try to delete the `FramelessWidgetsHelper` object, it may still be monitoring and controlling your widget, and Qt will delete it for you automatically. No need to worry about memory leaks.
|
||||
object is to call the static method `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)`. It will return the handle of the previously instantiated object if any, or it will instantiate a new object if it can't find one. It's safe to call this method multiple times for a same widget, it won't instantiate any new objects if there is one already. It also does not matter when and where you call that function as long as the top level widget is the same. The internally created objects will always be parented to the top level widget. Once you get the handle of the `FramelessWidgetsHelper` object, you can call `void FramelessWidgetsHelper::extendsContentIntoTitleBar()` to let it hide the default title bar provided by the operating system. In order to make sure `FramelessWidgetsHelper` can find the correct top level widget, you should call the `FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *)` function on a widget which has a complete parent-chain whose root parent is the top level widget. To make the frameless window draggable, you should provide a homemade title bar widget yourself, the title bar widget doesn't need to be in rectangular shape, it also doesn't need to be placed on the first row of the window. Call `void FramelessWidgetsHelper::setTitleBarWidget(QWidget *)` to let `FramelessHelper` know what's your title bar widget. By default, all the widgets in the title bar area won't be responsible to any mouse and keyboard events due to they have been intercepted by FramelessHelper. To make them recover the responsible state, you should make them visible to hit test. Call `void FramelessWidgetsHelper::setHitTestVisible(QWidget* )` to do that. You can of course call it on a widget that is not inside the title bar at all, it won't have any effect though. Due to Qt's own limitations, you need to make sure your widget has a complete parent-chain whose root parent is the top level widget. Do not ever try to delete the `FramelessWidgetsHelper` object, it may still be monitoring and controlling your widget, and Qt will delete it for you automatically. No need to worry about memory leaks.
|
||||
|
||||
There are also two classes called `FramelessWidget` and `FramelessMainWindow`, they are only simple wrappers of `FramelessWidgetsHelper`, which just saves the call of the `void FramelessWidgetsHelper::setContentExtendedIntoTitleBar(true)` function for you. You can absolutely use plain `QWidget` instead.
|
||||
There are also two classes called `FramelessWidget` and `FramelessMainWindow`, they are only simple wrappers of `FramelessWidgetsHelper`, which just saves the call of the `void FramelessWidgetsHelper::extendsContentIntoTitleBar()` function for you. You can absolutely use plain `QWidget` instead.
|
||||
|
||||
#### Code Snippet
|
||||
|
||||
|
@ -167,7 +214,7 @@ Then hide the standard title bar provided by the OS:
|
|||
MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
// You should do this early enough.
|
||||
FramelessWidgetsHelper::get(this)->setContentExtendedIntoTitleBar(true);
|
||||
FramelessWidgetsHelper::get(this)->extendsContentIntoTitleBar();
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
|
2
cmake
2
cmake
|
@ -1 +1 @@
|
|||
Subproject commit 5b496224b13f31a5cc07cb48b56aed8d5e7e29de
|
||||
Subproject commit 4b4b901807771eda16fb07f36a5cb40505f64087
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
set(DEMO_NAME FramelessHelperDemo-Dialog)
|
||||
|
||||
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_EXAMPLES_STANDALONE)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(${DEMO_NAME} VERSION 1.0)
|
||||
|
@ -102,3 +106,5 @@ if(FRAMELESSHELPER_EXAMPLES_DEPLOYQT)
|
|||
endif()
|
||||
deploy_qt_runtime(TARGET ${DEMO_NAME} ${__extra_flags})
|
||||
endif()
|
||||
|
||||
#dump_target_info(TARGETS ${DEMO_NAME})
|
||||
|
|
|
@ -39,16 +39,23 @@ Dialog::~Dialog() = default;
|
|||
void Dialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (!parent()) {
|
||||
Settings::set({}, kGeometry, geometry());
|
||||
Settings::set({}, kDevicePixelRatio, devicePixelRatioF());
|
||||
const QString id = objectName();
|
||||
Settings::set(id, kGeometry, geometry());
|
||||
Settings::set(id, kDevicePixelRatio, devicePixelRatioF());
|
||||
}
|
||||
FramelessDialog::closeEvent(event);
|
||||
}
|
||||
|
||||
void Dialog::setupUi()
|
||||
{
|
||||
setWindowTitle(tr("Qt Dialog demo"));
|
||||
setWindowTitle(tr("FramelessHelper demo application - QDialog"));
|
||||
setWindowIcon(QFileIconProvider().icon(QFileIconProvider::Computer));
|
||||
connect(this, &Dialog::objectNameChanged, this, [this](const QString &name){
|
||||
if (name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
setWindowTitle(windowTitle() + FRAMELESSHELPER_STRING_LITERAL(" [%1]").arg(name));
|
||||
});
|
||||
|
||||
titleBar = new StandardTitleBar(this);
|
||||
titleBar->setWindowIconVisible(true);
|
||||
|
@ -142,9 +149,10 @@ void Dialog::waitReady()
|
|||
{
|
||||
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
|
||||
helper->waitForReady();
|
||||
const auto savedGeometry = Settings::get<QRect>({}, kGeometry);
|
||||
const QString id = objectName();
|
||||
const auto savedGeometry = Settings::get<QRect>(id, kGeometry);
|
||||
if (savedGeometry.isValid() && !parent()) {
|
||||
const auto savedDpr = Settings::get<qreal>({}, kDevicePixelRatio);
|
||||
const auto savedDpr = Settings::get<qreal>(id, kDevicePixelRatio);
|
||||
// Qt doesn't support dpr < 1.
|
||||
const qreal oldDpr = std::max(savedDpr, qreal(1));
|
||||
const qreal scale = (devicePixelRatioF() / oldDpr);
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
#define CREATE_WINDOW(Name) \
|
||||
const auto Name = std::make_unique<Dialog>(); \
|
||||
Name->setObjectName(FRAMELESSHELPER_STRING_LITERAL(#Name)); \
|
||||
Name->waitReady(); \
|
||||
Name->show();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Log::setup(FRAMELESSHELPER_STRING_LITERAL("dialog"));
|
||||
|
@ -51,11 +57,11 @@ int main(int argc, char *argv[])
|
|||
FramelessHelper::Core::setApplicationOSThemeAware();
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
//FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
|
||||
const auto dialog = std::make_unique<Dialog>();
|
||||
dialog->waitReady();
|
||||
dialog->show();
|
||||
CREATE_WINDOW(dialog1)
|
||||
CREATE_WINDOW(dialog2)
|
||||
CREATE_WINDOW(dialog3)
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
set(DEMO_NAME FramelessHelperDemo-MainWindow)
|
||||
|
||||
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_EXAMPLES_STANDALONE)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(${DEMO_NAME} VERSION 1.0)
|
||||
|
@ -107,3 +111,5 @@ if(FRAMELESSHELPER_EXAMPLES_DEPLOYQT)
|
|||
endif()
|
||||
deploy_qt_runtime(TARGET ${DEMO_NAME} ${__extra_flags})
|
||||
endif()
|
||||
|
||||
#dump_target_info(TARGETS ${DEMO_NAME})
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
#define CREATE_WINDOW(Name) \
|
||||
const auto Name = std::make_unique<MainWindow>(); \
|
||||
Name->setObjectName(FRAMELESSHELPER_STRING_LITERAL(#Name)); \
|
||||
Name->waitReady(); \
|
||||
Name->show();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Log::setup(FRAMELESSHELPER_STRING_LITERAL("mainwindow"));
|
||||
|
@ -51,11 +57,11 @@ int main(int argc, char *argv[])
|
|||
FramelessHelper::Core::setApplicationOSThemeAware();
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
//FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
|
||||
const auto mainWindow = std::make_unique<MainWindow>();
|
||||
mainWindow->waitReady();
|
||||
mainWindow->show();
|
||||
CREATE_WINDOW(mainWindow1)
|
||||
CREATE_WINDOW(mainWindow2)
|
||||
CREATE_WINDOW(mainWindow3)
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
|
|
@ -60,9 +60,10 @@ MainWindow::~MainWindow() = default;
|
|||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (!parent()) {
|
||||
Settings::set({}, kGeometry, geometry());
|
||||
Settings::set({}, kState, saveState());
|
||||
Settings::set({}, kDevicePixelRatio, devicePixelRatioF());
|
||||
const QString id = objectName();
|
||||
Settings::set(id, kGeometry, geometry());
|
||||
Settings::set(id, kState, saveState());
|
||||
Settings::set(id, kDevicePixelRatio, devicePixelRatioF());
|
||||
}
|
||||
FramelessMainWindow::closeEvent(event);
|
||||
}
|
||||
|
@ -108,8 +109,14 @@ QMenuBar::item:pressed {
|
|||
#endif // Q_OS_MACOS
|
||||
helper->setHitTestVisible(mb); // IMPORTANT!
|
||||
|
||||
setWindowTitle(tr("FramelessHelper demo application - Qt MainWindow"));
|
||||
setWindowTitle(tr("FramelessHelper demo application - QMainWindow"));
|
||||
setWindowIcon(QFileIconProvider().icon(QFileIconProvider::Computer));
|
||||
connect(this, &MainWindow::objectNameChanged, this, [this](const QString &name){
|
||||
if (name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
setWindowTitle(windowTitle() + FRAMELESSHELPER_STRING_LITERAL(" [%1]").arg(name));
|
||||
});
|
||||
connect(m_mainWindow->pushButton, &QPushButton::clicked, this, [this]{
|
||||
const auto dialog = new Dialog(this);
|
||||
dialog->waitReady();
|
||||
|
@ -128,9 +135,10 @@ void MainWindow::waitReady()
|
|||
{
|
||||
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
|
||||
helper->waitForReady();
|
||||
const auto savedGeometry = Settings::get<QRect>({}, kGeometry);
|
||||
const QString id = objectName();
|
||||
const auto savedGeometry = Settings::get<QRect>(id, kGeometry);
|
||||
if (savedGeometry.isValid() && !parent()) {
|
||||
const auto savedDpr = Settings::get<qreal>({}, kDevicePixelRatio);
|
||||
const auto savedDpr = Settings::get<qreal>(id, kDevicePixelRatio);
|
||||
// Qt doesn't support dpr < 1.
|
||||
const qreal oldDpr = std::max(savedDpr, qreal(1));
|
||||
const qreal scale = (devicePixelRatioF() / oldDpr);
|
||||
|
@ -138,7 +146,7 @@ void MainWindow::waitReady()
|
|||
} else {
|
||||
helper->moveWindowToDesktopCenter();
|
||||
}
|
||||
const QByteArray savedState = Settings::get<QByteArray>({}, kState);
|
||||
const QByteArray savedState = Settings::get<QByteArray>(id, kState);
|
||||
if (!savedState.isEmpty() && !parent()) {
|
||||
restoreState(savedState);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
set(DEMO_NAME FramelessHelperDemo-OpenGLWidget)
|
||||
|
||||
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_EXAMPLES_STANDALONE)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(${DEMO_NAME} VERSION 1.0)
|
||||
|
@ -117,3 +121,5 @@ if(FRAMELESSHELPER_EXAMPLES_DEPLOYQT)
|
|||
endif()
|
||||
deploy_qt_runtime(TARGET ${DEMO_NAME} ${__extra_flags})
|
||||
endif()
|
||||
|
||||
#dump_target_info(TARGETS ${DEMO_NAME})
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
set(DEMO_NAME FramelessHelperDemo-Quick)
|
||||
|
||||
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_EXAMPLES_STANDALONE)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(${DEMO_NAME} VERSION 1.0)
|
||||
|
@ -138,3 +142,5 @@ if(FRAMELESSHELPER_EXAMPLES_DEPLOYQT)
|
|||
${__extra_flags}
|
||||
)
|
||||
endif()
|
||||
|
||||
#dump_target_info(TARGETS ${DEMO_NAME})
|
||||
|
|
|
@ -64,7 +64,7 @@ int main(int argc, char *argv[])
|
|||
FramelessHelper::Core::setApplicationOSThemeAware();
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
//FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
|
||||
// Enable QtRHI debug output if not explicitly requested by the user.
|
||||
if (!qEnvironmentVariableIsSet("QSG_INFO")) {
|
||||
|
@ -129,14 +129,14 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
|
||||
QObject::connect(engine.get(), &QQmlApplicationEngine::objectCreationFailed, qApp,
|
||||
QObject::connect(engine.get(), &QQmlApplicationEngine::objectCreationFailed, application.get(),
|
||||
[](const QUrl &url){
|
||||
qCritical() << "The QML engine failed to create component:" << url;
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
#elif !QMLTC_ENABLED
|
||||
const QMetaObject::Connection connection = QObject::connect(
|
||||
engine.get(), &QQmlApplicationEngine::objectCreated, &application,
|
||||
engine.get(), &QQmlApplicationEngine::objectCreated, application.get(),
|
||||
[&mainUrl, &connection](QObject *object, const QUrl &url) {
|
||||
if (url != mainUrl) {
|
||||
return;
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
set(DEMO_NAME FramelessHelperDemo-Widget)
|
||||
|
||||
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_EXAMPLES_STANDALONE)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(${DEMO_NAME} VERSION 1.0)
|
||||
|
@ -102,3 +106,5 @@ if(FRAMELESSHELPER_EXAMPLES_DEPLOYQT)
|
|||
endif()
|
||||
deploy_qt_runtime(TARGET ${DEMO_NAME} ${__extra_flags})
|
||||
endif()
|
||||
|
||||
#dump_target_info(TARGETS ${DEMO_NAME})
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
#define CREATE_WINDOW(Name) \
|
||||
const auto Name = std::make_unique<Widget>(); \
|
||||
Name->setObjectName(FRAMELESSHELPER_STRING_LITERAL(#Name)); \
|
||||
Name->waitReady(); \
|
||||
Name->show();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Log::setup(FRAMELESSHELPER_STRING_LITERAL("widget"));
|
||||
|
@ -51,17 +57,11 @@ int main(int argc, char *argv[])
|
|||
FramelessHelper::Core::setApplicationOSThemeAware();
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
//FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
|
||||
const auto window1 = std::make_unique<Widget>();
|
||||
window1->setObjectName(FRAMELESSHELPER_STRING_LITERAL("window1"));
|
||||
window1->waitReady();
|
||||
window1->show();
|
||||
|
||||
const auto window2 = std::make_unique<Widget>();
|
||||
window2->setObjectName(FRAMELESSHELPER_STRING_LITERAL("window2"));
|
||||
window2->waitReady();
|
||||
window2->show();
|
||||
CREATE_WINDOW(widget1)
|
||||
CREATE_WINDOW(widget2)
|
||||
CREATE_WINDOW(widget3)
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include <QtWidgets/qboxlayout.h>
|
||||
#include <QtWidgets/qfileiconprovider.h>
|
||||
#include <FramelessHelper/Core/framelessmanager.h>
|
||||
#include <FramelessHelper/Core/utils.h>
|
||||
#include <FramelessHelper/Widgets/framelesswidgetshelper.h>
|
||||
#include <FramelessHelper/Widgets/standardtitlebar.h>
|
||||
#include <FramelessHelper/Widgets/standardsystembutton.h>
|
||||
|
@ -81,7 +80,7 @@ void Widget::closeEvent(QCloseEvent *event)
|
|||
|
||||
void Widget::initialize()
|
||||
{
|
||||
setWindowTitle(tr("FramelessHelper demo application - Qt Widgets"));
|
||||
setWindowTitle(tr("FramelessHelper demo application - QWidget"));
|
||||
setWindowIcon(QFileIconProvider().icon(QFileIconProvider::Computer));
|
||||
resize(800, 600);
|
||||
m_titleBar = new StandardTitleBar(this);
|
||||
|
@ -144,7 +143,7 @@ void Widget::initialize()
|
|||
|
||||
void Widget::updateStyleSheet()
|
||||
{
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
|
||||
const QColor clockLabelTextColor = (dark ? kDefaultWhiteColor : kDefaultBlackColor);
|
||||
m_clockLabel->setStyleSheet(FRAMELESSHELPER_STRING_LITERAL("background-color: transparent; color: %1;")
|
||||
.arg(clockLabelTextColor.name()));
|
||||
|
|
|
@ -138,6 +138,14 @@
|
|||
# define IsMaximized(hwnd) (IsZoomed(hwnd) != FALSE)
|
||||
#endif
|
||||
|
||||
#ifndef RECT_WIDTH
|
||||
# define RECT_WIDTH(rect) ((rect).right - (rect).left)
|
||||
#endif
|
||||
|
||||
#ifndef RECT_HEIGHT
|
||||
# define RECT_HEIGHT(rect) ((rect).bottom - (rect).top)
|
||||
#endif
|
||||
|
||||
#ifndef MMSYSERR_NOERROR
|
||||
# define MMSYSERR_NOERROR (0)
|
||||
#endif
|
||||
|
|
|
@ -259,145 +259,147 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
|
|||
[[maybe_unused]] inline const QByteArray kSysMenuDisableRestoreVar
|
||||
= FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_SYSTEM_MENU_DISABLE_RESTORE");
|
||||
|
||||
enum class Option
|
||||
enum class Option : quint8
|
||||
{
|
||||
UseCrossPlatformQtImplementation = 0,
|
||||
ForceHideWindowFrameBorder = 1,
|
||||
ForceShowWindowFrameBorder = 2,
|
||||
DisableWindowsSnapLayout = 3,
|
||||
WindowUseRoundCorners = 4,
|
||||
CenterWindowBeforeShow = 5,
|
||||
EnableBlurBehindWindow = 6,
|
||||
ForceNonNativeBackgroundBlur = 7,
|
||||
DisableLazyInitializationForMicaMaterial = 8,
|
||||
ForceNativeBackgroundBlur = 9
|
||||
UseCrossPlatformQtImplementation,
|
||||
ForceHideWindowFrameBorder,
|
||||
ForceShowWindowFrameBorder,
|
||||
DisableWindowsSnapLayout,
|
||||
WindowUseRoundCorners,
|
||||
CenterWindowBeforeShow,
|
||||
EnableBlurBehindWindow,
|
||||
ForceNonNativeBackgroundBlur,
|
||||
DisableLazyInitializationForMicaMaterial,
|
||||
ForceNativeBackgroundBlur
|
||||
};
|
||||
Q_ENUM_NS(Option)
|
||||
|
||||
enum class SystemTheme
|
||||
enum class SystemTheme : quint8
|
||||
{
|
||||
Unknown = -1,
|
||||
Light = 0,
|
||||
Dark = 1,
|
||||
HighContrast = 2
|
||||
Unknown,
|
||||
Light,
|
||||
Dark,
|
||||
HighContrast
|
||||
};
|
||||
Q_ENUM_NS(SystemTheme)
|
||||
|
||||
enum class SystemButtonType
|
||||
enum class SystemButtonType : quint8
|
||||
{
|
||||
Unknown = -1,
|
||||
WindowIcon = 0,
|
||||
Help = 1,
|
||||
Minimize = 2,
|
||||
Maximize = 3,
|
||||
Restore = 4,
|
||||
Close = 5
|
||||
Unknown,
|
||||
WindowIcon,
|
||||
Help,
|
||||
Minimize,
|
||||
Maximize,
|
||||
Restore,
|
||||
Close
|
||||
};
|
||||
Q_ENUM_NS(SystemButtonType)
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
enum class DwmColorizationArea
|
||||
enum class DwmColorizationArea : quint8
|
||||
{
|
||||
None = 0,
|
||||
StartMenu_TaskBar_ActionCenter = 1,
|
||||
TitleBar_WindowBorder = 2,
|
||||
All = 3
|
||||
None,
|
||||
StartMenu_TaskBar_ActionCenter,
|
||||
TitleBar_WindowBorder,
|
||||
All
|
||||
};
|
||||
Q_ENUM_NS(DwmColorizationArea)
|
||||
#endif // Q_OS_WINDOWS
|
||||
|
||||
enum class ButtonState
|
||||
enum class ButtonState : quint8
|
||||
{
|
||||
Unspecified = -1,
|
||||
Hovered = 0,
|
||||
Pressed = 1,
|
||||
Clicked = 2
|
||||
Normal,
|
||||
Hovered,
|
||||
Pressed,
|
||||
Released
|
||||
};
|
||||
Q_ENUM_NS(ButtonState)
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
enum class WindowsVersion
|
||||
enum class WindowsVersion : quint8
|
||||
{
|
||||
_2000 = 0,
|
||||
_XP = 1,
|
||||
_XP_64 = 2,
|
||||
_2000,
|
||||
_XP,
|
||||
_XP_64,
|
||||
_Vista,
|
||||
_Vista_SP1,
|
||||
_Vista_SP2,
|
||||
_7,
|
||||
_7_SP1,
|
||||
_8,
|
||||
_8_1,
|
||||
_8_1_Update1,
|
||||
_10_1507,
|
||||
_10_1511,
|
||||
_10_1607,
|
||||
_10_1703,
|
||||
_10_1709,
|
||||
_10_1803,
|
||||
_10_1809,
|
||||
_10_1903,
|
||||
_10_1909,
|
||||
_10_2004,
|
||||
_10_20H2,
|
||||
_10_21H1,
|
||||
_10_21H2,
|
||||
_10_22H2,
|
||||
_11_21H2,
|
||||
_11_22H2,
|
||||
|
||||
_WS_03 = _XP_64, // Windows Server 2003
|
||||
_Vista = 3,
|
||||
_Vista_SP1 = 4,
|
||||
_Vista_SP2 = 5,
|
||||
_7 = 6,
|
||||
_7_SP1 = 7,
|
||||
_8 = 8,
|
||||
_8_1 = 9,
|
||||
_8_1_Update1 = 10,
|
||||
_10_1507 = 11,
|
||||
_10_1511 = 12,
|
||||
_10_1607 = 13,
|
||||
_10_1703 = 14,
|
||||
_10_1709 = 15,
|
||||
_10_1803 = 16,
|
||||
_10_1809 = 17,
|
||||
_10_1903 = 18,
|
||||
_10_1909 = 19,
|
||||
_10_2004 = 20,
|
||||
_10_20H2 = 21,
|
||||
_10_21H1 = 22,
|
||||
_10_21H2 = 23,
|
||||
_10_22H2 = 24,
|
||||
_10 = _10_1507,
|
||||
_11_21H2 = 25,
|
||||
_11_22H2 = 26,
|
||||
_11 = _11_21H2,
|
||||
|
||||
Latest = _11_22H2
|
||||
};
|
||||
Q_ENUM_NS(WindowsVersion)
|
||||
#endif // Q_OS_WINDOWS
|
||||
|
||||
enum class BlurMode
|
||||
enum class BlurMode : quint8
|
||||
{
|
||||
Disable = 0, // Do not enable blur behind window
|
||||
Default = 1, // Use platform default blur mode
|
||||
Windows_Aero = 2, // Windows only, use the traditional DWM blur
|
||||
Windows_Acrylic = 3, // Windows only, use the Acrylic blur
|
||||
Windows_Mica = 4, // Windows only, use the Mica material
|
||||
Windows_MicaAlt = 5 // Windows only, use the Mica Alt material
|
||||
Disable, // Do not enable blur behind window
|
||||
Default, // Use platform default blur mode
|
||||
Windows_Aero, // Windows only, use the traditional DWM blur
|
||||
Windows_Acrylic, // Windows only, use the Acrylic blur
|
||||
Windows_Mica, // Windows only, use the Mica material
|
||||
Windows_MicaAlt // Windows only, use the Mica Alt material
|
||||
};
|
||||
Q_ENUM_NS(BlurMode)
|
||||
|
||||
enum class WallpaperAspectStyle
|
||||
enum class WallpaperAspectStyle : quint8
|
||||
{
|
||||
Fill = 0, // Keep aspect ratio to fill, expand/crop if necessary.
|
||||
Fit = 1, // Keep aspect ratio to fill, but don't expand/crop.
|
||||
Stretch = 2, // Ignore aspect ratio to fill.
|
||||
Tile = 3,
|
||||
Center = 4,
|
||||
Span = 5 // ???
|
||||
Fill, // Keep aspect ratio to fill, expand/crop if necessary.
|
||||
Fit, // Keep aspect ratio to fill, but don't expand/crop.
|
||||
Stretch, // Ignore aspect ratio to fill.
|
||||
Tile,
|
||||
Center,
|
||||
Span // ???
|
||||
};
|
||||
Q_ENUM_NS(WallpaperAspectStyle)
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
enum class RegistryRootKey
|
||||
enum class RegistryRootKey : quint8
|
||||
{
|
||||
ClassesRoot = 0,
|
||||
CurrentUser = 1,
|
||||
LocalMachine = 2,
|
||||
Users = 3,
|
||||
PerformanceData = 4,
|
||||
CurrentConfig = 5,
|
||||
DynData = 6,
|
||||
CurrentUserLocalSettings = 7,
|
||||
PerformanceText = 8,
|
||||
PerformanceNlsText = 9
|
||||
ClassesRoot,
|
||||
CurrentUser,
|
||||
LocalMachine,
|
||||
Users,
|
||||
PerformanceData,
|
||||
CurrentConfig,
|
||||
DynData,
|
||||
CurrentUserLocalSettings,
|
||||
PerformanceText,
|
||||
PerformanceNlsText
|
||||
};
|
||||
Q_ENUM_NS(RegistryRootKey)
|
||||
#endif // Q_OS_WINDOWS
|
||||
|
||||
enum class WindowEdge : quint32
|
||||
enum class WindowEdge : quint8
|
||||
{
|
||||
Left = 0x00000001,
|
||||
Top = 0x00000002,
|
||||
Right = 0x00000004,
|
||||
Bottom = 0x00000008
|
||||
Left = 1 << 0,
|
||||
Top = 1 << 1,
|
||||
Right = 1 << 2,
|
||||
Bottom = 1 << 3
|
||||
};
|
||||
Q_ENUM_NS(WindowEdge)
|
||||
Q_DECLARE_FLAGS(WindowEdges, WindowEdge)
|
||||
|
@ -405,23 +407,23 @@ Q_FLAG_NS(WindowEdges)
|
|||
Q_DECLARE_OPERATORS_FOR_FLAGS(WindowEdges)
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
enum class DpiAwareness
|
||||
enum class DpiAwareness : quint8
|
||||
{
|
||||
Unknown = -1,
|
||||
Unaware = 0,
|
||||
System = 1,
|
||||
PerMonitor = 2,
|
||||
PerMonitorVersion2 = 3,
|
||||
Unaware_GdiScaled = 4
|
||||
Unknown,
|
||||
Unaware,
|
||||
System,
|
||||
PerMonitor,
|
||||
PerMonitorVersion2,
|
||||
Unaware_GdiScaled
|
||||
};
|
||||
Q_ENUM_NS(DpiAwareness)
|
||||
#endif // Q_OS_WINDOWS
|
||||
|
||||
enum class WindowCornerStyle
|
||||
enum class WindowCornerStyle : quint8
|
||||
{
|
||||
Default = 0,
|
||||
Square = 1,
|
||||
Round = 2
|
||||
Default,
|
||||
Square,
|
||||
Round
|
||||
};
|
||||
Q_ENUM_NS(WindowCornerStyle)
|
||||
|
||||
|
@ -440,6 +442,16 @@ struct Dpi
|
|||
{
|
||||
quint32 x = 0;
|
||||
quint32 y = 0;
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(const Dpi &lhs, const Dpi &rhs) noexcept
|
||||
{
|
||||
return ((lhs.x == rhs.x) && (lhs.y == rhs.y));
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator!=(const Dpi &lhs, const Dpi &rhs) noexcept
|
||||
{
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Global
|
||||
|
|
|
@ -36,7 +36,7 @@ class FRAMELESSHELPER_CORE_API FramelessManager : public QObject
|
|||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(FramelessManager)
|
||||
Q_DISABLE_COPY_MOVE(FramelessManager)
|
||||
Q_PROPERTY(Global::SystemTheme systemTheme READ systemTheme NOTIFY systemThemeChanged FINAL)
|
||||
Q_PROPERTY(Global::SystemTheme systemTheme READ systemTheme WRITE setOverrideTheme NOTIFY systemThemeChanged FINAL)
|
||||
Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemThemeChanged FINAL)
|
||||
Q_PROPERTY(QString wallpaper READ wallpaper NOTIFY wallpaperChanged FINAL)
|
||||
Q_PROPERTY(Global::WallpaperAspectStyle wallpaperAspectStyle READ wallpaperAspectStyle NOTIFY wallpaperChanged FINAL)
|
||||
|
@ -55,6 +55,7 @@ public:
|
|||
public Q_SLOTS:
|
||||
void addWindow(const SystemParameters *params);
|
||||
void removeWindow(const WId windowId);
|
||||
void setOverrideTheme(const Global::SystemTheme theme);
|
||||
|
||||
Q_SIGNALS:
|
||||
void systemThemeChanged();
|
||||
|
|
|
@ -38,7 +38,9 @@ class FRAMELESSHELPER_CORE_API MicaMaterial : public QObject
|
|||
|
||||
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged FINAL)
|
||||
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged FINAL)
|
||||
Q_PROPERTY(QColor fallbackColor READ fallbackColor WRITE setFallbackColor NOTIFY fallbackColorChanged FINAL)
|
||||
Q_PROPERTY(qreal noiseOpacity READ noiseOpacity WRITE setNoiseOpacity NOTIFY noiseOpacityChanged FINAL)
|
||||
Q_PROPERTY(bool fallbackEnabled READ isFallbackEnabled WRITE setFallbackEnabled NOTIFY fallbackEnabledChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit MicaMaterial(QObject *parent = nullptr);
|
||||
|
@ -50,16 +52,24 @@ public:
|
|||
Q_NODISCARD qreal tintOpacity() const;
|
||||
void setTintOpacity(const qreal value);
|
||||
|
||||
Q_NODISCARD QColor fallbackColor() const;
|
||||
void setFallbackColor(const QColor &value);
|
||||
|
||||
Q_NODISCARD qreal noiseOpacity() const;
|
||||
void setNoiseOpacity(const qreal value);
|
||||
|
||||
Q_NODISCARD bool isFallbackEnabled() const;
|
||||
void setFallbackEnabled(const bool value);
|
||||
|
||||
public Q_SLOTS:
|
||||
void paint(QPainter *painter, const QSize &size, const QPoint &pos);
|
||||
void paint(QPainter *painter, const QSize &size, const QPoint &pos, const bool active = true);
|
||||
|
||||
Q_SIGNALS:
|
||||
void tintColorChanged();
|
||||
void tintOpacityChanged();
|
||||
void fallbackColorChanged();
|
||||
void noiseOpacityChanged();
|
||||
void fallbackEnabledChanged();
|
||||
void shouldRedraw();
|
||||
|
||||
private:
|
||||
|
|
|
@ -61,6 +61,7 @@ using GetPropertyCallback = std::function<QVariant(const QByteArray &, const QVa
|
|||
using SetCursorCallback = std::function<void(const QCursor &)>;
|
||||
using UnsetCursorCallback = std::function<void()>;
|
||||
using GetWidgetHandleCallback = std::function<QObject *()>;
|
||||
using ForceChildrenRepaintCallback = std::function<void(const int)>;
|
||||
|
||||
struct SystemParameters
|
||||
{
|
||||
|
@ -90,6 +91,7 @@ struct SystemParameters
|
|||
SetCursorCallback setCursor = nullptr;
|
||||
UnsetCursorCallback unsetCursor = nullptr;
|
||||
GetWidgetHandleCallback getWidgetHandle = nullptr;
|
||||
ForceChildrenRepaintCallback forceChildrenRepaint = nullptr;
|
||||
};
|
||||
|
||||
using FramelessParams = SystemParameters *;
|
||||
|
|
|
@ -60,12 +60,16 @@ public:
|
|||
|
||||
Q_NODISCARD static bool usePureQtImplementation();
|
||||
|
||||
void setOverrideTheme(const Global::SystemTheme theme);
|
||||
Q_NODISCARD bool isThemeOverrided() const;
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
FramelessManager *q_ptr = nullptr;
|
||||
Global::SystemTheme m_systemTheme = Global::SystemTheme::Unknown;
|
||||
std::optional<Global::SystemTheme> m_overrideTheme = std::nullopt;
|
||||
QColor m_accentColor = {};
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Global::DwmColorizationArea m_colorizationArea = Global::DwmColorizationArea::None;
|
||||
|
|
|
@ -31,6 +31,12 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
class MicaMaterial;
|
||||
|
||||
using Transform = struct Transform
|
||||
{
|
||||
qreal Horizontal = 0;
|
||||
qreal Vertical = 0;
|
||||
};
|
||||
|
||||
class FRAMELESSHELPER_CORE_API MicaMaterialPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -44,10 +50,12 @@ public:
|
|||
Q_NODISCARD static MicaMaterialPrivate *get(MicaMaterial *q);
|
||||
Q_NODISCARD static const MicaMaterialPrivate *get(const MicaMaterial *q);
|
||||
|
||||
Q_NODISCARD static QColor systemFallbackColor();
|
||||
|
||||
public Q_SLOTS:
|
||||
void maybeGenerateBlurredWallpaper(const bool force = false);
|
||||
void updateMaterialBrush();
|
||||
void paint(QPainter *painter, const QSize &size, const QPoint &pos);
|
||||
void paint(QPainter *painter, const QSize &size, const QPoint &pos, const bool active = true);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
@ -57,9 +65,12 @@ private:
|
|||
MicaMaterial *q_ptr = nullptr;
|
||||
QColor tintColor = {};
|
||||
qreal tintOpacity = 0.0;
|
||||
QColor fallbackColor = {};
|
||||
qreal noiseOpacity = 0.0;
|
||||
bool fallbackEnabled = true;
|
||||
QBrush micaBrush = {};
|
||||
bool initialized = false;
|
||||
Transform transform = {};
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -52,7 +52,6 @@ FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges
|
|||
[[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId windowId);
|
||||
FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
|
||||
const SystemParameters *params, const bool considerTaskBar);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::SystemTheme getSystemTheme();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::WindowState windowStatesToWindowState(
|
||||
const Qt::WindowStates states);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isThemeChangeEvent(const QEvent * const event);
|
||||
|
@ -81,6 +80,11 @@ FRAMELESSHELPER_CORE_API void registerThemeChangeNotification();
|
|||
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint fromNativeLocalPosition(const QWindow *window, const QPoint &point);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint fromNativeGlobalPosition(const QWindow *window, const QPoint &point);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API int horizontalAdvance(const QFontMetrics &fm, const QString &str);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API qreal getRelativeScaleFactor(const quint32 oldDpi, const quint32 newDpi);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QSize rescaleSize(const QSize &oldSize, const quint32 oldDpi, const quint32 newDpi);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isValidGeometry(const QRect &rect);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 defaultScreenDpi();
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
|
||||
|
@ -122,8 +126,8 @@ FRAMELESSHELPER_CORE_API void setAeroSnappingEnabled(const WId windowId, const b
|
|||
FRAMELESSHELPER_CORE_API void tryToEnableHighestDpiAwarenessLevel();
|
||||
FRAMELESSHELPER_CORE_API void updateGlobalWin32ControlsTheme(const WId windowId, const bool dark);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_windows();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_windows();
|
||||
FRAMELESSHELPER_CORE_API void setCornerStyleForWindow(const WId windowId, const Global::WindowCornerStyle style);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmAccentColor();
|
||||
FRAMELESSHELPER_CORE_API void hideOriginalTitleBarElements
|
||||
(const WId windowId, const bool disable = true);
|
||||
FRAMELESSHELPER_CORE_API void setQtDarkModeAwareEnabled(const bool enable);
|
||||
|
@ -135,6 +139,10 @@ FRAMELESSHELPER_CORE_API void fixupChildWindowsDpiMessage(const WId windowId);
|
|||
FRAMELESSHELPER_CORE_API void fixupDialogsDpiScaling();
|
||||
FRAMELESSHELPER_CORE_API void setDarkModeAllowedForApp(const bool allow = true);
|
||||
FRAMELESSHELPER_CORE_API void bringWindowToFront(const WId windowId);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint getWindowPlacementOffset(const WId windowId);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QRect getWindowRestoreGeometry(const WId windowId);
|
||||
FRAMELESSHELPER_CORE_API void removeMicaWindow(const WId windowId);
|
||||
FRAMELESSHELPER_CORE_API void removeSysMenuHook(const WId windowId);
|
||||
#endif // Q_OS_WINDOWS
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
|
@ -161,7 +169,7 @@ FRAMELESSHELPER_CORE_API void clearWindowProperty(const WId windowId, const xcb_
|
|||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool tryHideSystemTitleBar(const WId windowId, const bool hide = true);
|
||||
FRAMELESSHELPER_CORE_API void openSystemMenu(const WId windowId, const QPoint &globalPos);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_linux();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getWmThemeColor();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_linux();
|
||||
FRAMELESSHELPER_CORE_API void sendMoveResizeMessage
|
||||
(const WId windowId, const uint32_t action, const QPoint &globalPos, const Qt::MouseButton button = Qt::LeftButton);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isCustomDecorationSupported();
|
||||
|
@ -171,8 +179,8 @@ FRAMELESSHELPER_CORE_API void sendMoveResizeMessage
|
|||
|
||||
#ifdef Q_OS_MACOS
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_macos();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getAccentColor_macos();
|
||||
FRAMELESSHELPER_CORE_API void setSystemTitleBarVisible(const WId windowId, const bool visible);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getControlsAccentColor();
|
||||
FRAMELESSHELPER_CORE_API void removeWindowProxy(const WId windowId);
|
||||
#endif // Q_OS_MACOS
|
||||
} // namespace Utils
|
||||
|
|
|
@ -90,7 +90,7 @@ public:
|
|||
explicit QuickGlobal(QObject *parent = nullptr);
|
||||
~QuickGlobal() override;
|
||||
|
||||
enum class SystemTheme
|
||||
enum class SystemTheme : quint8
|
||||
{
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(SystemTheme, Unknown)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(SystemTheme, Light)
|
||||
|
@ -99,7 +99,7 @@ public:
|
|||
};
|
||||
Q_ENUM(SystemTheme)
|
||||
|
||||
enum class SystemButtonType
|
||||
enum class SystemButtonType : quint8
|
||||
{
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(SystemButtonType, Unknown)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(SystemButtonType, WindowIcon)
|
||||
|
@ -111,16 +111,16 @@ public:
|
|||
};
|
||||
Q_ENUM(SystemButtonType)
|
||||
|
||||
enum class ButtonState
|
||||
enum class ButtonState : quint8
|
||||
{
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Unspecified)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Normal)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Hovered)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Pressed)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Clicked)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Released)
|
||||
};
|
||||
Q_ENUM(ButtonState)
|
||||
|
||||
enum class BlurMode
|
||||
enum class BlurMode : quint8
|
||||
{
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(BlurMode, Disable)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(BlurMode, Default)
|
||||
|
@ -131,7 +131,7 @@ public:
|
|||
};
|
||||
Q_ENUM(BlurMode)
|
||||
|
||||
enum class WindowEdge : quint32
|
||||
enum class WindowEdge : quint8
|
||||
{
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Left)
|
||||
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Top)
|
||||
|
|
|
@ -47,7 +47,7 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickUtils : public QObject, public QQm
|
|||
Q_PROPERTY(qreal titleBarHeight READ titleBarHeight CONSTANT FINAL)
|
||||
Q_PROPERTY(bool frameBorderVisible READ frameBorderVisible CONSTANT FINAL)
|
||||
Q_PROPERTY(qreal frameBorderThickness READ frameBorderThickness CONSTANT FINAL)
|
||||
Q_PROPERTY(QuickGlobal::SystemTheme systemTheme READ systemTheme NOTIFY systemThemeChanged FINAL)
|
||||
Q_PROPERTY(QuickGlobal::SystemTheme systemTheme READ systemTheme WRITE setOverrideTheme NOTIFY systemThemeChanged FINAL)
|
||||
Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemAccentColorChanged FINAL)
|
||||
Q_PROPERTY(bool titleBarColorized READ titleBarColorized NOTIFY titleBarColorizedChanged FINAL)
|
||||
Q_PROPERTY(QColor defaultSystemLightColor READ defaultSystemLightColor CONSTANT FINAL)
|
||||
|
@ -65,6 +65,7 @@ public:
|
|||
Q_NODISCARD bool frameBorderVisible() const;
|
||||
Q_NODISCARD qreal frameBorderThickness() const;
|
||||
Q_NODISCARD QuickGlobal::SystemTheme systemTheme() const;
|
||||
void setOverrideTheme(const QuickGlobal::SystemTheme theme);
|
||||
Q_NODISCARD QColor systemAccentColor() const;
|
||||
Q_NODISCARD bool titleBarColorized() const;
|
||||
Q_NODISCARD QColor defaultSystemLightColor() const;
|
||||
|
|
|
@ -88,6 +88,8 @@ public:
|
|||
Q_NODISCARD bool isReady() const;
|
||||
void waitForReady();
|
||||
|
||||
void repaintAllChildren(const int delay = 0) const;
|
||||
|
||||
private:
|
||||
Q_NODISCARD QRect mapItemGeometryToScene(const QQuickItem * const item) const;
|
||||
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, QuickGlobal::SystemButtonType *button) const;
|
||||
|
|
|
@ -26,8 +26,13 @@
|
|||
|
||||
#include <FramelessHelper/Quick/framelesshelperquick_global.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQuickRectangle;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class MicaMaterial;
|
||||
class QuickMicaMaterial;
|
||||
class WallpaperImageNode;
|
||||
|
||||
|
@ -48,15 +53,21 @@ public Q_SLOTS:
|
|||
void rebindWindow();
|
||||
void forceRegenerateWallpaperImageCache();
|
||||
void appendNode(WallpaperImageNode *node);
|
||||
void updateFallbackColor();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
friend class WallpaperImageNode;
|
||||
|
||||
QuickMicaMaterial *q_ptr = nullptr;
|
||||
QMetaObject::Connection m_rootWindowXChangedConnection = {};
|
||||
QMetaObject::Connection m_rootWindowYChangedConnection = {};
|
||||
QMetaObject::Connection m_rootWindowActiveChangedConnection = {};
|
||||
QList<QPointer<WallpaperImageNode>> m_nodes = {};
|
||||
QQuickRectangle *m_fallbackColorItem = nullptr;
|
||||
MicaMaterial *m_micaMaterial = nullptr;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -40,10 +40,38 @@ class FRAMELESSHELPER_QUICK_API QuickMicaMaterial : public QQuickItem
|
|||
Q_DISABLE_COPY_MOVE(QuickMicaMaterial)
|
||||
Q_DECLARE_PRIVATE(QuickMicaMaterial)
|
||||
|
||||
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged FINAL)
|
||||
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged FINAL)
|
||||
Q_PROPERTY(QColor fallbackColor READ fallbackColor WRITE setFallbackColor NOTIFY fallbackColorChanged FINAL)
|
||||
Q_PROPERTY(qreal noiseOpacity READ noiseOpacity WRITE setNoiseOpacity NOTIFY noiseOpacityChanged FINAL)
|
||||
Q_PROPERTY(bool fallbackEnabled READ isFallbackEnabled WRITE setFallbackEnabled NOTIFY fallbackEnabledChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit QuickMicaMaterial(QQuickItem *parent = nullptr);
|
||||
~QuickMicaMaterial() override;
|
||||
|
||||
Q_NODISCARD QColor tintColor() const;
|
||||
void setTintColor(const QColor &value);
|
||||
|
||||
Q_NODISCARD qreal tintOpacity() const;
|
||||
void setTintOpacity(const qreal value);
|
||||
|
||||
Q_NODISCARD QColor fallbackColor() const;
|
||||
void setFallbackColor(const QColor &value);
|
||||
|
||||
Q_NODISCARD qreal noiseOpacity() const;
|
||||
void setNoiseOpacity(const qreal value);
|
||||
|
||||
Q_NODISCARD bool isFallbackEnabled() const;
|
||||
void setFallbackEnabled(const bool value);
|
||||
|
||||
Q_SIGNALS:
|
||||
void tintColorChanged();
|
||||
void tintOpacityChanged();
|
||||
void fallbackColorChanged();
|
||||
void noiseOpacityChanged();
|
||||
void fallbackEnabledChanged();
|
||||
|
||||
protected:
|
||||
void itemChange(const ItemChange change, const ItemChangeData &value) override;
|
||||
[[nodiscard]] QSGNode *updatePaintNode(QSGNode *old, UpdatePaintNodeData *data) override;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <FramelessHelper/Widgets/framelesshelperwidgets_global.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtWidgets/qsizepolicy.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -89,6 +90,8 @@ public:
|
|||
Q_NODISCARD bool isReady() const;
|
||||
void waitForReady();
|
||||
|
||||
void repaintAllChildren(const int delay = 0) const;
|
||||
|
||||
private:
|
||||
Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const;
|
||||
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const;
|
||||
|
@ -106,6 +109,7 @@ private:
|
|||
QPointer<QWidget> m_window = nullptr;
|
||||
bool m_destroying = false;
|
||||
bool m_qpaReady = false;
|
||||
QSizePolicy m_savedSizePolicy = {};
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<LibraryPath>$(MSBuildThisFileDirectory)lib;$(LibraryPath)</LibraryPath>
|
||||
<LibraryPath>$(MSBuildThisFileDirectory)lib64;$(MSBuildThisFileDirectory)lib64\debug;$(MSBuildThisFileDirectory)lib64\release;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="QtSettings">
|
||||
<QtHeaderSearchPath>$(MSBuildThisFileDirectory)include;$(MSBuildThisFileDirectory)include\FramelessHelper;$(MSBuildThisFileDirectory)include\FramelessHelper\Core;$(MSBuildThisFileDirectory)include\FramelessHelper\Core\private;$(MSBuildThisFileDirectory)include\FramelessHelper\Widgets;$(MSBuildThisFileDirectory)include\FramelessHelper\Widgets\private;$(MSBuildThisFileDirectory)include\FramelessHelper\Quick;$(MSBuildThisFileDirectory)include\FramelessHelper\Quick\private;$(QtHeaderSearchPath)</QtHeaderSearchPath>
|
||||
|
|
|
@ -34,10 +34,10 @@
|
|||
#define _FRAMELESSHELPER_VERSION_DEFINED_
|
||||
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MAJOR = 2;
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MINOR = 3;
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_PATCH = 6;
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MINOR = 4;
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_PATCH = 0;
|
||||
//[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_TWEAK = 0;
|
||||
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_VERSION_STR[] = "2.3.6";
|
||||
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_VERSION_STR[] = "2.4.0";
|
||||
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_COMMIT_STR[] = "UNKNOWN";
|
||||
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_COMPILE_DATETIME_STR[] = "UNKNOWN";
|
||||
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(FRAMELESSHELPER_NO_PRIVATE)
|
||||
# Qt X11Extras is only available in Qt5.
|
||||
|
@ -48,11 +52,11 @@ if(UNIX AND NOT APPLE)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
set(SUB_MOD_NAME Core)
|
||||
set(SUB_PROJ_NAME ${PROJECT_NAME}${SUB_MOD_NAME})
|
||||
set(SUB_PROJ_PATH ${PROJECT_NAME}/${SUB_MOD_NAME})
|
||||
set(SUB_MODULE Core)
|
||||
set(SUB_MODULE_FULL_NAME ${PROJECT_NAME}${SUB_MODULE})
|
||||
set(SUB_MODULE_PATH ${PROJECT_NAME}/${SUB_MODULE})
|
||||
|
||||
set(INCLUDE_PREFIX ../../include/${SUB_PROJ_PATH})
|
||||
set(INCLUDE_PREFIX ../../include/${SUB_MODULE_PATH})
|
||||
|
||||
configure_file(framelesshelper.version.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/framelesshelper.version @ONLY)
|
||||
|
@ -138,18 +142,20 @@ elseif(UNIX)
|
|||
endif()
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(__rc_path "${CMAKE_CURRENT_BINARY_DIR}/${SUB_PROJ_NAME}.rc")
|
||||
set(__rc_path "${CMAKE_CURRENT_BINARY_DIR}/${SUB_MODULE_FULL_NAME}.rc")
|
||||
if(NOT EXISTS "${__rc_path}")
|
||||
generate_win32_rc_file(
|
||||
PATH "${__rc_path}"
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
COMPANY "wangwenx190"
|
||||
DESCRIPTION "${PROJECT_NAME} ${SUB_MOD_NAME} Module"
|
||||
DESCRIPTION "${PROJECT_NAME} ${SUB_MODULE} Module"
|
||||
COPYRIGHT "MIT License"
|
||||
ORIGINAL_FILENAME "${PROJECT_NAME}${SUB_MOD_NAME}.dll"
|
||||
ORIGINAL_FILENAME "${PROJECT_NAME}${SUB_MODULE}.dll"
|
||||
PRODUCT "${PROJECT_NAME}"
|
||||
COMMENTS "Built from commit ${PROJECT_VERSION_COMMIT} on ${PROJECT_COMPILE_DATETIME} (UTC)."
|
||||
LIBRARY
|
||||
)
|
||||
endif()
|
||||
list(APPEND SOURCES "${__rc_path}")
|
||||
endif()
|
||||
|
||||
|
@ -160,56 +166,22 @@ if(FRAMELESSHELPER_BUILD_STATIC)
|
|||
else()
|
||||
set(SUB_MOD_LIB_TYPE "SHARED")
|
||||
endif()
|
||||
add_library(${SUB_PROJ_NAME} ${SUB_MOD_LIB_TYPE} ${ALL_SOURCES})
|
||||
add_library(${PROJECT_NAME}::${SUB_PROJ_NAME} ALIAS ${SUB_PROJ_NAME})
|
||||
add_library(${PROJECT_NAME}::${SUB_MOD_NAME} ALIAS ${SUB_PROJ_NAME})
|
||||
add_library(${SUB_MODULE} ${SUB_MOD_LIB_TYPE} ${ALL_SOURCES})
|
||||
add_library(${SUB_MODULE_FULL_NAME} ALIAS ${SUB_MODULE})
|
||||
add_library(${PROJECT_NAME}::${SUB_MODULE} ALIAS ${SUB_MODULE})
|
||||
add_library(${PROJECT_NAME}::${SUB_MODULE_FULL_NAME} ALIAS ${SUB_MODULE})
|
||||
|
||||
set_target_properties(${SUB_PROJ_NAME} PROPERTIES
|
||||
set_target_properties(${SUB_MODULE} PROPERTIES
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}"
|
||||
OUTPUT_NAME "${SUB_MODULE_FULL_NAME}"
|
||||
)
|
||||
|
||||
set(SUB_MOD_TARGETS ${SUB_PROJ_NAME})
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(SUB_MOD_LIB_DIR "${CMAKE_INSTALL_BINDIR}")
|
||||
else()
|
||||
set(SUB_MOD_LIB_DIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
set(__prefix "")
|
||||
if(NOT WIN32)
|
||||
set(__prefix "lib")
|
||||
endif()
|
||||
set(__suffix "")
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
if(MSVC)
|
||||
set(__suffix "lib")
|
||||
else()
|
||||
set(__suffix "a")
|
||||
endif()
|
||||
else()
|
||||
if(WIN32)
|
||||
set(__suffix "dll")
|
||||
elseif(APPLE)
|
||||
set(__suffix "dylib")
|
||||
elseif(UNIX)
|
||||
set(__suffix "so")
|
||||
endif()
|
||||
endif()
|
||||
set(SUB_MOD_FILE_PREFIX "${__prefix}")
|
||||
set(SUB_MOD_FILE_SUFFIX "${__suffix}")
|
||||
set(SUB_MOD_FILE_BASENAME "${SUB_MOD_FILE_PREFIX}${SUB_PROJ_NAME}")
|
||||
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
|
||||
string(APPEND SUB_MOD_FILE_BASENAME "${CMAKE_DEBUG_POSTFIX}")
|
||||
endif()
|
||||
set(SUB_MOD_FILE_NAME "${SUB_MOD_FILE_BASENAME}.${SUB_MOD_FILE_SUFFIX}")
|
||||
unset(__suffix)
|
||||
unset(__prefix)
|
||||
set(__export_targets ${SUB_MODULE})
|
||||
|
||||
if(NOT FRAMELESSHELPER_NO_BUNDLE_RESOURCE)
|
||||
if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
|
||||
qt_add_resources(${SUB_PROJ_NAME} framelesshelpercore
|
||||
qt_add_resources(${SUB_MODULE} framelesshelpercore
|
||||
PREFIX
|
||||
"/org.wangwenx190.${PROJECT_NAME}"
|
||||
FILES
|
||||
|
@ -218,115 +190,103 @@ if(NOT FRAMELESSHELPER_NO_BUNDLE_RESOURCE)
|
|||
OUTPUT_TARGETS __qrc_targets
|
||||
)
|
||||
if(__qrc_targets)
|
||||
foreach(__target ${__qrc_targets})
|
||||
list(APPEND SUB_MOD_TARGETS ${__target})
|
||||
list(APPEND __export_targets ${__qrc_targets})
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
target_sources(${SUB_PROJ_NAME} PRIVATE
|
||||
foreach(__target ${__qrc_targets})
|
||||
target_sources(${SUB_MODULE} PRIVATE
|
||||
$<TARGET_OBJECTS:${__target}>
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
target_sources(${SUB_PROJ_NAME} PRIVATE
|
||||
target_sources(${SUB_MODULE} PRIVATE
|
||||
framelesshelpercore.qrc
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(__def FRAMELESSHELPER_CORE_STATIC)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_CORE_STATIC)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_DEBUG_OUTPUT)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
target_compile_definitions(${SUB_MODULE} PRIVATE
|
||||
FRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_BUNDLE_RESOURCE)
|
||||
set(__def FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_PRIVATE)
|
||||
set(__def FRAMELESSHELPER_CORE_NO_PRIVATE)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_CORE_NO_PRIVATE)
|
||||
endif()
|
||||
|
||||
if(DEFINED FRAMELESSHELPER_NAMESPACE)
|
||||
if("x${FRAMELESSHELPER_NAMESPACE}" STREQUAL "x")
|
||||
message(FATAL_ERROR "FRAMELESSHELPER_NAMESPACE can't be empty!")
|
||||
endif()
|
||||
set(__def FRAMELESSHELPER_NAMESPACE=${FRAMELESSHELPER_NAMESPACE})
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_NAMESPACE=${FRAMELESSHELPER_NAMESPACE})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
target_compile_definitions(${SUB_MODULE} PRIVATE
|
||||
FRAMELESSHELPER_CORE_LIBRARY
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
"-framework Foundation"
|
||||
"-framework Cocoa"
|
||||
"-framework AppKit"
|
||||
)
|
||||
elseif(UNIX)
|
||||
if(TARGET X11::xcb)
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
X11::xcb
|
||||
)
|
||||
endif()
|
||||
if(TARGET PkgConfig::GTK3)
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
PkgConfig::GTK3
|
||||
)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
target_compile_definitions(${SUB_MODULE} PRIVATE
|
||||
GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_PRIVATE)
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
)
|
||||
# Qt X11Extras was first introduced in 5.1 and got removed in 6.0
|
||||
# But it was again brought back as a private feature of QtGui in 6.2
|
||||
if(TARGET Qt5::X11Extras)
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
Qt5::X11Extras
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::CorePrivate
|
||||
Qt${QT_VERSION_MAJOR}::GuiPrivate
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(${SUB_PROJ_NAME} PUBLIC
|
||||
target_include_directories(${SUB_MODULE} PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/../..>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/private>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}/private>"
|
||||
)
|
||||
|
||||
setup_qt_stuff(TARGETS ${SUB_PROJ_NAME})
|
||||
setup_qt_stuff(TARGETS ${SUB_MODULE})
|
||||
set(__extra_flags)
|
||||
if(NOT FRAMELESSHELPER_NO_PERMISSIVE_CHECKS)
|
||||
list(APPEND __extra_flags PERMISSIVE)
|
||||
|
@ -346,31 +306,22 @@ endif()
|
|||
if(FRAMELESSHELPER_ENABLE_CFGUARD)
|
||||
list(APPEND __extra_flags CFGUARD)
|
||||
endif()
|
||||
setup_compile_params(TARGETS ${SUB_PROJ_NAME} ${__extra_flags})
|
||||
if(FRAMELESSHELPER_FORCE_LTO)
|
||||
list(APPEND __extra_flags FORCE_LTO)
|
||||
endif()
|
||||
setup_compile_params(TARGETS ${SUB_MODULE} ${__extra_flags})
|
||||
if(NOT FRAMELESSHELPER_NO_INSTALL)
|
||||
set(__cmake_dir "${CMAKE_CURRENT_BINARY_DIR}/cmake")
|
||||
set(__config_file "${__cmake_dir}/${SUB_PROJ_NAME}Config.cmake")
|
||||
configure_file(../../FramelessHelperModuleConfig.cmake.in ${__config_file} @ONLY)
|
||||
set(__targets_file "${__cmake_dir}/${SUB_PROJ_NAME}Targets.cmake")
|
||||
configure_file(../../FramelessHelperModuleTargets.cmake.in ${__targets_file} @ONLY)
|
||||
install(
|
||||
FILES "${__config_file}" "${__targets_file}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${SUB_PROJ_NAME}"
|
||||
)
|
||||
set(__inc_dir "${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}")
|
||||
install(
|
||||
FILES ${PUBLIC_HEADERS} ${PUBLIC_HEADERS_ALIAS}
|
||||
DESTINATION "${__inc_dir}"
|
||||
)
|
||||
install(
|
||||
FILES ${PRIVATE_HEADERS}
|
||||
DESTINATION "${__inc_dir}/private"
|
||||
)
|
||||
install(
|
||||
TARGETS ${SUB_MOD_TARGETS}
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${__inc_dir}"
|
||||
setup_package_export(
|
||||
TARGETS ${__export_targets}
|
||||
NAMESPACE ${PROJECT_NAME}
|
||||
PACKAGE_NAME ${PROJECT_NAME}
|
||||
COMPONENT ${SUB_MODULE}
|
||||
PUBLIC_HEADERS ${PUBLIC_HEADERS}
|
||||
ALIAS_HEADERS ${PUBLIC_HEADERS_ALIAS}
|
||||
PRIVATE_HEADERS ${PRIVATE_HEADERS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT FRAMELESSHELPER_NO_SUMMARY)
|
||||
dump_target_info(TARGETS ${SUB_MODULE})
|
||||
endif()
|
||||
|
|
|
@ -81,18 +81,10 @@ const ChromePalettePrivate *ChromePalettePrivate::get(const ChromePalette *q)
|
|||
void ChromePalettePrivate::refresh()
|
||||
{
|
||||
const bool colorized = Utils::isTitleBarColorized();
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
|
||||
titleBarActiveBackgroundColor_sys = [colorized, dark]() -> QColor {
|
||||
if (colorized) {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return Utils::getDwmAccentColor();
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return Utils::getWmThemeColor();
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return Utils::getControlsAccentColor();
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
return Utils::getAccentColor();
|
||||
} else {
|
||||
return (dark ? kDefaultBlackColor : kDefaultWhiteColor);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
|
||||
#include "framelessconfig_p.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
|
@ -81,7 +80,6 @@ static constexpr const auto OptionCount = std::size(OptionsTable);
|
|||
|
||||
struct ConfigData
|
||||
{
|
||||
QMutex mutex;
|
||||
bool loaded = false;
|
||||
bool options[OptionCount] = {};
|
||||
bool disableEnvVar = false;
|
||||
|
@ -134,7 +132,6 @@ FramelessConfig *FramelessConfig::instance()
|
|||
|
||||
void FramelessConfig::reload(const bool force)
|
||||
{
|
||||
const QMutexLocker locker(&g_data()->mutex);
|
||||
if (g_data()->loaded && !force) {
|
||||
return;
|
||||
}
|
||||
|
@ -160,25 +157,21 @@ void FramelessConfig::reload(const bool force)
|
|||
|
||||
void FramelessConfig::set(const Option option, const bool on)
|
||||
{
|
||||
const QMutexLocker locker(&g_data()->mutex);
|
||||
g_data()->options[static_cast<int>(option)] = on;
|
||||
}
|
||||
|
||||
bool FramelessConfig::isSet(const Option option) const
|
||||
{
|
||||
const QMutexLocker locker(&g_data()->mutex);
|
||||
return g_data()->options[static_cast<int>(option)];
|
||||
}
|
||||
|
||||
void FramelessConfig::setLoadFromEnvironmentVariablesDisabled(const bool on)
|
||||
{
|
||||
const QMutexLocker locker(&g_data()->mutex);
|
||||
g_data()->disableEnvVar = on;
|
||||
}
|
||||
|
||||
void FramelessConfig::setLoadFromConfigurationFileDisabled(const bool on)
|
||||
{
|
||||
const QMutexLocker locker(&g_data()->mutex);
|
||||
g_data()->disableCfgFile = on;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "framelessconfig_p.h"
|
||||
#include "framelesshelpercore_global_p.h"
|
||||
#include "utils.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
|
@ -61,7 +60,6 @@ struct QtHelperData
|
|||
|
||||
struct QtHelper
|
||||
{
|
||||
QMutex mutex;
|
||||
QHash<WId, QtHelperData> data = {};
|
||||
};
|
||||
|
||||
|
@ -78,18 +76,15 @@ void FramelessHelperQt::addWindow(FramelessParamsConst params)
|
|||
return;
|
||||
}
|
||||
const WId windowId = params->getWindowId();
|
||||
g_qtHelper()->mutex.lock();
|
||||
if (g_qtHelper()->data.contains(windowId)) {
|
||||
g_qtHelper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
QtHelperData data = {};
|
||||
data.params = *params;
|
||||
QWindow *window = params->getWindowHandle();
|
||||
// Give it a parent so that it can be deleted even if we forget to do so.
|
||||
// Give it a parent so that it can be automatically deleted by Qt.
|
||||
data.eventFilter = new FramelessHelperQt(window);
|
||||
g_qtHelper()->data.insert(windowId, data);
|
||||
g_qtHelper()->mutex.unlock();
|
||||
const auto shouldApplyFramelessFlag = []() -> bool {
|
||||
#ifdef Q_OS_MACOS
|
||||
return false;
|
||||
|
@ -121,16 +116,9 @@ void FramelessHelperQt::removeWindow(const WId windowId)
|
|||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_qtHelper()->mutex);
|
||||
if (!g_qtHelper()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
if (const auto eventFilter = g_qtHelper()->data.value(windowId).eventFilter) {
|
||||
if (QWindow * const window = Utils::findWindow(windowId)) {
|
||||
window->removeEventFilter(eventFilter);
|
||||
}
|
||||
delete eventFilter;
|
||||
}
|
||||
g_qtHelper()->data.remove(windowId);
|
||||
#ifdef Q_OS_MACOS
|
||||
Utils::removeWindowProxy(windowId);
|
||||
|
@ -162,20 +150,32 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
|||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
const QEvent::Type type = event->type();
|
||||
// We are only interested in some specific mouse events.
|
||||
// We are only interested in some specific mouse events (plus DPR change event).
|
||||
if ((type != QEvent::MouseButtonPress) && (type != QEvent::MouseButtonRelease)
|
||||
&& (type != QEvent::MouseButtonDblClick) && (type != QEvent::MouseMove)) {
|
||||
&& (type != QEvent::MouseButtonDblClick) && (type != QEvent::MouseMove)
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||
&& (type != QEvent::DevicePixelRatioChange)
|
||||
#else // QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
||||
&& (type != QEvent::ScreenChangeInternal) // Qt's internal event to notify screen change and DPR change.
|
||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||
) {
|
||||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
const auto window = qobject_cast<QWindow *>(object);
|
||||
const WId windowId = window->winId();
|
||||
g_qtHelper()->mutex.lock();
|
||||
if (!g_qtHelper()->data.contains(windowId)) {
|
||||
g_qtHelper()->mutex.unlock();
|
||||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
const QtHelperData data = g_qtHelper()->data.value(windowId);
|
||||
g_qtHelper()->mutex.unlock();
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||
if (type == QEvent::DevicePixelRatioChange)
|
||||
#else // QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
||||
if (type == QEvent::ScreenChangeInternal)
|
||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||
{
|
||||
data.params.forceChildrenRepaint(500);
|
||||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
const auto mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
const Qt::MouseButton button = mouseEvent->button();
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
|
@ -193,9 +193,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
|||
switch (type) {
|
||||
case QEvent::MouseButtonPress: {
|
||||
if (button == Qt::LeftButton) {
|
||||
g_qtHelper()->mutex.lock();
|
||||
g_qtHelper()->data[windowId].leftButtonPressed = true;
|
||||
g_qtHelper()->mutex.unlock();
|
||||
if (!windowFixedSize) {
|
||||
const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos);
|
||||
if (edges != Qt::Edges{}) {
|
||||
|
@ -208,12 +206,11 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
|||
} break;
|
||||
case QEvent::MouseButtonRelease: {
|
||||
if (button == Qt::LeftButton) {
|
||||
const QMutexLocker locker(&g_qtHelper()->mutex);
|
||||
g_qtHelper()->data[windowId].leftButtonPressed = false;
|
||||
}
|
||||
if (button == Qt::RightButton) {
|
||||
if (!ignoreThisEvent && insideTitleBar) {
|
||||
data.params.showSystemMenu(scenePos);
|
||||
data.params.showSystemMenu(globalPos);
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
|
@ -236,12 +233,10 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
|||
if (cs == Qt::ArrowCursor) {
|
||||
if (data.cursorShapeChanged) {
|
||||
data.params.unsetCursor();
|
||||
const QMutexLocker locker(&g_qtHelper()->mutex);
|
||||
g_qtHelper()->data[windowId].cursorShapeChanged = false;
|
||||
}
|
||||
} else {
|
||||
data.params.setCursor(cs);
|
||||
const QMutexLocker locker(&g_qtHelper()->mutex);
|
||||
g_qtHelper()->data[windowId].cursorShapeChanged = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "framelesshelper_windows.h"
|
||||
#include "framelesshelpercore_global_p.h"
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
|
@ -84,6 +83,8 @@ FRAMELESSHELPER_STRING_CONSTANT(TrackMouseEvent)
|
|||
FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(UnregisterClassW)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(DestroyWindow)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(GetWindowPlacement)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(SetWindowPlacement)
|
||||
[[maybe_unused]] static constexpr const char kFallbackTitleBarErrorMessage[] =
|
||||
"FramelessHelper is unable to create the fallback title bar window, and thus the snap layout feature will be disabled"
|
||||
" unconditionally. You can ignore this error and continue running your application, nothing else will be affected, "
|
||||
|
@ -98,11 +99,13 @@ struct Win32HelperData
|
|||
bool trackingMouse = false;
|
||||
WId fallbackTitleBarWindowId = 0;
|
||||
Dpi dpi = {};
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
QRect restoreGeometry = {};
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
};
|
||||
|
||||
struct Win32Helper
|
||||
{
|
||||
QMutex mutex;
|
||||
std::unique_ptr<FramelessHelperWin> nativeEventFilter = nullptr;
|
||||
QHash<WId, Win32HelperData> data = {};
|
||||
QHash<WId, WId> fallbackTitleBarToParentWindowMapping = {};
|
||||
|
@ -110,18 +113,16 @@ struct Win32Helper
|
|||
|
||||
Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
||||
|
||||
[[nodiscard]] static inline QString hwnd2str(const WId windowId)
|
||||
{
|
||||
// NULL handle is allowed here.
|
||||
return FRAMELESSHELPER_STRING_LITERAL("0x")
|
||||
+ QString::number(windowId, 16).toUpper();
|
||||
}
|
||||
[[nodiscard]] extern bool operator==(const RECT &lhs, const RECT &rhs) noexcept;
|
||||
[[nodiscard]] extern bool operator!=(const RECT &lhs, const RECT &rhs) noexcept;
|
||||
|
||||
[[nodiscard]] static inline QString hwnd2str(const HWND hwnd)
|
||||
{
|
||||
// NULL handle is allowed here.
|
||||
return hwnd2str(reinterpret_cast<WId>(hwnd));
|
||||
}
|
||||
[[nodiscard]] extern QRect rect2qrect(const RECT &rect);
|
||||
[[nodiscard]] extern RECT qrect2rect(const QRect &qrect);
|
||||
|
||||
[[nodiscard]] extern QString hwnd2str(const WId windowId);
|
||||
[[nodiscard]] extern QString hwnd2str(const HWND hwnd);
|
||||
|
||||
[[nodiscard]] extern std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd);
|
||||
|
||||
[[nodiscard]] static inline LRESULT CALLBACK FallbackTitleBarWindowProc
|
||||
(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
|
||||
|
@ -141,25 +142,21 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
const auto windowId = reinterpret_cast<WId>(hWnd);
|
||||
g_win32Helper()->mutex.lock();
|
||||
if (!g_win32Helper()->fallbackTitleBarToParentWindowMapping.contains(windowId)) {
|
||||
g_win32Helper()->mutex.unlock();
|
||||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
const WId parentWindowId = g_win32Helper()->fallbackTitleBarToParentWindowMapping.value(windowId);
|
||||
if (!g_win32Helper()->data.contains(parentWindowId)) {
|
||||
g_win32Helper()->mutex.unlock();
|
||||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
const Win32HelperData data = g_win32Helper()->data.value(parentWindowId);
|
||||
g_win32Helper()->mutex.unlock();
|
||||
const auto parentWindowHandle = reinterpret_cast<HWND>(parentWindowId);
|
||||
// All mouse events: client area mouse events + non-client area mouse events.
|
||||
// Hit-testing event should not be considered as a mouse event.
|
||||
const bool isMouseEvent = (((uMsg >= WM_MOUSEFIRST) && (uMsg <= WM_MOUSELAST)) ||
|
||||
((uMsg >= WM_NCMOUSEMOVE) && (uMsg <= WM_NCXBUTTONDBLCLK)));
|
||||
const auto releaseButtons = [&data](const std::optional<SystemButtonType> exclude) -> void {
|
||||
static constexpr const auto defaultButtonState = ButtonState::Unspecified;
|
||||
static constexpr const auto defaultButtonState = ButtonState::Normal;
|
||||
const SystemButtonType button = exclude.value_or(SystemButtonType::Unknown);
|
||||
if (button != SystemButtonType::WindowIcon) {
|
||||
data.params.setSystemButtonState(SystemButtonType::WindowIcon, defaultButtonState);
|
||||
|
@ -190,7 +187,7 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
};
|
||||
const auto clickButton = [&releaseButtons, &data](const SystemButtonType button) -> void {
|
||||
releaseButtons(button);
|
||||
data.params.setSystemButtonState(button, ButtonState::Clicked);
|
||||
data.params.setSystemButtonState(button, ButtonState::Released);
|
||||
};
|
||||
switch (uMsg) {
|
||||
case WM_NCHITTEST: {
|
||||
|
@ -207,8 +204,6 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
SystemButtonType buttonType = SystemButtonType::Unknown;
|
||||
if (data.params.isInsideSystemButtons(qtScenePos, &buttonType)) {
|
||||
switch (buttonType) {
|
||||
case SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(HTNOWHERE);
|
||||
case SystemButtonType::WindowIcon:
|
||||
return HTSYSMENU;
|
||||
case SystemButtonType::Help:
|
||||
|
@ -220,6 +215,8 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
return HTZOOM;
|
||||
case SystemButtonType::Close:
|
||||
return HTCLOSE;
|
||||
case SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(HTNOWHERE);
|
||||
}
|
||||
}
|
||||
// Returns "HTTRANSPARENT" to let the mouse event pass through this invisible
|
||||
|
@ -284,7 +281,6 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
WARNING << Utils::getSystemErrorMessage(kTrackMouseEvent);
|
||||
break;
|
||||
}
|
||||
const QMutexLocker locker(&g_win32Helper()->mutex);
|
||||
g_win32Helper()->data[parentWindowId].trackingMouse = true;
|
||||
}
|
||||
} break;
|
||||
|
@ -292,7 +288,6 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
case WM_MOUSELEAVE: {
|
||||
// When the mouse leaves the drag rect, make sure to dismiss any hover.
|
||||
releaseButtons(std::nullopt);
|
||||
const QMutexLocker locker(&g_win32Helper()->mutex);
|
||||
g_win32Helper()->data[parentWindowId].trackingMouse = false;
|
||||
} break;
|
||||
// NB: *Shouldn't be forwarding these* when they're not over the caption
|
||||
|
@ -406,7 +401,7 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
// snap layout feature introduced in Windows 11. So you may wonder, why not just
|
||||
// limit it to the area of the three system buttons, instead of covering the
|
||||
// whole title bar area? Well, I've tried that solution already and unfortunately
|
||||
// it doesn't work. And according to my experiment, it won't work either even if we
|
||||
// it doesn't work. And according to my experiments, it won't work either even if we
|
||||
// only reduce the window width for some pixels. So we have to make it expand to the
|
||||
// full width of the parent window to let it occupy the whole top area, and this time
|
||||
// it finally works. Since our current solution works well, I have no interest in digging
|
||||
|
@ -419,6 +414,22 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline void cleanupFallbackWindow()
|
||||
{
|
||||
const HINSTANCE instance = GetModuleHandleW(nullptr);
|
||||
if (!instance) {
|
||||
//WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW);
|
||||
return;
|
||||
}
|
||||
// According to MSDN, if the window class is registered from a shared library,
|
||||
// we will need to unregister it manually. Only the code which is directly
|
||||
// linked into the executable doesn't need manual unregistration, because
|
||||
// Windows will take care of it for us.
|
||||
if (UnregisterClassW(kFallbackTitleBarWindowClassName, instance) == FALSE) {
|
||||
//WARNING << Utils::getSystemErrorMessage(kUnregisterClassW);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline bool createFallbackTitleBarWindow(const WId parentWindowId, const bool hide)
|
||||
{
|
||||
Q_ASSERT(parentWindowId);
|
||||
|
@ -453,16 +464,7 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
wcex.lpfnWndProc = FallbackTitleBarWindowProc;
|
||||
wcex.hInstance = instance;
|
||||
if (RegisterClassExW(&wcex) != INVALID_ATOM) {
|
||||
registerUninitializeHook([](){
|
||||
const HINSTANCE instance = GetModuleHandleW(nullptr);
|
||||
if (!instance) {
|
||||
//WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW);
|
||||
return;
|
||||
}
|
||||
if (UnregisterClassW(kFallbackTitleBarWindowClassName, instance) == FALSE) {
|
||||
//WARNING << Utils::getSystemErrorMessage(kUnregisterClassW);
|
||||
}
|
||||
});
|
||||
qAddPostRoutine(cleanupFallbackWindow);
|
||||
return true;
|
||||
}
|
||||
WARNING << Utils::getSystemErrorMessage(kRegisterClassExW);
|
||||
|
@ -499,7 +501,6 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
|||
WARNING << "Failed to re-position the fallback title bar window.";
|
||||
return false;
|
||||
}
|
||||
const QMutexLocker locker(&g_win32Helper()->mutex);
|
||||
g_win32Helper()->data[parentWindowId].fallbackTitleBarWindowId = fallbackTitleBarWindowId;
|
||||
g_win32Helper()->fallbackTitleBarToParentWindowMapping.insert(fallbackTitleBarWindowId, parentWindowId);
|
||||
return true;
|
||||
|
@ -516,9 +517,7 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
|
|||
return;
|
||||
}
|
||||
const WId windowId = params->getWindowId();
|
||||
g_win32Helper()->mutex.lock();
|
||||
if (g_win32Helper()->data.contains(windowId)) {
|
||||
g_win32Helper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
Win32HelperData data = {};
|
||||
|
@ -529,7 +528,6 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
|
|||
g_win32Helper()->nativeEventFilter = std::make_unique<FramelessHelperWin>();
|
||||
qApp->installNativeEventFilter(g_win32Helper()->nativeEventFilter.get());
|
||||
}
|
||||
g_win32Helper()->mutex.unlock();
|
||||
DEBUG.noquote() << "The DPI of window" << hwnd2str(windowId) << "is" << data.dpi;
|
||||
#if 0
|
||||
params->setWindowFlags(params->getWindowFlags() | Qt::FramelessWindowHint);
|
||||
|
@ -557,7 +555,7 @@ void FramelessHelperWin::addWindow(FramelessParamsConst params)
|
|||
// Tell DWM we may need dark theme non-client area (title bar & frame border).
|
||||
FramelessHelper::Core::setApplicationOSThemeAware();
|
||||
if (WindowsVersionHelper::isWin10RS5OrGreater()) {
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
|
||||
const auto isWidget = [params]() -> bool {
|
||||
const auto widget = params->getWidgetHandle();
|
||||
return (widget && widget->isWidgetType());
|
||||
|
@ -587,9 +585,7 @@ void FramelessHelperWin::removeWindow(const WId windowId)
|
|||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
g_win32Helper()->mutex.lock();
|
||||
if (!g_win32Helper()->data.contains(windowId)) {
|
||||
g_win32Helper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
g_win32Helper()->data.remove(windowId);
|
||||
|
@ -599,21 +595,14 @@ void FramelessHelperWin::removeWindow(const WId windowId)
|
|||
g_win32Helper()->nativeEventFilter.reset();
|
||||
}
|
||||
}
|
||||
HWND hwnd = nullptr;
|
||||
auto it = g_win32Helper()->fallbackTitleBarToParentWindowMapping.constBegin();
|
||||
while (it != g_win32Helper()->fallbackTitleBarToParentWindowMapping.constEnd()) {
|
||||
if (it.value() == windowId) {
|
||||
const WId key = it.key();
|
||||
hwnd = reinterpret_cast<HWND>(key);
|
||||
g_win32Helper()->fallbackTitleBarToParentWindowMapping.remove(key);
|
||||
g_win32Helper()->fallbackTitleBarToParentWindowMapping.remove(it.key());
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
g_win32Helper()->mutex.unlock();
|
||||
if (DestroyWindow(reinterpret_cast<HWND>(hwnd)) == FALSE) {
|
||||
WARNING << Utils::getSystemErrorMessage(kDestroyWindow);
|
||||
}
|
||||
}
|
||||
|
||||
bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result)
|
||||
|
@ -645,16 +634,31 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
return false;
|
||||
}
|
||||
const auto windowId = reinterpret_cast<WId>(hWnd);
|
||||
g_win32Helper()->mutex.lock();
|
||||
if (!g_win32Helper()->data.contains(windowId)) {
|
||||
g_win32Helper()->mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
const Win32HelperData data = g_win32Helper()->data.value(windowId);
|
||||
g_win32Helper()->mutex.unlock();
|
||||
const bool frameBorderVisible = Utils::isWindowFrameBorderVisible();
|
||||
const WPARAM wParam = msg->wParam;
|
||||
const LPARAM lParam = msg->lParam;
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
const auto updateRestoreGeometry = [windowId, &data](const bool ignoreWindowState) -> void {
|
||||
if (!ignoreWindowState && !Utils::isWindowNoState(windowId)) {
|
||||
return;
|
||||
}
|
||||
const QRect rect = Utils::getWindowRestoreGeometry(windowId);
|
||||
if (!Utils::isValidGeometry(rect)) {
|
||||
WARNING << "The calculated restore geometry is invalid.";
|
||||
return;
|
||||
}
|
||||
if (Utils::isValidGeometry(data.restoreGeometry) && (data.restoreGeometry == rect)) {
|
||||
return;
|
||||
}
|
||||
g_win32Helper()->data[windowId].restoreGeometry = rect;
|
||||
};
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
|
||||
switch (uMsg) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) // Qt has done this for us since 5.9.0
|
||||
case WM_NCCREATE: {
|
||||
|
@ -819,28 +823,22 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// we have to use another way to judge this if we are running
|
||||
// on Windows 7 or Windows 8.
|
||||
if (WindowsVersionHelper::isWin8Point1OrGreater()) {
|
||||
MONITORINFOEXW monitorInfo;
|
||||
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
const HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!monitor) {
|
||||
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
break;
|
||||
}
|
||||
if (GetMonitorInfoW(monitor, &monitorInfo) == FALSE) {
|
||||
WARNING << Utils::getSystemErrorMessage(kGetMonitorInfoW);
|
||||
const std::optional<MONITORINFOEXW> monitorInfo = getMonitorForWindow(hWnd);
|
||||
if (!monitorInfo.has_value()) {
|
||||
WARNING << "Failed to retrieve the window's monitor.";
|
||||
break;
|
||||
}
|
||||
const RECT monitorRect = monitorInfo.value().rcMonitor;
|
||||
// This helper can be used to determine if there's a
|
||||
// auto-hide taskbar on the given edge of the monitor
|
||||
// we're currently on.
|
||||
const auto hasAutohideTaskbar = [&monitorInfo](const UINT edge) -> bool {
|
||||
APPBARDATA _abd;
|
||||
SecureZeroMemory(&_abd, sizeof(_abd));
|
||||
_abd.cbSize = sizeof(_abd);
|
||||
_abd.uEdge = edge;
|
||||
_abd.rc = monitorInfo.rcMonitor;
|
||||
const auto hTaskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAREX, &_abd));
|
||||
const auto hasAutohideTaskbar = [monitorRect](const UINT edge) -> bool {
|
||||
APPBARDATA abd2;
|
||||
SecureZeroMemory(&abd2, sizeof(abd2));
|
||||
abd2.cbSize = sizeof(abd2);
|
||||
abd2.uEdge = edge;
|
||||
abd2.rc = monitorRect;
|
||||
const auto hTaskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAREX, &abd2));
|
||||
return (hTaskbar != nullptr);
|
||||
};
|
||||
top = hasAutohideTaskbar(ABE_TOP);
|
||||
|
@ -849,24 +847,24 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
right = hasAutohideTaskbar(ABE_RIGHT);
|
||||
} else {
|
||||
int edge = -1;
|
||||
APPBARDATA _abd;
|
||||
SecureZeroMemory(&_abd, sizeof(_abd));
|
||||
_abd.cbSize = sizeof(_abd);
|
||||
_abd.hWnd = FindWindowW(L"Shell_TrayWnd", nullptr);
|
||||
if (_abd.hWnd) {
|
||||
APPBARDATA abd2;
|
||||
SecureZeroMemory(&abd2, sizeof(abd2));
|
||||
abd2.cbSize = sizeof(abd2);
|
||||
abd2.hWnd = FindWindowW(L"Shell_TrayWnd", nullptr);
|
||||
if (abd2.hWnd) {
|
||||
const HMONITOR windowMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!windowMonitor) {
|
||||
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
break;
|
||||
}
|
||||
const HMONITOR taskbarMonitor = MonitorFromWindow(_abd.hWnd, MONITOR_DEFAULTTOPRIMARY);
|
||||
const HMONITOR taskbarMonitor = MonitorFromWindow(abd2.hWnd, MONITOR_DEFAULTTOPRIMARY);
|
||||
if (!taskbarMonitor) {
|
||||
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
break;
|
||||
}
|
||||
if (taskbarMonitor == windowMonitor) {
|
||||
SHAppBarMessage(ABM_GETTASKBARPOS, &_abd);
|
||||
edge = _abd.uEdge;
|
||||
SHAppBarMessage(ABM_GETTASKBARPOS, &abd2);
|
||||
edge = abd2.uEdge;
|
||||
}
|
||||
} else {
|
||||
WARNING << Utils::getSystemErrorMessage(kFindWindowW);
|
||||
|
@ -1149,16 +1147,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
*result = FALSE; // Use the default linear DPI scaling provided by Windows.
|
||||
return true; // Jump over Qt's wrong handling logic.
|
||||
}
|
||||
const QSizeF oldSize = {qreal(clientRect.right - clientRect.left), qreal(clientRect.bottom - clientRect.top)};
|
||||
static constexpr const auto defaultDpi = qreal(USER_DEFAULT_SCREEN_DPI);
|
||||
// We need to round the scale factor according to Qt's rounding policy.
|
||||
const qreal oldDpr = Utils::roundScaleFactor(qreal(data.dpi.x) / defaultDpi);
|
||||
const auto newDpi = UINT(wParam);
|
||||
const qreal newDpr = Utils::roundScaleFactor(qreal(newDpi) / defaultDpi);
|
||||
const QSizeF newSize = (oldSize / oldDpr * newDpr);
|
||||
const QSize oldSize = {RECT_WIDTH(clientRect), RECT_HEIGHT(clientRect)};
|
||||
const QSize newSize = Utils::rescaleSize(oldSize, data.dpi.x, newDpi);
|
||||
const auto suggestedSize = reinterpret_cast<LPSIZE>(lParam);
|
||||
suggestedSize->cx = std::round(newSize.width());
|
||||
suggestedSize->cy = std::round(newSize.height());
|
||||
suggestedSize->cx = newSize.width();
|
||||
suggestedSize->cy = newSize.height();
|
||||
// If the window frame is visible, we need to expand the suggested size, currently
|
||||
// it's pure client size, we need to add the frame size to it. Windows expects a
|
||||
// full window size, including the window frame.
|
||||
|
@ -1176,25 +1170,59 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
}
|
||||
#endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
|
||||
case WM_DPICHANGED: {
|
||||
const Dpi dpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))};
|
||||
DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd) << "is" << dpi;
|
||||
g_win32Helper()->mutex.lock();
|
||||
g_win32Helper()->data[windowId].dpi = dpi;
|
||||
g_win32Helper()->mutex.unlock();
|
||||
#if (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
|
||||
// We need to wait until Qt has handled this message, otherwise everything
|
||||
// we have done here will always be overwritten.
|
||||
QTimer::singleShot(0, qApp, [data](){ // Copy the variables intentionally, otherwise they'll go out of scope when Qt finally use them.
|
||||
// Sync the internal window frame margins with the latest DPI, otherwise
|
||||
// we will get wrong window sizes after the DPI change.
|
||||
Utils::updateInternalWindowFrameMargins(data.params.getWindowHandle(), true);
|
||||
});
|
||||
#endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
|
||||
const Dpi oldDpi = data.dpi;
|
||||
const Dpi newDpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))};
|
||||
if (Q_UNLIKELY(newDpi == oldDpi)) {
|
||||
WARNING << "Wrong WM_DPICHANGED received: same DPI.";
|
||||
break;
|
||||
}
|
||||
DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd)
|
||||
<< "is" << newDpi << "(was" << oldDpi << ").";
|
||||
g_win32Helper()->data[windowId].dpi = newDpi;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
if (Utils::isValidGeometry(data.restoreGeometry)) {
|
||||
// Update the window size only. The position should not be changed.
|
||||
g_win32Helper()->data[windowId].restoreGeometry.setSize(
|
||||
Utils::rescaleSize(data.restoreGeometry.size(), oldDpi.x, newDpi.x));
|
||||
}
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
data.params.forceChildrenRepaint(500);
|
||||
} break;
|
||||
case WM_DWMCOMPOSITIONCHANGED: {
|
||||
// Re-apply the custom window frame if recovered from the basic theme.
|
||||
Utils::updateWindowFrameMargins(windowId, false);
|
||||
} break;
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
case WM_ENTERSIZEMOVE: // Sent to a window when the user drags the title bar or the resize border.
|
||||
case WM_EXITSIZEMOVE: // Sent to a window when the user releases the mouse button (from dragging the title bar or the resize border).
|
||||
updateRestoreGeometry(false);
|
||||
break;
|
||||
case WM_SIZE: {
|
||||
if (wParam != SIZE_MAXIMIZED) {
|
||||
break;
|
||||
}
|
||||
if (!Utils::isValidGeometry(data.restoreGeometry)) {
|
||||
updateRestoreGeometry(true);
|
||||
break;
|
||||
}
|
||||
WINDOWPLACEMENT wp;
|
||||
SecureZeroMemory(&wp, sizeof(wp));
|
||||
wp.length = sizeof(wp);
|
||||
if (GetWindowPlacement(hWnd, &wp) == FALSE) {
|
||||
WARNING << Utils::getSystemErrorMessage(kGetWindowPlacement);
|
||||
break;
|
||||
}
|
||||
// The restore geometry is correct, no need to bother.
|
||||
if (rect2qrect(wp.rcNormalPosition) == data.restoreGeometry) {
|
||||
break;
|
||||
}
|
||||
// OK, the restore geometry is wrong, let's correct it then :)
|
||||
wp.rcNormalPosition = qrect2rect(data.restoreGeometry);
|
||||
if (SetWindowPlacement(hWnd, &wp) == FALSE) {
|
||||
WARNING << Utils::getSystemErrorMessage(kSetWindowPlacement);
|
||||
}
|
||||
} break;
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 1))
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1294,7 +1322,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
&& (std::wcscmp(reinterpret_cast<LPCWSTR>(lParam), kThemeSettingChangeEventName) == 0)) {
|
||||
systemThemeChanged = true;
|
||||
if (WindowsVersionHelper::isWin10RS5OrGreater()) {
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
|
||||
const auto isWidget = [&data]() -> bool {
|
||||
const auto widget = data.params.getWidgetHandle();
|
||||
return (widget && widget->isWidgetType());
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "framelesshelpercore_global_p.h"
|
||||
#include "versionnumber_p.h"
|
||||
#include "utils.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qiodevice.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
@ -87,7 +86,7 @@ QDebug operator<<(QDebug d, const FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::Ver
|
|||
QDebug operator<<(QDebug d, const FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::Dpi &dpi)
|
||||
{
|
||||
const QDebugStateSaver saver(d);
|
||||
const qreal scaleFactor = (qreal(dpi.x) / qreal(96));
|
||||
const qreal scaleFactor = (qreal(dpi.x) / qreal(FRAMELESSHELPER_PREPEND_NAMESPACE(Utils)::defaultScreenDpi()));
|
||||
d.nospace().noquote() << "Dpi("
|
||||
<< "x: " << dpi.x << ", "
|
||||
<< "y: " << dpi.y << ", "
|
||||
|
@ -141,33 +140,16 @@ FRAMELESSHELPER_BYTEARRAY_CONSTANT(xcb)
|
|||
|
||||
[[maybe_unused]] static constexpr const char kNoLogoEnvVar[] = "FRAMELESSHELPER_NO_LOGO";
|
||||
|
||||
struct CoreData
|
||||
{
|
||||
QMutex mutex;
|
||||
QList<InitializeHookCallback> initHooks = {};
|
||||
QList<UninitializeHookCallback> uninitHooks = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(CoreData, coreData)
|
||||
|
||||
void registerInitializeHook(const InitializeHookCallback &cb)
|
||||
{
|
||||
Q_ASSERT(cb);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&coreData()->mutex);
|
||||
coreData()->initHooks.append(cb);
|
||||
Q_UNUSED(cb);
|
||||
WARNING << "registerInitializeHook: This function is deprecated and will be removed in a future version. Please consider using Qt's official Q_COREAPP_STARTUP_FUNCTION() macro instead.";
|
||||
}
|
||||
|
||||
void registerUninitializeHook(const UninitializeHookCallback &cb)
|
||||
{
|
||||
Q_ASSERT(cb);
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&coreData()->mutex);
|
||||
coreData()->uninitHooks.append(cb);
|
||||
Q_UNUSED(cb);
|
||||
WARNING << "registerUninitializeHook: This function is deprecated and will be removed in a future version. Please consider using Qt's official qAddPostRoutine() function instead.";
|
||||
}
|
||||
|
||||
namespace FramelessHelper::Core
|
||||
|
@ -226,17 +208,6 @@ void initialize()
|
|||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#endif
|
||||
|
||||
const QMutexLocker locker(&coreData()->mutex);
|
||||
if (!coreData()->initHooks.isEmpty()) {
|
||||
for (auto &&hook : std::as_const(coreData()->initHooks)) {
|
||||
Q_ASSERT(hook);
|
||||
if (!hook) {
|
||||
continue;
|
||||
}
|
||||
hook();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uninitialize()
|
||||
|
@ -246,18 +217,6 @@ void uninitialize()
|
|||
return;
|
||||
}
|
||||
uninited = true;
|
||||
|
||||
const QMutexLocker locker(&coreData()->mutex);
|
||||
if (coreData()->uninitHooks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (auto &&hook : std::as_const(coreData()->uninitHooks)) {
|
||||
Q_ASSERT(hook);
|
||||
if (!hook) {
|
||||
continue;
|
||||
}
|
||||
hook();
|
||||
}
|
||||
}
|
||||
|
||||
VersionInfo version()
|
||||
|
|
|
@ -32,11 +32,11 @@
|
|||
# include "framelesshelper_win.h"
|
||||
# include "winverhelper_p.h"
|
||||
#endif
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtGui/qfontdatabase.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||
# include <QtGui/qguiapplication.h>
|
||||
# include <QtGui/qstylehints.h>
|
||||
|
@ -62,7 +62,6 @@ using namespace Global;
|
|||
|
||||
struct FramelessManagerHelper
|
||||
{
|
||||
QMutex mutex;
|
||||
QList<WId> windowIds = {};
|
||||
};
|
||||
|
||||
|
@ -168,25 +167,25 @@ QFont FramelessManagerPrivate::getIconFont()
|
|||
|
||||
SystemTheme FramelessManagerPrivate::systemTheme() const
|
||||
{
|
||||
const QMutexLocker locker(&g_helper()->mutex);
|
||||
// The user's choice has top priority.
|
||||
if (isThemeOverrided()) {
|
||||
return m_overrideTheme.value();
|
||||
}
|
||||
return m_systemTheme;
|
||||
}
|
||||
|
||||
QColor FramelessManagerPrivate::systemAccentColor() const
|
||||
{
|
||||
const QMutexLocker locker(&g_helper()->mutex);
|
||||
return m_accentColor;
|
||||
}
|
||||
|
||||
QString FramelessManagerPrivate::wallpaper() const
|
||||
{
|
||||
const QMutexLocker locker(&g_helper()->mutex);
|
||||
return m_wallpaper;
|
||||
}
|
||||
|
||||
WallpaperAspectStyle FramelessManagerPrivate::wallpaperAspectStyle() const
|
||||
{
|
||||
const QMutexLocker locker(&g_helper()->mutex);
|
||||
return m_wallpaperAspectStyle;
|
||||
}
|
||||
|
||||
|
@ -197,13 +196,10 @@ void FramelessManagerPrivate::addWindow(FramelessParamsConst params)
|
|||
return;
|
||||
}
|
||||
const WId windowId = params->getWindowId();
|
||||
g_helper()->mutex.lock();
|
||||
if (g_helper()->windowIds.contains(windowId)) {
|
||||
g_helper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
g_helper()->windowIds.append(windowId);
|
||||
g_helper()->mutex.unlock();
|
||||
static const bool pureQt = usePureQtImplementation();
|
||||
if (pureQt) {
|
||||
FramelessHelperQt::addWindow(params);
|
||||
|
@ -214,6 +210,7 @@ void FramelessManagerPrivate::addWindow(FramelessParamsConst params)
|
|||
}
|
||||
Utils::installSystemMenuHook(windowId, params);
|
||||
#endif
|
||||
connect(params->getWindowHandle(), &QWindow::destroyed, FramelessManager::instance(), [windowId](){ removeWindow(windowId); });
|
||||
}
|
||||
|
||||
void FramelessManagerPrivate::removeWindow(const WId windowId)
|
||||
|
@ -222,13 +219,10 @@ void FramelessManagerPrivate::removeWindow(const WId windowId)
|
|||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
g_helper()->mutex.lock();
|
||||
if (!g_helper()->windowIds.contains(windowId)) {
|
||||
g_helper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
g_helper()->windowIds.removeAll(windowId);
|
||||
g_helper()->mutex.unlock();
|
||||
static const bool pureQt = usePureQtImplementation();
|
||||
if (pureQt) {
|
||||
FramelessHelperQt::removeWindow(windowId);
|
||||
|
@ -237,23 +231,17 @@ void FramelessManagerPrivate::removeWindow(const WId windowId)
|
|||
if (!pureQt) {
|
||||
FramelessHelperWin::removeWindow(windowId);
|
||||
}
|
||||
Utils::uninstallSystemMenuHook(windowId);
|
||||
Utils::removeSysMenuHook(windowId);
|
||||
Utils::removeMicaWindow(windowId);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot()
|
||||
{
|
||||
const QMutexLocker locker(&g_helper()->mutex);
|
||||
const SystemTheme currentSystemTheme = Utils::getSystemTheme();
|
||||
const SystemTheme currentSystemTheme = (Utils::shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light);
|
||||
const QColor currentAccentColor = Utils::getAccentColor();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
const DwmColorizationArea currentColorizationArea = Utils::getDwmColorizationArea();
|
||||
const QColor currentAccentColor = Utils::getDwmAccentColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
const QColor currentAccentColor = Utils::getWmThemeColor();
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
const QColor currentAccentColor = Utils::getControlsAccentColor();
|
||||
#endif
|
||||
bool notify = false;
|
||||
if (m_systemTheme != currentSystemTheme) {
|
||||
|
@ -270,7 +258,8 @@ void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot()
|
|||
notify = true;
|
||||
}
|
||||
#endif
|
||||
if (notify) {
|
||||
// Don't emit the signal if the user has overrided the global theme.
|
||||
if (notify && !isThemeOverrided()) {
|
||||
Q_Q(FramelessManager);
|
||||
Q_EMIT q->systemThemeChanged();
|
||||
DEBUG.nospace() << "System theme changed. Current theme: " << m_systemTheme
|
||||
|
@ -284,7 +273,6 @@ void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot()
|
|||
|
||||
void FramelessManagerPrivate::notifyWallpaperHasChangedOrNot()
|
||||
{
|
||||
const QMutexLocker locker(&g_helper()->mutex);
|
||||
const QString currentWallpaper = Utils::getWallpaperFilePath();
|
||||
const WallpaperAspectStyle currentWallpaperAspectStyle = Utils::getWallpaperAspectStyle();
|
||||
bool notify = false;
|
||||
|
@ -316,19 +304,32 @@ bool FramelessManagerPrivate::usePureQtImplementation()
|
|||
return result;
|
||||
}
|
||||
|
||||
void FramelessManagerPrivate::setOverrideTheme(const SystemTheme theme)
|
||||
{
|
||||
if ((!m_overrideTheme.has_value() && (theme == SystemTheme::Unknown))
|
||||
|| (m_overrideTheme.has_value() && (m_overrideTheme.value() == theme))) {
|
||||
return;
|
||||
}
|
||||
if (theme == SystemTheme::Unknown) {
|
||||
m_overrideTheme = std::nullopt;
|
||||
} else {
|
||||
m_overrideTheme = theme;
|
||||
}
|
||||
Q_Q(FramelessManager);
|
||||
Q_EMIT q->systemThemeChanged();
|
||||
}
|
||||
|
||||
bool FramelessManagerPrivate::isThemeOverrided() const
|
||||
{
|
||||
return (m_overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown);
|
||||
}
|
||||
|
||||
void FramelessManagerPrivate::initialize()
|
||||
{
|
||||
const QMutexLocker locker(&g_helper()->mutex);
|
||||
m_systemTheme = Utils::getSystemTheme();
|
||||
m_systemTheme = (Utils::shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light);
|
||||
m_accentColor = Utils::getAccentColor();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
m_colorizationArea = Utils::getDwmColorizationArea();
|
||||
m_accentColor = Utils::getDwmAccentColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
m_accentColor = Utils::getWmThemeColor();
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
m_accentColor = Utils::getControlsAccentColor();
|
||||
#endif
|
||||
m_wallpaper = Utils::getWallpaperFilePath();
|
||||
m_wallpaperAspectStyle = Utils::getWallpaperAspectStyle();
|
||||
|
@ -409,4 +410,10 @@ void FramelessManager::removeWindow(const WId windowId)
|
|||
d->removeWindow(windowId);
|
||||
}
|
||||
|
||||
void FramelessManager::setOverrideTheme(const SystemTheme theme)
|
||||
{
|
||||
Q_D(FramelessManager);
|
||||
d->setOverrideTheme(theme);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -28,10 +28,12 @@
|
|||
#include "utils.h"
|
||||
#include "framelessconfig_p.h"
|
||||
#include <QtCore/qsysinfo.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qthread.h>
|
||||
#include <QtGui/qpixmap.h>
|
||||
#include <QtGui/qimage.h>
|
||||
#include <QtGui/qimagereader.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
|
@ -57,25 +59,51 @@ static Q_LOGGING_CATEGORY(lcMicaMaterial, "wangwenx190.framelesshelper.core.mica
|
|||
|
||||
using namespace Global;
|
||||
|
||||
[[maybe_unused]] static constexpr const QSize kMaximumPictureSize = { 1920, 1080 };
|
||||
[[maybe_unused]] static constexpr const QImage::Format kDefaultImageFormat = QImage::Format_ARGB32_Premultiplied;
|
||||
|
||||
[[maybe_unused]] static constexpr const qreal kDefaultTintOpacity = 0.7;
|
||||
[[maybe_unused]] static constexpr const qreal kDefaultNoiseOpacity = 0.04;
|
||||
[[maybe_unused]] static constexpr const qreal kDefaultBlurRadius = 128.0;
|
||||
|
||||
[[maybe_unused]] static Q_COLOR_CONSTEXPR const QColor kDefaultSystemLightColor2 = {243, 243, 243}; // #F3F3F3
|
||||
|
||||
[[maybe_unused]] static Q_COLOR_CONSTEXPR const QColor kDefaultFallbackColorDark = {44, 44, 44}; // #2C2C2C
|
||||
[[maybe_unused]] static Q_COLOR_CONSTEXPR const QColor kDefaultFallbackColorLight = {249, 249, 249}; // #F9F9F9
|
||||
|
||||
#ifndef FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(NoiseImageFilePath, ":/org.wangwenx190.FramelessHelper/resources/images/noise.png")
|
||||
#endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE
|
||||
|
||||
struct MicaMaterialData
|
||||
{
|
||||
QMutex mutex;
|
||||
QPixmap blurredWallpaper = {};
|
||||
bool graphicsResourcesReady = false;
|
||||
QMutex mutex{};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(MicaMaterialData, g_micaMaterialData)
|
||||
|
||||
[[maybe_unused]] [[nodiscard]] static inline constexpr bool operator>(const QSize &lhs, const QSize &rhs) noexcept
|
||||
{
|
||||
return ((lhs.width() * lhs.height()) > (rhs.width() * rhs.height()));
|
||||
}
|
||||
|
||||
[[maybe_unused]] [[nodiscard]] static inline constexpr bool operator>=(const QSize &lhs, const QSize &rhs) noexcept
|
||||
{
|
||||
return (operator>(lhs, rhs) || operator==(lhs, rhs));
|
||||
}
|
||||
|
||||
[[maybe_unused]] [[nodiscard]] static inline constexpr bool operator<(const QSize &lhs, const QSize &rhs) noexcept
|
||||
{
|
||||
return (operator!=(lhs, rhs) && !operator>(lhs, rhs));
|
||||
}
|
||||
|
||||
[[maybe_unused]] [[nodiscard]] static inline constexpr bool operator<=(const QSize &lhs, const QSize &rhs) noexcept
|
||||
{
|
||||
return (operator<(lhs, rhs) || operator==(lhs, rhs));
|
||||
}
|
||||
|
||||
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
template<const int shift>
|
||||
[[nodiscard]] static inline constexpr int qt_static_shift(const int value)
|
||||
|
@ -191,11 +219,11 @@ static inline void qt_blurrow(QImage &im, const int line, const int alpha)
|
|||
template<const int aprec, const int zprec, const bool alphaOnly>
|
||||
static inline void expblur(QImage &img, qreal radius, const bool improvedQuality = false, const int transposed = 0)
|
||||
{
|
||||
Q_ASSERT((img.format() == QImage::Format_ARGB32_Premultiplied)
|
||||
Q_ASSERT((img.format() == kDefaultImageFormat)
|
||||
|| (img.format() == QImage::Format_RGB32)
|
||||
|| (img.format() == QImage::Format_Indexed8)
|
||||
|| (img.format() == QImage::Format_Grayscale8));
|
||||
if ((img.format() != QImage::Format_ARGB32_Premultiplied)
|
||||
if ((img.format() != kDefaultImageFormat)
|
||||
&& (img.format() != QImage::Format_RGB32)
|
||||
&& (img.format() != QImage::Format_Indexed8)
|
||||
&& (img.format() != QImage::Format_Grayscale8)) {
|
||||
|
@ -344,9 +372,9 @@ static inline void expblur(QImage &img, qreal radius, const bool improvedQuality
|
|||
|
||||
return dest;
|
||||
}
|
||||
if ((source.format() != QImage::Format_ARGB32_Premultiplied)
|
||||
if ((source.format() != kDefaultImageFormat)
|
||||
&& (source.format() != QImage::Format_RGB32)) {
|
||||
srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
srcImage = source.convertToFormat(kDefaultImageFormat);
|
||||
}
|
||||
|
||||
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
|
||||
|
@ -376,9 +404,9 @@ static inline void expblur(QImage &img, qreal radius, const bool improvedQuality
|
|||
[[maybe_unused]] static inline void qt_blurImage(QPainter *p, QImage &blurImage,
|
||||
qreal radius, const bool quality, const bool alphaOnly, const int transposed = 0)
|
||||
{
|
||||
if ((blurImage.format() != QImage::Format_ARGB32_Premultiplied)
|
||||
if ((blurImage.format() != kDefaultImageFormat)
|
||||
&& (blurImage.format() != QImage::Format_RGB32)) {
|
||||
blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
blurImage = blurImage.convertToFormat(kDefaultImageFormat);
|
||||
}
|
||||
|
||||
qreal scale = 1.0;
|
||||
|
@ -472,6 +500,130 @@ static inline void expblur(QImage &img, qreal radius, const bool improvedQuality
|
|||
return {x, y, w, h};
|
||||
}
|
||||
|
||||
class WallpaperThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(WallpaperThread)
|
||||
|
||||
public:
|
||||
explicit WallpaperThread(QObject *parent = nullptr) : QThread(parent) {}
|
||||
~WallpaperThread() override = default;
|
||||
|
||||
Q_SIGNALS:
|
||||
void imageUpdated(const Transform &);
|
||||
|
||||
protected:
|
||||
void run() override
|
||||
{
|
||||
Transform transform = {};
|
||||
// ### FIXME: Ideally, we should not use virtual desktop size here.
|
||||
QSize monitorSize = QGuiApplication::primaryScreen()->virtualSize();
|
||||
if (monitorSize.isEmpty()) {
|
||||
WARNING << "Failed to retrieve the monitor size. Using default size (1920x1080) instead ...";
|
||||
monitorSize = kMaximumPictureSize;
|
||||
}
|
||||
const QSize imageSize = (monitorSize > kMaximumPictureSize ? kMaximumPictureSize : monitorSize);
|
||||
if (imageSize != monitorSize) {
|
||||
transform.Horizontal = (qreal(imageSize.width()) / qreal(monitorSize.width()));
|
||||
transform.Vertical = (qreal(imageSize.height()) / qreal(monitorSize.height()));
|
||||
}
|
||||
const QString wallpaperFilePath = Utils::getWallpaperFilePath();
|
||||
if (wallpaperFilePath.isEmpty()) {
|
||||
WARNING << "Failed to retrieve the wallpaper file path.";
|
||||
return;
|
||||
}
|
||||
QImageReader reader(wallpaperFilePath);
|
||||
if (!reader.canRead()) {
|
||||
WARNING << "Qt can't read the wallpaper file:" << reader.errorString();
|
||||
return;
|
||||
}
|
||||
const QSize actualSize = reader.size();
|
||||
if (actualSize.isEmpty()) {
|
||||
WARNING << "The wallpaper picture size is invalid.";
|
||||
return;
|
||||
}
|
||||
const QSize correctedSize = (actualSize > kMaximumPictureSize ? kMaximumPictureSize : actualSize);
|
||||
if (correctedSize != actualSize) {
|
||||
DEBUG << "The wallpaper picture size is greater than 1920x1080, it will be shrinked to reduce memory consumption.";
|
||||
reader.setScaledSize(correctedSize);
|
||||
}
|
||||
QImage image(correctedSize, kDefaultImageFormat);
|
||||
if (!reader.read(&image)) {
|
||||
WARNING << "Failed to read the wallpaper image:" << reader.errorString();
|
||||
return;
|
||||
}
|
||||
if (image.isNull()) {
|
||||
WARNING << "The obtained image data is null.";
|
||||
return;
|
||||
}
|
||||
WallpaperAspectStyle aspectStyle = Utils::getWallpaperAspectStyle();
|
||||
QImage buffer(imageSize, kDefaultImageFormat);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (aspectStyle == WallpaperAspectStyle::Center) {
|
||||
buffer.fill(kDefaultBlackColor);
|
||||
}
|
||||
#endif
|
||||
if ((aspectStyle == WallpaperAspectStyle::Stretch)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fit)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fill)) {
|
||||
Qt::AspectRatioMode mode = Qt::KeepAspectRatioByExpanding;
|
||||
if (aspectStyle == WallpaperAspectStyle::Stretch) {
|
||||
mode = Qt::IgnoreAspectRatio;
|
||||
} else if (aspectStyle == WallpaperAspectStyle::Fit) {
|
||||
mode = Qt::KeepAspectRatio;
|
||||
}
|
||||
QSize newSize = image.size();
|
||||
newSize.scale(imageSize, mode);
|
||||
image = image.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
static constexpr const QPoint desktopOriginPoint = {0, 0};
|
||||
const QRect desktopRect = {desktopOriginPoint, imageSize};
|
||||
if (aspectStyle == WallpaperAspectStyle::Tile) {
|
||||
QPainter bufferPainter(&buffer);
|
||||
bufferPainter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
bufferPainter.fillRect(desktopRect, QBrush(image));
|
||||
} else {
|
||||
QPainter bufferPainter(&buffer);
|
||||
bufferPainter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
const QRect rect = alignedRect(Qt::LeftToRight, Qt::AlignCenter, image.size(), desktopRect);
|
||||
bufferPainter.drawImage(rect.topLeft(), image);
|
||||
}
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
g_micaMaterialData()->blurredWallpaper = QPixmap(imageSize);
|
||||
g_micaMaterialData()->blurredWallpaper.fill(kDefaultTransparentColor);
|
||||
QPainter painter(&g_micaMaterialData()->blurredWallpaper);
|
||||
painter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
painter.drawImage(desktopOriginPoint, buffer);
|
||||
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
qt_blurImage(&painter, buffer, kDefaultBlurRadius, true, false);
|
||||
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
Q_EMIT imageUpdated(transform);
|
||||
}
|
||||
};
|
||||
|
||||
struct ThreadData
|
||||
{
|
||||
std::unique_ptr<WallpaperThread> thread = nullptr;
|
||||
QMutex mutex{};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(ThreadData, g_threadData)
|
||||
|
||||
static inline void threadCleaner()
|
||||
{
|
||||
const QMutexLocker locker(&g_threadData()->mutex);
|
||||
if (g_threadData()->thread && g_threadData()->thread->isRunning()) {
|
||||
g_threadData()->thread->requestInterruption();
|
||||
g_threadData()->thread->quit();
|
||||
g_threadData()->thread->wait();
|
||||
}
|
||||
}
|
||||
|
||||
MicaMaterialPrivate::MicaMaterialPrivate(MicaMaterial *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
|
@ -510,67 +662,13 @@ void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force)
|
|||
return;
|
||||
}
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
const QSize size = QGuiApplication::primaryScreen()->virtualSize();
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
g_micaMaterialData()->blurredWallpaper = QPixmap(size);
|
||||
g_micaMaterialData()->blurredWallpaper.fill(kDefaultTransparentColor);
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
const QString wallpaperFilePath = Utils::getWallpaperFilePath();
|
||||
if (wallpaperFilePath.isEmpty()) {
|
||||
WARNING << "Failed to retrieve the wallpaper file path.";
|
||||
return;
|
||||
const QMutexLocker locker(&g_threadData()->mutex);
|
||||
if (g_threadData()->thread->isRunning()) {
|
||||
g_threadData()->thread->requestInterruption();
|
||||
g_threadData()->thread->quit();
|
||||
g_threadData()->thread->wait();
|
||||
}
|
||||
QImage image(wallpaperFilePath);
|
||||
if (image.isNull()) {
|
||||
WARNING << "QImage doesn't support this kind of file:" << wallpaperFilePath;
|
||||
return;
|
||||
}
|
||||
WallpaperAspectStyle aspectStyle = Utils::getWallpaperAspectStyle();
|
||||
QImage buffer(size, QImage::Format_ARGB32_Premultiplied);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (aspectStyle == WallpaperAspectStyle::Center) {
|
||||
buffer.fill(kDefaultBlackColor);
|
||||
}
|
||||
#endif
|
||||
if ((aspectStyle == WallpaperAspectStyle::Stretch)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fit)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fill)) {
|
||||
Qt::AspectRatioMode mode = Qt::KeepAspectRatioByExpanding;
|
||||
if (aspectStyle == WallpaperAspectStyle::Stretch) {
|
||||
mode = Qt::IgnoreAspectRatio;
|
||||
} else if (aspectStyle == WallpaperAspectStyle::Fit) {
|
||||
mode = Qt::KeepAspectRatio;
|
||||
}
|
||||
QSize newSize = image.size();
|
||||
newSize.scale(size, mode);
|
||||
image = image.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
static constexpr const QPoint desktopOriginPoint = {0, 0};
|
||||
const QRect desktopRect = {desktopOriginPoint, size};
|
||||
if (aspectStyle == WallpaperAspectStyle::Tile) {
|
||||
QPainter bufferPainter(&buffer);
|
||||
bufferPainter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
bufferPainter.fillRect(desktopRect, QBrush(image));
|
||||
} else {
|
||||
QPainter bufferPainter(&buffer);
|
||||
bufferPainter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
const QRect rect = alignedRect(Qt::LeftToRight, Qt::AlignCenter, image.size(), desktopRect);
|
||||
bufferPainter.drawImage(rect.topLeft(), image);
|
||||
}
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
QPainter painter(&g_micaMaterialData()->blurredWallpaper);
|
||||
painter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
painter.drawImage(desktopOriginPoint, buffer);
|
||||
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
qt_blurImage(&painter, buffer, kDefaultBlurRadius, true, false);
|
||||
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
Q_Q(MicaMaterial);
|
||||
Q_EMIT q->shouldRedraw();
|
||||
g_threadData()->thread->start(QThread::LowPriority);
|
||||
}
|
||||
|
||||
void MicaMaterialPrivate::updateMaterialBrush()
|
||||
|
@ -579,8 +677,8 @@ void MicaMaterialPrivate::updateMaterialBrush()
|
|||
framelesshelpercore_initResource();
|
||||
static const QImage noiseTexture = QImage(kNoiseImageFilePath);
|
||||
#endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE
|
||||
QImage micaTexture = QImage(QSize(64, 64), QImage::Format_ARGB32_Premultiplied);
|
||||
QColor fillColor = (Utils::shouldAppsUseDarkMode() ? kDefaultSystemDarkColor : kDefaultSystemLightColor2);
|
||||
QImage micaTexture = QImage(QSize(64, 64), kDefaultImageFormat);
|
||||
QColor fillColor = ((FramelessManager::instance()->systemTheme() == SystemTheme::Dark) ? kDefaultSystemDarkColor : kDefaultSystemLightColor2);
|
||||
fillColor.setAlphaF(0.9f);
|
||||
micaTexture.fill(fillColor);
|
||||
QPainter painter(&micaTexture);
|
||||
|
@ -600,30 +698,68 @@ void MicaMaterialPrivate::updateMaterialBrush()
|
|||
}
|
||||
}
|
||||
|
||||
void MicaMaterialPrivate::paint(QPainter *painter, const QSize &size, const QPoint &pos)
|
||||
void MicaMaterialPrivate::paint(QPainter *painter, const QSize &size, const QPoint &pos, const bool active)
|
||||
{
|
||||
Q_ASSERT(painter);
|
||||
if (!painter) {
|
||||
Q_ASSERT(!size.isEmpty());
|
||||
if (!painter || size.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
prepareGraphicsResources();
|
||||
static constexpr const QPoint originPoint = {0, 0};
|
||||
static constexpr const QPointF originPoint = {0, 0};
|
||||
QPointF correctedPos = pos;
|
||||
QSizeF correctedSize = size;
|
||||
if (!qFuzzyIsNull(transform.Horizontal) && (transform.Horizontal > qreal(0))
|
||||
&& !qFuzzyCompare(transform.Horizontal, qreal(1))) {
|
||||
correctedPos.setX(correctedPos.x() * transform.Horizontal);
|
||||
correctedSize.setWidth(correctedSize.width() * transform.Horizontal);
|
||||
}
|
||||
if (!qFuzzyIsNull(transform.Vertical) && (transform.Vertical > qreal(0))
|
||||
&& !qFuzzyCompare(transform.Vertical, qreal(1))) {
|
||||
correctedPos.setY(correctedPos.y() * transform.Vertical);
|
||||
correctedSize.setHeight(correctedSize.height() * transform.Vertical);
|
||||
}
|
||||
painter->save();
|
||||
painter->setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
painter->drawPixmap(originPoint, g_micaMaterialData()->blurredWallpaper, QRect(pos, size));
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
if (active) {
|
||||
const QMutexLocker locker(&g_micaMaterialData()->mutex);
|
||||
painter->drawPixmap(originPoint, g_micaMaterialData()->blurredWallpaper, QRectF{correctedPos, correctedSize});
|
||||
}
|
||||
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
painter->setOpacity(1.0);
|
||||
painter->fillRect(QRect(originPoint, size), micaBrush);
|
||||
painter->setOpacity(qreal(1));
|
||||
painter->fillRect(QRectF{originPoint, correctedSize}, [this, active]() -> QBrush {
|
||||
if (!fallbackEnabled || active) {
|
||||
return micaBrush;
|
||||
}
|
||||
if (fallbackColor.isValid()) {
|
||||
return fallbackColor;
|
||||
}
|
||||
return systemFallbackColor();
|
||||
}());
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void MicaMaterialPrivate::initialize()
|
||||
{
|
||||
g_threadData()->mutex.lock();
|
||||
if (!g_threadData()->thread) {
|
||||
g_threadData()->thread = std::make_unique<WallpaperThread>();
|
||||
qAddPostRoutine(threadCleaner);
|
||||
}
|
||||
connect(g_threadData()->thread.get(), &WallpaperThread::imageUpdated, this, [this](const Transform &t){
|
||||
transform = t;
|
||||
if (initialized) {
|
||||
Q_Q(MicaMaterial);
|
||||
Q_EMIT q->shouldRedraw();
|
||||
}
|
||||
});
|
||||
g_threadData()->mutex.unlock();
|
||||
|
||||
tintColor = kDefaultTransparentColor;
|
||||
tintOpacity = kDefaultTintOpacity;
|
||||
// Leave fallbackColor invalid, we need to use this state to judge
|
||||
// whether we should use the system color instead.
|
||||
noiseOpacity = kDefaultNoiseOpacity;
|
||||
|
||||
updateMaterialBrush();
|
||||
|
@ -654,6 +790,11 @@ void MicaMaterialPrivate::prepareGraphicsResources()
|
|||
maybeGenerateBlurredWallpaper();
|
||||
}
|
||||
|
||||
QColor MicaMaterialPrivate::systemFallbackColor()
|
||||
{
|
||||
return ((FramelessManager::instance()->systemTheme() == SystemTheme::Dark) ? kDefaultFallbackColorDark : kDefaultFallbackColorLight);
|
||||
}
|
||||
|
||||
MicaMaterial::MicaMaterial(QObject *parent)
|
||||
: QObject(parent), d_ptr(new MicaMaterialPrivate(this))
|
||||
{
|
||||
|
@ -701,6 +842,28 @@ void MicaMaterial::setTintOpacity(const qreal value)
|
|||
Q_EMIT tintOpacityChanged();
|
||||
}
|
||||
|
||||
QColor MicaMaterial::fallbackColor() const
|
||||
{
|
||||
Q_D(const MicaMaterial);
|
||||
return d->fallbackColor;
|
||||
}
|
||||
|
||||
void MicaMaterial::setFallbackColor(const QColor &value)
|
||||
{
|
||||
Q_ASSERT(value.isValid());
|
||||
if (!value.isValid()) {
|
||||
return;
|
||||
}
|
||||
Q_D(MicaMaterial);
|
||||
if (d->fallbackColor == value) {
|
||||
return;
|
||||
}
|
||||
d->prepareGraphicsResources();
|
||||
d->fallbackColor = value;
|
||||
d->updateMaterialBrush();
|
||||
Q_EMIT fallbackColorChanged();
|
||||
}
|
||||
|
||||
qreal MicaMaterial::noiseOpacity() const
|
||||
{
|
||||
Q_D(const MicaMaterial);
|
||||
|
@ -719,10 +882,30 @@ void MicaMaterial::setNoiseOpacity(const qreal value)
|
|||
Q_EMIT noiseOpacityChanged();
|
||||
}
|
||||
|
||||
void MicaMaterial::paint(QPainter *painter, const QSize &size, const QPoint &pos)
|
||||
bool MicaMaterial::isFallbackEnabled() const
|
||||
{
|
||||
Q_D(const MicaMaterial);
|
||||
return d->fallbackEnabled;
|
||||
}
|
||||
|
||||
void MicaMaterial::setFallbackEnabled(const bool value)
|
||||
{
|
||||
Q_D(MicaMaterial);
|
||||
d->paint(painter, size, pos);
|
||||
if (d->fallbackEnabled == value) {
|
||||
return;
|
||||
}
|
||||
d->prepareGraphicsResources();
|
||||
d->fallbackEnabled = value;
|
||||
d->updateMaterialBrush();
|
||||
Q_EMIT fallbackEnabledChanged();
|
||||
}
|
||||
|
||||
void MicaMaterial::paint(QPainter *painter, const QSize &size, const QPoint &pos, const bool active)
|
||||
{
|
||||
Q_D(MicaMaterial);
|
||||
d->paint(painter, size, pos, active);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
#include "micamaterial.moc"
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#endif // SYSAPILOADER_QLIBRARY
|
||||
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qvarlengtharray.h>
|
||||
|
@ -74,7 +73,6 @@ static Q_LOGGING_CATEGORY(lcSysApiLoader, "wangwenx190.framelesshelper.core.sysa
|
|||
|
||||
struct SysApiLoaderData
|
||||
{
|
||||
QMutex mutex;
|
||||
QHash<QString, QFunctionPointer> functionCache = {};
|
||||
};
|
||||
|
||||
|
@ -197,7 +195,6 @@ bool SysApiLoader::isAvailable(const QString &library, const QString &function)
|
|||
return false;
|
||||
}
|
||||
const QString key = generateUniqueKey(library, function);
|
||||
const QMutexLocker locker(&g_loaderData()->mutex);
|
||||
if (g_loaderData()->functionCache.contains(key)) {
|
||||
if (LoaderDebugFlag) {
|
||||
DEBUG << Q_FUNC_INFO << "Function cache found:" << key;
|
||||
|
@ -227,7 +224,6 @@ QFunctionPointer SysApiLoader::get(const QString &library, const QString &functi
|
|||
return nullptr;
|
||||
}
|
||||
const QString key = generateUniqueKey(library, function);
|
||||
const QMutexLocker locker(&g_loaderData()->mutex);
|
||||
if (g_loaderData()->functionCache.contains(key)) {
|
||||
if (LoaderDebugFlag) {
|
||||
DEBUG << Q_FUNC_INFO << "Function cache found:" << key;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtGui/qfontmetrics.h>
|
||||
#include <QtGui/qpalette.h>
|
||||
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
# include <QtGui/private/qhighdpiscaling_p.h>
|
||||
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
|
@ -92,7 +93,7 @@ static const QHash<int, FONT_ICON> g_fontIconsTable = {
|
|||
if (!screen) {
|
||||
return {};
|
||||
}
|
||||
return screen->virtualGeometry().topLeft();
|
||||
return screen->geometry().topLeft();
|
||||
}
|
||||
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
|
||||
|
@ -228,8 +229,8 @@ void Utils::moveWindowToDesktopCenter(FramelessParamsConst params, const bool co
|
|||
if (!screen) {
|
||||
return;
|
||||
}
|
||||
const QSize screenSize = (considerTaskBar ? screen->availableVirtualSize() : screen->virtualSize());
|
||||
const QPoint offset = (considerTaskBar ? screen->availableVirtualGeometry().topLeft() : QPoint(0, 0));
|
||||
const QSize screenSize = (considerTaskBar ? screen->availableSize() : screen->size());
|
||||
const QPoint offset = (considerTaskBar ? screen->availableGeometry().topLeft() : QPoint(0, 0));
|
||||
const int newX = std::round(qreal(screenSize.width() - windowSize.width()) / 2.0);
|
||||
const int newY = std::round(qreal(screenSize.height() - windowSize.height()) / 2.0);
|
||||
params->setWindowPosition(QPoint(newX + offset.x(), newY + offset.y()));
|
||||
|
@ -265,7 +266,7 @@ bool Utils::isThemeChangeEvent(const QEvent * const event)
|
|||
|
||||
QColor Utils::calculateSystemButtonBackgroundColor(const SystemButtonType button, const ButtonState state)
|
||||
{
|
||||
if (state == ButtonState::Unspecified) {
|
||||
if (state == ButtonState::Normal) {
|
||||
return kDefaultTransparentColor;
|
||||
}
|
||||
const bool isClose = (button == SystemButtonType::Close);
|
||||
|
@ -276,15 +277,7 @@ QColor Utils::calculateSystemButtonBackgroundColor(const SystemButtonType button
|
|||
return kDefaultSystemCloseButtonBackgroundColor;
|
||||
}
|
||||
if (isTitleColor) {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return getDwmAccentColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
return getWmThemeColor();
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
return getControlsAccentColor();
|
||||
#endif
|
||||
return getAccentColor();
|
||||
}
|
||||
return kDefaultSystemButtonBackgroundColor;
|
||||
}();
|
||||
|
@ -522,4 +515,70 @@ int Utils::horizontalAdvance(const QFontMetrics &fm, const QString &str)
|
|||
#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
|
||||
}
|
||||
|
||||
qreal Utils::getRelativeScaleFactor(const quint32 oldDpi, const quint32 newDpi)
|
||||
{
|
||||
if (newDpi == oldDpi) {
|
||||
return qreal(1);
|
||||
}
|
||||
static const quint32 defaultDpi = defaultScreenDpi();
|
||||
if ((oldDpi < defaultDpi) || (newDpi < defaultDpi)) {
|
||||
return qreal(1);
|
||||
}
|
||||
// We need to round the scale factor according to Qt's rounding policy.
|
||||
const qreal oldDpr = roundScaleFactor(qreal(oldDpi) / qreal(defaultDpi));
|
||||
const qreal newDpr = roundScaleFactor(qreal(newDpi) / qreal(defaultDpi));
|
||||
return qreal(newDpr / oldDpr);
|
||||
}
|
||||
|
||||
QSize Utils::rescaleSize(const QSize &oldSize, const quint32 oldDpi, const quint32 newDpi)
|
||||
{
|
||||
if (oldSize.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
if (newDpi == oldDpi) {
|
||||
return oldSize;
|
||||
}
|
||||
const qreal scaleFactor = getRelativeScaleFactor(oldDpi, newDpi);
|
||||
if (qFuzzyIsNull(scaleFactor)) {
|
||||
return {};
|
||||
}
|
||||
if (qFuzzyCompare(scaleFactor, qreal(1))) {
|
||||
return oldSize;
|
||||
}
|
||||
const QSizeF newSize = QSizeF(oldSize) * scaleFactor;
|
||||
return newSize.toSize(); // The numbers will be rounded to the nearest integer.
|
||||
}
|
||||
|
||||
bool Utils::isValidGeometry(const QRect &rect)
|
||||
{
|
||||
// The position of the rectangle is not relevant.
|
||||
return ((rect.right() > rect.left()) && (rect.bottom() > rect.top()));
|
||||
}
|
||||
|
||||
quint32 Utils::defaultScreenDpi()
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
return 72;
|
||||
#else // !Q_OS_MACOS
|
||||
return 96;
|
||||
#endif // Q_OS_MACOS
|
||||
}
|
||||
|
||||
QColor Utils::getAccentColor()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||
return QGuiApplication::palette().color(QPalette::AccentColor);
|
||||
#else // (QT_VERSION < QT_VERSION_CHECK(6, 6, 0))
|
||||
# ifdef Q_OS_WINDOWS
|
||||
return getAccentColor_windows();
|
||||
# elif defined(Q_OS_LINUX)
|
||||
return getAccentColor_linux();
|
||||
# elif defined(Q_OS_MACOS)
|
||||
return getAccentColor_macos();
|
||||
# else
|
||||
return QGuiApplication::palette().color(QPalette::Highlight);
|
||||
# endif
|
||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -344,12 +344,6 @@ xcb_connection_t *Utils::x11_connection()
|
|||
#endif // FRAMELESSHELPER_HAS_X11EXTRAS
|
||||
}
|
||||
|
||||
SystemTheme Utils::getSystemTheme()
|
||||
{
|
||||
// ### TODO: how to detect high contrast mode on Linux?
|
||||
return (shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light);
|
||||
}
|
||||
|
||||
void Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
|
@ -390,7 +384,7 @@ bool Utils::isTitleBarColorized()
|
|||
return false;
|
||||
}
|
||||
|
||||
QColor Utils::getWmThemeColor()
|
||||
QColor Utils::getAccentColor_linux()
|
||||
{
|
||||
// ### TODO
|
||||
return QGuiApplication::palette().color(QPalette::Highlight);
|
||||
|
@ -577,7 +571,7 @@ void Utils::registerThemeChangeNotification()
|
|||
|
||||
QColor Utils::getFrameBorderColor(const bool active)
|
||||
{
|
||||
return (active ? getWmThemeColor() : kDefaultDarkGrayColor);
|
||||
return (active ? getAccentColor() : kDefaultDarkGrayColor);
|
||||
}
|
||||
|
||||
xcb_atom_t Utils::internAtom(const char *name)
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "framelessconfig_p.h"
|
||||
#include "framelesshelpercore_global_p.h"
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
|
@ -234,7 +233,6 @@ public:
|
|||
qwindow = qtWindow;
|
||||
nswindow = macWindow;
|
||||
instances.insert(macWindow, this);
|
||||
saveState();
|
||||
if (!windowClass) {
|
||||
windowClass = [nswindow class];
|
||||
Q_ASSERT(windowClass);
|
||||
|
@ -246,41 +244,12 @@ public:
|
|||
{
|
||||
instances.remove(nswindow);
|
||||
if (instances.count() <= 0) {
|
||||
restoreImplementations();
|
||||
windowClass = nil;
|
||||
}
|
||||
restoreState();
|
||||
nswindow = nil;
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
void saveState()
|
||||
{
|
||||
oldStyleMask = nswindow.styleMask;
|
||||
oldTitlebarAppearsTransparent = nswindow.titlebarAppearsTransparent;
|
||||
oldTitleVisibility = nswindow.titleVisibility;
|
||||
oldHasShadow = nswindow.hasShadow;
|
||||
oldShowsToolbarButton = nswindow.showsToolbarButton;
|
||||
oldMovableByWindowBackground = nswindow.movableByWindowBackground;
|
||||
oldMovable = nswindow.movable;
|
||||
oldCloseButtonVisible = ![nswindow standardWindowButton:NSWindowCloseButton].hidden;
|
||||
oldMiniaturizeButtonVisible = ![nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden;
|
||||
oldZoomButtonVisible = ![nswindow standardWindowButton:NSWindowZoomButton].hidden;
|
||||
}
|
||||
|
||||
void restoreState()
|
||||
{
|
||||
nswindow.styleMask = oldStyleMask;
|
||||
nswindow.titlebarAppearsTransparent = oldTitlebarAppearsTransparent;
|
||||
nswindow.titleVisibility = oldTitleVisibility;
|
||||
nswindow.hasShadow = oldHasShadow;
|
||||
nswindow.showsToolbarButton = oldShowsToolbarButton;
|
||||
nswindow.movableByWindowBackground = oldMovableByWindowBackground;
|
||||
nswindow.movable = oldMovable;
|
||||
[nswindow standardWindowButton:NSWindowCloseButton].hidden = !oldCloseButtonVisible;
|
||||
[nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden = !oldMiniaturizeButtonVisible;
|
||||
[nswindow standardWindowButton:NSWindowZoomButton].hidden = !oldZoomButtonVisible;
|
||||
}
|
||||
|
||||
void replaceImplementations()
|
||||
{
|
||||
|
@ -362,9 +331,12 @@ public Q_SLOTS:
|
|||
nswindow.showsToolbarButton = NO;
|
||||
nswindow.movableByWindowBackground = NO;
|
||||
nswindow.movable = NO;
|
||||
// For some unknown reason, we don't need the following hack in Qt versions below or equal to 6.2.4.
|
||||
#if (QT_VERSION > QT_VERSION_CHECK(6, 2, 4))
|
||||
[nswindow standardWindowButton:NSWindowCloseButton].hidden = (visible ? NO : YES);
|
||||
[nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden = (visible ? NO : YES);
|
||||
[nswindow standardWindowButton:NSWindowZoomButton].hidden = (visible ? NO : YES);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setBlurBehindWindowEnabled(const bool enable)
|
||||
|
@ -431,7 +403,7 @@ public Q_SLOTS:
|
|||
return;
|
||||
}
|
||||
const auto view = static_cast<NSVisualEffectView *>(blurEffect);
|
||||
if (Utils::shouldAppsUseDarkMode()) {
|
||||
if (FramelessManager::instance()->systemTheme() == SystemTheme::Dark) {
|
||||
view.appearance = [NSAppearance appearanceNamed:@"NSAppearanceNameVibrantDark"];
|
||||
} else {
|
||||
view.appearance = [NSAppearance appearanceNamed:@"NSAppearanceNameVibrantLight"];
|
||||
|
@ -514,17 +486,6 @@ private:
|
|||
//NSEvent *lastMouseDownEvent = nil;
|
||||
NSView *blurEffect = nil;
|
||||
|
||||
NSWindowStyleMask oldStyleMask = 0;
|
||||
BOOL oldTitlebarAppearsTransparent = NO;
|
||||
BOOL oldHasShadow = NO;
|
||||
BOOL oldShowsToolbarButton = NO;
|
||||
BOOL oldMovableByWindowBackground = NO;
|
||||
BOOL oldMovable = NO;
|
||||
BOOL oldCloseButtonVisible = NO;
|
||||
BOOL oldMiniaturizeButtonVisible = NO;
|
||||
BOOL oldZoomButtonVisible = NO;
|
||||
NSWindowTitleVisibility oldTitleVisibility = NSWindowTitleVisible;
|
||||
|
||||
QMetaObject::Connection widthChangeConnection = {};
|
||||
QMetaObject::Connection heightChangeConnection = {};
|
||||
QMetaObject::Connection themeChangeConnection = {};
|
||||
|
@ -551,7 +512,6 @@ private:
|
|||
|
||||
struct MacUtilsData
|
||||
{
|
||||
QMutex mutex;
|
||||
QHash<WId, NSWindowProxy *> hash = {};
|
||||
};
|
||||
|
||||
|
@ -571,13 +531,27 @@ Q_GLOBAL_STATIC(MacUtilsData, g_macUtilsData);
|
|||
return [nsview window];
|
||||
}
|
||||
|
||||
static inline void cleanupProxy()
|
||||
{
|
||||
if (g_macUtilsData()->hash.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (auto &&proxy : std::as_const(g_macUtilsData()->hash)) {
|
||||
Q_ASSERT(proxy);
|
||||
if (!proxy) {
|
||||
continue;
|
||||
}
|
||||
delete proxy;
|
||||
}
|
||||
g_macUtilsData()->hash.clear();
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline NSWindowProxy *ensureWindowProxy(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return nil;
|
||||
}
|
||||
const QMutexLocker locker(&g_macUtilsData()->mutex);
|
||||
if (!g_macUtilsData()->hash.contains(windowId)) {
|
||||
QWindow * const qwindow = Utils::findWindow(windowId);
|
||||
Q_ASSERT(qwindow);
|
||||
|
@ -592,33 +566,14 @@ Q_GLOBAL_STATIC(MacUtilsData, g_macUtilsData);
|
|||
const auto proxy = new NSWindowProxy(qwindow, nswindow);
|
||||
g_macUtilsData()->hash.insert(windowId, proxy);
|
||||
}
|
||||
volatile static const auto hook = []() -> int {
|
||||
registerUninitializeHook([](){
|
||||
const QMutexLocker locker(&g_macUtilsData()->mutex);
|
||||
if (g_macUtilsData()->hash.isEmpty()) {
|
||||
return;
|
||||
static bool cleanerInstalled = false;
|
||||
if (!cleanerInstalled) {
|
||||
cleanerInstalled = true;
|
||||
qAddPostRoutine(cleanupProxy);
|
||||
}
|
||||
for (auto &&proxy : std::as_const(g_macUtilsData()->hash)) {
|
||||
Q_ASSERT(proxy);
|
||||
if (!proxy) {
|
||||
continue;
|
||||
}
|
||||
delete proxy;
|
||||
}
|
||||
g_macUtilsData()->hash.clear();
|
||||
});
|
||||
return 0;
|
||||
}();
|
||||
Q_UNUSED(hook);
|
||||
return g_macUtilsData()->hash.value(windowId);
|
||||
}
|
||||
|
||||
SystemTheme Utils::getSystemTheme()
|
||||
{
|
||||
// ### TODO: how to detect high contrast mode on macOS?
|
||||
return (shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light);
|
||||
}
|
||||
|
||||
void Utils::setSystemTitleBarVisible(const WId windowId, const bool visible)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
|
@ -676,7 +631,7 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
|
|||
#endif
|
||||
}
|
||||
|
||||
QColor Utils::getControlsAccentColor()
|
||||
QColor Utils::getAccentColor_macos()
|
||||
{
|
||||
return qt_mac_toQColor([NSColor controlAccentColor]);
|
||||
}
|
||||
|
@ -778,7 +733,6 @@ void Utils::removeWindowProxy(const WId windowId)
|
|||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_macUtilsData()->mutex);
|
||||
if (!g_macUtilsData()->hash.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
|
@ -792,7 +746,7 @@ void Utils::removeWindowProxy(const WId windowId)
|
|||
|
||||
QColor Utils::getFrameBorderColor(const bool active)
|
||||
{
|
||||
return (active ? getControlsAccentColor() : kDefaultDarkGrayColor);
|
||||
return (active ? getAccentColor() : kDefaultDarkGrayColor);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "framelesshelpercore_global_p.h"
|
||||
#include "versionnumber_p.h"
|
||||
#include "scopeguard_p.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
|
@ -186,6 +185,7 @@ FRAMELESSHELPER_STRING_CONSTANT(SendMessageTimeoutW)
|
|||
FRAMELESSHELPER_STRING_CONSTANT(AttachThreadInput)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(BringWindowToTop)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(SetActiveWindow)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(RedrawWindow)
|
||||
|
||||
struct Win32UtilsHelperData
|
||||
{
|
||||
|
@ -195,20 +195,12 @@ struct Win32UtilsHelperData
|
|||
|
||||
struct Win32UtilsHelper
|
||||
{
|
||||
QMutex mutex;
|
||||
QHash<WId, Win32UtilsHelperData> data = {};
|
||||
QList<WId> micaWindowIds = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Win32UtilsHelper, g_utilsHelper)
|
||||
|
||||
struct MicaWindowData
|
||||
{
|
||||
QMutex mutex;
|
||||
QList<WId> windowIds = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(MicaWindowData, g_micaData)
|
||||
|
||||
struct SYSTEM_METRIC
|
||||
{
|
||||
int DPI_96 = 0; // 100%. The scale factor for the device is 1x.
|
||||
|
@ -236,6 +228,62 @@ struct SYSTEM_METRIC
|
|||
{SM_CXPADDEDBORDER, { 4, 5, 5, 6, 6, 6, 7, 7, 8, 9, 10, 12, 14, 16, 18, 20}}
|
||||
};
|
||||
|
||||
[[nodiscard]] bool operator==(const RECT &lhs, const RECT &rhs) noexcept
|
||||
{
|
||||
return ((lhs.left == rhs.left) && (lhs.top == rhs.top)
|
||||
&& (lhs.right == rhs.right) && (lhs.bottom == rhs.bottom));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const RECT &lhs, const RECT &rhs) noexcept
|
||||
{
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] QRect rect2qrect(const RECT &rect)
|
||||
{
|
||||
return QRect{QPoint{rect.left, rect.top}, QSize{RECT_WIDTH(rect), RECT_HEIGHT(rect)}};
|
||||
}
|
||||
|
||||
[[nodiscard]] RECT qrect2rect(const QRect &qrect)
|
||||
{
|
||||
return {qrect.left(), qrect.top(), qrect.right(), qrect.bottom()};
|
||||
}
|
||||
|
||||
[[nodiscard]] QString hwnd2str(const WId windowId)
|
||||
{
|
||||
// NULL handle is allowed here.
|
||||
return FRAMELESSHELPER_STRING_LITERAL("0x") + QString::number(windowId, 16).toUpper().rightJustified(8, u'0');
|
||||
}
|
||||
|
||||
[[nodiscard]] QString hwnd2str(const HWND hwnd)
|
||||
{
|
||||
// NULL handle is allowed here.
|
||||
return hwnd2str(reinterpret_cast<WId>(hwnd));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd)
|
||||
{
|
||||
Q_ASSERT(hwnd);
|
||||
if (!hwnd) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// Use "MONITOR_DEFAULTTONEAREST" here so that we can still get the correct
|
||||
// monitor even if the window is minimized.
|
||||
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!monitor) {
|
||||
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
return std::nullopt;
|
||||
}
|
||||
MONITORINFOEXW monitorInfo;
|
||||
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (GetMonitorInfoW(monitor, &monitorInfo) == FALSE) {
|
||||
WARNING << Utils::getSystemErrorMessage(kGetMonitorInfoW);
|
||||
return std::nullopt;
|
||||
}
|
||||
return monitorInfo;
|
||||
};
|
||||
|
||||
[[nodiscard]] static inline QString dwmRegistryKey()
|
||||
{
|
||||
static const QString key = QString::fromWCharArray(kDwmRegistryKey);
|
||||
|
@ -296,7 +344,7 @@ struct SYSTEM_METRIC
|
|||
return (VerifyVersionInfoW(&osvi, (VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER), dwlConditionMask) != FALSE);
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline QString __getSystemErrorMessage(const QString &function, const DWORD code)
|
||||
[[nodiscard]] static inline QString getSystemErrorMessageImpl(const QString &function, const DWORD code)
|
||||
{
|
||||
Q_ASSERT(!function.isEmpty());
|
||||
if (function.isEmpty()) {
|
||||
|
@ -321,7 +369,7 @@ struct SYSTEM_METRIC
|
|||
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline QString __getSystemErrorMessage(const QString &function, const HRESULT hr)
|
||||
[[nodiscard]] static inline QString getSystemErrorMessageImpl(const QString &function, const HRESULT hr)
|
||||
{
|
||||
Q_ASSERT(!function.isEmpty());
|
||||
if (function.isEmpty()) {
|
||||
|
@ -331,36 +379,9 @@ struct SYSTEM_METRIC
|
|||
return kSuccessMessageText;
|
||||
}
|
||||
const DWORD dwError = HRESULT_CODE(hr);
|
||||
return __getSystemErrorMessage(function, dwError);
|
||||
return getSystemErrorMessageImpl(function, dwError);
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline bool operator==(const RECT &lhs, const RECT &rhs) noexcept
|
||||
{
|
||||
return ((lhs.left == rhs.left) && (lhs.top == rhs.top)
|
||||
&& (lhs.right == rhs.right) && (lhs.bottom == rhs.bottom));
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd)
|
||||
{
|
||||
Q_ASSERT(hwnd);
|
||||
if (!hwnd) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!monitor) {
|
||||
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
return std::nullopt;
|
||||
}
|
||||
MONITORINFOEXW monitorInfo;
|
||||
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (GetMonitorInfoW(monitor, &monitorInfo) == FALSE) {
|
||||
WARNING << Utils::getSystemErrorMessage(kGetMonitorInfoW);
|
||||
return std::nullopt;
|
||||
}
|
||||
return monitorInfo;
|
||||
};
|
||||
|
||||
static inline void moveWindowToMonitor(const HWND hwnd, const MONITORINFOEXW &activeMonitor)
|
||||
{
|
||||
Q_ASSERT(hwnd);
|
||||
|
@ -468,13 +489,10 @@ static inline void moveWindowToMonitor(const HWND hwnd, const MONITORINFOEXW &ac
|
|||
return 0;
|
||||
}
|
||||
const auto windowId = reinterpret_cast<WId>(hWnd);
|
||||
g_utilsHelper()->mutex.lock();
|
||||
if (!g_utilsHelper()->data.contains(windowId)) {
|
||||
g_utilsHelper()->mutex.unlock();
|
||||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
const Win32UtilsHelperData data = g_utilsHelper()->data.value(windowId);
|
||||
g_utilsHelper()->mutex.unlock();
|
||||
const auto getNativePosFromMouse = [lParam]() -> QPoint {
|
||||
return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
};
|
||||
|
@ -594,7 +612,7 @@ bool Utils::isDwmCompositionEnabled()
|
|||
BOOL enabled = FALSE;
|
||||
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmIsCompositionEnabled, &enabled);
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kDwmIsCompositionEnabled, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmIsCompositionEnabled, hr);
|
||||
return resultFromRegistry();
|
||||
}
|
||||
return (enabled != FALSE);
|
||||
|
@ -607,11 +625,18 @@ void Utils::triggerFrameChange(const WId windowId)
|
|||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
static constexpr const UINT flags =
|
||||
static constexpr const UINT swpFlags =
|
||||
(SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE
|
||||
| SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
|
||||
if (SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, flags) == FALSE) {
|
||||
if (SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, swpFlags) == FALSE) {
|
||||
WARNING << getSystemErrorMessage(kSetWindowPos);
|
||||
return;
|
||||
}
|
||||
static constexpr const UINT rdwFlags =
|
||||
(RDW_ERASE | RDW_FRAME | RDW_INVALIDATE
|
||||
| RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
if (RedrawWindow(hwnd, nullptr, nullptr, rdwFlags) == FALSE) {
|
||||
WARNING << getSystemErrorMessage(kRedrawWindow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -629,9 +654,7 @@ void Utils::updateWindowFrameMargins(const WId windowId, const bool reset)
|
|||
if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) {
|
||||
return;
|
||||
}
|
||||
g_micaData()->mutex.lock();
|
||||
const bool micaEnabled = g_micaData()->windowIds.contains(windowId);
|
||||
g_micaData()->mutex.unlock();
|
||||
const bool micaEnabled = g_utilsHelper()->micaWindowIds.contains(windowId);
|
||||
const auto margins = [micaEnabled, reset]() -> MARGINS {
|
||||
// To make Mica/Mica Alt work for normal Win32 windows, we have to
|
||||
// let the window frame extend to the whole window (or disable the
|
||||
|
@ -649,7 +672,7 @@ void Utils::updateWindowFrameMargins(const WId windowId, const bool reset)
|
|||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmExtendFrameIntoClientArea, hwnd, &margins);
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kDwmExtendFrameIntoClientArea, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmExtendFrameIntoClientArea, hr);
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(windowId);
|
||||
|
@ -712,7 +735,7 @@ QString Utils::getSystemErrorMessage(const QString &function)
|
|||
if (code == ERROR_SUCCESS) {
|
||||
return {};
|
||||
}
|
||||
return __getSystemErrorMessage(function, code);
|
||||
return getSystemErrorMessageImpl(function, code);
|
||||
}
|
||||
|
||||
QColor Utils::getDwmColorizationColor()
|
||||
|
@ -735,7 +758,7 @@ QColor Utils::getDwmColorizationColor()
|
|||
BOOL opaque = FALSE;
|
||||
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmGetColorizationColor, &color, &opaque);
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kDwmGetColorizationColor, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmGetColorizationColor, hr);
|
||||
return resultFromRegistry();
|
||||
}
|
||||
return QColor::fromRgba(color);
|
||||
|
@ -959,7 +982,7 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal)
|
|||
if (SUCCEEDED(hr) && (dpiX > 0) && (dpiY > 0)) {
|
||||
return (horizontal ? dpiX : dpiY);
|
||||
} else {
|
||||
WARNING << __getSystemErrorMessage(kGetDpiForMonitor, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kGetDpiForMonitor, hr);
|
||||
}
|
||||
}
|
||||
// GetScaleFactorForMonitor() is only available on Windows 8 and onwards.
|
||||
|
@ -969,7 +992,7 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal)
|
|||
if (SUCCEEDED(hr) && (factor != _DEVICE_SCALE_FACTOR_INVALID)) {
|
||||
return quint32(std::round(qreal(USER_DEFAULT_SCREEN_DPI) * qreal(factor) / qreal(100)));
|
||||
} else {
|
||||
WARNING << __getSystemErrorMessage(kGetScaleFactorForMonitor, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kGetScaleFactorForMonitor, hr);
|
||||
}
|
||||
}
|
||||
// This solution is supported on Windows 2000 and onwards.
|
||||
|
@ -1028,10 +1051,10 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal)
|
|||
WARNING << "GetDesktopDpi() failed.";
|
||||
}
|
||||
} else {
|
||||
WARNING << __getSystemErrorMessage(kReloadSystemMetrics, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kReloadSystemMetrics, hr);
|
||||
}
|
||||
} else {
|
||||
WARNING << __getSystemErrorMessage(kD2D1CreateFactory, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kD2D1CreateFactory, hr);
|
||||
}
|
||||
if (d2dFactory) {
|
||||
d2dFactory->Release();
|
||||
|
@ -1239,10 +1262,10 @@ QColor Utils::getFrameBorderColor(const bool active)
|
|||
if (!WindowsVersionHelper::isWin10OrGreater()) {
|
||||
return (active ? kDefaultBlackColor : kDefaultDarkGrayColor);
|
||||
}
|
||||
const bool dark = shouldAppsUseDarkMode();
|
||||
const bool dark = (FramelessManager::instance()->systemTheme() == SystemTheme::Dark);
|
||||
if (active) {
|
||||
if (isFrameBorderColorized()) {
|
||||
return getDwmAccentColor();
|
||||
return getAccentColor();
|
||||
}
|
||||
return (dark ? kDefaultFrameBorderActiveColor : kDefaultTransparentColor);
|
||||
} else {
|
||||
|
@ -1394,7 +1417,6 @@ void Utils::installSystemMenuHook(const WId windowId, FramelessParamsConst param
|
|||
if (!windowId || !params) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_utilsHelper()->mutex);
|
||||
if (g_utilsHelper()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1424,7 +1446,6 @@ void Utils::uninstallSystemMenuHook(const WId windowId)
|
|||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_utilsHelper()->mutex);
|
||||
if (!g_utilsHelper()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1499,7 +1520,7 @@ void Utils::tryToEnableHighestDpiAwarenessLevel()
|
|||
DEBUG << kDpiNoAccessErrorMessage;
|
||||
return true;
|
||||
}
|
||||
WARNING << __getSystemErrorMessage(kSetProcessDpiAwarenessContext, dwError);
|
||||
WARNING << getSystemErrorMessageImpl(kSetProcessDpiAwarenessContext, dwError);
|
||||
return false;
|
||||
};
|
||||
if (currentAwareness == DpiAwareness::PerMonitorVersion2) {
|
||||
|
@ -1540,7 +1561,7 @@ void Utils::tryToEnableHighestDpiAwarenessLevel()
|
|||
DEBUG << kDpiNoAccessErrorMessage;
|
||||
return true;
|
||||
}
|
||||
WARNING << __getSystemErrorMessage(kSetProcessDpiAwareness, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kSetProcessDpiAwareness, hr);
|
||||
return false;
|
||||
};
|
||||
if (currentAwareness == DpiAwareness::PerMonitorVersion2) {
|
||||
|
@ -1580,17 +1601,6 @@ void Utils::tryToEnableHighestDpiAwarenessLevel()
|
|||
}
|
||||
}
|
||||
|
||||
SystemTheme Utils::getSystemTheme()
|
||||
{
|
||||
if (isHighContrastModeEnabled()) {
|
||||
return SystemTheme::HighContrast;
|
||||
}
|
||||
if (WindowsVersionHelper::isWin10RS1OrGreater() && shouldAppsUseDarkMode()) {
|
||||
return SystemTheme::Dark;
|
||||
}
|
||||
return SystemTheme::Light;
|
||||
}
|
||||
|
||||
void Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
|
@ -1608,14 +1618,14 @@ void Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
|
|||
const HRESULT hr = API_CALL_FUNCTION(uxtheme, SetWindowTheme, hwnd,
|
||||
(dark ? kSystemDarkThemeResourceName : kSystemLightThemeResourceName), nullptr);
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kSetWindowTheme, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kSetWindowTheme, hr);
|
||||
}
|
||||
}
|
||||
|
||||
bool Utils::shouldAppsUseDarkMode_windows()
|
||||
{
|
||||
// The global dark mode was first introduced in Windows 10 1607.
|
||||
if (!WindowsVersionHelper::isWin10RS1OrGreater()) {
|
||||
if (!WindowsVersionHelper::isWin10RS1OrGreater() || isHighContrastModeEnabled()) {
|
||||
return false;
|
||||
}
|
||||
#ifndef FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
|
@ -1688,7 +1698,7 @@ void Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle
|
|||
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmSetWindowAttribute,
|
||||
hwnd, _DWMWA_WINDOW_CORNER_PREFERENCE, &wcp, sizeof(wcp));
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1706,11 +1716,9 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
return false;
|
||||
}
|
||||
const auto restoreWindowFrameMargins = [windowId]() -> void {
|
||||
g_micaData()->mutex.lock();
|
||||
if (g_micaData()->windowIds.contains(windowId)) {
|
||||
g_micaData()->windowIds.removeAll(windowId);
|
||||
if (g_utilsHelper()->micaWindowIds.contains(windowId)) {
|
||||
g_utilsHelper()->micaWindowIds.removeAll(windowId);
|
||||
}
|
||||
g_micaData()->mutex.unlock();
|
||||
updateWindowFrameMargins(windowId, false);
|
||||
};
|
||||
const bool preferMicaAlt = (qEnvironmentVariableIntValue("FRAMELESSHELPER_PREFER_MICA_ALT") != 0);
|
||||
|
@ -1750,7 +1758,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt));
|
||||
if (FAILED(hr)) {
|
||||
result = false;
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
} else if (WindowsVersionHelper::isWin11OrGreater()) {
|
||||
const BOOL enable = FALSE;
|
||||
|
@ -1758,7 +1766,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable));
|
||||
if (FAILED(hr)) {
|
||||
result = false;
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
} else {
|
||||
ACCENT_POLICY policy;
|
||||
|
@ -1781,11 +1789,9 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
return result;
|
||||
} else {
|
||||
if ((blurMode == BlurMode::Windows_Mica) || (blurMode == BlurMode::Windows_MicaAlt)) {
|
||||
g_micaData()->mutex.lock();
|
||||
if (!g_micaData()->windowIds.contains(windowId)) {
|
||||
g_micaData()->windowIds.append(windowId);
|
||||
if (!g_utilsHelper()->micaWindowIds.contains(windowId)) {
|
||||
g_utilsHelper()->micaWindowIds.append(windowId);
|
||||
}
|
||||
g_micaData()->mutex.unlock();
|
||||
// By giving a negative value, DWM will extend the window frame into the whole
|
||||
// client area. We need this step because the Mica material can only be applied
|
||||
// to the non-client area of a window. Without this step, you'll get a window
|
||||
|
@ -1813,7 +1819,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
if (SUCCEEDED(hr)) {
|
||||
return true;
|
||||
} else {
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
} else {
|
||||
const BOOL enable = TRUE;
|
||||
|
@ -1822,11 +1828,11 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
if (SUCCEEDED(hr)) {
|
||||
return true;
|
||||
} else {
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WARNING << __getSystemErrorMessage(kDwmExtendFrameIntoClientArea, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmExtendFrameIntoClientArea, hr);
|
||||
}
|
||||
restoreWindowFrameMargins();
|
||||
} else {
|
||||
|
@ -1839,7 +1845,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
if (color.isValid()) {
|
||||
return color;
|
||||
}
|
||||
QColor clr = (shouldAppsUseDarkMode() ? kDefaultSystemDarkColor : kDefaultSystemLightColor);
|
||||
QColor clr = ((FramelessManager::instance()->systemTheme() == SystemTheme::Dark) ? kDefaultSystemDarkColor : kDefaultSystemLightColor);
|
||||
clr.setAlphaF(0.9f);
|
||||
return clr;
|
||||
}();
|
||||
|
@ -1895,14 +1901,14 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
if (SUCCEEDED(hr)) {
|
||||
return true;
|
||||
}
|
||||
WARNING << __getSystemErrorMessage(kDwmEnableBlurBehindWindow, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmEnableBlurBehindWindow, hr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QColor Utils::getDwmAccentColor()
|
||||
QColor Utils::getAccentColor_windows()
|
||||
{
|
||||
// According to my test, this AccentColor will be exactly the same with
|
||||
// According to my experiments, this AccentColor will be exactly the same with
|
||||
// ColorizationColor, what's the meaning of it? But Microsoft products
|
||||
// usually read this setting instead of using DwmGetColorizationColor(),
|
||||
// so we'd better also do the same thing.
|
||||
|
@ -1918,7 +1924,7 @@ QColor Utils::getDwmAccentColor()
|
|||
return alternative;
|
||||
}
|
||||
// The retrieved value is in the #AABBGGRR format, we need to
|
||||
// convert it to the #AARRGGBB format that Qt accepts.
|
||||
// convert it to the #AARRGGBB format which Qt expects.
|
||||
const QColor abgr = QColor::fromRgba(qvariant_cast<DWORD>(value));
|
||||
if (!abgr.isValid()) {
|
||||
return alternative;
|
||||
|
@ -1990,7 +1996,7 @@ void Utils::hideOriginalTitleBarElements(const WId windowId, const bool disable)
|
|||
const DWORD mask = (disable ? validBits : 0);
|
||||
const HRESULT hr = _SetWindowThemeNonClientAttributes(hwnd, mask, mask);
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kSetWindowThemeAttribute, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kSetWindowThemeAttribute, hr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2086,7 +2092,7 @@ void Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
|
|||
}
|
||||
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmSetWindowAttribute, hWnd, borderFlag, &darkFlag, sizeof(darkFlag));
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
_FlushMenuThemes();
|
||||
|
@ -2114,7 +2120,7 @@ void Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
|
|||
}
|
||||
const HRESULT hr = API_CALL_FUNCTION(dwmapi, DwmSetWindowAttribute, hWnd, borderFlag, &darkFlag, sizeof(darkFlag));
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
_FlushMenuThemes();
|
||||
|
@ -2217,7 +2223,7 @@ DpiAwareness Utils::getDpiAwarenessForCurrentProcess(bool *highest)
|
|||
_PROCESS_DPI_AWARENESS pda = _PROCESS_DPI_UNAWARE;
|
||||
const HRESULT hr = API_CALL_FUNCTION4(shcore, GetProcessDpiAwareness, nullptr, &pda);
|
||||
if (FAILED(hr)) {
|
||||
WARNING << __getSystemErrorMessage(kGetProcessDpiAwareness, hr);
|
||||
WARNING << getSystemErrorMessageImpl(kGetProcessDpiAwareness, hr);
|
||||
return DpiAwareness::Unknown;
|
||||
}
|
||||
auto result = DpiAwareness::Unknown;
|
||||
|
@ -2390,4 +2396,72 @@ void Utils::bringWindowToFront(const WId windowId)
|
|||
moveWindowToMonitor(hwnd, activeMonitor.value());
|
||||
}
|
||||
|
||||
QPoint Utils::getWindowPlacementOffset(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return {};
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
const auto exStyle = static_cast<DWORD>(GetWindowLongPtrW(hwnd, GWL_EXSTYLE));
|
||||
if (exStyle == 0) {
|
||||
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
return {};
|
||||
}
|
||||
// Tool windows are special and they don't need any offset.
|
||||
if (exStyle & WS_EX_TOOLWINDOW) {
|
||||
return {};
|
||||
}
|
||||
const std::optional<MONITORINFOEXW> mi = getMonitorForWindow(hwnd);
|
||||
if (!mi.has_value()) {
|
||||
WARNING << "Failed to retrieve the window's monitor.";
|
||||
return {};
|
||||
}
|
||||
const RECT work = mi.value().rcWork;
|
||||
const RECT total = mi.value().rcMonitor;
|
||||
return {work.left - total.left, work.top - total.top};
|
||||
}
|
||||
|
||||
QRect Utils::getWindowRestoreGeometry(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return {};
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
WINDOWPLACEMENT wp;
|
||||
SecureZeroMemory(&wp, sizeof(wp));
|
||||
wp.length = sizeof(wp);
|
||||
if (GetWindowPlacement(hwnd, &wp) == FALSE) {
|
||||
WARNING << getSystemErrorMessage(kGetWindowPlacement);
|
||||
return {};
|
||||
}
|
||||
return rect2qrect(wp.rcNormalPosition).translated(getWindowPlacementOffset(windowId));
|
||||
}
|
||||
|
||||
void Utils::removeMicaWindow(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
if (!g_utilsHelper()->micaWindowIds.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
g_utilsHelper()->micaWindowIds.removeAll(windowId);
|
||||
}
|
||||
|
||||
void Utils::removeSysMenuHook(const WId windowId)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
if (!g_utilsHelper()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
g_utilsHelper()->data.remove(windowId);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -112,20 +112,15 @@ void WindowBorderPainterPrivate::paint(QPainter *painter, const QSize &size, con
|
|||
return;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
QList<QLine> lines = {};
|
||||
QList<QLineF> lines = {};
|
||||
#else
|
||||
QVector<QLine> lines = {};
|
||||
QVector<QLineF> lines = {};
|
||||
#endif
|
||||
const QPoint leftTop = {0, 0};
|
||||
// In fact, we should use "size.width() - 1" here in theory but we can't
|
||||
// because Qt's drawing system has some rounding errors internally and if
|
||||
// we minus one here we'll get a one pixel gap, so sad. But drawing a line
|
||||
// with a little extra pixels won't hurt anyway.
|
||||
const QPoint rightTop = {size.width(), 0};
|
||||
// Same here as above: we should use "size.height() - 1" ideally but we
|
||||
// can't, sadly.
|
||||
const QPoint rightBottom = {size.width(), size.height()};
|
||||
const QPoint leftBottom = {0, size.height()};
|
||||
static constexpr const auto gap = qreal(0.5);
|
||||
const QPointF leftTop = {gap, gap};
|
||||
const QPointF rightTop = {qreal(size.width()) - gap, gap};
|
||||
const QPointF rightBottom = {qreal(size.width()) - gap, qreal(size.height()) - gap};
|
||||
const QPointF leftBottom = {gap, qreal(size.height()) - gap};
|
||||
const WindowEdges edges = m_edges.value_or(getNativeBorderEdges());
|
||||
if (edges & WindowEdge::Left) {
|
||||
lines.append({leftBottom, leftTop});
|
||||
|
@ -143,10 +138,7 @@ void WindowBorderPainterPrivate::paint(QPainter *painter, const QSize &size, con
|
|||
return;
|
||||
}
|
||||
painter->save();
|
||||
painter->setRenderHints(QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
// We can't enable antialiasing here, because the border is too thin and antialiasing
|
||||
// will break it's painting.
|
||||
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
QPen pen = {};
|
||||
pen.setColor([active, this]() -> QColor {
|
||||
QColor color = {};
|
||||
|
|
|
@ -24,14 +24,18 @@
|
|||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS QuickTemplates2 QuickControls2)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS QuickTemplates2 QuickControls2)
|
||||
|
||||
set(SUB_MOD_NAME Quick)
|
||||
set(SUB_PROJ_NAME ${PROJECT_NAME}${SUB_MOD_NAME})
|
||||
set(SUB_PROJ_PATH ${PROJECT_NAME}/${SUB_MOD_NAME})
|
||||
set(SUB_MODULE Quick)
|
||||
set(SUB_MODULE_FULL_NAME ${PROJECT_NAME}${SUB_MODULE})
|
||||
set(SUB_MODULE_PATH ${PROJECT_NAME}/${SUB_MODULE})
|
||||
|
||||
set(INCLUDE_PREFIX ../../include/${SUB_PROJ_PATH})
|
||||
set(INCLUDE_PREFIX ../../include/${SUB_MODULE_PATH})
|
||||
|
||||
set(PUBLIC_HEADERS
|
||||
${INCLUDE_PREFIX}/framelesshelperquick_global.h
|
||||
|
@ -84,18 +88,20 @@ set(SOURCES
|
|||
)
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(__rc_path "${CMAKE_CURRENT_BINARY_DIR}/${SUB_PROJ_NAME}.rc")
|
||||
set(__rc_path "${CMAKE_CURRENT_BINARY_DIR}/${SUB_MODULE_FULL_NAME}.rc")
|
||||
if(NOT EXISTS "${__rc_path}")
|
||||
generate_win32_rc_file(
|
||||
PATH "${__rc_path}"
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
COMPANY "wangwenx190"
|
||||
DESCRIPTION "${PROJECT_NAME} ${SUB_MOD_NAME} Module"
|
||||
DESCRIPTION "${PROJECT_NAME} ${SUB_MODULE} Module"
|
||||
COPYRIGHT "MIT License"
|
||||
ORIGINAL_FILENAME "${PROJECT_NAME}${SUB_MOD_NAME}.dll"
|
||||
ORIGINAL_FILENAME "${PROJECT_NAME}${SUB_MODULE}.dll"
|
||||
PRODUCT "${PROJECT_NAME}"
|
||||
COMMENTS "Built from commit ${PROJECT_VERSION_COMMIT} on ${PROJECT_COMPILE_DATETIME} (UTC)."
|
||||
LIBRARY
|
||||
)
|
||||
endif()
|
||||
list(APPEND SOURCES "${__rc_path}")
|
||||
endif()
|
||||
|
||||
|
@ -106,65 +112,34 @@ if(FRAMELESSHELPER_BUILD_STATIC)
|
|||
else()
|
||||
set(SUB_MOD_LIB_TYPE "SHARED")
|
||||
endif()
|
||||
add_library(${SUB_PROJ_NAME} ${SUB_MOD_LIB_TYPE} ${ALL_SOURCES})
|
||||
add_library(${PROJECT_NAME}::${SUB_PROJ_NAME} ALIAS ${SUB_PROJ_NAME})
|
||||
add_library(${PROJECT_NAME}::${SUB_MOD_NAME} ALIAS ${SUB_PROJ_NAME})
|
||||
add_library(${SUB_MODULE} ${SUB_MOD_LIB_TYPE} ${ALL_SOURCES})
|
||||
add_library(${SUB_MODULE_FULL_NAME} ALIAS ${SUB_MODULE})
|
||||
add_library(${PROJECT_NAME}::${SUB_MODULE} ALIAS ${SUB_MODULE})
|
||||
add_library(${PROJECT_NAME}::${SUB_MODULE_FULL_NAME} ALIAS ${SUB_MODULE})
|
||||
|
||||
set_target_properties(${SUB_PROJ_NAME} PROPERTIES
|
||||
set_target_properties(${SUB_MODULE} PROPERTIES
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}"
|
||||
OUTPUT_NAME "${SUB_MODULE_FULL_NAME}"
|
||||
)
|
||||
|
||||
set(SUB_MOD_TARGETS ${SUB_PROJ_NAME})
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(SUB_MOD_LIB_DIR "${CMAKE_INSTALL_BINDIR}")
|
||||
else()
|
||||
set(SUB_MOD_LIB_DIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
set(__prefix "")
|
||||
if(NOT WIN32)
|
||||
set(__prefix "lib")
|
||||
endif()
|
||||
set(__suffix "")
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
if(MSVC)
|
||||
set(__suffix "lib")
|
||||
else()
|
||||
set(__suffix "a")
|
||||
endif()
|
||||
else()
|
||||
if(WIN32)
|
||||
set(__suffix "dll")
|
||||
elseif(APPLE)
|
||||
set(__suffix "dylib")
|
||||
elseif(UNIX)
|
||||
set(__suffix "so")
|
||||
endif()
|
||||
endif()
|
||||
set(SUB_MOD_FILE_PREFIX "${__prefix}")
|
||||
set(SUB_MOD_FILE_SUFFIX "${__suffix}")
|
||||
set(SUB_MOD_FILE_BASENAME "${SUB_MOD_FILE_PREFIX}${SUB_PROJ_NAME}")
|
||||
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
|
||||
string(APPEND SUB_MOD_FILE_BASENAME "${CMAKE_DEBUG_POSTFIX}")
|
||||
endif()
|
||||
set(SUB_MOD_FILE_NAME "${SUB_MOD_FILE_BASENAME}.${SUB_MOD_FILE_SUFFIX}")
|
||||
unset(__suffix)
|
||||
unset(__prefix)
|
||||
set(__export_targets ${SUB_MODULE})
|
||||
|
||||
set(__import_base_dir "${PROJECT_BINARY_DIR}/imports")
|
||||
if(DEFINED FRAMELESSHELPER_IMPORT_DIR)
|
||||
set(__import_base_dir "${FRAMELESSHELPER_IMPORT_DIR}")
|
||||
endif()
|
||||
set(__import_uri "org/wangwenx190/${PROJECT_NAME}")
|
||||
set(__import_dir "${__import_base_dir}/${__import_uri}")
|
||||
|
||||
if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
|
||||
qt_add_qml_module(${SUB_PROJ_NAME}
|
||||
# qt_add_qml_module() was introduced in Qt 6.2 but qt_query_qml_module()
|
||||
# was introduced in 6.3, to simplify the CMake code, I decide to limit the
|
||||
# version check to 6.3, otherwise we'll need a lot of code to query and
|
||||
# calculate the generated files, which will also break Ninja Multi-Config
|
||||
# builds.
|
||||
if(QT_VERSION VERSION_GREATER_EQUAL "6.3")
|
||||
qt_add_qml_module(${SUB_MODULE}
|
||||
URI "org.wangwenx190.${PROJECT_NAME}"
|
||||
VERSION "1.0"
|
||||
OUTPUT_DIRECTORY "${__import_dir}"
|
||||
OUTPUT_DIRECTORY "${__import_base_dir}/org/wangwenx190/${PROJECT_NAME}"
|
||||
RESOURCE_PREFIX "/"
|
||||
#NO_RESOURCE_TARGET_PATH # Can't be used for non-executables.
|
||||
OUTPUT_TARGETS __qml_targets
|
||||
|
@ -174,114 +149,127 @@ if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
|
|||
QtQuick.Controls.Basic/auto
|
||||
)
|
||||
if(__qml_targets)
|
||||
foreach(__target ${__qml_targets})
|
||||
list(APPEND SUB_MOD_TARGETS ${__target})
|
||||
list(APPEND __export_targets ${__qml_targets})
|
||||
# We have some resources bundled into the library,
|
||||
# however, for static builds, the object files will
|
||||
# not be packed into our final static library file,
|
||||
# and thus it causes linker errors for our users,
|
||||
# so we need this hack here.
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
target_sources(${SUB_PROJ_NAME} PRIVATE
|
||||
foreach(__target ${__qml_targets})
|
||||
target_sources(${SUB_MODULE} PRIVATE
|
||||
$<TARGET_OBJECTS:${__target}>
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
if(NOT FRAMELESSHELPER_NO_INSTALL)
|
||||
set(__lib_prefix)
|
||||
if(UNIX)
|
||||
set(__lib_prefix lib)
|
||||
endif()
|
||||
set(__lib_suffix "$<$<CONFIG:Debug>:${CMAKE_DEBUG_POSTFIX}>")
|
||||
set(__lib_ext)
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
if(MSVC)
|
||||
set(__lib_ext lib)
|
||||
else()
|
||||
set(__lib_ext a)
|
||||
endif()
|
||||
else()
|
||||
if(WIN32)
|
||||
set(__lib_ext dll)
|
||||
elseif(APPLE)
|
||||
set(__lib_ext dylib)
|
||||
elseif(UNIX)
|
||||
set(__lib_ext so)
|
||||
endif()
|
||||
endif()
|
||||
install(
|
||||
FILES
|
||||
"${__import_dir}/qmldir"
|
||||
"${__import_dir}/${SUB_PROJ_NAME}.qmltypes"
|
||||
"${__import_dir}/${__lib_prefix}${SUB_PROJ_NAME}plugin${__lib_suffix}.${__lib_ext}"
|
||||
DESTINATION "qml/${__import_uri}"
|
||||
qt_query_qml_module(${SUB_MODULE}
|
||||
URI module_uri
|
||||
VERSION module_version
|
||||
PLUGIN_TARGET module_plugin_target
|
||||
TARGET_PATH module_target_path
|
||||
QMLDIR module_qmldir
|
||||
TYPEINFO module_typeinfo
|
||||
#QML_FILES module_qml_files
|
||||
#QML_FILES_DEPLOY_PATHS module_qml_files_deploy_paths
|
||||
#RESOURCES module_resources
|
||||
#RESOURCES_DEPLOY_PATHS module_resources_deploy_paths
|
||||
)
|
||||
if(module_target_path)
|
||||
set(__qml_plugin_dir "qml/${module_target_path}")
|
||||
if(module_plugin_target)
|
||||
install(TARGETS ${module_plugin_target}
|
||||
RUNTIME DESTINATION "${__qml_plugin_dir}"
|
||||
LIBRARY DESTINATION "${__qml_plugin_dir}"
|
||||
ARCHIVE DESTINATION "${__qml_plugin_dir}"
|
||||
)
|
||||
endif()
|
||||
if(module_qmldir)
|
||||
install(FILES "${module_qmldir}" DESTINATION "${__qml_plugin_dir}")
|
||||
endif()
|
||||
if(module_typeinfo)
|
||||
install(FILES "${module_typeinfo}" DESTINATION "${__qml_plugin_dir}")
|
||||
endif()
|
||||
if(module_qml_files)
|
||||
list(LENGTH module_qml_files num_files)
|
||||
math(EXPR last_index "${num_files} - 1")
|
||||
foreach(i RANGE 0 ${last_index})
|
||||
list(GET module_qml_files ${i} src_file)
|
||||
list(GET module_qml_files_deploy_paths ${i} deploy_path)
|
||||
get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
|
||||
install(FILES "${src_file}" DESTINATION "${__qml_plugin_dir}/${dest_dir}")
|
||||
endforeach()
|
||||
endif()
|
||||
if(module_resources)
|
||||
list(LENGTH module_resources num_files)
|
||||
math(EXPR last_index "${num_files} - 1")
|
||||
foreach(i RANGE 0 ${last_index})
|
||||
list(GET module_resources ${i} src_file)
|
||||
list(GET module_resources_deploy_paths ${i} deploy_path)
|
||||
get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
|
||||
install(FILES "${src_file}" DESTINATION "${__qml_plugin_dir}/${dest_dir}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(__def FRAMELESSHELPER_QUICK_STATIC)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_QUICK_STATIC)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_DEBUG_OUTPUT)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
target_compile_definitions(${SUB_MODULE} PRIVATE
|
||||
FRAMELESSHELPER_QUICK_NO_DEBUG_OUTPUT
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_BUNDLE_RESOURCE)
|
||||
set(__def FRAMELESSHELPER_QUICK_NO_BUNDLE_RESOURCE)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_QUICK_NO_BUNDLE_RESOURCE)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_PRIVATE)
|
||||
set(__def FRAMELESSHELPER_QUICK_NO_PRIVATE)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_QUICK_NO_PRIVATE)
|
||||
endif()
|
||||
|
||||
if(DEFINED FRAMELESSHELPER_NAMESPACE)
|
||||
if("x${FRAMELESSHELPER_NAMESPACE}" STREQUAL "x")
|
||||
message(FATAL_ERROR "FRAMELESSHELPER_NAMESPACE can't be empty!")
|
||||
endif()
|
||||
set(__def FRAMELESSHELPER_NAMESPACE=${FRAMELESSHELPER_NAMESPACE})
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_NAMESPACE=${FRAMELESSHELPER_NAMESPACE})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
target_compile_definitions(${SUB_MODULE} PRIVATE
|
||||
FRAMELESSHELPER_QUICK_LIBRARY
|
||||
)
|
||||
|
||||
if(FRAMELESSHELPER_NO_PRIVATE)
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Quick
|
||||
)
|
||||
else()
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::QuickPrivate
|
||||
Qt${QT_VERSION_MAJOR}::QuickTemplates2Private
|
||||
Qt${QT_VERSION_MAJOR}::QuickControls2Private
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${SUB_PROJ_NAME} PUBLIC
|
||||
target_link_libraries(${SUB_MODULE} PUBLIC
|
||||
${PROJECT_NAME}::Core
|
||||
)
|
||||
|
||||
target_include_directories(${SUB_PROJ_NAME} PUBLIC
|
||||
target_include_directories(${SUB_MODULE} PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/../..>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/private>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}/private>"
|
||||
)
|
||||
|
||||
setup_qt_stuff(TARGETS ${SUB_PROJ_NAME} ALLOW_KEYWORD)
|
||||
setup_qt_stuff(TARGETS ${SUB_MODULE} ALLOW_KEYWORD)
|
||||
set(__extra_flags)
|
||||
if(NOT FRAMELESSHELPER_NO_PERMISSIVE_CHECKS)
|
||||
list(APPEND __extra_flags PERMISSIVE)
|
||||
|
@ -301,31 +289,22 @@ endif()
|
|||
if(FRAMELESSHELPER_ENABLE_CFGUARD)
|
||||
list(APPEND __extra_flags CFGUARD)
|
||||
endif()
|
||||
setup_compile_params(TARGETS ${SUB_PROJ_NAME} ${__extra_flags})
|
||||
if(FRAMELESSHELPER_FORCE_LTO)
|
||||
list(APPEND __extra_flags FORCE_LTO)
|
||||
endif()
|
||||
setup_compile_params(TARGETS ${SUB_MODULE} ${__extra_flags})
|
||||
if(NOT FRAMELESSHELPER_NO_INSTALL)
|
||||
set(__cmake_dir "${CMAKE_CURRENT_BINARY_DIR}/cmake")
|
||||
set(__config_file "${__cmake_dir}/${SUB_PROJ_NAME}Config.cmake")
|
||||
configure_file(../../FramelessHelperModuleConfig.cmake.in ${__config_file} @ONLY)
|
||||
set(__targets_file "${__cmake_dir}/${SUB_PROJ_NAME}Targets.cmake")
|
||||
configure_file(../../FramelessHelperModuleTargets.cmake.in ${__targets_file} @ONLY)
|
||||
install(
|
||||
FILES "${__config_file}" "${__targets_file}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${SUB_PROJ_NAME}"
|
||||
)
|
||||
set(__inc_dir "${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}")
|
||||
install(
|
||||
FILES ${PUBLIC_HEADERS} ${PUBLIC_HEADERS_ALIAS}
|
||||
DESTINATION "${__inc_dir}"
|
||||
)
|
||||
install(
|
||||
FILES ${PRIVATE_HEADERS}
|
||||
DESTINATION "${__inc_dir}/private"
|
||||
)
|
||||
install(
|
||||
TARGETS ${SUB_MOD_TARGETS}
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${__inc_dir}"
|
||||
setup_package_export(
|
||||
TARGETS ${__export_targets}
|
||||
NAMESPACE ${PROJECT_NAME}
|
||||
PACKAGE_NAME ${PROJECT_NAME}
|
||||
COMPONENT ${SUB_MODULE}
|
||||
PUBLIC_HEADERS ${PUBLIC_HEADERS}
|
||||
ALIAS_HEADERS ${PUBLIC_HEADERS_ALIAS}
|
||||
PRIVATE_HEADERS ${PRIVATE_HEADERS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT FRAMELESSHELPER_NO_SUMMARY)
|
||||
dump_target_info(TARGETS ${SUB_MODULE})
|
||||
endif()
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#ifdef Q_OS_WINDOWS
|
||||
# include <FramelessHelper/Core/private/winverhelper_p.h>
|
||||
#endif // Q_OS_WINDOWS
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
#include <QtCore/qeventloop.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
@ -86,7 +85,6 @@ struct QuickHelperData
|
|||
|
||||
struct QuickHelper
|
||||
{
|
||||
QMutex mutex;
|
||||
QHash<WId, QuickHelperData> data = {};
|
||||
};
|
||||
|
||||
|
@ -160,7 +158,6 @@ void FramelessQuickHelperPrivate::setTitleBarItem(QQuickItem *value)
|
|||
if (!value) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
QuickHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
|
@ -181,13 +178,10 @@ void FramelessQuickHelperPrivate::attach()
|
|||
return;
|
||||
}
|
||||
|
||||
g_quickHelper()->mutex.lock();
|
||||
QuickHelperData * const data = getWindowDataMutable();
|
||||
if (!data || data->ready) {
|
||||
g_quickHelper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
g_quickHelper()->mutex.unlock();
|
||||
|
||||
SystemParameters params = {};
|
||||
params.getWindowId = [window]() -> WId { return window->winId(); };
|
||||
|
@ -224,13 +218,12 @@ void FramelessQuickHelperPrivate::attach()
|
|||
params.setCursor = [window](const QCursor &cursor) -> void { window->setCursor(cursor); };
|
||||
params.unsetCursor = [window]() -> void { window->unsetCursor(); };
|
||||
params.getWidgetHandle = []() -> QObject * { return nullptr; };
|
||||
params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); };
|
||||
|
||||
FramelessManager::instance()->addWindow(¶ms);
|
||||
|
||||
g_quickHelper()->mutex.lock();
|
||||
data->params = params;
|
||||
data->ready = true;
|
||||
g_quickHelper()->mutex.unlock();
|
||||
|
||||
// We have to wait for a little time before moving the top level window
|
||||
// , because the platform window may not finish initializing by the time
|
||||
|
@ -257,7 +250,6 @@ void FramelessQuickHelperPrivate::detach()
|
|||
return;
|
||||
}
|
||||
const WId windowId = w->winId();
|
||||
const QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
if (!g_quickHelper()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
|
@ -272,14 +264,11 @@ void FramelessQuickHelperPrivate::setSystemButton(QQuickItem *item, const QuickG
|
|||
if (!item || (buttonType == QuickGlobal::SystemButtonType::Unknown)) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
QuickHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
switch (buttonType) {
|
||||
case QuickGlobal::SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(static_cast<void>(0));
|
||||
case QuickGlobal::SystemButtonType::WindowIcon:
|
||||
data->windowIconButton = item;
|
||||
break;
|
||||
|
@ -296,6 +285,8 @@ void FramelessQuickHelperPrivate::setSystemButton(QQuickItem *item, const QuickG
|
|||
case QuickGlobal::SystemButtonType::Close:
|
||||
data->closeButton = item;
|
||||
break;
|
||||
case QuickGlobal::SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(static_cast<void>(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +296,6 @@ void FramelessQuickHelperPrivate::setHitTestVisible(QQuickItem *item, const bool
|
|||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
QuickHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
|
@ -325,7 +315,6 @@ void FramelessQuickHelperPrivate::setHitTestVisible(const QRect &rect, const boo
|
|||
if (!rect.isValid()) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
QuickHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
|
@ -685,6 +674,38 @@ void FramelessQuickHelperPrivate::waitForReady()
|
|||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickHelperPrivate::repaintAllChildren(const int delay) const
|
||||
{
|
||||
Q_Q(const FramelessQuickHelper);
|
||||
QQuickWindow * const window = q->window();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
const auto update = [window]() -> void {
|
||||
window->requestUpdate();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
// Sync the internal window frame margins with the latest DPI, otherwise
|
||||
// we will get wrong window sizes after the DPI change.
|
||||
Utils::updateInternalWindowFrameMargins(window, true);
|
||||
#endif // Q_OS_WINDOWS
|
||||
const QList<QQuickItem *> items = window->findChildren<QQuickItem *>();
|
||||
if (items.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (auto &&item : std::as_const(items)) {
|
||||
// Only items with the "QQuickItem::ItemHasContents" flag enabled are allowed to call "update()".
|
||||
if (item->flags() & QQuickItem::ItemHasContents) {
|
||||
item->update();
|
||||
}
|
||||
}
|
||||
};
|
||||
if (delay > 0) {
|
||||
QTimer::singleShot(delay, this, update);
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
QRect FramelessQuickHelperPrivate::mapItemGeometryToScene(const QQuickItem * const item) const
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
|
@ -827,8 +848,6 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
|
|||
const QuickHelperData data = getWindowData();
|
||||
QQuickAbstractButton *quickButton = nullptr;
|
||||
switch (button) {
|
||||
case QuickGlobal::SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(void(0));
|
||||
case QuickGlobal::SystemButtonType::WindowIcon:
|
||||
if (data.windowIconButton) {
|
||||
if (const auto btn = qobject_cast<QQuickAbstractButton *>(data.windowIconButton)) {
|
||||
|
@ -865,15 +884,19 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
|
|||
}
|
||||
}
|
||||
break;
|
||||
case QuickGlobal::SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(void(0));
|
||||
}
|
||||
if (!quickButton) {
|
||||
return;
|
||||
}
|
||||
if (quickButton) {
|
||||
const auto updateButtonState = [state](QQuickAbstractButton *btn) -> void {
|
||||
Q_ASSERT(btn);
|
||||
if (!btn) {
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case QuickGlobal::ButtonState::Unspecified: {
|
||||
case QuickGlobal::ButtonState::Normal: {
|
||||
btn->setPressed(false);
|
||||
btn->setHovered(false);
|
||||
} break;
|
||||
|
@ -885,7 +908,7 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
|
|||
btn->setHovered(true);
|
||||
btn->setPressed(true);
|
||||
} break;
|
||||
case QuickGlobal::ButtonState::Clicked: {
|
||||
case QuickGlobal::ButtonState::Released: {
|
||||
// Clicked: pressed --> released, so behave like hovered.
|
||||
btn->setPressed(false);
|
||||
btn->setHovered(true);
|
||||
|
@ -894,7 +917,6 @@ void FramelessQuickHelperPrivate::setSystemButtonState(const QuickGlobal::System
|
|||
}
|
||||
};
|
||||
updateButtonState(quickButton);
|
||||
}
|
||||
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
}
|
||||
|
||||
|
@ -907,7 +929,6 @@ QuickHelperData FramelessQuickHelperPrivate::getWindowData() const
|
|||
return {};
|
||||
}
|
||||
const WId windowId = window->winId();
|
||||
const QMutexLocker locker(&g_quickHelper()->mutex);
|
||||
if (!g_quickHelper()->data.contains(windowId)) {
|
||||
g_quickHelper()->data.insert(windowId, {});
|
||||
}
|
||||
|
|
|
@ -91,7 +91,13 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
return new FramelessQuickUtils;
|
||||
});
|
||||
qmlRegisterAnonymousType<QuickChromePalette>(QUICK_URI_SHORT);
|
||||
|
||||
#if (QT_VERSION <= QT_VERSION_CHECK(5, 16, 0))
|
||||
qRegisterMetaType<QuickGlobal::SystemTheme>("QuickGlobal::SystemTheme");
|
||||
qRegisterMetaType<QuickGlobal::SystemButtonType>("QuickGlobal::SystemButtonType");
|
||||
qRegisterMetaType<QuickGlobal::ButtonState>("QuickGlobal::ButtonState");
|
||||
qRegisterMetaType<QuickGlobal::BlurMode>("QuickGlobal::BlurMode");
|
||||
qRegisterMetaType<QuickGlobal::WindowEdge>("QuickGlobal::WindowEdge");
|
||||
#endif
|
||||
qmlRegisterType<FramelessQuickHelper>(QUICK_URI_EXPAND("FramelessHelper"));
|
||||
qmlRegisterType<QuickMicaMaterial>(QUICK_URI_EXPAND("MicaMaterial"));
|
||||
qmlRegisterType<QuickImageItem>(QUICK_URI_EXPAND("ImageItem"));
|
||||
|
|
|
@ -84,20 +84,17 @@ qreal FramelessQuickUtils::frameBorderThickness() const
|
|||
|
||||
QuickGlobal::SystemTheme FramelessQuickUtils::systemTheme() const
|
||||
{
|
||||
return FRAMELESSHELPER_ENUM_CORE_TO_QUICK(SystemTheme, Utils::getSystemTheme());
|
||||
return FRAMELESSHELPER_ENUM_CORE_TO_QUICK(SystemTheme, FramelessManager::instance()->systemTheme());
|
||||
}
|
||||
|
||||
void FramelessQuickUtils::setOverrideTheme(const QuickGlobal::SystemTheme theme)
|
||||
{
|
||||
FramelessManager::instance()->setOverrideTheme(FRAMELESSHELPER_ENUM_QUICK_TO_CORE(SystemTheme, theme));
|
||||
}
|
||||
|
||||
QColor FramelessQuickUtils::systemAccentColor() const
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return Utils::getDwmAccentColor();
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return Utils::getWmThemeColor();
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return Utils::getControlsAccentColor();
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
return Utils::getAccentColor();
|
||||
}
|
||||
|
||||
bool FramelessQuickUtils::titleBarColorized() const
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
#include "quickmicamaterial.h"
|
||||
#include "quickmicamaterial_p.h"
|
||||
#include <FramelessHelper/Core/micamaterial.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <FramelessHelper/Core/framelessmanager.h>
|
||||
#include <FramelessHelper/Core/private/micamaterial_p.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
|
@ -34,6 +35,8 @@
|
|||
#include <QtQuick/qsgsimpletexturenode.h>
|
||||
#ifndef FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
# include <QtQuick/private/qquickitem_p.h>
|
||||
# include <QtQuick/private/qquickrectangle_p.h>
|
||||
# include <QtQuick/private/qquickanchors_p.h>
|
||||
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
@ -54,13 +57,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
struct QuickMicaData
|
||||
{
|
||||
QMutex mutex;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(QuickMicaData, g_data)
|
||||
|
||||
class WallpaperImageNode : public QObject, public QSGTransformNode
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -82,7 +78,6 @@ private:
|
|||
QPointer<QuickMicaMaterial> m_item = nullptr;
|
||||
QSGSimpleTextureNode *m_node = nullptr;
|
||||
QPixmap m_pixmapCache = {};
|
||||
MicaMaterial *m_micaMaterial = nullptr;
|
||||
};
|
||||
|
||||
WallpaperImageNode::WallpaperImageNode(QuickMicaMaterial *item)
|
||||
|
@ -95,28 +90,29 @@ WallpaperImageNode::WallpaperImageNode(QuickMicaMaterial *item)
|
|||
initialize();
|
||||
}
|
||||
|
||||
WallpaperImageNode::~WallpaperImageNode() = default;
|
||||
WallpaperImageNode::~WallpaperImageNode(){
|
||||
if (m_texture) {
|
||||
delete m_texture;
|
||||
m_texture = nullptr;
|
||||
}
|
||||
if (m_node) {
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void WallpaperImageNode::initialize()
|
||||
{
|
||||
g_data()->mutex.lock();
|
||||
|
||||
QQuickWindow * const window = m_item->window();
|
||||
m_micaMaterial = new MicaMaterial(this);
|
||||
|
||||
m_node = new QSGSimpleTextureNode;
|
||||
m_node->setFiltering(QSGTexture::Linear);
|
||||
|
||||
g_data()->mutex.unlock();
|
||||
|
||||
maybeGenerateWallpaperImageCache();
|
||||
maybeUpdateWallpaperImageClipRect();
|
||||
|
||||
appendChildNode(m_node);
|
||||
|
||||
connect(m_micaMaterial, &MicaMaterial::shouldRedraw, this, [this](){
|
||||
maybeGenerateWallpaperImageCache(true);
|
||||
});
|
||||
connect(window, &QQuickWindow::beforeRendering, this,
|
||||
&WallpaperImageNode::maybeUpdateWallpaperImageClipRect, Qt::DirectConnection);
|
||||
|
||||
|
@ -125,7 +121,6 @@ void WallpaperImageNode::initialize()
|
|||
|
||||
void WallpaperImageNode::maybeGenerateWallpaperImageCache(const bool force)
|
||||
{
|
||||
const QMutexLocker locker(&g_data()->mutex);
|
||||
if (!m_pixmapCache.isNull() && !force) {
|
||||
return;
|
||||
}
|
||||
|
@ -134,7 +129,10 @@ void WallpaperImageNode::maybeGenerateWallpaperImageCache(const bool force)
|
|||
m_pixmapCache = QPixmap(desktopSize);
|
||||
m_pixmapCache.fill(kDefaultTransparentColor);
|
||||
QPainter painter(&m_pixmapCache);
|
||||
m_micaMaterial->paint(&painter, desktopSize, originPoint);
|
||||
MicaMaterial * const mica = QuickMicaMaterialPrivate::get(m_item)->m_micaMaterial;
|
||||
Q_ASSERT(mica);
|
||||
// We need the real wallpaper image here, so always use "active" state.
|
||||
mica->paint(&painter, desktopSize, originPoint, true);
|
||||
if (m_texture) {
|
||||
delete m_texture;
|
||||
m_texture = nullptr;
|
||||
|
@ -145,7 +143,6 @@ void WallpaperImageNode::maybeGenerateWallpaperImageCache(const bool force)
|
|||
|
||||
void WallpaperImageNode::maybeUpdateWallpaperImageClipRect()
|
||||
{
|
||||
const QMutexLocker locker(&g_data()->mutex);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
const QSizeF itemSize = m_item->size();
|
||||
#else
|
||||
|
@ -188,10 +185,30 @@ const QuickMicaMaterialPrivate *QuickMicaMaterialPrivate::get(const QuickMicaMat
|
|||
void QuickMicaMaterialPrivate::initialize()
|
||||
{
|
||||
Q_Q(QuickMicaMaterial);
|
||||
|
||||
q->setFlag(QuickMicaMaterial::ItemHasContents);
|
||||
q->setSmooth(true);
|
||||
q->setAntialiasing(true);
|
||||
q->setClip(true);
|
||||
|
||||
m_micaMaterial = new MicaMaterial(this);
|
||||
connect(m_micaMaterial, &MicaMaterial::tintColorChanged, q, &QuickMicaMaterial::tintColorChanged);
|
||||
connect(m_micaMaterial, &MicaMaterial::tintOpacityChanged, q, &QuickMicaMaterial::tintOpacityChanged);
|
||||
connect(m_micaMaterial, &MicaMaterial::fallbackColorChanged, q, &QuickMicaMaterial::fallbackColorChanged);
|
||||
connect(m_micaMaterial, &MicaMaterial::noiseOpacityChanged, q, &QuickMicaMaterial::noiseOpacityChanged);
|
||||
connect(m_micaMaterial, &MicaMaterial::fallbackEnabledChanged, q, &QuickMicaMaterial::fallbackEnabledChanged);
|
||||
connect(m_micaMaterial, &MicaMaterial::shouldRedraw, this, &QuickMicaMaterialPrivate::forceRegenerateWallpaperImageCache);
|
||||
|
||||
#ifndef FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
m_fallbackColorItem = new QQuickRectangle(q);
|
||||
QQuickItemPrivate::get(m_fallbackColorItem)->anchors()->setFill(q);
|
||||
QQuickPen * const border = m_fallbackColorItem->border();
|
||||
border->setColor(kDefaultTransparentColor);
|
||||
border->setWidth(0);
|
||||
updateFallbackColor();
|
||||
m_fallbackColorItem->setVisible(false);
|
||||
connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &QuickMicaMaterialPrivate::updateFallbackColor);
|
||||
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
}
|
||||
|
||||
void QuickMicaMaterialPrivate::rebindWindow()
|
||||
|
@ -218,6 +235,19 @@ void QuickMicaMaterialPrivate::rebindWindow()
|
|||
}
|
||||
m_rootWindowXChangedConnection = connect(window, &QQuickWindow::xChanged, q, [q](){ q->update(); });
|
||||
m_rootWindowYChangedConnection = connect(window, &QQuickWindow::yChanged, q, [q](){ q->update(); });
|
||||
#ifndef FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
if (m_rootWindowActiveChangedConnection) {
|
||||
disconnect(m_rootWindowActiveChangedConnection);
|
||||
m_rootWindowActiveChangedConnection = {};
|
||||
}
|
||||
m_rootWindowActiveChangedConnection = connect(window, &QQuickWindow::activeChanged, q, [this, window](){
|
||||
if (m_micaMaterial->isFallbackEnabled()) {
|
||||
m_fallbackColorItem->setVisible(!window->isActive());
|
||||
} else {
|
||||
m_fallbackColorItem->setVisible(false);
|
||||
}
|
||||
});
|
||||
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
}
|
||||
|
||||
void QuickMicaMaterialPrivate::forceRegenerateWallpaperImageCache()
|
||||
|
@ -244,6 +274,21 @@ void QuickMicaMaterialPrivate::appendNode(WallpaperImageNode *node)
|
|||
m_nodes.append(node);
|
||||
}
|
||||
|
||||
void QuickMicaMaterialPrivate::updateFallbackColor()
|
||||
{
|
||||
#ifndef FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
if (!m_fallbackColorItem || !m_micaMaterial) {
|
||||
return;
|
||||
}
|
||||
const QColor color = m_micaMaterial->fallbackColor();
|
||||
if (color.isValid()) {
|
||||
m_fallbackColorItem->setColor(color);
|
||||
return;
|
||||
}
|
||||
m_fallbackColorItem->setColor(MicaMaterialPrivate::systemFallbackColor());
|
||||
#endif // FRAMELESSHELPER_QUICK_NO_PRIVATE
|
||||
}
|
||||
|
||||
QuickMicaMaterial::QuickMicaMaterial(QQuickItem *parent)
|
||||
: QQuickItem(parent), d_ptr(new QuickMicaMaterialPrivate(this))
|
||||
{
|
||||
|
@ -251,6 +296,66 @@ QuickMicaMaterial::QuickMicaMaterial(QQuickItem *parent)
|
|||
|
||||
QuickMicaMaterial::~QuickMicaMaterial() = default;
|
||||
|
||||
QColor QuickMicaMaterial::tintColor() const
|
||||
{
|
||||
Q_D(const QuickMicaMaterial);
|
||||
return d->m_micaMaterial->tintColor();
|
||||
}
|
||||
|
||||
void QuickMicaMaterial::setTintColor(const QColor &value)
|
||||
{
|
||||
Q_D(QuickMicaMaterial);
|
||||
d->m_micaMaterial->setTintColor(value);
|
||||
}
|
||||
|
||||
qreal QuickMicaMaterial::tintOpacity() const
|
||||
{
|
||||
Q_D(const QuickMicaMaterial);
|
||||
return d->m_micaMaterial->tintOpacity();
|
||||
}
|
||||
|
||||
void QuickMicaMaterial::setTintOpacity(const qreal value)
|
||||
{
|
||||
Q_D(QuickMicaMaterial);
|
||||
d->m_micaMaterial->setTintOpacity(value);
|
||||
}
|
||||
|
||||
QColor QuickMicaMaterial::fallbackColor() const
|
||||
{
|
||||
Q_D(const QuickMicaMaterial);
|
||||
return d->m_micaMaterial->fallbackColor();
|
||||
}
|
||||
|
||||
void QuickMicaMaterial::setFallbackColor(const QColor &value)
|
||||
{
|
||||
Q_D(QuickMicaMaterial);
|
||||
d->m_micaMaterial->setFallbackColor(value);
|
||||
}
|
||||
|
||||
qreal QuickMicaMaterial::noiseOpacity() const
|
||||
{
|
||||
Q_D(const QuickMicaMaterial);
|
||||
return d->m_micaMaterial->noiseOpacity();
|
||||
}
|
||||
|
||||
void QuickMicaMaterial::setNoiseOpacity(const qreal value)
|
||||
{
|
||||
Q_D(QuickMicaMaterial);
|
||||
d->m_micaMaterial->setNoiseOpacity(value);
|
||||
}
|
||||
|
||||
bool QuickMicaMaterial::isFallbackEnabled() const
|
||||
{
|
||||
Q_D(const QuickMicaMaterial);
|
||||
return d->m_micaMaterial->isFallbackEnabled();
|
||||
}
|
||||
|
||||
void QuickMicaMaterial::setFallbackEnabled(const bool value)
|
||||
{
|
||||
Q_D(QuickMicaMaterial);
|
||||
d->m_micaMaterial->setFallbackEnabled(value);
|
||||
}
|
||||
|
||||
void QuickMicaMaterial::itemChange(const ItemChange change, const ItemChangeData &value)
|
||||
{
|
||||
QQuickItem::itemChange(change, value);
|
||||
|
|
|
@ -24,11 +24,15 @@
|
|||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(SUB_MOD_NAME Widgets)
|
||||
set(SUB_PROJ_NAME ${PROJECT_NAME}${SUB_MOD_NAME})
|
||||
set(SUB_PROJ_PATH ${PROJECT_NAME}/${SUB_MOD_NAME})
|
||||
if(FRAMELESSHELPER_ENABLE_UNIVERSAL_BUILD)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
set(INCLUDE_PREFIX ../../include/${SUB_PROJ_PATH})
|
||||
set(SUB_MODULE Widgets)
|
||||
set(SUB_MODULE_FULL_NAME ${PROJECT_NAME}${SUB_MODULE})
|
||||
set(SUB_MODULE_PATH ${PROJECT_NAME}/${SUB_MODULE})
|
||||
|
||||
set(INCLUDE_PREFIX ../../include/${SUB_MODULE_PATH})
|
||||
|
||||
set(PUBLIC_HEADERS
|
||||
${INCLUDE_PREFIX}/framelesshelperwidgets_global.h
|
||||
|
@ -72,18 +76,20 @@ set(SOURCES
|
|||
)
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(__rc_path "${CMAKE_CURRENT_BINARY_DIR}/${SUB_PROJ_NAME}.rc")
|
||||
set(__rc_path "${CMAKE_CURRENT_BINARY_DIR}/${SUB_MODULE_FULL_NAME}.rc")
|
||||
if(NOT EXISTS "${__rc_path}")
|
||||
generate_win32_rc_file(
|
||||
PATH "${__rc_path}"
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
COMPANY "wangwenx190"
|
||||
DESCRIPTION "${PROJECT_NAME} ${SUB_MOD_NAME} Module"
|
||||
DESCRIPTION "${PROJECT_NAME} ${SUB_MODULE} Module"
|
||||
COPYRIGHT "MIT License"
|
||||
ORIGINAL_FILENAME "${PROJECT_NAME}${SUB_MOD_NAME}.dll"
|
||||
ORIGINAL_FILENAME "${PROJECT_NAME}${SUB_MODULE}.dll"
|
||||
PRODUCT "${PROJECT_NAME}"
|
||||
COMMENTS "Built from commit ${PROJECT_VERSION_COMMIT} on ${PROJECT_COMPILE_DATETIME} (UTC)."
|
||||
LIBRARY
|
||||
)
|
||||
endif()
|
||||
list(APPEND SOURCES "${__rc_path}")
|
||||
endif()
|
||||
|
||||
|
@ -94,110 +100,64 @@ if(FRAMELESSHELPER_BUILD_STATIC)
|
|||
else()
|
||||
set(SUB_MOD_LIB_TYPE "SHARED")
|
||||
endif()
|
||||
add_library(${SUB_PROJ_NAME} ${SUB_MOD_LIB_TYPE} ${ALL_SOURCES})
|
||||
add_library(${PROJECT_NAME}::${SUB_PROJ_NAME} ALIAS ${SUB_PROJ_NAME})
|
||||
add_library(${PROJECT_NAME}::${SUB_MOD_NAME} ALIAS ${SUB_PROJ_NAME})
|
||||
add_library(${SUB_MODULE} ${SUB_MOD_LIB_TYPE} ${ALL_SOURCES})
|
||||
add_library(${SUB_MODULE_FULL_NAME} ALIAS ${SUB_MODULE})
|
||||
add_library(${PROJECT_NAME}::${SUB_MODULE} ALIAS ${SUB_MODULE})
|
||||
add_library(${PROJECT_NAME}::${SUB_MODULE_FULL_NAME} ALIAS ${SUB_MODULE})
|
||||
|
||||
set_target_properties(${SUB_PROJ_NAME} PROPERTIES
|
||||
set_target_properties(${SUB_MODULE} PROPERTIES
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}"
|
||||
OUTPUT_NAME "${SUB_MODULE_FULL_NAME}"
|
||||
)
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(SUB_MOD_LIB_DIR "${CMAKE_INSTALL_BINDIR}")
|
||||
else()
|
||||
set(SUB_MOD_LIB_DIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
set(__prefix "")
|
||||
if(NOT WIN32)
|
||||
set(__prefix "lib")
|
||||
endif()
|
||||
set(__suffix "")
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
if(MSVC)
|
||||
set(__suffix "lib")
|
||||
else()
|
||||
set(__suffix "a")
|
||||
endif()
|
||||
else()
|
||||
if(WIN32)
|
||||
set(__suffix "dll")
|
||||
elseif(APPLE)
|
||||
set(__suffix "dylib")
|
||||
elseif(UNIX)
|
||||
set(__suffix "so")
|
||||
endif()
|
||||
endif()
|
||||
set(SUB_MOD_FILE_PREFIX "${__prefix}")
|
||||
set(SUB_MOD_FILE_SUFFIX "${__suffix}")
|
||||
set(SUB_MOD_FILE_BASENAME "${SUB_MOD_FILE_PREFIX}${SUB_PROJ_NAME}")
|
||||
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
|
||||
string(APPEND SUB_MOD_FILE_BASENAME "${CMAKE_DEBUG_POSTFIX}")
|
||||
endif()
|
||||
set(SUB_MOD_FILE_NAME "${SUB_MOD_FILE_BASENAME}.${SUB_MOD_FILE_SUFFIX}")
|
||||
unset(__suffix)
|
||||
unset(__prefix)
|
||||
|
||||
if(FRAMELESSHELPER_BUILD_STATIC)
|
||||
set(__def FRAMELESSHELPER_WIDGETS_STATIC)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_WIDGETS_STATIC)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_DEBUG_OUTPUT)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
target_compile_definitions(${SUB_MODULE} PRIVATE
|
||||
FRAMELESSHELPER_WIDGETS_NO_DEBUG_OUTPUT
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_BUNDLE_RESOURCE)
|
||||
set(__def FRAMELESSHELPER_WIDGETS_NO_BUNDLE_RESOURCE)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_WIDGETS_NO_BUNDLE_RESOURCE)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_NO_PRIVATE)
|
||||
set(__def FRAMELESSHELPER_WIDGETS_NO_PRIVATE)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_WIDGETS_NO_PRIVATE)
|
||||
endif()
|
||||
|
||||
if(DEFINED FRAMELESSHELPER_NAMESPACE)
|
||||
if("x${FRAMELESSHELPER_NAMESPACE}" STREQUAL "x")
|
||||
message(FATAL_ERROR "FRAMELESSHELPER_NAMESPACE can't be empty!")
|
||||
endif()
|
||||
set(__def FRAMELESSHELPER_NAMESPACE=${FRAMELESSHELPER_NAMESPACE})
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PUBLIC ${__def})
|
||||
list(APPEND SUB_MOD_DEFS ${__def})
|
||||
unset(__def)
|
||||
target_compile_definitions(${SUB_MODULE} PUBLIC FRAMELESSHELPER_NAMESPACE=${FRAMELESSHELPER_NAMESPACE})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
target_compile_definitions(${SUB_MODULE} PRIVATE
|
||||
FRAMELESSHELPER_WIDGETS_LIBRARY
|
||||
)
|
||||
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
target_link_libraries(${SUB_MODULE} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
)
|
||||
|
||||
target_link_libraries(${SUB_PROJ_NAME} PUBLIC
|
||||
target_link_libraries(${SUB_MODULE} PUBLIC
|
||||
${PROJECT_NAME}::Core
|
||||
)
|
||||
|
||||
target_include_directories(${SUB_PROJ_NAME} PUBLIC
|
||||
target_include_directories(${SUB_MODULE} PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/../..>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PREFIX}/private>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_MODULE_PATH}/private>"
|
||||
)
|
||||
|
||||
setup_qt_stuff(TARGETS ${SUB_PROJ_NAME})
|
||||
setup_qt_stuff(TARGETS ${SUB_MODULE})
|
||||
set(__extra_flags)
|
||||
if(NOT FRAMELESSHELPER_NO_PERMISSIVE_CHECKS)
|
||||
list(APPEND __extra_flags PERMISSIVE)
|
||||
|
@ -217,31 +177,22 @@ endif()
|
|||
if(FRAMELESSHELPER_ENABLE_CFGUARD)
|
||||
list(APPEND __extra_flags CFGUARD)
|
||||
endif()
|
||||
setup_compile_params(TARGETS ${SUB_PROJ_NAME} ${__extra_flags})
|
||||
if(FRAMELESSHELPER_FORCE_LTO)
|
||||
list(APPEND __extra_flags FORCE_LTO)
|
||||
endif()
|
||||
setup_compile_params(TARGETS ${SUB_MODULE} ${__extra_flags})
|
||||
if(NOT FRAMELESSHELPER_NO_INSTALL)
|
||||
set(__cmake_dir "${CMAKE_CURRENT_BINARY_DIR}/cmake")
|
||||
set(__config_file "${__cmake_dir}/${SUB_PROJ_NAME}Config.cmake")
|
||||
configure_file(../../FramelessHelperModuleConfig.cmake.in ${__config_file} @ONLY)
|
||||
set(__targets_file "${__cmake_dir}/${SUB_PROJ_NAME}Targets.cmake")
|
||||
configure_file(../../FramelessHelperModuleTargets.cmake.in ${__targets_file} @ONLY)
|
||||
install(
|
||||
FILES "${__config_file}" "${__targets_file}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${SUB_PROJ_NAME}"
|
||||
)
|
||||
set(__inc_dir "${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}")
|
||||
install(
|
||||
FILES ${PUBLIC_HEADERS} ${PUBLIC_HEADERS_ALIAS}
|
||||
DESTINATION "${__inc_dir}"
|
||||
)
|
||||
install(
|
||||
FILES ${PRIVATE_HEADERS}
|
||||
DESTINATION "${__inc_dir}/private"
|
||||
)
|
||||
install(
|
||||
TARGETS ${SUB_PROJ_NAME}
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${__inc_dir}"
|
||||
setup_package_export(
|
||||
TARGETS ${SUB_MODULE}
|
||||
NAMESPACE ${PROJECT_NAME}
|
||||
PACKAGE_NAME ${PROJECT_NAME}
|
||||
COMPONENT ${SUB_MODULE}
|
||||
PUBLIC_HEADERS ${PUBLIC_HEADERS}
|
||||
ALIAS_HEADERS ${PUBLIC_HEADERS_ALIAS}
|
||||
PRIVATE_HEADERS ${PRIVATE_HEADERS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT FRAMELESSHELPER_NO_SUMMARY)
|
||||
dump_target_info(TARGETS ${SUB_MODULE})
|
||||
endif()
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include <FramelessHelper/Core/utils.h>
|
||||
#include <FramelessHelper/Core/private/framelessconfig_p.h>
|
||||
#include <FramelessHelper/Core/private/framelesshelpercore_global_p.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
#include <QtCore/qeventloop.h>
|
||||
|
@ -82,12 +81,81 @@ struct WidgetsHelperData
|
|||
|
||||
struct WidgetsHelper
|
||||
{
|
||||
QMutex mutex;
|
||||
QHash<WId, WidgetsHelperData> data = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(WidgetsHelper, g_widgetsHelper)
|
||||
|
||||
[[nodiscard]] static inline bool isWidgetFixedSize(const QWidget * const widget)
|
||||
{
|
||||
Q_ASSERT(widget);
|
||||
if (!widget) {
|
||||
return false;
|
||||
}
|
||||
// "Qt::MSWindowsFixedSizeDialogHint" is used cross-platform actually.
|
||||
if (widget->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) {
|
||||
return true;
|
||||
}
|
||||
// Caused by setFixedWidth/Height/Size().
|
||||
const QSize minSize = widget->minimumSize();
|
||||
const QSize maxSize = widget->maximumSize();
|
||||
if (!minSize.isEmpty() && !maxSize.isEmpty() && (minSize == maxSize)) {
|
||||
return true;
|
||||
}
|
||||
// Usually set by the user.
|
||||
const QSizePolicy sizePolicy = widget->sizePolicy();
|
||||
if ((sizePolicy.horizontalPolicy() == QSizePolicy::Fixed)
|
||||
&& (sizePolicy.verticalPolicy() == QSizePolicy::Fixed)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void forceWidgetRepaint(QWidget * const widget)
|
||||
{
|
||||
Q_ASSERT(widget);
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
// Tell the widget to repaint itself, but it may not happen due to QWidget's
|
||||
// internal painting optimizations.
|
||||
widget->update();
|
||||
// Try to force the widget to repaint itself, in case:
|
||||
// (1) It's a child widget;
|
||||
// (2) It's a top level window but not minimized/maximized/fullscreen.
|
||||
if (!widget->isWindow() || !(widget->windowState() & (Qt::WindowMinimized | Qt::WindowMaximized | Qt::WindowFullScreen))) {
|
||||
// A widget will most likely repaint itself if it's size is changed.
|
||||
if (!isWidgetFixedSize(widget)) {
|
||||
const QSize originalSize = widget->size();
|
||||
static constexpr const auto margins = QMargins{10, 10, 10, 10};
|
||||
widget->resize(originalSize.shrunkBy(margins));
|
||||
widget->resize(originalSize.grownBy(margins));
|
||||
widget->resize(originalSize);
|
||||
}
|
||||
// However, some widgets won't repaint themselves unless their position is changed.
|
||||
const QPoint originalPosition = widget->pos();
|
||||
static constexpr const auto offset = QPoint{10, 10};
|
||||
widget->move(originalPosition - offset);
|
||||
widget->move(originalPosition + offset);
|
||||
widget->move(originalPosition);
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
// There's some additional things to do for top level windows on Windows.
|
||||
if (widget->isWindow()) {
|
||||
// Don't crash if the QWindow instance has not been created yet.
|
||||
if (QWindow * const window = widget->windowHandle()) {
|
||||
// Sync the internal window frame margins with the latest DPI, otherwise
|
||||
// we will get wrong window sizes after the DPI change.
|
||||
Utils::updateInternalWindowFrameMargins(window, true);
|
||||
}
|
||||
}
|
||||
#endif // Q_OS_WINDOWS
|
||||
// Let's try again with the ordinary way.
|
||||
widget->update();
|
||||
// ### TODO: I observed the font size is often wrong after DPI changes,
|
||||
// do we need to refresh the font settings here as well?
|
||||
}
|
||||
|
||||
FramelessWidgetsHelperPrivate::FramelessWidgetsHelperPrivate(FramelessWidgetsHelper *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
|
@ -126,18 +194,7 @@ bool FramelessWidgetsHelperPrivate::isWindowFixedSize() const
|
|||
if (!m_window) {
|
||||
return false;
|
||||
}
|
||||
if (m_window->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) {
|
||||
return true;
|
||||
}
|
||||
const QSize minSize = m_window->minimumSize();
|
||||
const QSize maxSize = m_window->maximumSize();
|
||||
if (!minSize.isEmpty() && !maxSize.isEmpty() && (minSize == maxSize)) {
|
||||
return true;
|
||||
}
|
||||
if (m_window->sizePolicy() == QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return isWidgetFixedSize(m_window);
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelperPrivate::setWindowFixedSize(const bool value)
|
||||
|
@ -149,8 +206,11 @@ void FramelessWidgetsHelperPrivate::setWindowFixedSize(const bool value)
|
|||
return;
|
||||
}
|
||||
if (value) {
|
||||
m_savedSizePolicy = m_window->sizePolicy();
|
||||
m_window->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_window->setFixedSize(m_window->size());
|
||||
} else {
|
||||
m_window->setSizePolicy(m_savedSizePolicy);
|
||||
m_window->setMinimumSize(kDefaultWindowSize);
|
||||
m_window->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
|
||||
}
|
||||
|
@ -345,6 +405,28 @@ void FramelessWidgetsHelperPrivate::waitForReady()
|
|||
#endif
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelperPrivate::repaintAllChildren(const int delay) const
|
||||
{
|
||||
if (!m_window) {
|
||||
return;
|
||||
}
|
||||
const auto update = [this]() -> void {
|
||||
forceWidgetRepaint(m_window);
|
||||
const QList<QWidget *> widgets = m_window->findChildren<QWidget *>();
|
||||
if (widgets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (auto &&widget : std::as_const(widgets)) {
|
||||
forceWidgetRepaint(widget);
|
||||
}
|
||||
};
|
||||
if (delay > 0) {
|
||||
QTimer::singleShot(delay, this, update);
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelperPrivate::isContentExtendedIntoTitleBar() const
|
||||
{
|
||||
return getWindowData().ready;
|
||||
|
@ -356,7 +438,6 @@ void FramelessWidgetsHelperPrivate::setTitleBarWidget(QWidget *widget)
|
|||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
WidgetsHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
|
@ -379,7 +460,6 @@ void FramelessWidgetsHelperPrivate::setHitTestVisible(QWidget *widget, const boo
|
|||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
WidgetsHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
|
@ -399,7 +479,6 @@ void FramelessWidgetsHelperPrivate::setHitTestVisible(const QRect &rect, const b
|
|||
if (!rect.isValid()) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
WidgetsHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
|
@ -446,13 +525,10 @@ void FramelessWidgetsHelperPrivate::attach()
|
|||
window->setAttribute(Qt::WA_NativeWindow);
|
||||
}
|
||||
|
||||
g_widgetsHelper()->mutex.lock();
|
||||
WidgetsHelperData * const data = getWindowDataMutable();
|
||||
if (!data || data->ready) {
|
||||
g_widgetsHelper()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
g_widgetsHelper()->mutex.unlock();
|
||||
|
||||
SystemParameters params = {};
|
||||
params.getWindowId = [window]() -> WId { return window->winId(); };
|
||||
|
@ -487,13 +563,12 @@ void FramelessWidgetsHelperPrivate::attach()
|
|||
params.setCursor = [window](const QCursor &cursor) -> void { window->setCursor(cursor); };
|
||||
params.unsetCursor = [window]() -> void { window->unsetCursor(); };
|
||||
params.getWidgetHandle = [window]() -> QObject * { return window; };
|
||||
params.forceChildrenRepaint = [this](const int delay) -> void { repaintAllChildren(delay); };
|
||||
|
||||
FramelessManager::instance()->addWindow(¶ms);
|
||||
|
||||
g_widgetsHelper()->mutex.lock();
|
||||
data->params = params;
|
||||
data->ready = true;
|
||||
g_widgetsHelper()->mutex.unlock();
|
||||
|
||||
// We have to wait for a little time before moving the top level window
|
||||
// , because the platform window may not finish initializing by the time
|
||||
|
@ -519,7 +594,6 @@ void FramelessWidgetsHelperPrivate::detach()
|
|||
return;
|
||||
}
|
||||
const WId windowId = m_window->winId();
|
||||
const QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
if (!g_widgetsHelper()->data.contains(windowId)) {
|
||||
return;
|
||||
}
|
||||
|
@ -564,7 +638,6 @@ WidgetsHelperData FramelessWidgetsHelperPrivate::getWindowData() const
|
|||
return {};
|
||||
}
|
||||
const WId windowId = m_window->winId();
|
||||
const QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
if (!g_widgetsHelper()->data.contains(windowId)) {
|
||||
g_widgetsHelper()->data.insert(windowId, {});
|
||||
}
|
||||
|
@ -716,8 +789,6 @@ void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType
|
|||
const WidgetsHelperData data = getWindowData();
|
||||
QWidget *widgetButton = nullptr;
|
||||
switch (button) {
|
||||
case SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(void(0));
|
||||
case SystemButtonType::WindowIcon:
|
||||
if (data.windowIconButton) {
|
||||
widgetButton = data.windowIconButton;
|
||||
|
@ -744,15 +815,19 @@ void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType
|
|||
widgetButton = data.closeButton;
|
||||
}
|
||||
break;
|
||||
case SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(void(0));
|
||||
}
|
||||
if (!widgetButton) {
|
||||
return;
|
||||
}
|
||||
if (widgetButton) {
|
||||
const auto updateButtonState = [state](QWidget *btn) -> void {
|
||||
Q_ASSERT(btn);
|
||||
if (!btn) {
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case ButtonState::Unspecified: {
|
||||
case ButtonState::Normal: {
|
||||
QMetaObject::invokeMethod(btn, "setPressed", Q_ARG(bool, false));
|
||||
QMetaObject::invokeMethod(btn, "setHovered", Q_ARG(bool, false));
|
||||
} break;
|
||||
|
@ -764,7 +839,7 @@ void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType
|
|||
QMetaObject::invokeMethod(btn, "setHovered", Q_ARG(bool, true));
|
||||
QMetaObject::invokeMethod(btn, "setPressed", Q_ARG(bool, true));
|
||||
} break;
|
||||
case ButtonState::Clicked: {
|
||||
case ButtonState::Released: {
|
||||
// Clicked: pressed --> released, so behave like hovered.
|
||||
QMetaObject::invokeMethod(btn, "setPressed", Q_ARG(bool, false));
|
||||
QMetaObject::invokeMethod(btn, "setHovered", Q_ARG(bool, true));
|
||||
|
@ -781,7 +856,6 @@ void FramelessWidgetsHelperPrivate::setSystemButtonState(const SystemButtonType
|
|||
updateButtonState(widgetButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessWidgetsHelperPrivate::moveWindowToDesktopCenter()
|
||||
|
@ -856,14 +930,11 @@ void FramelessWidgetsHelperPrivate::setSystemButton(QWidget *widget, const Syste
|
|||
if (!widget || (buttonType == SystemButtonType::Unknown)) {
|
||||
return;
|
||||
}
|
||||
const QMutexLocker locker(&g_widgetsHelper()->mutex);
|
||||
WidgetsHelperData *data = getWindowDataMutable();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
switch (buttonType) {
|
||||
case SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(void(0));
|
||||
case SystemButtonType::WindowIcon:
|
||||
data->windowIconButton = widget;
|
||||
break;
|
||||
|
@ -880,6 +951,8 @@ void FramelessWidgetsHelperPrivate::setSystemButton(QWidget *widget, const Syste
|
|||
case SystemButtonType::Close:
|
||||
data->closeButton = widget;
|
||||
break;
|
||||
case SystemButtonType::Unknown:
|
||||
Q_UNREACHABLE_RETURN(void(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -173,9 +173,7 @@ bool WidgetsSharedHelper::eventFilter(QObject *object, QEvent *event)
|
|||
break;
|
||||
case QEvent::Move:
|
||||
case QEvent::Resize:
|
||||
if (m_micaEnabled) {
|
||||
m_targetWidget->update();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -189,7 +187,8 @@ void WidgetsSharedHelper::repaintMica()
|
|||
return;
|
||||
}
|
||||
QPainter painter(m_targetWidget);
|
||||
m_micaMaterial->paint(&painter, m_targetWidget->size(), m_targetWidget->mapToGlobal(QPoint(0, 0)));
|
||||
m_micaMaterial->paint(&painter, m_targetWidget->size(),
|
||||
m_targetWidget->mapToGlobal(QPoint(0, 0)), m_targetWidget->isActiveWindow());
|
||||
}
|
||||
|
||||
void WidgetsSharedHelper::repaintBorder()
|
||||
|
|
Loading…
Reference in New Issue