chore: baseline usable version
55
.gitignore
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# 构建目录 (最重要的!)
|
||||||
|
/build/
|
||||||
|
/build*/
|
||||||
|
*.user
|
||||||
|
|
||||||
|
# C++ 编译产物
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.ilk
|
||||||
|
*.pdb
|
||||||
|
*.suo
|
||||||
|
|
||||||
|
# 库文件
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# MOC 和 UI 生成的文件
|
||||||
|
moc_*.cpp
|
||||||
|
ui_*.h
|
||||||
|
qrc_*.cpp
|
||||||
|
|
||||||
|
# 本地 IDE 设置
|
||||||
|
.DS_Store
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# clangd 缓存
|
||||||
|
.cache/
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
|
# 预编译第三方库 (请参阅 README 中的构建说明)
|
||||||
|
libs/libmpv/
|
||||||
|
|
||||||
|
# Release 构建产物
|
||||||
|
*.zip
|
||||||
|
|
||||||
|
# AI 辅助工具
|
||||||
|
.antigravityignore
|
||||||
|
.antigravityrules
|
||||||
|
.gemini/
|
||||||
|
.agents/
|
||||||
|
_agents/
|
||||||
|
# <20><><EFBFBD>Ӳݸ<D3B2>
|
||||||
|
linuxdo_post.md
|
||||||
|
|
||||||
|
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
dist/
|
||||||
|
release/
|
||||||
|
build/
|
||||||
|
.idea
|
||||||
|
cmake-build-debug/
|
||||||
|
packaging/
|
||||||
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "libs/qwindowkit"]
|
||||||
|
path = libs/qwindowkit
|
||||||
|
url = https://github.com/stdware/qwindowkit.git
|
||||||
114
CMakeLists.txt
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
project(qEmby VERSION 0.0.5 LANGUAGES CXX)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 13.0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(QEmbyPlatformDeps)
|
||||||
|
|
||||||
|
set(QEMBY_RUNTIME_LIB_SUBDIR "qemby" CACHE STRING
|
||||||
|
"Subdirectory under the install libdir for bundled private runtime libraries")
|
||||||
|
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_options(/MP)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 允许通过缓存变量或环境变量提供 Qt 安装路径
|
||||||
|
# Windows 未显式指定时仍会尝试兼容现有本地默认路径
|
||||||
|
# ==========================================
|
||||||
|
set(QEMBY_QT_ROOT "" CACHE PATH
|
||||||
|
"Optional Qt installation root or CMake prefix path")
|
||||||
|
qemby_append_default_qt_prefixes()
|
||||||
|
|
||||||
|
# 寻找 Qt6 (不再允许降级)
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Widgets Core Network Concurrent OpenGLWidgets LinguistTools WebSockets Svg)
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
find_package(Qt6 QUIET COMPONENTS DBus)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 【关键修复】: 为第三方子模块 (qwindowkit/qmsetup) 注入所需的 Qt 版本环境变量
|
||||||
|
# ==========================================
|
||||||
|
set(QT_VERSION_MAJOR ${Qt6_VERSION_MAJOR})
|
||||||
|
set(QT_VERSION_MINOR ${Qt6_VERSION_MINOR})
|
||||||
|
set(QT_VERSION ${Qt6_VERSION})
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 引入 QCoro (C++20 Coroutines for Qt)
|
||||||
|
# ==========================================
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
function(qemby_ensure_noop_install_script build_dir)
|
||||||
|
if(NOT build_dir)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${build_dir}")
|
||||||
|
file(WRITE "${build_dir}/cmake_install.cmake"
|
||||||
|
"# qEmby placeholder install script for third-party dependency\n")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
set(_qemby_saved_skip_install_rules ${CMAKE_SKIP_INSTALL_RULES})
|
||||||
|
set(CMAKE_SKIP_INSTALL_RULES ON)
|
||||||
|
FetchContent_Declare(
|
||||||
|
QCoro
|
||||||
|
GIT_REPOSITORY https://github.com/danvratil/qcoro.git
|
||||||
|
GIT_TAG v0.10.0
|
||||||
|
)
|
||||||
|
|
||||||
|
# 强制 QCoro 使用 Qt6 进行编译,并关闭不必要的测试与示例构建以加快编译速度
|
||||||
|
set(QCORO_QT_MAJOR_VERSION 6 CACHE STRING "Use Qt6 for QCoro" FORCE)
|
||||||
|
set(QCORO_BUILD_EXAMPLES OFF CACHE BOOL "Disable QCoro examples" FORCE)
|
||||||
|
set(QCORO_WITH_QML OFF CACHE BOOL "Disable QCoro QML module" FORCE)
|
||||||
|
set(QCORO_WITH_QTQUICK OFF CACHE BOOL "Disable QCoro QtQuick module" FORCE)
|
||||||
|
set(BUILD_TESTING OFF CACHE BOOL "Disable QCoro tests" FORCE)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(QCoro)
|
||||||
|
FetchContent_GetProperties(QCoro)
|
||||||
|
qemby_ensure_noop_install_script("${qcoro_BINARY_DIR}")
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 引入 spdlog (高性能线程安全日志库, MIT License)
|
||||||
|
# ==========================================
|
||||||
|
FetchContent_Declare(
|
||||||
|
spdlog
|
||||||
|
GIT_REPOSITORY https://github.com/gabime/spdlog.git
|
||||||
|
GIT_TAG v1.15.3
|
||||||
|
)
|
||||||
|
set(SPDLOG_BUILD_EXAMPLE OFF CACHE BOOL "Disable spdlog examples" FORCE)
|
||||||
|
set(SPDLOG_BUILD_TESTS OFF CACHE BOOL "Disable spdlog tests" FORCE)
|
||||||
|
set(SPDLOG_INSTALL OFF CACHE BOOL "Disable spdlog install rules" FORCE)
|
||||||
|
FetchContent_MakeAvailable(spdlog)
|
||||||
|
FetchContent_GetProperties(spdlog)
|
||||||
|
qemby_ensure_noop_install_script("${spdlog_BINARY_DIR}")
|
||||||
|
set(CMAKE_SKIP_INSTALL_RULES ${_qemby_saved_skip_install_rules})
|
||||||
|
unset(_qemby_saved_skip_install_rules)
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
set(QWINDOWKIT_INSTALL OFF CACHE BOOL
|
||||||
|
"Disable QWindowKit development install rules inside qEmby" FORCE)
|
||||||
|
|
||||||
|
add_subdirectory(libs/qwindowkit)
|
||||||
|
add_subdirectory(libs/qwindowkit/examples/shared)
|
||||||
|
add_subdirectory(src/qEmbyCore)
|
||||||
|
add_subdirectory(src/qEmbyApp)
|
||||||
|
|
||||||
|
include(QEmbyPackaging)
|
||||||
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025-2026 AlanHJ
|
||||||
|
|
||||||
|
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.
|
||||||
376
README.md
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img src="src/qEmbyApp/resources/svg/qemby_logo.svg" width="120" alt="qEmby Logo"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h1 align="center">qEmby</h1>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<b>A modern desktop client for Emby & Jellyfin media servers</b><br/>
|
||||||
|
<b>Emby & Jellyfin 媒体服务器的现代桌面客户端</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"/></a>
|
||||||
|
<a href="https://github.com/AlanHJ/qEmby/releases/latest"><img src="https://img.shields.io/github/v/release/AlanHJ/qEmby?include_prereleases&label=Download" alt="Release"/></a>
|
||||||
|
<img src="https://img.shields.io/badge/Qt-6.x-green.svg" alt="Qt 6"/>
|
||||||
|
<img src="https://img.shields.io/badge/C%2B%2B-20-orange.svg" alt="C++20"/>
|
||||||
|
<img src="https://img.shields.io/badge/Platform-Windows%20|%20Linux%20|%20macOS-lightgrey.svg" alt="Platform: Windows | Linux | macOS"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="#中文">中文</a> | <a href="#english">English</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="中文"></a>
|
||||||
|
|
||||||
|
## 📸 应用截图
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="screenshots/2.png" width="45%" alt="首页"/>
|
||||||
|
<img src="screenshots/5.png" width="45%" alt="影片详情"/>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<img src="screenshots/3.png" width="45%" alt="设置"/>
|
||||||
|
<img src="screenshots/4.png" width="45%" alt="管理仪表盘"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## 📥 下载
|
||||||
|
|
||||||
|
最新版本:**v0.0.5**
|
||||||
|
|
||||||
|
| 安装包 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| [qEmby-v0.0.5-Win-x64-Setup.exe](https://github.com/AlanHJ/qEmby/releases/download/v0.0.5/qEmby-v0.0.5-Win-x64-Setup.exe) | Windows 10/11 x64 安装包 |
|
||||||
|
| [qEmby-v0.0.5-Win-x64.zip](https://github.com/AlanHJ/qEmby/releases/download/v0.0.5/qEmby-v0.0.5-Win-x64.zip) | Windows 10/11 x64 绿色便携版 |
|
||||||
|
| [qemby-0.0.5-macos-arm64.dmg](https://github.com/AlanHJ/qEmby/releases/download/v0.0.5/qemby-0.0.5-macos-arm64.dmg) | macOS 26+ (Apple 芯片) |
|
||||||
|
|
||||||
|
旧版 Windows、Linux 和 macOS 构建可以在 [Releases](https://github.com/AlanHJ/qEmby/releases) 页面下载。
|
||||||
|
|
||||||
|
## 🚀 v0.0.5 更新内容
|
||||||
|
|
||||||
|
- 优化了剧集详情页展示,支持版本切换。
|
||||||
|
- 支持播放状态展示和切换。
|
||||||
|
- 增加了详情页的缓存,加快下一次载入速度。
|
||||||
|
- 优化了播放界面 OSD,支持上一集和下一集,支持连续播放。
|
||||||
|
- 优化了媒体库等上下滑动的流畅度,优化了加载图片的逻辑。
|
||||||
|
- 新增播放完成画廊,默认关闭,可以在设置中打开。
|
||||||
|
|
||||||
|
## ✨ 功能特性
|
||||||
|
|
||||||
|
- 🎬 浏览和管理你的 Emby / Jellyfin 媒体库
|
||||||
|
- ▶️ 内置 **libmpv** 驱动的视频播放器
|
||||||
|
- 💬 弹幕播放,支持搜索、匹配、缓存和原生覆盖层渲染
|
||||||
|
- 🧩 支持元数据编辑、媒体识别、图片更新和播放列表管理
|
||||||
|
- 📥 下载管理器
|
||||||
|
- 🌗 深色 / 浅色主题切换
|
||||||
|
- 🌐 国际化支持(中文 / 英文 / 法语)
|
||||||
|
- 🔍 支持搜索历史的媒体搜索
|
||||||
|
- 📺 当前支持电视剧、电影媒体类型
|
||||||
|
- 📦 提供 Windows 安装包 / 绿色版,以及 Linux AppImage / deb 包
|
||||||
|
- ⚡ 基于 C++20 协程的异步操作(QCoro)
|
||||||
|
- 🪟 原生风格的自定义窗口边框(QWindowKit)
|
||||||
|
|
||||||
|
## 💻 平台支持
|
||||||
|
|
||||||
|
| 平台 | 状态 |
|
||||||
|
|---|---|
|
||||||
|
| Windows 10/11 x64 | ✅ 已适配 |
|
||||||
|
| Linux x64 (AppImage / deb) | ✅ 已适配 |
|
||||||
|
| macOS 26+ (Apple Silicon) | ✅ 已适配 |
|
||||||
|
|
||||||
|
## 📋 开发路线图
|
||||||
|
|
||||||
|
- [x] Emby / Jellyfin 媒体库浏览
|
||||||
|
- [x] 内置视频播放器(libmpv)
|
||||||
|
- [x] 深色 / 浅色主题
|
||||||
|
- [x] 国际化支持(中文 / 英文)
|
||||||
|
- [x] 媒体搜索与搜索历史
|
||||||
|
- [x] 电视剧、电影支持
|
||||||
|
- [x] 服务器管理仪表盘
|
||||||
|
- [x] 支持添加到播放列表和从播放列表中移除
|
||||||
|
- [x] 支持识别来更新元数据
|
||||||
|
- [x] 支持修改元数据和图片
|
||||||
|
- [x] 弹幕系统(搜索、匹配、设置、渲染)
|
||||||
|
- [x] 下载管理器
|
||||||
|
- [ ] AI 字幕生成
|
||||||
|
- [x] Linux 平台适配
|
||||||
|
- [x] macOS 平台适配
|
||||||
|
|
||||||
|
> 本项目为个人兴趣开发,欢迎贡献和反馈!
|
||||||
|
|
||||||
|
## 🛠️ 技术栈
|
||||||
|
|
||||||
|
| 组件 | 技术 |
|
||||||
|
|---|---|
|
||||||
|
| 框架 | Qt 6.x (Widgets) |
|
||||||
|
| 语言 | C++20 |
|
||||||
|
| 视频播放 | libmpv |
|
||||||
|
| 异步 | QCoro (Qt C++20 协程) |
|
||||||
|
| 日志 | spdlog |
|
||||||
|
| 窗口框架 | QWindowKit |
|
||||||
|
| 构建系统 | CMake |
|
||||||
|
|
||||||
|
## 📦 环境要求
|
||||||
|
|
||||||
|
- **Qt 6.x**(包含 Widgets、Core、Network、Concurrent、OpenGLWidgets、LinguistTools、WebSockets 模块)
|
||||||
|
- **CMake** ≥ 3.16
|
||||||
|
- 支持 **C++20** 的编译器(推荐 MSVC 2022)
|
||||||
|
- **libmpv** 开发文件(见下方说明)
|
||||||
|
- **Git**(用于克隆子模块)
|
||||||
|
|
||||||
|
## 🚀 构建指南
|
||||||
|
|
||||||
|
### 1. 克隆仓库
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recursive https://github.com/AlanHJ/qEmby.git
|
||||||
|
cd qEmby
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 获取 libmpv
|
||||||
|
|
||||||
|
下载 libmpv 开发包,并放置到 `libs/libmpv/` 目录下,结构如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
libs/libmpv/
|
||||||
|
├── bin/
|
||||||
|
│ └── libmpv-2.dll
|
||||||
|
├── include/
|
||||||
|
│ └── mpv/
|
||||||
|
│ ├── client.h
|
||||||
|
│ └── render.h (等)
|
||||||
|
└── lib/
|
||||||
|
└── libmpv.dll.a
|
||||||
|
```
|
||||||
|
|
||||||
|
libmpv 获取方式:
|
||||||
|
- [shinchiro/mpv-winbuild-cmake](https://github.com/shinchiro/mpv-winbuild-cmake/releases)(Windows 预编译版本)
|
||||||
|
- [mpv-player/mpv](https://github.com/mpv-player/mpv)(从源码编译)
|
||||||
|
|
||||||
|
### 3. 配置和构建
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -DCMAKE_PREFIX_PATH="/path/to/Qt6/lib/cmake"
|
||||||
|
cmake --build build --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
> **提示:** 在 Windows 上使用 MSVC 时,也可以直接在 Qt Creator 或 Visual Studio 中打开 CMake 项目。
|
||||||
|
|
||||||
|
## 📁 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
qEmby/
|
||||||
|
├── CMakeLists.txt # 根 CMake 配置
|
||||||
|
├── libs/
|
||||||
|
│ ├── libmpv/ # libmpv SDK(未纳入版本控制,见构建指南)
|
||||||
|
│ └── qwindowkit/ # QWindowKit(git 子模块)
|
||||||
|
└── src/
|
||||||
|
├── qEmbyCore/ # 核心库(API、模型、服务)
|
||||||
|
│ ├── api/ # Emby/Jellyfin API 客户端
|
||||||
|
│ ├── config/ # 配置管理
|
||||||
|
│ ├── models/ # 数据模型
|
||||||
|
│ └── services/ # 业务逻辑服务
|
||||||
|
└── qEmbyApp/ # 桌面应用
|
||||||
|
├── components/ # 可复用 UI 组件
|
||||||
|
├── managers/ # 应用管理器
|
||||||
|
├── resources/ # 图标、主题、翻译
|
||||||
|
├── utils/ # 工具类
|
||||||
|
└── views/ # 应用视图
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💬 交流社区
|
||||||
|
|
||||||
|
加入 Telegram 交流群:[https://t.me/+qXQ-zU56z9gxOWNl](https://t.me/+qXQ-zU56z9gxOWNl)
|
||||||
|
|
||||||
|
> **注意:** 本项目是为爱发电项目,测试覆盖不全,敬请谅解。如有问题请通过 [GitHub Issues](https://github.com/AlanHJ/qEmby/issues) 反馈。
|
||||||
|
|
||||||
|
## 📄 许可证
|
||||||
|
|
||||||
|
本项目基于 [MIT 许可证](LICENSE) 开源。
|
||||||
|
|
||||||
|
## 🙏 致谢
|
||||||
|
|
||||||
|
- [Qt](https://www.qt.io/) — 应用框架 (LGPL v3)
|
||||||
|
- [mpv](https://mpv.io/) — 媒体播放引擎 (LGPL v2.1+)
|
||||||
|
- [QWindowKit](https://github.com/stdware/qwindowkit) — 自定义窗口框架 (Apache-2.0)
|
||||||
|
- [QCoro](https://github.com/danvratil/qcoro) — Qt C++20 协程库 (MIT)
|
||||||
|
- [spdlog](https://github.com/gabime/spdlog) — 高性能日志库 (MIT)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="english"></a>
|
||||||
|
|
||||||
|
## 📸 Screenshots
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="screenshots/2.png" width="45%" alt="Home"/>
|
||||||
|
<img src="screenshots/5.png" width="45%" alt="Detail"/>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<img src="screenshots/3.png" width="45%" alt="Settings"/>
|
||||||
|
<img src="screenshots/4.png" width="45%" alt="Admin Dashboard"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## 📥 Download
|
||||||
|
|
||||||
|
Latest release: **v0.0.5**
|
||||||
|
|
||||||
|
| Package | Description |
|
||||||
|
|---|---|
|
||||||
|
| [qEmby-v0.0.5-Win-x64-Setup.exe](https://github.com/AlanHJ/qEmby/releases/download/v0.0.5/qEmby-v0.0.5-Win-x64-Setup.exe) | Windows 10/11 x64 installer |
|
||||||
|
| [qEmby-v0.0.5-Win-x64.zip](https://github.com/AlanHJ/qEmby/releases/download/v0.0.5/qEmby-v0.0.5-Win-x64.zip) | Windows 10/11 x64 portable package |
|
||||||
|
| [qemby-0.0.5-macos-arm64.dmg](https://github.com/AlanHJ/qEmby/releases/download/v0.0.5/qemby-0.0.5-macos-arm64.dmg) | macOS 26+ (Apple Silicon) |
|
||||||
|
|
||||||
|
Older Windows, Linux and macOS builds are available on the [Releases](https://github.com/AlanHJ/qEmby/releases) page.
|
||||||
|
|
||||||
|
## 🚀 What's New in v0.0.5
|
||||||
|
|
||||||
|
- Optimized episode detail page display with version switching support.
|
||||||
|
- Added playback status display and switching.
|
||||||
|
- Added detail page caching for faster subsequent loading.
|
||||||
|
- Enhanced player OSD with previous/next episode and continuous playback.
|
||||||
|
- Improved scrolling smoothness in media library views and optimized image loading logic.
|
||||||
|
- Added post-playback gallery (disabled by default, configurable in settings).
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- 🎬 Browse and manage your Emby / Jellyfin media library
|
||||||
|
- ▶️ Built-in video player powered by **libmpv**
|
||||||
|
- 💬 Danmaku playback with search, matching, cache and native overlay rendering
|
||||||
|
- 🧩 Metadata editing, media identification, image updates and playlist tools
|
||||||
|
- 📥 Download manager
|
||||||
|
- 🌗 Dark and Light theme support
|
||||||
|
- 🌐 Internationalization support (Chinese / English)
|
||||||
|
- 🔍 Media search with history
|
||||||
|
- 📺 TV series and movies media types
|
||||||
|
- 📦 Windows installer / portable packages and Linux AppImage / deb packages
|
||||||
|
- ⚡ Asynchronous operations with C++20 coroutines (QCoro)
|
||||||
|
- 🪟 Custom window frame with native look (QWindowKit)
|
||||||
|
|
||||||
|
## 💻 Platform Support
|
||||||
|
|
||||||
|
| Platform | Status |
|
||||||
|
|---|---|
|
||||||
|
| Windows 10/11 x64 | ✅ Supported |
|
||||||
|
| Linux x64 (AppImage / deb) | ✅ Supported |
|
||||||
|
| macOS 26+ (Apple Silicon) | ✅ Supported |
|
||||||
|
|
||||||
|
## 📋 Roadmap
|
||||||
|
|
||||||
|
- [x] Emby / Jellyfin media library browsing
|
||||||
|
- [x] Built-in video player (libmpv)
|
||||||
|
- [x] Dark / Light theme
|
||||||
|
- [x] Internationalization (Chinese / English)
|
||||||
|
- [x] Media search with history
|
||||||
|
- [x] TV series & movies support
|
||||||
|
- [x] Server administration dashboard
|
||||||
|
- [x] Playlist support (add/remove items)
|
||||||
|
- [x] Media identification & metadata refresh
|
||||||
|
- [x] Metadata and image editing
|
||||||
|
- [x] Danmaku (bullet comments) system
|
||||||
|
- [x] Download manager
|
||||||
|
- [ ] AI-powered subtitle generation
|
||||||
|
- [x] Linux platform support
|
||||||
|
- [x] macOS platform support
|
||||||
|
|
||||||
|
> This is a personal hobby project, developed out of interest. Contributions and feedback are welcome!
|
||||||
|
|
||||||
|
## 🛠️ Tech Stack
|
||||||
|
|
||||||
|
| Component | Technology |
|
||||||
|
|---|---|
|
||||||
|
| Framework | Qt 6.x (Widgets) |
|
||||||
|
| Language | C++20 |
|
||||||
|
| Video Player | libmpv |
|
||||||
|
| Async | QCoro (C++20 Coroutines for Qt) |
|
||||||
|
| Logging | spdlog |
|
||||||
|
| Window Kit | QWindowKit |
|
||||||
|
| Build System | CMake |
|
||||||
|
|
||||||
|
## 📦 Prerequisites
|
||||||
|
|
||||||
|
- **Qt 6.x** (with Widgets, Core, Network, Concurrent, OpenGLWidgets, LinguistTools, WebSockets)
|
||||||
|
- **CMake** ≥ 3.16
|
||||||
|
- **C++20** compatible compiler (MSVC 2022 recommended)
|
||||||
|
- **libmpv** development files (see below)
|
||||||
|
- **Git** (for cloning submodules)
|
||||||
|
|
||||||
|
## 🚀 Build
|
||||||
|
|
||||||
|
### 1. Clone the repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recursive https://github.com/AlanHJ/qEmby.git
|
||||||
|
cd qEmby
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Get libmpv
|
||||||
|
|
||||||
|
Download the libmpv development package and place it in `libs/libmpv/` with the following structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
libs/libmpv/
|
||||||
|
├── bin/
|
||||||
|
│ └── libmpv-2.dll
|
||||||
|
├── include/
|
||||||
|
│ └── mpv/
|
||||||
|
│ ├── client.h
|
||||||
|
│ └── render.h (etc.)
|
||||||
|
└── lib/
|
||||||
|
└── libmpv.dll.a
|
||||||
|
```
|
||||||
|
|
||||||
|
You can get libmpv from:
|
||||||
|
- [shinchiro/mpv-winbuild-cmake](https://github.com/shinchiro/mpv-winbuild-cmake/releases) (Windows builds)
|
||||||
|
- [mpv-player/mpv](https://github.com/mpv-player/mpv) (build from source)
|
||||||
|
|
||||||
|
### 3. Configure and build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -DCMAKE_PREFIX_PATH="/path/to/Qt6/lib/cmake"
|
||||||
|
cmake --build build --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Tip:** On Windows with MSVC, you can also open the project in Qt Creator or Visual Studio with CMake support.
|
||||||
|
|
||||||
|
## 📁 Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
qEmby/
|
||||||
|
├── CMakeLists.txt # Root CMake configuration
|
||||||
|
├── libs/
|
||||||
|
│ ├── libmpv/ # libmpv SDK (not tracked, see Build section)
|
||||||
|
│ └── qwindowkit/ # QWindowKit (git submodule)
|
||||||
|
└── src/
|
||||||
|
├── qEmbyCore/ # Core library (API, models, services)
|
||||||
|
│ ├── api/ # Emby/Jellyfin API client
|
||||||
|
│ ├── config/ # Configuration management
|
||||||
|
│ ├── models/ # Data models
|
||||||
|
│ └── services/ # Business logic services
|
||||||
|
└── qEmbyApp/ # Desktop application
|
||||||
|
├── components/ # Reusable UI components
|
||||||
|
├── managers/ # Application managers
|
||||||
|
├── resources/ # Icons, themes, translations
|
||||||
|
├── utils/ # Utility classes
|
||||||
|
└── views/ # Application views
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💬 Community
|
||||||
|
|
||||||
|
Join our Telegram group: [https://t.me/+qXQ-zU56z9gxOWNl](https://t.me/+qXQ-zU56z9gxOWNl)
|
||||||
|
|
||||||
|
> **Note:** This is a passion project with limited testing. Your understanding is appreciated. Please report any issues via [GitHub Issues](https://github.com/AlanHJ/qEmby/issues).
|
||||||
|
|
||||||
|
## 📄 License
|
||||||
|
|
||||||
|
This project is licensed under the [MIT License](LICENSE).
|
||||||
|
|
||||||
|
## 🙏 Acknowledgements
|
||||||
|
|
||||||
|
- [Qt](https://www.qt.io/) — Application framework (LGPL v3)
|
||||||
|
- [mpv](https://mpv.io/) — Media player engine (LGPL v2.1+)
|
||||||
|
- [QWindowKit](https://github.com/stdware/qwindowkit) — Custom window frame (Apache-2.0)
|
||||||
|
- [QCoro](https://github.com/danvratil/qcoro) — C++20 Coroutines for Qt (MIT)
|
||||||
|
- [spdlog](https://github.com/gabime/spdlog) — Fast logging library (MIT)
|
||||||
77
cmake/QEmbyPackaging.cmake
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
include_guard(GLOBAL)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(_qemby_runtime_install_dir "${CMAKE_INSTALL_BINDIR}")
|
||||||
|
if(QEMBY_RUNTIME_LIB_SUBDIR)
|
||||||
|
set(_qemby_runtime_install_dir
|
||||||
|
"${CMAKE_INSTALL_LIBDIR}/${QEMBY_RUNTIME_LIB_SUBDIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_qemby_runtime_target IN ITEMS qEmbyApp qEmbyCore QWKCore QWKWidgets)
|
||||||
|
if(TARGET "${_qemby_runtime_target}")
|
||||||
|
set_target_properties("${_qemby_runtime_target}" PROPERTIES
|
||||||
|
INSTALL_RPATH "$ORIGIN"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(_qemby_qwk_install_targets)
|
||||||
|
foreach(_qemby_qwk_target IN ITEMS QWKCore QWKWidgets)
|
||||||
|
if(TARGET "${_qemby_qwk_target}")
|
||||||
|
list(APPEND _qemby_qwk_install_targets "${_qemby_qwk_target}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(_qemby_qwk_install_targets)
|
||||||
|
install(TARGETS ${_qemby_qwk_install_targets}
|
||||||
|
LIBRARY DESTINATION "${_qemby_runtime_install_dir}"
|
||||||
|
RUNTIME DESTINATION "${_qemby_runtime_install_dir}"
|
||||||
|
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(QEMBY_RUNTIME_LIB_SUBDIR)
|
||||||
|
set(_qemby_launcher_exec
|
||||||
|
"${CMAKE_INSTALL_LIBDIR}/${QEMBY_RUNTIME_LIB_SUBDIR}/qEmbyApp")
|
||||||
|
else()
|
||||||
|
set(_qemby_launcher_exec "${CMAKE_INSTALL_BINDIR}/qEmbyApp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_qemby_launcher "${CMAKE_CURRENT_BINARY_DIR}/qemby")
|
||||||
|
file(WRITE "${_qemby_launcher}"
|
||||||
|
"#!/bin/sh\n"
|
||||||
|
"prefix_dir=$(CDPATH= cd -- \"$(dirname -- \"$0\")/..\" && pwd)\n"
|
||||||
|
"exec \"$prefix_dir/${_qemby_launcher_exec}\" \"$@\"\n"
|
||||||
|
)
|
||||||
|
install(PROGRAMS "${_qemby_launcher}"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_qemby_desktop_file "${CMAKE_CURRENT_BINARY_DIR}/qemby.desktop")
|
||||||
|
file(WRITE "${_qemby_desktop_file}"
|
||||||
|
"[Desktop Entry]\n"
|
||||||
|
"Type=Application\n"
|
||||||
|
"Name=qEmby\n"
|
||||||
|
"Comment=Desktop client for Emby and Jellyfin media servers\n"
|
||||||
|
"Exec=qemby\n"
|
||||||
|
"Icon=qemby\n"
|
||||||
|
"Terminal=false\n"
|
||||||
|
"Categories=AudioVideo;Video;Player;\n"
|
||||||
|
)
|
||||||
|
install(FILES "${_qemby_desktop_file}"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_DATADIR}/applications"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES "${CMAKE_SOURCE_DIR}/src/qEmbyApp/resources/svg/qemby_logo.svg"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps"
|
||||||
|
RENAME qemby.svg
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
|
||||||
|
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
|
||||||
|
set(CPACK_PACKAGE_VENDOR "qEmby")
|
||||||
|
|
||||||
|
include(CPack)
|
||||||
68
cmake/QEmbyPlatformDeps.cmake
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
include_guard(GLOBAL)
|
||||||
|
|
||||||
|
function(qemby_append_default_qt_prefixes)
|
||||||
|
set(_qemby_qt_prefixes)
|
||||||
|
|
||||||
|
if(QEMBY_QT_ROOT)
|
||||||
|
list(APPEND _qemby_qt_prefixes
|
||||||
|
"${QEMBY_QT_ROOT}"
|
||||||
|
"${QEMBY_QT_ROOT}/lib/cmake"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(DEFINED ENV{QTDIR} AND NOT "$ENV{QTDIR}" STREQUAL "")
|
||||||
|
list(APPEND _qemby_qt_prefixes
|
||||||
|
"$ENV{QTDIR}"
|
||||||
|
"$ENV{QTDIR}/lib/cmake"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND _qemby_qt_prefixes
|
||||||
|
"E:/Qt6/6.9.2/msvc2022_64"
|
||||||
|
"E:/Qt6/6.9.2/msvc2022_64/lib/cmake"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_qemby_qt_prefix IN LISTS _qemby_qt_prefixes)
|
||||||
|
if(EXISTS "${_qemby_qt_prefix}")
|
||||||
|
list(APPEND CMAKE_PREFIX_PATH "${_qemby_qt_prefix}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(CMAKE_PREFIX_PATH)
|
||||||
|
list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(qemby_link_libmpv target)
|
||||||
|
if(NOT TARGET "${target}")
|
||||||
|
message(FATAL_ERROR "qemby_link_libmpv: target '${target}' does not exist")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(_qemby_mpv_root "${CMAKE_SOURCE_DIR}/libs/libmpv")
|
||||||
|
set(_qemby_mpv_include_dir "${_qemby_mpv_root}/include")
|
||||||
|
|
||||||
|
find_library(MPV_LIBRARY
|
||||||
|
NAMES mpv libmpv mpv-2 libmpv-2
|
||||||
|
PATHS "${_qemby_mpv_root}/lib"
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT MPV_LIBRARY OR NOT EXISTS "${_qemby_mpv_include_dir}/mpv/client.h")
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Could not find bundled libmpv. Place the libmpv SDK under libs/libmpv.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories("${target}" PRIVATE "${_qemby_mpv_include_dir}")
|
||||||
|
target_link_libraries("${target}" PRIVATE "${MPV_LIBRARY}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(MPV REQUIRED IMPORTED_TARGET mpv)
|
||||||
|
target_link_libraries("${target}" PRIVATE PkgConfig::MPV)
|
||||||
|
endfunction()
|
||||||
191
docs/日志.md
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
PID: 175765 (qEmbyApp)
|
||||||
|
UID: 1000 (carry)
|
||||||
|
GID: 1000 (carry)
|
||||||
|
Signal: 11 (SEGV)
|
||||||
|
Timestamp: Tue 2026-06-02 23:11:06 CST (4s ago)
|
||||||
|
Command Line: /usr/lib/qemby/qEmbyApp
|
||||||
|
Executable: /usr/lib/qemby/qEmbyApp
|
||||||
|
Control Group: /user.slice/user-1000.slice/user@1000.service/app.slice/app-qemby@8ff009190f4e4b38bc41611225ac1527.service
|
||||||
|
Unit: user@1000.service
|
||||||
|
User Unit: app-qemby@8ff009190f4e4b38bc41611225ac1527.service
|
||||||
|
Slice: user-1000.slice
|
||||||
|
Owner UID: 1000 (carry)
|
||||||
|
Boot ID: 0f5ae2ec38e1407888fd6408682d668f
|
||||||
|
Machine ID: 6e2f5cc0492944268af4a0786b730302
|
||||||
|
Hostname: carryarch
|
||||||
|
Storage: /var/lib/systemd/coredump/core.qEmbyApp.1000.0f5ae2ec38e1407888fd6408682d668f.175765.1780413066000000.zst (present)
|
||||||
|
Size on Disk: 8.4M
|
||||||
|
Message: Process 175765 (qEmbyApp) of user 1000 dumped core.
|
||||||
|
|
||||||
|
Stack trace of thread 175765:
|
||||||
|
#0 0x00007efc0ffebe57 n/a (libcrypto.so.3 + 0x3ebe57)
|
||||||
|
#1 0x00007efc141f081b n/a (libQt6Core.so.6 + 0x1f081b)
|
||||||
|
#2 0x00007efc1556ce17 _ZN14QStackedWidget14currentChangedEi (libQt6Widgets.so.6 + 0x36ce17)
|
||||||
|
#3 0x00007efc141f081b n/a (libQt6Core.so.6 + 0x1f081b)
|
||||||
|
#4 0x00007efc15343551 _ZN14QStackedLayout15setCurrentIndexEi (libQt6Widgets.so.6 + 0x143551)
|
||||||
|
#5 0x0000555fe097dcef _ZN9QtPrivate15QCallableObjectIZZN10MainWindow14navigateToHomeEvENKUlvE_clEvEUlvE_NS_4ListIJEEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb (qEmbyApp + 0x266cef)
|
||||||
|
#6 0x00007efc141f081b n/a (libQt6Core.so.6 + 0x1f081b)
|
||||||
|
#7 0x00007efc143358c7 _ZN25QAbstractAnimationPrivate8setStateEN18QAbstractAnimation5StateE (libQt6Core.so.6 + 0x3358c7)
|
||||||
|
#8 0x00007efc14335e2b n/a (libQt6Core.so.6 + 0x335e2b)
|
||||||
|
#9 0x00007efc1432c9d1 _ZN13QUnifiedTimer21updateAnimationTimersEv (libQt6Core.so.6 + 0x32c9d1)
|
||||||
|
#10 0x00007efc14334ff5 n/a (libQt6Core.so.6 + 0x334ff5)
|
||||||
|
#11 0x00007efc141e7cf9 _ZN7QObject5eventEP6QEvent (libQt6Core.so.6 + 0x1e7cf9)
|
||||||
|
#12 0x00007efc1530411f _ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent (libQt6Widgets.so.6 + 0x10411f)
|
||||||
|
#13 0x00007efc14183658 _ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent (libQt6Core.so.6 + 0x183658)
|
||||||
|
#14 0x00007efc1436b2f5 _ZN14QTimerInfoList14activateTimersEv (libQt6Core.so.6 + 0x36b2f5)
|
||||||
|
#15 0x00007efc1449fc19 n/a (libQt6Core.so.6 + 0x49fc19)
|
||||||
|
#16 0x00007efc0faadbfd n/a (libglib-2.0.so.0 + 0x61bfd)
|
||||||
|
#17 0x00007efc0faafe57 n/a (libglib-2.0.so.0 + 0x63e57)
|
||||||
|
#18 0x00007efc0faaffe5 g_main_context_iteration (libglib-2.0.so.0 + 0x63fe5)
|
||||||
|
#19 0x00007efc1449d0b2 _ZN20QEventDispatcherGlib13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE (libQt6Core.so.6 + 0x49d0b2)
|
||||||
|
#20 0x00007efc14191983 _ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE (libQt6Core.so.6 + 0x191983)
|
||||||
|
#21 0x00007efc14186eaa _ZN16QCoreApplication4execEv (libQt6Core.so.6 + 0x186eaa)
|
||||||
|
#22 0x0000555fe07fa5d5 main (qEmbyApp + 0xe35d5)
|
||||||
|
#23 0x00007efc13827741 n/a (libc.so.6 + 0x27741)
|
||||||
|
#24 0x00007efc13827879 __libc_start_main (libc.so.6 + 0x27879)
|
||||||
|
#25 0x0000555fe07faaf5 _start (qEmbyApp + 0xe3af5)
|
||||||
|
|
||||||
|
Stack trace of thread 175777:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175774:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175773:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175772:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175790:
|
||||||
|
#0 0x00007efc1413f3c8 _ZNK9QIODevice12bytesToWriteEv (libQt6Core.so.6 + 0x13f3c8)
|
||||||
|
#1 0x00007efc15ac8063 _ZN22QAbstractSocketPrivate13writeToSocketEv (libQt6Network.so.6 + 0xc0063)
|
||||||
|
#2 0x00007efc141e7d46 _ZN7QObject5eventEP6QEvent (libQt6Core.so.6 + 0x1e7d46)
|
||||||
|
#3 0x00007efc1530411f _ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent (libQt6Widgets.so.6 + 0x10411f)
|
||||||
|
#4 0x00007efc14183658 _ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent (libQt6Core.so.6 + 0x183658)
|
||||||
|
#5 0x00007efc14183a61 _ZN23QCoreApplicationPrivate16sendPostedEventsEP7QObjectiP11QThreadData (libQt6Core.so.6 + 0x183a61)
|
||||||
|
#6 0x00007efc1449fc98 n/a (libQt6Core.so.6 + 0x49fc98)
|
||||||
|
#7 0x00007efc0faadbfd n/a (libglib-2.0.so.0 + 0x61bfd)
|
||||||
|
#8 0x00007efc0faafe57 n/a (libglib-2.0.so.0 + 0x63e57)
|
||||||
|
#9 0x00007efc0faaffe5 g_main_context_iteration (libglib-2.0.so.0 + 0x63fe5)
|
||||||
|
#10 0x00007efc1449d0b2 _ZN20QEventDispatcherGlib13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE (libQt6Core.so.6 + 0x49d0b2)
|
||||||
|
#11 0x00007efc14191983 _ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE (libQt6Core.so.6 + 0x191983)
|
||||||
|
#12 0x00007efc142b9342 _ZN7QThread4execEv (libQt6Core.so.6 + 0x2b9342)
|
||||||
|
#13 0x00007efc14378595 n/a (libQt6Core.so.6 + 0x378595)
|
||||||
|
#14 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#15 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175775:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175769:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894b04 n/a (libc.so.6 + 0x94b04)
|
||||||
|
#3 0x00007efc1390f9ce __poll (libc.so.6 + 0x10f9ce)
|
||||||
|
#4 0x00007efc01c5220b n/a (libxcb.so.1 + 0xd20b)
|
||||||
|
#5 0x00007efc01c53f3d xcb_wait_for_event (libxcb.so.1 + 0xef3d)
|
||||||
|
#6 0x00007efbfd2383d9 n/a (libQt6XcbQpa.so.6 + 0x563d9)
|
||||||
|
#7 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#8 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#9 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175788:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175768:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894b04 n/a (libc.so.6 + 0x94b04)
|
||||||
|
#3 0x00007efc1390fff6 ppoll (libc.so.6 + 0x10fff6)
|
||||||
|
#4 0x00007efc0faafedf n/a (libglib-2.0.so.0 + 0x63edf)
|
||||||
|
#5 0x00007efc0faaffe5 g_main_context_iteration (libglib-2.0.so.0 + 0x63fe5)
|
||||||
|
#6 0x00007efc1449d0b2 _ZN20QEventDispatcherGlib13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE (libQt6Core.so.6 + 0x49d0b2)
|
||||||
|
#7 0x00007efc14191983 _ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE (libQt6Core.so.6 + 0x191983)
|
||||||
|
#8 0x00007efc142b9342 _ZN7QThread4execEv (libQt6Core.so.6 + 0x2b9342)
|
||||||
|
#9 0x00007efc15fb37d1 n/a (libQt6DBus.so.6 + 0x397d1)
|
||||||
|
#10 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#11 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#12 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175771:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175776:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
|
||||||
|
Stack trace of thread 175789:
|
||||||
|
#0 0x00007efc138a0a52 n/a (libc.so.6 + 0xa0a52)
|
||||||
|
#1 0x00007efc13894abc n/a (libc.so.6 + 0x94abc)
|
||||||
|
#2 0x00007efc13894e07 n/a (libc.so.6 + 0x94e07)
|
||||||
|
#3 0x00007efc13897882 pthread_cond_timedwait (libc.so.6 + 0x97882)
|
||||||
|
#4 0x00007efc143713a9 _ZN14QWaitCondition4waitEP6QMutex14QDeadlineTimer (libQt6Core.so.6 + 0x3713a9)
|
||||||
|
#5 0x00007efc142b6e86 n/a (libQt6Core.so.6 + 0x2b6e86)
|
||||||
|
#6 0x00007efc143784fb n/a (libQt6Core.so.6 + 0x3784fb)
|
||||||
|
#7 0x00007efc138981b9 n/a (libc.so.6 + 0x981b9)
|
||||||
|
#8 0x00007efc1391d21c n/a (libc.so.6 + 0x11d21c)
|
||||||
|
ELF object binary architecture: AMD x86-64
|
||||||
130
libs/qwindowkit/.clang-format
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# References:
|
||||||
|
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||||
|
# https://code.qt.io/cgit/qt/qt5.git/tree/_clang-format
|
||||||
|
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
Standard: c++17
|
||||||
|
|
||||||
|
# 指针和引用的对齐方式。
|
||||||
|
# 可能的值有:
|
||||||
|
# PAS_Left (在配置中: Left) 指针左对齐。
|
||||||
|
# PAS_Right (在配置中: Right) 指针右对齐。
|
||||||
|
# PAS_Middle (在配置中: Middle) 指针中间对齐。
|
||||||
|
PointerAlignment: Right
|
||||||
|
|
||||||
|
# public/protected/private 等访问修饰符偏移量
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
|
||||||
|
# 缩进长度
|
||||||
|
IndentWidth: 4
|
||||||
|
|
||||||
|
# 连续空行的最大数
|
||||||
|
MaxEmptyLinesToKeep: 999
|
||||||
|
|
||||||
|
# 在OC中的@property后面添加一个空格。例如:使用“@property (readonly)”而不是“@property(readonly)”
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
|
||||||
|
# OC块中所拍的字符数
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
|
||||||
|
# 取决于值, 语句“int f() { return 0; }”可以被放到一个单行。
|
||||||
|
# 可能的值有:
|
||||||
|
# SFS_None (在配置中: None) 从不合并方法或函数到单独的一行。
|
||||||
|
# SFS_Empty (在配置中: Empty) 仅合并空的函数。
|
||||||
|
# SFS_Inline (在配置中: Inline) 仅合并类中定义的方法或函数. 意味着 “empty”.
|
||||||
|
# SFS_All (在配置中: All) 合并所有的方法适应单行.
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
|
||||||
|
# 如果为真(true), 语句“if (a) return;” 能被放到单行。
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
|
||||||
|
# 如果为真(true), 对齐注释。
|
||||||
|
AlignTrailingComments: true
|
||||||
|
|
||||||
|
# 如果为真,对齐连续的宏定义
|
||||||
|
AlignConsecutiveMacros: true
|
||||||
|
|
||||||
|
# 如果为真(true),将会在“[”之后和“]”之前插入空格。
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
|
||||||
|
# 如果为真(true), 将会在“(”之后和“)”之前插入空格。
|
||||||
|
SpacesInParentheses : false
|
||||||
|
|
||||||
|
# 如果为真(true), 校准连续的声明。
|
||||||
|
# 这将会校准连续多行的声明的名字。这将会导致像下面这样的格式:
|
||||||
|
# int aaaa = 12;
|
||||||
|
# float b = 23;
|
||||||
|
# std::string ccc = 23;
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
|
||||||
|
# 如果为真(true),连续调整多行
|
||||||
|
# 这将会调整连续行中的分配操作符。这将会导致像下面这样的格式:
|
||||||
|
# int aaaa = 12;
|
||||||
|
# int b = 23;
|
||||||
|
# int ccc = 23;
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
|
||||||
|
# 如果为假(false),移除分配操作符(=)前空格。
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
|
||||||
|
# 如果为真(true), 将会在字面量容器中插入空格(例如 OC和Javascript的数组和字典字面量)。
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
|
||||||
|
# 缩进case标签
|
||||||
|
IndentCaseLabels: true
|
||||||
|
|
||||||
|
# 如果表达式中包含函数调用,并且函数调用因为表达式太长被放到了下一行,是否缩进
|
||||||
|
IndentWrappedFunctionNames: true
|
||||||
|
|
||||||
|
# 如果为真(true), 保持块的起始空行。
|
||||||
|
# true: false:
|
||||||
|
# if (foo) { vs. if (foo) {
|
||||||
|
# bar();
|
||||||
|
# bar(); }
|
||||||
|
# }
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
|
||||||
|
# 允许所有参数都被放在下一行
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
|
||||||
|
# 使用C风格强制类型转换后,是否在中间添加一个空格
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
|
||||||
|
# 在模板定义后换行
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
|
||||||
|
# Tab长度
|
||||||
|
TabWidth: 4
|
||||||
|
|
||||||
|
# 是否使用Tab
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
# 在括号后对齐参数
|
||||||
|
# someLongFunction(argument1,
|
||||||
|
# argument2);
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
|
||||||
|
# 名字空间内部缩进
|
||||||
|
NamespaceIndentation: All
|
||||||
|
|
||||||
|
# 一行最长列数
|
||||||
|
ColumnLimit: 100
|
||||||
|
|
||||||
|
# 按层次缩进宏定义
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
|
||||||
|
# 预处理语句缩进为 2
|
||||||
|
PPIndentWidth: 2
|
||||||
|
|
||||||
|
# 数组元素对齐
|
||||||
|
AlignArrayOfStructures: Left
|
||||||
|
|
||||||
|
# 不对头文件排序
|
||||||
|
SortIncludes: Never
|
||||||
|
|
||||||
|
FixNamespaceComments: false
|
||||||
|
|
||||||
|
StatementMacros: ['__qas_attr__', '__qas_exclude__', '__qas_include__']
|
||||||
|
|
||||||
|
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE ]
|
||||||
98
libs/qwindowkit/.gitignore
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# This file is used to ignore files which are generated
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.log
|
||||||
|
*.autosave
|
||||||
|
*.a
|
||||||
|
*.core
|
||||||
|
*.moc
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*_pch.h.cpp
|
||||||
|
*_resource.rc
|
||||||
|
*.qm
|
||||||
|
.#*
|
||||||
|
*.*#
|
||||||
|
core
|
||||||
|
!core/
|
||||||
|
tags
|
||||||
|
.DS_Store
|
||||||
|
.directory
|
||||||
|
*.debug
|
||||||
|
Makefile*
|
||||||
|
*.prl
|
||||||
|
*.app
|
||||||
|
moc_*.cpp
|
||||||
|
ui_*.h
|
||||||
|
qrc_*.cpp
|
||||||
|
Thumbs.db
|
||||||
|
# *.res
|
||||||
|
# *.rc
|
||||||
|
/.qmake.cache
|
||||||
|
/.qmake.stash
|
||||||
|
|
||||||
|
# qtcreator generated files
|
||||||
|
*.pro.user*
|
||||||
|
|
||||||
|
# xemacs temporary files
|
||||||
|
*.flc
|
||||||
|
|
||||||
|
# Vim temporary files
|
||||||
|
.*.swp
|
||||||
|
|
||||||
|
# Visual Studio generated files
|
||||||
|
*.ib_pdb_index
|
||||||
|
*.idb
|
||||||
|
*.ilk
|
||||||
|
*.pdb
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.vcproj
|
||||||
|
*vcproj.*.*.user
|
||||||
|
*.ncb
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.vcxproj
|
||||||
|
*vcxproj.*
|
||||||
|
|
||||||
|
# MinGW generated files
|
||||||
|
*.Debug
|
||||||
|
*.Release
|
||||||
|
|
||||||
|
# Python byte code
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
# --------
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
*/.DS_Store
|
||||||
|
|
||||||
|
build-*
|
||||||
|
build/
|
||||||
|
cmake-build*
|
||||||
|
*.user
|
||||||
|
*.lnk
|
||||||
|
_workingDir*
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
.cache
|
||||||
|
cache
|
||||||
|
.vs
|
||||||
|
out/
|
||||||
|
CMakeSettings.json
|
||||||
|
# /vcpkg
|
||||||
|
/data
|
||||||
|
/*.natvis
|
||||||
|
|
||||||
|
*.sublime-*
|
||||||
|
setup-vcpkg.json
|
||||||
|
setup-vcpkg-temp*
|
||||||
4
libs/qwindowkit/.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[submodule "qmsetup"]
|
||||||
|
path = qmsetup
|
||||||
|
url = ../../stdware/qmsetup.git
|
||||||
|
branch = main
|
||||||
144
libs/qwindowkit/CMakeLists.txt
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
project(QWindowKit
|
||||||
|
VERSION 1.5.1.0
|
||||||
|
LANGUAGES CXX
|
||||||
|
HOMEPAGE_URL "https://github.com/stdware/qwindowkit"
|
||||||
|
DESCRIPTION "Cross-platform window customization framework"
|
||||||
|
)
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Build Options
|
||||||
|
# ----------------------------------
|
||||||
|
option(QWINDOWKIT_BUILD_STATIC "Build static libraries" OFF)
|
||||||
|
option(QWINDOWKIT_BUILD_WIDGETS "Build widgets module" ON)
|
||||||
|
option(QWINDOWKIT_BUILD_QUICK "Build quick module" OFF)
|
||||||
|
option(QWINDOWKIT_BUILD_EXAMPLES "Build examples" OFF)
|
||||||
|
option(QWINDOWKIT_BUILD_DOCUMENTATIONS "Build documentations" OFF)
|
||||||
|
option(QWINDOWKIT_INSTALL "Install library" ON)
|
||||||
|
|
||||||
|
option(QWINDOWKIT_FORCE_QT_WINDOW_CONTEXT "Force use Qt Window Context" OFF)
|
||||||
|
option(QWINDOWKIT_ENABLE_WINDOWS_SYSTEM_BORDERS "Enable system borders on Windows" ON)
|
||||||
|
option(QWINDOWKIT_ENABLE_STYLE_AGENT "Enable building style agent" ON)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
|
||||||
|
Detailed Introcuction to Configure Options:
|
||||||
|
|
||||||
|
`QWINDOWKIT_BUILD_DOCUMENTATIONS`
|
||||||
|
- If you have installed `Doxygen`, you can ENABLE this option so that the documentations
|
||||||
|
will also be built and installed.
|
||||||
|
- If not, you can read the comments in `qdoc` style in `cpp` files to get detailed usages
|
||||||
|
of the public APIs.
|
||||||
|
|
||||||
|
`QWINDOWKIT_ENABLE_WINDOWS_SYSTEM_BORDERS`
|
||||||
|
- If you don't want the system borders on Windows 10/11, you can DISABLE this option.
|
||||||
|
- If so, the Windows 10 top border issue will disappear. However, part of the client edge
|
||||||
|
area will be occupied as the resizing margins.
|
||||||
|
|
||||||
|
`QWINDOWKIT_FORCE_QT_WINDOW_CONTEXT`
|
||||||
|
- If you want to use pure Qt emulated frameless implementation, you can ENABLE this option.
|
||||||
|
- If so, all system native features will be lost.
|
||||||
|
- The Qt Window Context is supported on all platforms.
|
||||||
|
|
||||||
|
`QWINDOWKIT_ENABLE_STYLE_AGENT`
|
||||||
|
- Select whether to exclude the style component by DISABLING this option according to your
|
||||||
|
requirements and your Qt version.
|
||||||
|
|
||||||
|
#]]
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# CMake Settings
|
||||||
|
# ----------------------------------
|
||||||
|
if(MSVC)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /manifest:no")
|
||||||
|
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /manifest:no")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /manifest:no")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
|
||||||
|
set(CMAKE_DEBUG_POSTFIX "d")
|
||||||
|
endif()
|
||||||
|
elseif(MINGW)
|
||||||
|
if(NOT DEFINED CMAKE_STATIC_LIBRARY_PREFIX)
|
||||||
|
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_SHARED_LIBRARY_PREFIX)
|
||||||
|
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_IMPORT_LIBRARY_PREFIX)
|
||||||
|
set(CMAKE_IMPORT_LIBRARY_PREFIX "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||||
|
set(CMAKE_BUILD_TYPE "Release")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_CROSSCOMPILING)
|
||||||
|
set(CMAKE_INSTALL_RPATH "\$ORIGIN:\$ORIGIN/../lib")
|
||||||
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
|
||||||
|
set(CMAKE_C_VISIBILITY_PRESET "hidden")
|
||||||
|
set(CMAKE_CXX_VISIBILITY_PRESET "hidden")
|
||||||
|
|
||||||
|
if(QWINDOWKIT_INSTALL)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Project Variables
|
||||||
|
# ----------------------------------
|
||||||
|
set(QWINDOWKIT_VERSION ${PROJECT_VERSION})
|
||||||
|
set(QWINDOWKIT_INSTALL_NAME ${PROJECT_NAME})
|
||||||
|
|
||||||
|
string(TIMESTAMP _QWINDOWKIT_CURRENT_YEAR "%Y")
|
||||||
|
set(QWINDOWKIT_COPYRIGHT "Copyright 2023-${_QWINDOWKIT_CURRENT_YEAR} Stdware Collections")
|
||||||
|
set(QWINDOWKIT_DESCRIPTION ${PROJECT_DESCRIPTION})
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Find basic dependencies
|
||||||
|
# ----------------------------------
|
||||||
|
find_package(qmsetup QUIET)
|
||||||
|
|
||||||
|
if(NOT TARGET qmsetup::library)
|
||||||
|
# Modify this variable according to your project structure
|
||||||
|
set(_source_dir ${CMAKE_CURRENT_SOURCE_DIR}/qmsetup)
|
||||||
|
|
||||||
|
# Import install function
|
||||||
|
include("${_source_dir}/cmake/modules/private/InstallPackage.cmake")
|
||||||
|
|
||||||
|
# Install package in place
|
||||||
|
set(_package_path)
|
||||||
|
qm_install_package(qmsetup
|
||||||
|
SOURCE_DIR ${_source_dir}
|
||||||
|
BUILD_TYPE Release
|
||||||
|
RESULT_PATH _package_path
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find package again
|
||||||
|
find_package(qmsetup REQUIRED PATHS ${_package_path})
|
||||||
|
|
||||||
|
# Update import path
|
||||||
|
set(qmsetup_DIR ${_package_path} CACHE PATH "" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
qm_import(Filesystem)
|
||||||
|
qm_init_directories()
|
||||||
|
|
||||||
|
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Add source modules
|
||||||
|
# ----------------------------------
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
if(QWINDOWKIT_BUILD_EXAMPLES)
|
||||||
|
add_subdirectory(examples)
|
||||||
|
endif()
|
||||||
202
libs/qwindowkit/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright (C) 2023-2025 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
316
libs/qwindowkit/README.md
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
# QWindowKit
|
||||||
|
|
||||||
|
Cross-platform window customization framework for Qt Widgets and Qt Quick.
|
||||||
|
|
||||||
|
This project inherited the major implementations from [wangwenx190 FramelessHelper](https://github.com/wangwenx190/framelesshelper), with a complete refactoring and upgrading of the architecture.
|
||||||
|
|
||||||
|
Feature requests are welcome.
|
||||||
|
|
||||||
|
## Stay In Touch :triangular_flag_on_post:
|
||||||
|
|
||||||
|
You can share your findings, thoughts and ideas on improving / implementing QWindowKit functionalities on more platforms and apps!
|
||||||
|
|
||||||
|
- Chat with us on [Discord](https://discord.gg/grrM4Tmesy)
|
||||||
|
- 中文用户可加入 QQ 群 876419693
|
||||||
|
|
||||||
|
## Supported Platforms
|
||||||
|
|
||||||
|
- Microsoft Windows
|
||||||
|
- Apple macOS (11+)
|
||||||
|
- GNU/Linux
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Full support of Windows 11 Snap Layout
|
||||||
|
- Better workaround to handle Windows 10 top border issue
|
||||||
|
- Support Mac system buttons geometry customization
|
||||||
|
- Simpler APIs, more detailed documentations and comments
|
||||||
|
|
||||||
|
## Gallery
|
||||||
|
|
||||||
|
### Windows 11 (With Snap Layout)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Windows 10 (And 7, Vista)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### macOS & Linux
|
||||||
|
|
||||||
|
| macOS | Linux (Ubuntu 20.04) |
|
||||||
|
|:-------------------------------:|:---------------------------------:|
|
||||||
|
|  |  |
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
| Component | Requirement | Details |
|
||||||
|
|:---------:|:-----------:|:-------------------------:|
|
||||||
|
| Qt | \>=5.12 | Core, Gui, Widgets, Quick |
|
||||||
|
| Compiler | \>=C++17 | MSVC 2019, GCC, Clang |
|
||||||
|
| CMake | \>=3.19 | >=3.20 is recommended |
|
||||||
|
|
||||||
|
Please read [Vulnerabilities](#Vulnerabilities) carefully to acquire detailed requirements.
|
||||||
|
|
||||||
|
### Tested Compilers
|
||||||
|
|
||||||
|
- Windows
|
||||||
|
- MSVC: 2019, 2022
|
||||||
|
- MinGW (GCC): 13.2.0
|
||||||
|
- macOS
|
||||||
|
- Clang 14.0.3
|
||||||
|
- Ubuntu
|
||||||
|
- GCC: 9.4.0
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- Qt 5.12 or higher
|
||||||
|
- [qmsetup](https://github.com/stdware/qmsetup)
|
||||||
|
|
||||||
|
## Integrate
|
||||||
|
|
||||||
|
### Build & Install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone --recursive https://github.com/stdware/qwindowkit
|
||||||
|
cd qwindowkit
|
||||||
|
|
||||||
|
cmake -B build -S . \
|
||||||
|
-DCMAKE_PREFIX_PATH=<QT_DIR> \
|
||||||
|
-Dqmsetup_DIR=<dir> \ # Optional
|
||||||
|
-DQWINDOWKIT_BUILD_QUICK=TRUE \ # Optional
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/path/install \
|
||||||
|
-G "Ninja Multi-Config"
|
||||||
|
|
||||||
|
cmake --build build --target install --config Debug
|
||||||
|
cmake --build build --target install --config Release
|
||||||
|
```
|
||||||
|
Read the root `CMakeLists.txt` for more build options.
|
||||||
|
|
||||||
|
You can also include this directory as a subproject if you choose CMake as your build system.
|
||||||
|
|
||||||
|
For other build systems, you need to install with CMake first and include the corresponding configuration files in your project.
|
||||||
|
|
||||||
|
### Import
|
||||||
|
|
||||||
|
#### CMake Project
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake -B build -DQWindowKit_DIR=/path/install/lib/cmake/QWindowKit
|
||||||
|
```
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
find_package(QWindowKit COMPONENTS Core Widgets Quick REQUIRED)
|
||||||
|
target_link_libraries(widgets_app PUBLIC QWindowKit::Widgets)
|
||||||
|
target_link_libraries(quick_app PUBLIC QWindowKit::Quick)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### QMake Project
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
# WidgetsApp.pro
|
||||||
|
include("/path/install/share/QWindowKit/qmake/QWKWidgets.pri")
|
||||||
|
|
||||||
|
# QuickApp.pro
|
||||||
|
include("/path/install/share/QWindowKit/qmake/QWKQuick.pri")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Visual Studio Project
|
||||||
|
|
||||||
|
See [Visual Studio Guide](./docs/visual-studio-guide.md) for detailed usages.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Qt Widgets Application
|
||||||
|
|
||||||
|
#### Initialization
|
||||||
|
|
||||||
|
The following initialization should be done before any widget constructs.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Setup Window Agent
|
||||||
|
|
||||||
|
First, setup `WidgetWindowAgent` for your top `QWidget` instance. (Each window needs its own agent.)
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#include <QWKWidgets/widgetwindowagent.h>
|
||||||
|
|
||||||
|
MyWidget::MyWidget(QWidget *parent) {
|
||||||
|
// ...
|
||||||
|
auto agent = new QWK::WidgetWindowAgent(this);
|
||||||
|
agent->setup(this);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't want to derive a new widget class or change the constructor, you can initialize the agent after the window
|
||||||
|
constructs.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
auto w = new MyWidget();
|
||||||
|
auto agent = new QWK::WidgetWindowAgent(w);
|
||||||
|
agent->setup(w);
|
||||||
|
```
|
||||||
|
|
||||||
|
You should call `QWK::WidgetWindowAgent::setup()` as early as possible, especially when you need to set the size constrains. QWindowKit will change some Qt internal data which will affect how Qt calculates the window size, and thus you need to let QWindowKit initialize at the very beginning.
|
||||||
|
|
||||||
|
#### Construct Title bar
|
||||||
|
|
||||||
|
Then, construct your title bar widget, without which the window lacks the basic interaction feature, and it's better to
|
||||||
|
put it into the window's layout.
|
||||||
|
|
||||||
|
You can use the [`WindowBar`](examples/shared/widgetframe/windowbar.h) provided by `WidgetFrame` in the examples as the
|
||||||
|
container of your title bar components.
|
||||||
|
|
||||||
|
Let `WidgetWindowAgent` know which widget the title bar is.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
agent->setTitleBar(myTitleBar);
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, set system button hints to let `WidgetWindowAgent` know the role of the child widgets, which is important for the
|
||||||
|
Snap Layout to work.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
agent->setSystemButton(QWK::WindowAgentBase::WindowIcon, myTitleBar->iconButton());
|
||||||
|
agent->setSystemButton(QWK::WindowAgentBase::Minimize, myTitleBar->minButton());
|
||||||
|
agent->setSystemButton(QWK::WindowAgentBase::Maximize, myTitleBar->maxButton());
|
||||||
|
agent->setSystemButton(QWK::WindowAgentBase::Close, myTitleBar->closeButton());
|
||||||
|
```
|
||||||
|
|
||||||
|
Doing this does not mean that these buttons' click events are automatically associated with window actions, you still need to manually connect the signals and slots to emulate the native window behaviors.
|
||||||
|
|
||||||
|
On macOS, this step can be skipped because it is better to use the buttons provided by the system.
|
||||||
|
|
||||||
|
Last but not least, set hit-test visible hint to let `WidgetWindowAgent` know which widgets are willing to receive mouse events.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
agent->setHitTestVisible(myTitleBar->menuBar(), true);
|
||||||
|
```
|
||||||
|
|
||||||
|
The rest region within the title bar will be regarded as the draggable area for the user to move the window, and thus any QWidgets inside it will not receive any user interaction events such as mouse events/focus events/etc anymore, but you can still send/post such events to these widgets manually, either through Qt API or system API.
|
||||||
|
|
||||||
|
- If you want to disable window maximization, you can remove the `Qt::WindowMaximizeButtonHint` flag from the window.
|
||||||
|
|
||||||
|
<!-- #### Window Attributes (Experimental)
|
||||||
|
|
||||||
|
On Windows 11, you can use this API to enable system effects.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
agent->setWindowAttribute("mica", true);
|
||||||
|
```
|
||||||
|
|
||||||
|
Available keys: `mica`, `mica-alt`, `acrylic`, `dark-mode`. -->
|
||||||
|
|
||||||
|
### Qt Quick Application
|
||||||
|
|
||||||
|
#### Initialization
|
||||||
|
|
||||||
|
Make sure you have registered `QWindowKit` into QtQuick:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <QWKQuick/qwkquickglobal.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
QQmlApplicationEngine engine;
|
||||||
|
// ...
|
||||||
|
QWK::registerTypes(&engine);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Setup Window Components
|
||||||
|
|
||||||
|
Then you can use `QWindowKit` data types and classes by importing its URI:
|
||||||
|
|
||||||
|
```qml
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Window 2.15
|
||||||
|
import QWindowKit 1.0
|
||||||
|
|
||||||
|
Window {
|
||||||
|
id: window
|
||||||
|
visible: false // We hide it first, so we can move the window to our desired position silently.
|
||||||
|
Component.onCompleted: {
|
||||||
|
windowAgent.setup(window)
|
||||||
|
window.visible = true
|
||||||
|
}
|
||||||
|
WindowAgent {
|
||||||
|
id: windowAgent
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can omit the version number or use "auto" instead of "1.0" for the module URI if you are using Qt6.
|
||||||
|
|
||||||
|
As we just mentioned above, if you are going to set the size constrains, please do it after `windowAgent.setup()` is called.
|
||||||
|
|
||||||
|
### Learn More
|
||||||
|
|
||||||
|
See [examples](examples) for more demo use cases. The examples have no High DPI support.
|
||||||
|
|
||||||
|
- QWindowKit Internals [TODO]
|
||||||
|
- [FramelessHelper Related](docs/framelesshelper-related.md)
|
||||||
|
|
||||||
|
|
||||||
|
### Vulnerabilities
|
||||||
|
|
||||||
|
#### Qt Version
|
||||||
|
- To achieve better frameless functionality, QWindowKit depends heavily on Qt's internal implementation. However, there are many differences in different versions of Qt, and earlier versions of Qt5 and Qt6 have many bugs which make it extremely difficult for QWindowKit to workaround without changing the Qt source code.
|
||||||
|
- And also due to limited manpower, although QWindowKit can be successfully compiled on Qt 5.12 or later, it can hardly work perfectly on all Qt versions.
|
||||||
|
- Therefore, the following Qt version ranges are recommended, if there are any exceptions with QWindowKit in your application, make sure the Qt version you use is in the ranges before raising the issue.
|
||||||
|
- Qt 5: 5.15.2 or higher (you may be able to build QWK on top of older Qt versions, however, QWK may not behave well and we won't accept bug reports from these unsupported versions)
|
||||||
|
- Qt 6: 6.6.2 or higher (the newer, the better)
|
||||||
|
|
||||||
|
#### Hot Switch
|
||||||
|
- Once you have made the window frameless, it will not be able to switch back to the system frame again unless you destroy your window and recreate it with different settings.
|
||||||
|
|
||||||
|
- Do not use `QWidget::setWindowFlags` to change the window flags after `windowAgent.setup()` is called. As a result, `QWK::WidgetWindowAgent` can not be setup on `QDockWidget`.
|
||||||
|
|
||||||
|
#### Native Child Widget
|
||||||
|
- If you are about to add a widget with `Qt::WA_NativeWindow` property enabled as a descendent of the frameless window, you should enable `Qt::WA_DontCreateNativeAncestors` of it in advance.
|
||||||
|
|
||||||
|
#### Size Constrains
|
||||||
|
- If you want to disable window resizing, you can set a fixed size, which is officially supported by QWindowKit. If you use other special means to achieve this (eg. hook Win32 messages), QWK doesn't guarantee everything can still be fully functional.
|
||||||
|
- If you set a maximized width or height, the window should not be maximized because you cannot get the correct window size through Qt APIs. You may workaround this by using system APIs such as `GetWindowRect` or `GetClientRect`. The root cause lies deep in Qt QPA implementations and currently we don't know how to fix it without modifying Qt itself.
|
||||||
|
|
||||||
|
#### Windows 10
|
||||||
|
- Due to the inherent defects in the Windows 10 window system, the top border will disappear when the system title bar is removed. We have filtered Qt's event and perfectly reshown the system top border, thanks to the implementation of Windows Terminal for our reference. However, this workaround only works with QtWidgets and QtQuick (**only when rendering through OpenGL/D3D11/D3D12, not Vulkan**) applications.
|
||||||
|
- For QtQuick applications, when rendering through Vulkan, the top border will become a solid black line, that's a known issue and currently we are not able to fix it. Please use QWK's borderless version if you can't change your graphics backend.
|
||||||
|
- For QtQuick applications, when rendering through D3D11/D3D12, you may see a strange white line on window top, it may disappear if you resize the window. Currently it's a bug and we are working hard to find a suitable solution for it, for now you can set the environment variable `QT_QPA_DISABLE_REDIRECTION_SURFACE` to a non-zero value in your `main` function before any `QCoreApplication` instance is created to workaround this issue. This environment variable is first introduced in Qt 6.7.0 (qtbase/838fc606c170fac112f7bb5971c2507b7b56d08a). You must **NOT** enable this feature for OpenGL/Vulkan because their rendering will be totally broken.
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- Fix mouse cursor mapping issues
|
||||||
|
- More documentations
|
||||||
|
- When do we support Linux native features?
|
||||||
|
|
||||||
|
## Special Thanks
|
||||||
|
|
||||||
|
- [Maplespe](https://github.com/Maplespe)
|
||||||
|
- [zhiyiYo](https://github.com/zhiyiYo)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
QWindowKit is licensed under the [Apache 2.0 License](./LICENSE).
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
**You MUST keep a copyright notice of QWindowKit in a prominent place on your project, such as the README document and the About Dialog.**
|
||||||
|
|
||||||
|
**You MUST NOT remove the license text from the header files and source files of QWindowKit.**
|
||||||
|
|
||||||
|
-->
|
||||||
89
libs/qwindowkit/docs/framelesshelper-related.md
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# FramelessHelper 2.x
|
||||||
|
|
||||||
|
Cross-platform window customization framework for Qt Widgets and Qt Quick. Supports Windows, Linux and macOS.
|
||||||
|
|
||||||
|
## Join with Us :triangular_flag_on_post:
|
||||||
|
|
||||||
|
You can join our [Discord channel](https://discord.gg/grrM4Tmesy) to communicate with us. You can share your findings, thoughts and ideas on improving / implementing FramelessHelper functionalities on more platforms and apps!
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
### Title Bar Design Guidance
|
||||||
|
|
||||||
|
- Microsoft: <https://docs.microsoft.com/en-us/windows/apps/design/basics/titlebar-design>
|
||||||
|
- KDE: <https://develop.kde.org/hig/>
|
||||||
|
- GNOME: <https://developer.gnome.org/hig/patterns/containers/header-bars.html>
|
||||||
|
- Apple: <https://developer.apple.com/design/human-interface-guidelines/macos/windows-and-views/window-anatomy/>
|
||||||
|
|
||||||
|
## Platform Notes
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
- If DWM composition is disabled in some very rare cases (only possible on Windows 7), the top-left corner and top-right corner will appear in round shape. The round corners can be restored to square if you re-enable DWM composition.
|
||||||
|
- There's an OpenGL driver bug which will cause some frameless windows have a strange black bar right on top of your homemade title bar, and it also makes the controls in your windows shifted to the bottom-right corner for some pixels. It's a bug of your graphics card driver, specifically, your OpenGL driver, not FramelessHelper. There are some solutions provided by our users but some of them may not work in all conditions, you can pick one from them:
|
||||||
|
|
||||||
|
Solution | Principle
|
||||||
|
-------- | ---------
|
||||||
|
Upgrade the graphics driver | Try to use a newer driver which may ship with the fix
|
||||||
|
Change the system theme to "Basic" (in contrary to "Windows Aero") | Let Windows use pure software rendering
|
||||||
|
If there are multiple graphics cards, use another one instead | Try to use a different driver which may don't have such bug at all
|
||||||
|
Upgrade the system to at least Windows 11 | Windows 11 redesigned the windowing system so the bug can no longer be triggered
|
||||||
|
Remove the `WS_THICKFRAME` and `WS_OVERLAPPED` styles from the window, and maybe also add the `WS_POPUP` style at the same time, and don't do anything inside the `WM_NCCALCSIZE` block (just return `false` directly or remove/comment out the whole block) | Try to mirror Qt's `FramelessWindowHint`'s behavior
|
||||||
|
Use `Qt::FramelessWindowHint` instead of doing the `WM_NCCALCSIZE` trick | Qt's rendering code path is totally different between these two solutions
|
||||||
|
Force Qt to use the ANGLE backend instead of the Desktop OpenGL | ANGLE will translate OpenGL directives into D3D ones
|
||||||
|
Force Qt to use pure software rendering instead of rendering through OpenGL | Qt is not using OpenGL at all
|
||||||
|
Force Qt to use the Mesa 3D libraries instead of normal OpenGL | Try to use a different OpenGL implementation
|
||||||
|
Use Direct3D/Vulkan/Metal instead of OpenGL | Just don't use the buggy OpenGL
|
||||||
|
|
||||||
|
If you are lucky enough, one of them may fix the issue for you. If not, you may try to use multiple solutions together. **But I can't guarantee the issue can 100% be fixed.**
|
||||||
|
- Due to there are many sub-versions of Windows 10, it's highly recommended to use the latest version of Windows 10, at least **no older than Windows 10 1809**. If you try to use this framework on some very old Windows 10 versions such as 1507 or 1607, there may be some compatibility issues. Using this framework on Windows 7 is also supported but not recommended. To get the most stable behavior and the best appearance, you should use it on the latest version of Windows 10 or Windows 11.
|
||||||
|
- To make the snap layout work as expected, there are some additional rules for your homemade system buttons to follow:
|
||||||
|
- **Add a manifest file to your application. In the manifest file, you need to claim your application supports Windows 11 explicitly. This step is VERY VERY IMPORTANT. Without this step, the snap layout feature can't be enabled.**
|
||||||
|
- Call `setSystemButton()` for each button (it can be any *QWidget* or *QQuickItem*) to let FramelessHelper know which is the minimize/maximize/close button.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
- FramelessHelper will force your application to use the _XCB_ platform plugin when running on Wayland.
|
||||||
|
- The resize area is inside of the window.
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
- Some users reported that the window is not resizable on some old macOS versions.
|
||||||
|
|
||||||
|
## Special Thanks
|
||||||
|
|
||||||
|
*Ordered by first contribution time (it may not be very accurate, sorry)*
|
||||||
|
|
||||||
|
- [Yuhang Zhao](https://github.com/wangwenx190): Help me create this project. This project is mainly based on his code.
|
||||||
|
- [Julien](https://github.com/JulienMaille): Help me test this library on many various environments and help me fix the bugs we found. Contributed many code to improve this library. The MainWindow example is mostly based on his code.
|
||||||
|
- [Altair Wei](https://github.com/altairwei): Help me fix quite some small bugs and give me many important suggestions, the 2.x version is also inspired by his idea during our discussions.
|
||||||
|
- [Kenji Mouri](https://github.com/MouriNaruto): Give me a lot of help on Win32 native developing.
|
||||||
|
- [Dylan Liu](https://github.com/mentalfl0w): Help me improve the build process on macOS.
|
||||||
|
- [SineStriker](https://github.com/SineStriker): Spent over a whole week helping me improve the Snap Layout implementation, fixing potential bugs and also give me a lot of professional and useful suggestions. Without his great effort, the new implementation may never come.
|
||||||
|
- And also thanks to other contributors not listed here! Without their valuable help, this library wouldn't have such good quality and user experience!
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
```text
|
||||||
|
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.
|
||||||
|
```
|
||||||
BIN
libs/qwindowkit/docs/images/linux.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
libs/qwindowkit/docs/images/mac.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
libs/qwindowkit/docs/images/vs-guide-1.png
Normal file
|
After Width: | Height: | Size: 360 KiB |
BIN
libs/qwindowkit/docs/images/vs-guide-2.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
libs/qwindowkit/docs/images/vs-guide-3.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
libs/qwindowkit/docs/images/win10.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
libs/qwindowkit/docs/images/win11.png
Normal file
|
After Width: | Height: | Size: 349 KiB |
15
libs/qwindowkit/docs/visual-studio-guide.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Visual Studio Guide
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
First, click the "View" menu, find "Other Windows", click "Property Manager".
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Then, right click the project name item and pop up a context menu, click "Add
|
||||||
|
Existing Property Sheet...".
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Finally, find the "QWindowKit.props" in the "[Build output folder of
|
||||||
|
QWindowKit]\share\QWindowKit" folder, click "Open" button.
|
||||||
23
libs/qwindowkit/examples/CMakeLists.txt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
set(QWK_EXAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
macro(qwk_add_example _target)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
|
add_executable(${_target})
|
||||||
|
qm_configure_target(${_target} ${ARGN})
|
||||||
|
qm_add_win_rc(${_target} ICON ${QWK_EXAMPLES_DIR}/shared/resources/app/example.ico)
|
||||||
|
qm_add_win_manifest(${_target})
|
||||||
|
qm_add_mac_bundle(${_target} ICON ${QWK_EXAMPLES_DIR}/shared/resources/app/example.icns)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
add_subdirectory(shared)
|
||||||
|
|
||||||
|
if(QWINDOWKIT_BUILD_WIDGETS)
|
||||||
|
add_subdirectory(mainwindow)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(QWINDOWKIT_BUILD_QUICK)
|
||||||
|
add_subdirectory(qml)
|
||||||
|
endif()
|
||||||
10
libs/qwindowkit/examples/mainwindow/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
project(QWKExample_MainWindow)
|
||||||
|
|
||||||
|
file(GLOB _src *.h *.cpp)
|
||||||
|
|
||||||
|
qwk_add_example(${PROJECT_NAME}
|
||||||
|
FEATURES cxx_std_17
|
||||||
|
SOURCES ${_src} mainwindow.qrc ../shared/resources/shared.qrc
|
||||||
|
QT_LINKS Core Gui Widgets # MultimediaWidgets
|
||||||
|
LINKS QWKWidgets WidgetFrame
|
||||||
|
)
|
||||||
170
libs/qwindowkit/examples/mainwindow/dark-style.qss
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/* Window bar */
|
||||||
|
|
||||||
|
QWK--WindowBar[bar-active=true] {
|
||||||
|
/*background-color: #3C3C3C;*/
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar[bar-active=false] {
|
||||||
|
/*background-color: #505050;*/
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Title label */
|
||||||
|
|
||||||
|
QWK--WindowBar>QLabel#win-title-label {
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
color: #ECECEC;
|
||||||
|
background-color: transparent;
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* System buttons */
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton[system-button=true] {
|
||||||
|
qproperty-iconSize: 12px 12px;
|
||||||
|
min-width: 50px;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#pin-button {
|
||||||
|
qproperty-iconNormal: url(":/window-bar/pin.svg");
|
||||||
|
qproperty-iconChecked: url(":/window-bar/pin-fill.svg");
|
||||||
|
qproperty-iconSize: 15px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#pin-button:hover,
|
||||||
|
QWK--WindowBar>QAbstractButton#pin-button:pressed {
|
||||||
|
background-color: rgba(255, 255, 255, 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#min-button {
|
||||||
|
qproperty-iconNormal: url(":/window-bar/minimize.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#min-button:hover,
|
||||||
|
QWK--WindowBar>QAbstractButton#min-button:pressed {
|
||||||
|
background-color: rgba(255, 255, 255, 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#max-button {
|
||||||
|
qproperty-iconNormal: url(":/window-bar/maximize.svg");
|
||||||
|
qproperty-iconChecked: url(":/window-bar/restore.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#max-button:hover,
|
||||||
|
QWK--WindowBar>QAbstractButton#max-button:pressed {
|
||||||
|
background-color: rgba(255, 255, 255, 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#close-button {
|
||||||
|
qproperty-iconNormal: url(":/window-bar/close.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#close-button:hover,
|
||||||
|
QWK--WindowBar>QAbstractButton#close-button:pressed {
|
||||||
|
background-color: #e81123;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Icon button */
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#icon-button {
|
||||||
|
qproperty-iconNormal: url(":/app/example.png");
|
||||||
|
qproperty-iconSize: 18px 18px;
|
||||||
|
min-width: 40px;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Menu Bar */
|
||||||
|
|
||||||
|
QMenuBar {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar>QToolButton#qt_menubar_ext_button {
|
||||||
|
qproperty-icon: url(":/window-bar/more-line.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar>QToolButton#qt_menubar_ext_button:hover,
|
||||||
|
QMenuBar>QToolButton#qt_menubar_ext_button:pressed {
|
||||||
|
background-color: rgba(255, 255, 255, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar::item {
|
||||||
|
color: #CCCCCC;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar::item:selected {
|
||||||
|
background-color: rgba(255, 255, 255, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
|
||||||
|
QMenu {
|
||||||
|
padding: 4px;
|
||||||
|
background: #303030;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::indicator {
|
||||||
|
left: 6px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::icon {
|
||||||
|
left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::item {
|
||||||
|
background: transparent;
|
||||||
|
color: #CCCCCC;
|
||||||
|
padding: 6px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::item:selected {
|
||||||
|
color: white;
|
||||||
|
background-color: #0060C0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::item:disabled {
|
||||||
|
color: #666666;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::separator {
|
||||||
|
height: 2px;
|
||||||
|
background-color: #5B5B5B;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Window */
|
||||||
|
|
||||||
|
MainWindow {
|
||||||
|
background-color: #1E1E1E;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow[custom-style=true] {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#clock-widget {
|
||||||
|
font-size: 75px;
|
||||||
|
color: #FEFEFE;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
168
libs/qwindowkit/examples/mainwindow/light-style.qss
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/* Window bar */
|
||||||
|
|
||||||
|
QWK--WindowBar[bar-active=true] {
|
||||||
|
background-color: #195ABE;
|
||||||
|
/* background-color: transparent; */
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar[bar-active=false] {
|
||||||
|
background-color: #195ABE;
|
||||||
|
/* background-color: transparent; */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Title label */
|
||||||
|
|
||||||
|
QWK--WindowBar>QLabel#win-title-label {
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
color: #ECECEC;
|
||||||
|
background-color: transparent;
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* System buttons */
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton[system-button=true] {
|
||||||
|
qproperty-iconSize: 12px 12px;
|
||||||
|
min-width: 50px;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#pin-button {
|
||||||
|
qproperty-iconNormal: url(":/window-bar/pin.svg");
|
||||||
|
qproperty-iconChecked: url(":/window-bar/pin-fill.svg");
|
||||||
|
qproperty-iconSize: 15px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#pin-button:hover,
|
||||||
|
QWK--WindowBar>QAbstractButton#pin-button:pressed {
|
||||||
|
background-color: rgba(0, 0, 0, 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#min-button {
|
||||||
|
qproperty-iconNormal: url(":/window-bar/minimize.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#min-button:hover,
|
||||||
|
QWK--WindowBar>QAbstractButton#min-button:pressed {
|
||||||
|
background-color: rgba(0, 0, 0, 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#max-button {
|
||||||
|
qproperty-iconNormal: url(":/window-bar/maximize.svg");
|
||||||
|
qproperty-iconChecked: url(":/window-bar/restore.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#max-button:hover,
|
||||||
|
QWK--WindowBar>QAbstractButton#max-button:pressed {
|
||||||
|
background-color: rgba(0, 0, 0, 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#close-button {
|
||||||
|
qproperty-iconNormal: url(":/window-bar/close.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#close-button:hover,
|
||||||
|
QWK--WindowBar>QAbstractButton#close-button:pressed {
|
||||||
|
background-color: #e81123;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Icon button */
|
||||||
|
|
||||||
|
QWK--WindowBar>QAbstractButton#icon-button {
|
||||||
|
qproperty-iconNormal: url(":/app/example.png");
|
||||||
|
qproperty-iconSize: 18px 18px;
|
||||||
|
min-width: 40px;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Menu Bar */
|
||||||
|
|
||||||
|
QMenuBar {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar>QToolButton#qt_menubar_ext_button {
|
||||||
|
qproperty-icon: url(":/window-bar/more-line.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar>QToolButton#qt_menubar_ext_button:hover,
|
||||||
|
QMenuBar>QToolButton#qt_menubar_ext_button:pressed {
|
||||||
|
background-color: rgba(255, 255, 255, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar::item {
|
||||||
|
color: #EEEEEE;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar::item:selected {
|
||||||
|
background-color: rgba(255, 255, 255, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
|
||||||
|
QMenu {
|
||||||
|
padding: 4px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #E0E0E0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::indicator {
|
||||||
|
left: 6px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::icon {
|
||||||
|
left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::item {
|
||||||
|
background: transparent;
|
||||||
|
color: #333333;
|
||||||
|
padding: 6px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::item:selected {
|
||||||
|
background-color: rgba(0, 0, 0, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::item:disabled {
|
||||||
|
color: #CCCCCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu::separator {
|
||||||
|
height: 2px;
|
||||||
|
background-color: #CCCCCC;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Window */
|
||||||
|
|
||||||
|
MainWindow {
|
||||||
|
background-color: #F3F3F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow[custom-style=true] {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#clock-widget {
|
||||||
|
font-size: 75px;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
34
libs/qwindowkit/examples/mainwindow/main.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
qputenv("QT_WIN_DEBUG_CONSOLE", "attach");
|
||||||
|
qputenv("QSG_INFO", "1");
|
||||||
|
//qputenv("QT_WIDGETS_HIGHDPI_DOWNSCALE", "1");
|
||||||
|
//qputenv("QT_WIDGETS_RHI", "1");
|
||||||
|
//qputenv("QSG_RHI_BACKEND", "d3d12");
|
||||||
|
//qputenv("QSG_RHI_HDR", "scrgb");
|
||||||
|
//qputenv("QT_QPA_DISABLE_REDIRECTION_SURFACE", "1");
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
|
||||||
|
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||||
|
#endif
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
385
libs/qwindowkit/examples/mainwindow/mainwindow.cpp
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtCore/QFile>
|
||||||
|
#include <QtCore/QTime>
|
||||||
|
#include <QtCore/QTimer>
|
||||||
|
#include <QtGui/QPainter>
|
||||||
|
#include <QtGui/QWindow>
|
||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
#include <QtWidgets/QStyle>
|
||||||
|
#include <QtWidgets/QPushButton>
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
# include <QtGui/QActionGroup>
|
||||||
|
#else
|
||||||
|
# include <QtWidgets/QActionGroup>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// #include <QtWebEngineWidgets/QWebEngineView>
|
||||||
|
|
||||||
|
#include <QWKWidgets/widgetwindowagent.h>
|
||||||
|
|
||||||
|
#include <widgetframe/windowbar.h>
|
||||||
|
#include <widgetframe/windowbutton.h>
|
||||||
|
|
||||||
|
class ClockWidget : public QLabel {
|
||||||
|
public:
|
||||||
|
explicit ClockWidget(QWidget *parent = nullptr) : QLabel(parent) {
|
||||||
|
startTimer(100);
|
||||||
|
setAlignment(Qt::AlignCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ClockWidget() override = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void timerEvent(QTimerEvent *event) override {
|
||||||
|
QLabel::timerEvent(event);
|
||||||
|
setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss")));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
||||||
|
setAttribute(Qt::WA_DontCreateNativeAncestors);
|
||||||
|
|
||||||
|
installWindowAgent();
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
auto clockWidget = new ClockWidget();
|
||||||
|
clockWidget->setObjectName(QStringLiteral("clock-widget"));
|
||||||
|
clockWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
setCentralWidget(clockWidget);
|
||||||
|
#else
|
||||||
|
auto webView = new QWebEngineView();
|
||||||
|
webView->load(QUrl("https://www.baidu.com"));
|
||||||
|
setCentralWidget(webView);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
loadStyleSheet(Dark);
|
||||||
|
|
||||||
|
setWindowTitle(tr("Example MainWindow"));
|
||||||
|
resize(800, 600);
|
||||||
|
|
||||||
|
// setFixedHeight(600);
|
||||||
|
// windowAgent->centralize();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void emulateLeaveEvent(QWidget *widget) {
|
||||||
|
Q_ASSERT(widget);
|
||||||
|
if (!widget) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QTimer::singleShot(0, widget, [widget]() {
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||||
|
const QScreen *screen = widget->screen();
|
||||||
|
#else
|
||||||
|
const QScreen *screen = widget->windowHandle()->screen();
|
||||||
|
#endif
|
||||||
|
const QPoint globalPos = QCursor::pos(screen);
|
||||||
|
if (!QRect(widget->mapToGlobal(QPoint{0, 0}), widget->size()).contains(globalPos)) {
|
||||||
|
QCoreApplication::postEvent(widget, new QEvent(QEvent::Leave));
|
||||||
|
if (widget->testAttribute(Qt::WA_Hover)) {
|
||||||
|
const QPoint localPos = widget->mapFromGlobal(globalPos);
|
||||||
|
const QPoint scenePos = widget->window()->mapFromGlobal(globalPos);
|
||||||
|
static constexpr const auto oldPos = QPoint{};
|
||||||
|
const Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
|
||||||
|
const auto event =
|
||||||
|
new QHoverEvent(QEvent::HoverLeave, scenePos, globalPos, oldPos, modifiers);
|
||||||
|
Q_UNUSED(localPos);
|
||||||
|
#elif (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
|
||||||
|
const auto event = new QHoverEvent(QEvent::HoverLeave, localPos, globalPos, oldPos, modifiers);
|
||||||
|
Q_UNUSED(scenePos);
|
||||||
|
#else
|
||||||
|
const auto event = new QHoverEvent(QEvent::HoverLeave, localPos, oldPos, modifiers);
|
||||||
|
Q_UNUSED(scenePos);
|
||||||
|
#endif
|
||||||
|
QCoreApplication::postEvent(widget, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow() = default;
|
||||||
|
|
||||||
|
bool MainWindow::event(QEvent *event) {
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::WindowActivate: {
|
||||||
|
auto menu = menuWidget();
|
||||||
|
if (menu) {
|
||||||
|
menu->setProperty("bar-active", true);
|
||||||
|
style()->polish(menu);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QEvent::WindowDeactivate: {
|
||||||
|
auto menu = menuWidget();
|
||||||
|
if (menu) {
|
||||||
|
menu->setProperty("bar-active", false);
|
||||||
|
style()->polish(menu);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QMainWindow::event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::installWindowAgent() {
|
||||||
|
// 1. Setup window agent
|
||||||
|
windowAgent = new QWK::WidgetWindowAgent(this);
|
||||||
|
windowAgent->setup(this);
|
||||||
|
|
||||||
|
// 2. Construct your title bar
|
||||||
|
auto menuBar = [this]() {
|
||||||
|
auto menuBar = new QMenuBar(this);
|
||||||
|
|
||||||
|
// Virtual menu
|
||||||
|
auto file = new QMenu(tr("File(&F)"), menuBar);
|
||||||
|
file->addAction(new QAction(tr("New(&N)"), menuBar));
|
||||||
|
file->addAction(new QAction(tr("Open(&O)"), menuBar));
|
||||||
|
file->addSeparator();
|
||||||
|
|
||||||
|
auto edit = new QMenu(tr("Edit(&E)"), menuBar);
|
||||||
|
edit->addAction(new QAction(tr("Undo(&U)"), menuBar));
|
||||||
|
edit->addAction(new QAction(tr("Redo(&R)"), menuBar));
|
||||||
|
|
||||||
|
// Theme action
|
||||||
|
auto darkAction = new QAction(tr("Enable dark theme"), menuBar);
|
||||||
|
darkAction->setCheckable(true);
|
||||||
|
connect(darkAction, &QAction::triggered, this, [this](bool checked) {
|
||||||
|
loadStyleSheet(checked ? Dark : Light); //
|
||||||
|
});
|
||||||
|
connect(this, &MainWindow::themeChanged, darkAction, [this, darkAction]() {
|
||||||
|
darkAction->setChecked(currentTheme == Dark); //
|
||||||
|
});
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
auto noneAction = new QAction(tr("None"), menuBar);
|
||||||
|
noneAction->setData(QStringLiteral("none"));
|
||||||
|
noneAction->setCheckable(true);
|
||||||
|
noneAction->setChecked(true);
|
||||||
|
|
||||||
|
auto dwmBlurAction = new QAction(tr("Enable DWM blur"), menuBar);
|
||||||
|
dwmBlurAction->setData(QStringLiteral("dwm-blur"));
|
||||||
|
dwmBlurAction->setCheckable(true);
|
||||||
|
|
||||||
|
auto acrylicAction = new QAction(tr("Enable acrylic material"), menuBar);
|
||||||
|
acrylicAction->setData(QStringLiteral("acrylic-material"));
|
||||||
|
acrylicAction->setCheckable(true);
|
||||||
|
|
||||||
|
auto micaAction = new QAction(tr("Enable mica"), menuBar);
|
||||||
|
micaAction->setData(QStringLiteral("mica"));
|
||||||
|
micaAction->setCheckable(true);
|
||||||
|
|
||||||
|
auto micaAltAction = new QAction(tr("Enable mica alt"), menuBar);
|
||||||
|
micaAltAction->setData(QStringLiteral("mica-alt"));
|
||||||
|
micaAltAction->setCheckable(true);
|
||||||
|
|
||||||
|
auto winStyleGroup = new QActionGroup(menuBar);
|
||||||
|
winStyleGroup->addAction(noneAction);
|
||||||
|
winStyleGroup->addAction(dwmBlurAction);
|
||||||
|
winStyleGroup->addAction(acrylicAction);
|
||||||
|
winStyleGroup->addAction(micaAction);
|
||||||
|
winStyleGroup->addAction(micaAltAction);
|
||||||
|
connect(winStyleGroup, &QActionGroup::triggered, this,
|
||||||
|
[this, winStyleGroup](QAction *action) {
|
||||||
|
// Unset all custom style attributes first, otherwise the style will not display
|
||||||
|
// correctly
|
||||||
|
for (const QAction *_act : winStyleGroup->actions()) {
|
||||||
|
const QString data = _act->data().toString();
|
||||||
|
if (data.isEmpty() || data == QStringLiteral("none")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
windowAgent->setWindowAttribute(data, false);
|
||||||
|
}
|
||||||
|
const QString data = action->data().toString();
|
||||||
|
if (data == QStringLiteral("none")) {
|
||||||
|
setProperty("custom-style", false);
|
||||||
|
} else if (!data.isEmpty()) {
|
||||||
|
windowAgent->setWindowAttribute(data, true);
|
||||||
|
setProperty("custom-style", true);
|
||||||
|
}
|
||||||
|
style()->polish(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
// Set whether to use system buttons (close/minimize/zoom)
|
||||||
|
// - true: Hide system buttons (use custom UI controls)
|
||||||
|
// - false: Show native system buttons (default behavior)
|
||||||
|
windowAgent->setWindowAttribute(QStringLiteral("no-system-buttons"), false);
|
||||||
|
|
||||||
|
auto darkBlurAction = new QAction(tr("Dark blur"), menuBar);
|
||||||
|
darkBlurAction->setCheckable(true);
|
||||||
|
connect(darkBlurAction, &QAction::toggled, this, [this](bool checked) {
|
||||||
|
if (!windowAgent->setWindowAttribute(QStringLiteral("blur-effect"), "dark")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (checked) {
|
||||||
|
setProperty("custom-style", true);
|
||||||
|
style()->polish(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto lightBlurAction = new QAction(tr("Light blur"), menuBar);
|
||||||
|
lightBlurAction->setCheckable(true);
|
||||||
|
connect(lightBlurAction, &QAction::toggled, this, [this](bool checked) {
|
||||||
|
if (!windowAgent->setWindowAttribute(QStringLiteral("blur-effect"), "light")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (checked) {
|
||||||
|
setProperty("custom-style", true);
|
||||||
|
style()->polish(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto noBlurAction = new QAction(tr("No blur"), menuBar);
|
||||||
|
noBlurAction->setCheckable(true);
|
||||||
|
connect(noBlurAction, &QAction::toggled, this, [this](bool checked) {
|
||||||
|
if (!windowAgent->setWindowAttribute(QStringLiteral("blur-effect"), "none")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (checked) {
|
||||||
|
setProperty("custom-style", false);
|
||||||
|
style()->polish(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto macStyleGroup = new QActionGroup(menuBar);
|
||||||
|
macStyleGroup->addAction(darkBlurAction);
|
||||||
|
macStyleGroup->addAction(lightBlurAction);
|
||||||
|
macStyleGroup->addAction(noBlurAction);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Real menu
|
||||||
|
auto settings = new QMenu(tr("Settings(&S)"), menuBar);
|
||||||
|
settings->addAction(darkAction);
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
settings->addSeparator();
|
||||||
|
settings->addAction(noneAction);
|
||||||
|
settings->addAction(dwmBlurAction);
|
||||||
|
settings->addAction(acrylicAction);
|
||||||
|
settings->addAction(micaAction);
|
||||||
|
settings->addAction(micaAltAction);
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
settings->addAction(darkBlurAction);
|
||||||
|
settings->addAction(lightBlurAction);
|
||||||
|
settings->addAction(noBlurAction);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
menuBar->addMenu(file);
|
||||||
|
menuBar->addMenu(edit);
|
||||||
|
menuBar->addMenu(settings);
|
||||||
|
return menuBar;
|
||||||
|
}();
|
||||||
|
menuBar->setObjectName(QStringLiteral("win-menu-bar"));
|
||||||
|
|
||||||
|
auto titleLabel = new QLabel();
|
||||||
|
titleLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
titleLabel->setObjectName(QStringLiteral("win-title-label"));
|
||||||
|
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
|
auto iconButton = new QWK::WindowButton();
|
||||||
|
iconButton->setObjectName(QStringLiteral("icon-button"));
|
||||||
|
iconButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||||
|
|
||||||
|
auto pinButton = new QWK::WindowButton();
|
||||||
|
pinButton->setCheckable(true);
|
||||||
|
pinButton->setObjectName(QStringLiteral("pin-button"));
|
||||||
|
pinButton->setProperty("system-button", true);
|
||||||
|
pinButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||||
|
|
||||||
|
auto minButton = new QWK::WindowButton();
|
||||||
|
minButton->setObjectName(QStringLiteral("min-button"));
|
||||||
|
minButton->setProperty("system-button", true);
|
||||||
|
minButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||||
|
|
||||||
|
auto maxButton = new QWK::WindowButton();
|
||||||
|
maxButton->setCheckable(true);
|
||||||
|
maxButton->setObjectName(QStringLiteral("max-button"));
|
||||||
|
maxButton->setProperty("system-button", true);
|
||||||
|
maxButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||||
|
|
||||||
|
auto closeButton = new QWK::WindowButton();
|
||||||
|
closeButton->setObjectName(QStringLiteral("close-button"));
|
||||||
|
closeButton->setProperty("system-button", true);
|
||||||
|
closeButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto windowBar = new QWK::WindowBar();
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
|
windowBar->setIconButton(iconButton);
|
||||||
|
windowBar->setPinButton(pinButton);
|
||||||
|
windowBar->setMinButton(minButton);
|
||||||
|
windowBar->setMaxButton(maxButton);
|
||||||
|
windowBar->setCloseButton(closeButton);
|
||||||
|
#endif
|
||||||
|
windowBar->setMenuBar(menuBar);
|
||||||
|
windowBar->setTitleLabel(titleLabel);
|
||||||
|
windowBar->setHostWidget(this);
|
||||||
|
|
||||||
|
windowAgent->setTitleBar(windowBar);
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
|
windowAgent->setHitTestVisible(pinButton, true);
|
||||||
|
windowAgent->setSystemButton(QWK::WindowAgentBase::WindowIcon, iconButton);
|
||||||
|
windowAgent->setSystemButton(QWK::WindowAgentBase::Minimize, minButton);
|
||||||
|
windowAgent->setSystemButton(QWK::WindowAgentBase::Maximize, maxButton);
|
||||||
|
windowAgent->setSystemButton(QWK::WindowAgentBase::Close, closeButton);
|
||||||
|
#endif
|
||||||
|
windowAgent->setHitTestVisible(menuBar, true);
|
||||||
|
|
||||||
|
#if defined(Q_OS_MAC) && 0
|
||||||
|
windowAgent->setSystemButtonAreaCallback([](const QSize &size) {
|
||||||
|
static constexpr const int width = 75;
|
||||||
|
return QRect(QPoint(size.width() - width, 0), QSize(width, size.height())); //
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setMenuWidget(windowBar);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
|
connect(windowBar, &QWK::WindowBar::pinRequested, this, [this, pinButton](bool pin) {
|
||||||
|
if (isHidden() || isMinimized() || isMaximized() || isFullScreen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setWindowFlag(Qt::WindowStaysOnTopHint, pin);
|
||||||
|
show();
|
||||||
|
pinButton->setChecked(pin);
|
||||||
|
});
|
||||||
|
connect(windowBar, &QWK::WindowBar::minimizeRequested, this, &QWidget::showMinimized);
|
||||||
|
connect(windowBar, &QWK::WindowBar::maximizeRequested, this, [this, maxButton](bool max) {
|
||||||
|
if (max) {
|
||||||
|
showMaximized();
|
||||||
|
} else {
|
||||||
|
showNormal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's a Qt issue that if a QAbstractButton::clicked triggers a window's maximization,
|
||||||
|
// the button remains to be hovered until the mouse move. As a result, we need to
|
||||||
|
// manually send leave events to the button.
|
||||||
|
emulateLeaveEvent(maxButton);
|
||||||
|
});
|
||||||
|
connect(windowBar, &QWK::WindowBar::closeRequested, this, &QWidget::close);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::loadStyleSheet(Theme theme) {
|
||||||
|
if (!styleSheet().isEmpty() && theme == currentTheme)
|
||||||
|
return;
|
||||||
|
currentTheme = theme;
|
||||||
|
|
||||||
|
if (QFile qss(theme == Dark ? QStringLiteral(":/dark-style.qss")
|
||||||
|
: QStringLiteral(":/light-style.qss"));
|
||||||
|
qss.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
setStyleSheet(QString::fromUtf8(qss.readAll()));
|
||||||
|
Q_EMIT themeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
42
libs/qwindowkit/examples/mainwindow/mainwindow.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QtWidgets/QMainWindow>
|
||||||
|
|
||||||
|
namespace QWK {
|
||||||
|
class WidgetWindowAgent;
|
||||||
|
class StyleAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget *parent = nullptr);
|
||||||
|
~MainWindow() override;
|
||||||
|
|
||||||
|
enum Theme {
|
||||||
|
Dark,
|
||||||
|
Light,
|
||||||
|
};
|
||||||
|
Q_ENUM(Theme)
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void themeChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool event(QEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void installWindowAgent();
|
||||||
|
void loadStyleSheet(Theme theme);
|
||||||
|
|
||||||
|
Theme currentTheme{};
|
||||||
|
|
||||||
|
QWK::WidgetWindowAgent *windowAgent;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
||||||
6
libs/qwindowkit/examples/mainwindow/mainwindow.qrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>dark-style.qss</file>
|
||||||
|
<file>light-style.qss</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
10
libs/qwindowkit/examples/qml/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
project(QWKExample_QML)
|
||||||
|
|
||||||
|
file(GLOB _src *.h *.cpp *.qrc)
|
||||||
|
|
||||||
|
qwk_add_example(${PROJECT_NAME}
|
||||||
|
FEATURES cxx_std_17
|
||||||
|
SOURCES ${_src} ../shared/resources/shared.qrc
|
||||||
|
QT_LINKS Core Gui Qml Quick
|
||||||
|
LINKS QWKQuick
|
||||||
|
)
|
||||||
260
libs/qwindowkit/examples/qml/FramelessWindow.qml
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Window 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import Qt.labs.platform 1.1
|
||||||
|
import QWindowKit 1.0
|
||||||
|
|
||||||
|
Window {
|
||||||
|
property bool showWhenReady: true
|
||||||
|
property alias titleBar: titleBar
|
||||||
|
|
||||||
|
id: window
|
||||||
|
width: 800
|
||||||
|
height: 600
|
||||||
|
color: darkStyle.windowBackgroundColor
|
||||||
|
title: qsTr("QWindowKit QtQuick Demo")
|
||||||
|
Component.onCompleted: {
|
||||||
|
windowAgent.setup(window)
|
||||||
|
windowAgent.setWindowAttribute("dark-mode", true)
|
||||||
|
if (window.showWhenReady) {
|
||||||
|
window.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: lightStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: darkStyle
|
||||||
|
readonly property color windowBackgroundColor: "#1E1E1E"
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 100
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: timeLabel.text = Qt.formatTime(new Date(), "hh:mm:ss")
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowAgent {
|
||||||
|
id: windowAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
onTapped: contextMenu.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: titleBar
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
height: 32
|
||||||
|
//color: window.active ? "#3C3C3C" : "#505050"
|
||||||
|
color: "transparent"
|
||||||
|
Component.onCompleted: windowAgent.setTitleBar(titleBar)
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: iconButton
|
||||||
|
anchors {
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: 10
|
||||||
|
}
|
||||||
|
width: 18
|
||||||
|
height: 18
|
||||||
|
mipmap: true
|
||||||
|
source: "qrc:///app/example.png"
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
Component.onCompleted: windowAgent.setSystemButton(WindowAgent.WindowIcon, iconButton)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors {
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
left: iconButton.right
|
||||||
|
leftMargin: 10
|
||||||
|
}
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
text: window.title
|
||||||
|
font.pixelSize: 14
|
||||||
|
color: "#ECECEC"
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
height: parent.height
|
||||||
|
|
||||||
|
QWKButton {
|
||||||
|
id: minButton
|
||||||
|
height: parent.height
|
||||||
|
source: "qrc:///window-bar/minimize.svg"
|
||||||
|
onClicked: window.showMinimized()
|
||||||
|
Component.onCompleted: windowAgent.setSystemButton(WindowAgent.Minimize, minButton)
|
||||||
|
}
|
||||||
|
|
||||||
|
QWKButton {
|
||||||
|
id: maxButton
|
||||||
|
height: parent.height
|
||||||
|
source: window.visibility === Window.Maximized ? "qrc:///window-bar/restore.svg" : "qrc:///window-bar/maximize.svg"
|
||||||
|
onClicked: {
|
||||||
|
if (window.visibility === Window.Maximized) {
|
||||||
|
window.showNormal()
|
||||||
|
} else {
|
||||||
|
window.showMaximized()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component.onCompleted: windowAgent.setSystemButton(WindowAgent.Maximize, maxButton)
|
||||||
|
}
|
||||||
|
|
||||||
|
QWKButton {
|
||||||
|
id: closeButton
|
||||||
|
height: parent.height
|
||||||
|
source: "qrc:///window-bar/close.svg"
|
||||||
|
background: Rectangle {
|
||||||
|
color: {
|
||||||
|
if (!closeButton.enabled) {
|
||||||
|
return "gray";
|
||||||
|
}
|
||||||
|
if (closeButton.pressed) {
|
||||||
|
return "#e81123";
|
||||||
|
}
|
||||||
|
if (closeButton.hovered) {
|
||||||
|
return "#e81123";
|
||||||
|
}
|
||||||
|
return "transparent";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onClicked: window.close()
|
||||||
|
Component.onCompleted: windowAgent.setSystemButton(WindowAgent.Close, closeButton)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: timeLabel
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font {
|
||||||
|
pointSize: 75
|
||||||
|
bold: true
|
||||||
|
}
|
||||||
|
color: "#FEFEFE"
|
||||||
|
Component.onCompleted: {
|
||||||
|
if ($curveRenderingAvailable) {
|
||||||
|
console.log("Curve rendering for text is available.")
|
||||||
|
timeLabel.renderType = Text.CurveRendering
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: contextMenu
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: themeMenu
|
||||||
|
title: qsTr("Theme")
|
||||||
|
|
||||||
|
MenuItemGroup {
|
||||||
|
id: themeMenuGroup
|
||||||
|
items: themeMenu.items
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Light")
|
||||||
|
checkable: true
|
||||||
|
onTriggered: windowAgent.setWindowAttribute("dark-mode", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Dark")
|
||||||
|
checkable: true
|
||||||
|
checked: true
|
||||||
|
onTriggered: windowAgent.setWindowAttribute("dark-mode", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: specialEffectMenu
|
||||||
|
title: qsTr("Special effect")
|
||||||
|
|
||||||
|
MenuItemGroup {
|
||||||
|
id: specialEffectMenuGroup
|
||||||
|
items: specialEffectMenu.items
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
enabled: Qt.platform.os === "windows"
|
||||||
|
text: qsTr("None")
|
||||||
|
checkable: true
|
||||||
|
checked: true
|
||||||
|
onTriggered: {
|
||||||
|
window.color = darkStyle.windowBackgroundColor
|
||||||
|
windowAgent.setWindowAttribute("dwm-blur", false)
|
||||||
|
windowAgent.setWindowAttribute("acrylic-material", false)
|
||||||
|
windowAgent.setWindowAttribute("mica", false)
|
||||||
|
windowAgent.setWindowAttribute("mica-alt", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
enabled: Qt.platform.os === "windows"
|
||||||
|
text: qsTr("DWM blur")
|
||||||
|
checkable: true
|
||||||
|
onTriggered: {
|
||||||
|
window.color = "transparent"
|
||||||
|
windowAgent.setWindowAttribute("acrylic-material", false)
|
||||||
|
windowAgent.setWindowAttribute("mica", false)
|
||||||
|
windowAgent.setWindowAttribute("mica-alt", false)
|
||||||
|
windowAgent.setWindowAttribute("dwm-blur", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
enabled: Qt.platform.os === "windows"
|
||||||
|
text: qsTr("Acrylic material")
|
||||||
|
checkable: true
|
||||||
|
onTriggered: {
|
||||||
|
window.color = "transparent"
|
||||||
|
windowAgent.setWindowAttribute("dwm-blur", false)
|
||||||
|
windowAgent.setWindowAttribute("mica", false)
|
||||||
|
windowAgent.setWindowAttribute("mica-alt", false)
|
||||||
|
windowAgent.setWindowAttribute("acrylic-material", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
enabled: Qt.platform.os === "windows"
|
||||||
|
text: qsTr("Mica")
|
||||||
|
checkable: true
|
||||||
|
onTriggered: {
|
||||||
|
window.color = "transparent"
|
||||||
|
windowAgent.setWindowAttribute("dwm-blur", false)
|
||||||
|
windowAgent.setWindowAttribute("acrylic-material", false)
|
||||||
|
windowAgent.setWindowAttribute("mica-alt", false)
|
||||||
|
windowAgent.setWindowAttribute("mica", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
enabled: Qt.platform.os === "windows"
|
||||||
|
text: qsTr("Mica Alt")
|
||||||
|
checkable: true
|
||||||
|
onTriggered: {
|
||||||
|
window.color = "transparent"
|
||||||
|
windowAgent.setWindowAttribute("dwm-blur", false)
|
||||||
|
windowAgent.setWindowAttribute("acrylic-material", false)
|
||||||
|
windowAgent.setWindowAttribute("mica", false)
|
||||||
|
windowAgent.setWindowAttribute("mica-alt", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
libs/qwindowkit/examples/qml/QWKButton.qml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: root
|
||||||
|
width: height * 1.5
|
||||||
|
leftPadding: 0
|
||||||
|
topPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
bottomPadding: 0
|
||||||
|
leftInset: 0
|
||||||
|
topInset: 0
|
||||||
|
rightInset: 0
|
||||||
|
bottomInset: 0
|
||||||
|
property alias source: image.source
|
||||||
|
contentItem: Item {
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
anchors.centerIn: parent
|
||||||
|
mipmap: true
|
||||||
|
width: 12
|
||||||
|
height: 12
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: {
|
||||||
|
if (!root.enabled) {
|
||||||
|
return "gray";
|
||||||
|
}
|
||||||
|
if (root.pressed) {
|
||||||
|
return Qt.rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
if (root.hovered) {
|
||||||
|
return Qt.rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
return "transparent";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
libs/qwindowkit/examples/qml/main.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include <QtGui/QGuiApplication>
|
||||||
|
#include <QtQml/QQmlApplicationEngine>
|
||||||
|
#include <QtQml/QQmlContext>
|
||||||
|
#include <QtQuick/QQuickWindow>
|
||||||
|
|
||||||
|
#include <QWKQuick/qwkquickglobal.h>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// Indicates to hybrid graphics systems to prefer the discrete part by default.
|
||||||
|
extern "C" {
|
||||||
|
Q_DECL_EXPORT unsigned long NvOptimusEnablement = 0x00000001;
|
||||||
|
Q_DECL_EXPORT int AmdPowerXpressRequestHighPerformance = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
qputenv("QT_WIN_DEBUG_CONSOLE", "attach"); // or "new": create a separate console window
|
||||||
|
qputenv("QSG_INFO", "1");
|
||||||
|
qputenv("QSG_NO_VSYNC", "1");
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
qputenv("QT_QUICK_CONTROLS_STYLE", "Basic");
|
||||||
|
#else
|
||||||
|
qputenv("QT_QUICK_CONTROLS_STYLE", "Default");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
qputenv("QSG_RHI_BACKEND", "d3d11"); // options: d3d11, d3d12, opengl, vulkan
|
||||||
|
qputenv("QT_QPA_DISABLE_REDIRECTION_SURFACE", "1");
|
||||||
|
#endif
|
||||||
|
//qputenv("QSG_RHI_HDR", "scrgb"); // other options: hdr10, p3
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
|
||||||
|
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||||
|
#endif
|
||||||
|
QGuiApplication application(argc, argv);
|
||||||
|
// Make sure alpha channel is requested, our special effects on Windows depends on it.
|
||||||
|
QQuickWindow::setDefaultAlphaBuffer(true);
|
||||||
|
QQmlApplicationEngine engine;
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
||||||
|
const bool curveRenderingAvailable = true;
|
||||||
|
#else
|
||||||
|
const bool curveRenderingAvailable = false;
|
||||||
|
#endif
|
||||||
|
engine.rootContext()->setContextProperty(QStringLiteral("$curveRenderingAvailable"), QVariant(curveRenderingAvailable));
|
||||||
|
QWK::registerTypes(&engine);
|
||||||
|
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
|
||||||
|
return application.exec();
|
||||||
|
}
|
||||||
42
libs/qwindowkit/examples/qml/main.qml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Window 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
FramelessWindow {
|
||||||
|
property FramelessWindow childWindow: FramelessWindow {
|
||||||
|
showWhenReady: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Drawer {
|
||||||
|
id: drawer
|
||||||
|
width: 0.66 * parent.width
|
||||||
|
height: parent.height
|
||||||
|
edge: Qt.RightEdge
|
||||||
|
onAboutToShow: titleBar.enabled = false
|
||||||
|
onAboutToHide: titleBar.enabled = true
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Content goes here!"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
bottom: parent.bottom
|
||||||
|
bottomMargin: 20
|
||||||
|
}
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Open Child Window")
|
||||||
|
onClicked: childWindow.visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Open Drawer")
|
||||||
|
onClicked: drawer.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
libs/qwindowkit/examples/qml/qml.qrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>main.qml</file>
|
||||||
|
<file>QWKButton.qml</file>
|
||||||
|
<file>FramelessWindow.qml</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
1
libs/qwindowkit/examples/shared/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
add_subdirectory(widgetframe)
|
||||||
BIN
libs/qwindowkit/examples/shared/resources/app/example.icns
Normal file
BIN
libs/qwindowkit/examples/shared/resources/app/example.ico
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
libs/qwindowkit/examples/shared/resources/app/example.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
13
libs/qwindowkit/examples/shared/resources/shared.qrc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>window-bar/close.svg</file>
|
||||||
|
<file>window-bar/fullscreen.svg</file>
|
||||||
|
<file>window-bar/maximize.svg</file>
|
||||||
|
<file>window-bar/minimize.svg</file>
|
||||||
|
<file>window-bar/restore.svg</file>
|
||||||
|
<file>window-bar/more-line.svg</file>
|
||||||
|
<file>window-bar/pin.svg</file>
|
||||||
|
<file>window-bar/pin-fill.svg</file>
|
||||||
|
<file>app/example.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" width="10.88" height="10.88"
|
||||||
|
viewBox="0 0 10.88 10.88">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: none;
|
||||||
|
stroke: white;
|
||||||
|
stroke-miterlimit: 10;
|
||||||
|
stroke-width: 1.25px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<line class="cls-1" x1="0.44" y1="0.44" x2="10.44" y2="10.44" />
|
||||||
|
<line class="cls-1" x1="0.44" y1="10.44" x2="10.44" y2="0.44" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 444 B |
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1594017175519"
|
||||||
|
class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1933"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16">
|
||||||
|
<defs>
|
||||||
|
<style type="text/css"></style>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
d="M874.666667 128h-170.666667a21.333333 21.333333 0 0 0 0 42.666667h119.168l-176.917333 176.917333a21.333333 21.333333 0 1 0 30.165333 30.165333L853.333333 200.832V320a21.333333 21.333333 0 0 0 42.666667 0V149.333333a21.333333 21.333333 0 0 0-21.333333-21.333333zM347.584 646.250667L170.666667 823.168V704a21.333333 21.333333 0 0 0-42.666667 0v170.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h170.666667a21.333333 21.333333 0 0 0 0-42.666667H200.832l176.917333-176.917333a21.333333 21.333333 0 0 0-30.165333-30.165333zM874.666667 682.666667a21.333333 21.333333 0 0 0-21.333334 21.333333v119.168l-176.917333-176.917333a21.333333 21.333333 0 0 0-30.165333 30.165333L823.168 853.333333H704a21.333333 21.333333 0 0 0 0 42.666667h170.666667a21.333333 21.333333 0 0 0 21.333333-21.333333v-170.666667a21.333333 21.333333 0 0 0-21.333333-21.333333zM200.832 170.666667H320a21.333333 21.333333 0 0 0 0-42.666667H149.333333a21.333333 21.333333 0 0 0-21.333333 21.333333v170.666667a21.333333 21.333333 0 0 0 42.666667 0V200.832l176.917333 176.917333a21.333333 21.333333 0 0 0 30.165333-30.165333z"
|
||||||
|
fill="#ffffff" p-id="1934"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,12 @@
|
|||||||
|
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: none;
|
||||||
|
stroke: white;
|
||||||
|
stroke-miterlimit: 10;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<rect class="cls-1" x="0.5" y="0.5" width="9" height="9" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 328 B |
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||||
|
y="0px" viewBox="0 0 10 10" style="enable-background:new 0 0 10 10;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0 {
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<rect y="4.5" class="st0" width="10" height="1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 467 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||||
|
<path fill="none" d="M0 0h24v24H0z" />
|
||||||
|
<path fill="white"
|
||||||
|
d="M4.5 10.5c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5S6 12.825 6 12s-.675-1.5-1.5-1.5zm15 0c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5S21 12.825 21 12s-.675-1.5-1.5-1.5zm-7.5 0c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5 1.5-.675 1.5-1.5-.675-1.5-1.5-1.5z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 419 B |
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg t="1735286082742" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" p-id="2501" width="512" height="512"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<path
|
||||||
|
d="M648.728381 130.779429a73.142857 73.142857 0 0 1 22.674286 15.433142l191.561143 191.756191a73.142857 73.142857 0 0 1-22.137905 118.564571l-67.876572 30.061715-127.341714 127.488-10.093714 140.239238a73.142857 73.142857 0 0 1-124.684191 46.445714l-123.66019-123.782095-210.724572 211.699809-51.833904-51.614476 210.846476-211.821714-127.926857-128.024381a73.142857 73.142857 0 0 1 46.299428-124.635429l144.237715-10.776381 125.074285-125.220571 29.379048-67.779048a73.142857 73.142857 0 0 1 96.207238-38.034285z"
|
||||||
|
p-id="2502" fill="white"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 932 B |
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg t="1735285955420" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" p-id="2053" width="512" height="512"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<path
|
||||||
|
d="M648.728381 130.779429a73.142857 73.142857 0 0 1 22.674286 15.433142l191.561143 191.756191a73.142857 73.142857 0 0 1-22.137905 118.564571l-67.876572 30.061715-127.341714 127.488-10.093714 140.239238a73.142857 73.142857 0 0 1-124.684191 46.445714l-123.66019-123.782095-210.724572 211.699809-51.833904-51.614476 210.846476-211.821714-127.926857-128.024381a73.142857 73.142857 0 0 1 46.299428-124.635429l144.237715-10.776381 125.074285-125.220571 29.379048-67.779048a73.142857 73.142857 0 0 1 96.207238-38.034285z m-29.086476 67.120761l-34.913524 80.530286-154.087619 154.331429-171.398095 12.751238 303.323428 303.542857 12.044191-167.399619 156.233143-156.428191 80.384-35.59619-191.585524-191.73181z"
|
||||||
|
p-id="2054" fill="white"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,16 @@
|
|||||||
|
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: none;
|
||||||
|
stroke: white;
|
||||||
|
stroke-miterlimit: 10;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<rect class="cls-1" x="0.5" y="2.5" width="9" height="9" />
|
||||||
|
<line class="cls-1" x1="2.5" y1="2.5" x2="2.5" y2="0.5" />
|
||||||
|
<line class="cls-1" x1="12" y1="0.5" x2="2" y2="0.5" />
|
||||||
|
<line class="cls-1" x1="11.5" y1="10" x2="11.5" />
|
||||||
|
<line class="cls-1" x1="10" y1="9.5" x2="12" y2="9.5" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 559 B |
17
libs/qwindowkit/examples/shared/widgetframe/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
project(WidgetFrame)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
|
file(GLOB _src *.h *.cpp)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} STATIC)
|
||||||
|
|
||||||
|
qm_configure_target(${PROJECT_NAME}
|
||||||
|
FEATURES cxx_std_17
|
||||||
|
SOURCES ${_src}
|
||||||
|
QT_LINKS Core Gui Widgets
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC . ..)
|
||||||
408
libs/qwindowkit/examples/shared/widgetframe/windowbar.cpp
Normal file
@@ -0,0 +1,408 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include "windowbar.h"
|
||||||
|
#include "windowbar_p.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtCore/QLocale>
|
||||||
|
#include <QtGui/QtEvents>
|
||||||
|
|
||||||
|
namespace QWK {
|
||||||
|
|
||||||
|
WindowBarPrivate::WindowBarPrivate() {
|
||||||
|
w = nullptr;
|
||||||
|
autoTitle = true;
|
||||||
|
autoIcon = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowBarPrivate::~WindowBarPrivate() = default;
|
||||||
|
|
||||||
|
void WindowBarPrivate::init() {
|
||||||
|
Q_Q(WindowBar);
|
||||||
|
layout = new QHBoxLayout();
|
||||||
|
if (QLocale::system().textDirection() == Qt::RightToLeft) {
|
||||||
|
layout->setDirection(QBoxLayout::RightToLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
layout->setSpacing(0);
|
||||||
|
for (int i = IconButton; i <= CloseButton; ++i) {
|
||||||
|
insertDefaultSpace(i);
|
||||||
|
}
|
||||||
|
q->setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBarPrivate::setWidgetAt(int index, QWidget *widget) {
|
||||||
|
auto item = layout->takeAt(index);
|
||||||
|
auto orgWidget = item->widget();
|
||||||
|
if (orgWidget) {
|
||||||
|
orgWidget->deleteLater();
|
||||||
|
}
|
||||||
|
delete item;
|
||||||
|
if (!widget) {
|
||||||
|
insertDefaultSpace(index);
|
||||||
|
} else {
|
||||||
|
layout->insertWidget(index, widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *WindowBarPrivate::takeWidgetAt(int index) {
|
||||||
|
auto item = layout->itemAt(index);
|
||||||
|
auto orgWidget = item->widget();
|
||||||
|
if (orgWidget) {
|
||||||
|
item = layout->takeAt(index);
|
||||||
|
delete item;
|
||||||
|
insertDefaultSpace(index);
|
||||||
|
}
|
||||||
|
return orgWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowBar::WindowBar(QWidget *parent) : WindowBar(*new WindowBarPrivate(), parent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowBar::~WindowBar() = default;
|
||||||
|
|
||||||
|
QMenuBar *WindowBar::menuBar() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QMenuBar *>(d->widgetAt(WindowBarPrivate::MenuWidget));
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel *WindowBar::titleLabel() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QLabel *>(d->widgetAt(WindowBarPrivate::TitleLabel));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::iconButton() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::IconButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::backButton() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::BackButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::homeButton() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::HomeButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::favButton() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::FavButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *WindowBar::centerWidget() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return d->widgetAt(WindowBarPrivate::CenterWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::pinButton() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::PinButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::minButton() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::MinimizeButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::maxButton() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::MaximizeButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::closeButton() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::CloseButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setMenuBar(QMenuBar *menuBar) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeMenuBar();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!menuBar)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::MenuWidget, menuBar);
|
||||||
|
menuBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setTitleLabel(QLabel *label) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeTitleLabel();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!label)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::TitleLabel, label);
|
||||||
|
if (d->autoTitle && d->w)
|
||||||
|
label->setText(d->w->windowTitle());
|
||||||
|
label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setIconButton(QAbstractButton *btn) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeIconButton();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!btn)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::IconButton, btn);
|
||||||
|
if (d->autoIcon && d->w)
|
||||||
|
btn->setIcon(d->w->windowIcon());
|
||||||
|
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setBackButton(QAbstractButton *btn) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeBackButton();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!btn)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::BackButton, btn);
|
||||||
|
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setHomeButton(QAbstractButton *btn) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeHomeButton();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!btn)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::HomeButton, btn);
|
||||||
|
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setFavButton(QAbstractButton *btn) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeFavButton();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!btn)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::FavButton, btn);
|
||||||
|
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setCenterWidget(QWidget *widget) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeCenterWidget();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::CenterWidget, widget);
|
||||||
|
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setPinButton(QAbstractButton *btn) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takePinButton();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!btn)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::PinButton, btn);
|
||||||
|
connect(btn, &QAbstractButton::clicked, this, &WindowBar::pinRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setMinButton(QAbstractButton *btn) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeMinButton();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!btn)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::MinimizeButton, btn);
|
||||||
|
connect(btn, &QAbstractButton::clicked, this, &WindowBar::minimizeRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setMaxButton(QAbstractButton *btn) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeMaxButton();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!btn)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::MaximizeButton, btn);
|
||||||
|
connect(btn, &QAbstractButton::clicked, this, &WindowBar::maximizeRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setCloseButton(QAbstractButton *btn) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto org = takeCloseButton();
|
||||||
|
if (org)
|
||||||
|
org->deleteLater();
|
||||||
|
if (!btn)
|
||||||
|
return;
|
||||||
|
d->setWidgetAt(WindowBarPrivate::CloseButton, btn);
|
||||||
|
connect(btn, &QAbstractButton::clicked, this, &WindowBar::closeRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenuBar *WindowBar::takeMenuBar() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
return static_cast<QMenuBar *>(d->takeWidgetAt(WindowBarPrivate::MenuWidget));
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel *WindowBar::takeTitleLabel() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
return static_cast<QLabel *>(d->takeWidgetAt(WindowBarPrivate::TitleLabel));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::takeIconButton() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::IconButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::takeBackButton() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::BackButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::takeHomeButton() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::HomeButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::takeFavButton() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
return static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::FavButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *WindowBar::takeCenterWidget() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
return d->takeWidgetAt(WindowBarPrivate::CenterWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::takePinButton() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto btn = static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::PinButton));
|
||||||
|
if (!btn) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::pinRequested);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::takeMinButton() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto btn = static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::MinimizeButton));
|
||||||
|
if (!btn) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::minimizeRequested);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::takeMaxButton() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto btn = static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::MaximizeButton));
|
||||||
|
if (!btn) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::maximizeRequested);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton *WindowBar::takeCloseButton() {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto btn = static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::CloseButton));
|
||||||
|
if (!btn) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::closeRequested);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *WindowBar::hostWidget() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return d->w;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setHostWidget(QWidget *w) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
|
||||||
|
QWidget *org = d->w;
|
||||||
|
if (org) {
|
||||||
|
org->removeEventFilter(this);
|
||||||
|
}
|
||||||
|
d_ptr->w = w;
|
||||||
|
if (w) {
|
||||||
|
w->installEventFilter(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowBar::titleFollowWindow() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return d->autoTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setTitleFollowWindow(bool value) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
d->autoTitle = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowBar::iconFollowWindow() const {
|
||||||
|
Q_D(const WindowBar);
|
||||||
|
return d->autoIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::setIconFollowWindow(bool value) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
d->autoIcon = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowBar::eventFilter(QObject *obj, QEvent *event) {
|
||||||
|
Q_D(WindowBar);
|
||||||
|
auto w = d->w;
|
||||||
|
if (obj == w) {
|
||||||
|
QAbstractButton *iconBtn = iconButton();
|
||||||
|
QLabel *label = titleLabel();
|
||||||
|
QAbstractButton *maxBtn = maxButton();
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::WindowIconChange: {
|
||||||
|
if (d_ptr->autoIcon && iconBtn) {
|
||||||
|
iconBtn->setIcon(w->windowIcon());
|
||||||
|
iconChanged(w->windowIcon());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::WindowTitleChange: {
|
||||||
|
if (d_ptr->autoTitle && label) {
|
||||||
|
label->setText(w->windowTitle());
|
||||||
|
titleChanged(w->windowTitle());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::WindowStateChange: {
|
||||||
|
if (maxBtn) {
|
||||||
|
maxBtn->setChecked(w->isMaximized());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QWidget::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::titleChanged(const QString &text) {
|
||||||
|
Q_UNUSED(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBar::iconChanged(const QIcon &icon){Q_UNUSED(icon)}
|
||||||
|
|
||||||
|
WindowBar::WindowBar(WindowBarPrivate &d, QWidget *parent)
|
||||||
|
: QFrame(parent), d_ptr(&d) {
|
||||||
|
d.q_ptr = this;
|
||||||
|
|
||||||
|
d.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
91
libs/qwindowkit/examples/shared/widgetframe/windowbar.h
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#ifndef WINDOWBAR_H
|
||||||
|
#define WINDOWBAR_H
|
||||||
|
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QAbstractButton>
|
||||||
|
#include <QMenuBar>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace QWK {
|
||||||
|
|
||||||
|
class WindowBarPrivate;
|
||||||
|
|
||||||
|
class WindowBar : public QFrame {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DECLARE_PRIVATE(WindowBar)
|
||||||
|
public:
|
||||||
|
explicit WindowBar(QWidget *parent = nullptr);
|
||||||
|
~WindowBar();
|
||||||
|
|
||||||
|
public:
|
||||||
|
QMenuBar *menuBar() const;
|
||||||
|
QLabel *titleLabel() const;
|
||||||
|
QAbstractButton *iconButton() const;
|
||||||
|
QAbstractButton *backButton() const;
|
||||||
|
QAbstractButton *homeButton() const;
|
||||||
|
QAbstractButton *favButton() const;
|
||||||
|
QWidget *centerWidget() const;
|
||||||
|
QAbstractButton *pinButton() const;
|
||||||
|
QAbstractButton *minButton() const;
|
||||||
|
QAbstractButton *maxButton() const;
|
||||||
|
QAbstractButton *closeButton() const;
|
||||||
|
|
||||||
|
void setMenuBar(QMenuBar *menuBar);
|
||||||
|
void setTitleLabel(QLabel *label);
|
||||||
|
void setIconButton(QAbstractButton *btn);
|
||||||
|
void setBackButton(QAbstractButton *btn);
|
||||||
|
void setHomeButton(QAbstractButton *btn);
|
||||||
|
void setFavButton(QAbstractButton *btn);
|
||||||
|
void setCenterWidget(QWidget *widget);
|
||||||
|
void setPinButton(QAbstractButton *btn);
|
||||||
|
void setMinButton(QAbstractButton *btn);
|
||||||
|
void setMaxButton(QAbstractButton *btn);
|
||||||
|
void setCloseButton(QAbstractButton *btn);
|
||||||
|
|
||||||
|
QMenuBar *takeMenuBar();
|
||||||
|
QLabel *takeTitleLabel();
|
||||||
|
QAbstractButton *takeIconButton();
|
||||||
|
QAbstractButton *takeBackButton();
|
||||||
|
QAbstractButton *takeHomeButton();
|
||||||
|
QAbstractButton *takeFavButton();
|
||||||
|
QWidget *takeCenterWidget();
|
||||||
|
QAbstractButton *takePinButton();
|
||||||
|
QAbstractButton *takeMinButton();
|
||||||
|
QAbstractButton *takeMaxButton();
|
||||||
|
QAbstractButton *takeCloseButton();
|
||||||
|
|
||||||
|
QWidget *hostWidget() const;
|
||||||
|
void setHostWidget(QWidget *w);
|
||||||
|
|
||||||
|
bool titleFollowWindow() const;
|
||||||
|
void setTitleFollowWindow(bool value);
|
||||||
|
|
||||||
|
bool iconFollowWindow() const;
|
||||||
|
void setIconFollowWindow(bool value);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void pinRequested(bool pin = false);
|
||||||
|
void minimizeRequested();
|
||||||
|
void maximizeRequested(bool max = false);
|
||||||
|
void closeRequested();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
|
virtual void titleChanged(const QString &text);
|
||||||
|
virtual void iconChanged(const QIcon &icon);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
WindowBar(WindowBarPrivate &d, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
QScopedPointer<WindowBarPrivate> d_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WINDOWBAR_H
|
||||||
62
libs/qwindowkit/examples/shared/widgetframe/windowbar_p.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#ifndef WINDOWBARPRIVATE_H
|
||||||
|
#define WINDOWBARPRIVATE_H
|
||||||
|
|
||||||
|
#include <QBoxLayout>
|
||||||
|
|
||||||
|
#include "windowbar.h"
|
||||||
|
|
||||||
|
namespace QWK {
|
||||||
|
|
||||||
|
class WindowBarPrivate {
|
||||||
|
Q_DECLARE_PUBLIC(WindowBar)
|
||||||
|
public:
|
||||||
|
WindowBarPrivate();
|
||||||
|
virtual ~WindowBarPrivate();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
WindowBar *q_ptr;
|
||||||
|
|
||||||
|
QWidget *w;
|
||||||
|
bool autoTitle;
|
||||||
|
bool autoIcon;
|
||||||
|
|
||||||
|
enum WindowBarItem {
|
||||||
|
IconButton,
|
||||||
|
MenuWidget,
|
||||||
|
TitleLabel,
|
||||||
|
BackButton,
|
||||||
|
HomeButton,
|
||||||
|
FavButton,
|
||||||
|
CenterWidget,
|
||||||
|
PinButton,
|
||||||
|
MinimizeButton,
|
||||||
|
MaximizeButton,
|
||||||
|
CloseButton,
|
||||||
|
};
|
||||||
|
|
||||||
|
QHBoxLayout *layout;
|
||||||
|
|
||||||
|
inline QWidget *widgetAt(int index) const {
|
||||||
|
return layout->itemAt(index)->widget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWidgetAt(int index, QWidget *widget);
|
||||||
|
|
||||||
|
QWidget *takeWidgetAt(int index);
|
||||||
|
|
||||||
|
inline void insertDefaultSpace(int index) {
|
||||||
|
layout->insertSpacerItem(index, new QSpacerItem(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(WindowBarPrivate)
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WINDOWBARPRIVATE_H
|
||||||
94
libs/qwindowkit/examples/shared/widgetframe/windowbutton.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include "windowbutton.h"
|
||||||
|
#include "windowbutton_p.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtGui/QtEvents>
|
||||||
|
|
||||||
|
namespace QWK {
|
||||||
|
|
||||||
|
WindowButtonPrivate::WindowButtonPrivate() = default;
|
||||||
|
|
||||||
|
WindowButtonPrivate::~WindowButtonPrivate() = default;
|
||||||
|
|
||||||
|
void WindowButtonPrivate::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowButtonPrivate::reloadIcon() {
|
||||||
|
Q_Q(WindowButton);
|
||||||
|
|
||||||
|
if (!q->isEnabled() && !iconDisabled.isNull()) {
|
||||||
|
q->setIcon(iconDisabled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (q->isChecked() && !iconChecked.isNull()) {
|
||||||
|
q->setIcon(iconChecked);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iconNormal.isNull()) {
|
||||||
|
q->setIcon(iconNormal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowButton::WindowButton(QWidget *parent) : WindowButton(*new WindowButtonPrivate(), parent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowButton::~WindowButton() = default;
|
||||||
|
|
||||||
|
QIcon WindowButton::iconNormal() const {
|
||||||
|
Q_D(const WindowButton);
|
||||||
|
return d->iconNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowButton::setIconNormal(const QIcon &icon) {
|
||||||
|
Q_D(WindowButton);
|
||||||
|
d->iconNormal = icon;
|
||||||
|
d->reloadIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon WindowButton::iconChecked() const {
|
||||||
|
Q_D(const WindowButton);
|
||||||
|
return d->iconChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowButton::setIconChecked(const QIcon &icon) {
|
||||||
|
Q_D(WindowButton);
|
||||||
|
d->iconChecked = icon;
|
||||||
|
d->reloadIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon WindowButton::iconDisabled() const {
|
||||||
|
Q_D(const WindowButton);
|
||||||
|
return d->iconDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowButton::setIconDisabled(const QIcon &icon) {
|
||||||
|
Q_D(WindowButton);
|
||||||
|
d->iconDisabled = icon;
|
||||||
|
d->reloadIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowButton::checkStateSet() {
|
||||||
|
Q_D(WindowButton);
|
||||||
|
d->reloadIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowButton::mouseDoubleClickEvent(QMouseEvent *event) {
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
Q_EMIT doubleClicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowButton::WindowButton(WindowButtonPrivate &d, QWidget *parent)
|
||||||
|
: QPushButton(parent), d_ptr(&d) {
|
||||||
|
d.q_ptr = this;
|
||||||
|
|
||||||
|
d.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
50
libs/qwindowkit/examples/shared/widgetframe/windowbutton.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#ifndef WINDOWBUTTON_H
|
||||||
|
#define WINDOWBUTTON_H
|
||||||
|
|
||||||
|
#include <QtWidgets/QPushButton>
|
||||||
|
|
||||||
|
namespace QWK {
|
||||||
|
|
||||||
|
class WindowButtonPrivate;
|
||||||
|
|
||||||
|
class WindowButton : public QPushButton {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DECLARE_PRIVATE(WindowButton)
|
||||||
|
Q_PROPERTY(QIcon iconNormal READ iconNormal WRITE setIconNormal FINAL)
|
||||||
|
Q_PROPERTY(QIcon iconChecked READ iconChecked WRITE setIconChecked FINAL)
|
||||||
|
Q_PROPERTY(QIcon iconDisabled READ iconDisabled WRITE setIconDisabled FINAL)
|
||||||
|
public:
|
||||||
|
explicit WindowButton(QWidget *parent = nullptr);
|
||||||
|
~WindowButton();
|
||||||
|
|
||||||
|
public:
|
||||||
|
QIcon iconNormal() const;
|
||||||
|
void setIconNormal(const QIcon &icon);
|
||||||
|
|
||||||
|
QIcon iconChecked() const;
|
||||||
|
void setIconChecked(const QIcon &icon);
|
||||||
|
|
||||||
|
QIcon iconDisabled() const;
|
||||||
|
void setIconDisabled(const QIcon &icon);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void doubleClicked();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void checkStateSet() override;
|
||||||
|
|
||||||
|
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
WindowButton(WindowButtonPrivate &d, QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
QScopedPointer<WindowButtonPrivate> d_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WINDOWBUTTON_H
|
||||||
31
libs/qwindowkit/examples/shared/widgetframe/windowbutton_p.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
|
||||||
|
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#ifndef WINDOWBUTTONPRIVATE_H
|
||||||
|
#define WINDOWBUTTONPRIVATE_H
|
||||||
|
|
||||||
|
#include "windowbutton.h"
|
||||||
|
|
||||||
|
namespace QWK {
|
||||||
|
|
||||||
|
class WindowButtonPrivate {
|
||||||
|
Q_DECLARE_PUBLIC(WindowButton)
|
||||||
|
public:
|
||||||
|
WindowButtonPrivate();
|
||||||
|
virtual ~WindowButtonPrivate();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
WindowButton *q_ptr;
|
||||||
|
|
||||||
|
QIcon iconNormal;
|
||||||
|
QIcon iconChecked;
|
||||||
|
QIcon iconDisabled;
|
||||||
|
|
||||||
|
void reloadIcon();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WINDOWBUTTONPRIVATE_H
|
||||||
130
libs/qwindowkit/qmsetup/.clang-format
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# References:
|
||||||
|
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||||
|
# https://code.qt.io/cgit/qt/qt5.git/tree/_clang-format
|
||||||
|
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
Standard: c++17
|
||||||
|
|
||||||
|
# 指针和引用的对齐方式。
|
||||||
|
# 可能的值有:
|
||||||
|
# PAS_Left (在配置中: Left) 指针左对齐。
|
||||||
|
# PAS_Right (在配置中: Right) 指针右对齐。
|
||||||
|
# PAS_Middle (在配置中: Middle) 指针中间对齐。
|
||||||
|
PointerAlignment: Right
|
||||||
|
|
||||||
|
# public/protected/private 等访问修饰符偏移量
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
|
||||||
|
# 缩进长度
|
||||||
|
IndentWidth: 4
|
||||||
|
|
||||||
|
# 连续空行的最大数
|
||||||
|
MaxEmptyLinesToKeep: 999
|
||||||
|
|
||||||
|
# 在OC中的@property后面添加一个空格。例如:使用“@property (readonly)”而不是“@property(readonly)”
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
|
||||||
|
# OC块中所拍的字符数
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
|
||||||
|
# 取决于值, 语句“int f() { return 0; }”可以被放到一个单行。
|
||||||
|
# 可能的值有:
|
||||||
|
# SFS_None (在配置中: None) 从不合并方法或函数到单独的一行。
|
||||||
|
# SFS_Empty (在配置中: Empty) 仅合并空的函数。
|
||||||
|
# SFS_Inline (在配置中: Inline) 仅合并类中定义的方法或函数. 意味着 “empty”.
|
||||||
|
# SFS_All (在配置中: All) 合并所有的方法适应单行.
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
|
||||||
|
# 如果为真(true), 语句“if (a) return;” 能被放到单行。
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
|
||||||
|
# 如果为真(true), 对齐注释。
|
||||||
|
AlignTrailingComments: true
|
||||||
|
|
||||||
|
# 如果为真,对齐连续的宏定义
|
||||||
|
AlignConsecutiveMacros: true
|
||||||
|
|
||||||
|
# 如果为真(true),将会在“[”之后和“]”之前插入空格。
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
|
||||||
|
# 如果为真(true), 将会在“(”之后和“)”之前插入空格。
|
||||||
|
SpacesInParentheses : false
|
||||||
|
|
||||||
|
# 如果为真(true), 校准连续的声明。
|
||||||
|
# 这将会校准连续多行的声明的名字。这将会导致像下面这样的格式:
|
||||||
|
# int aaaa = 12;
|
||||||
|
# float b = 23;
|
||||||
|
# std::string ccc = 23;
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
|
||||||
|
# 如果为真(true),连续调整多行
|
||||||
|
# 这将会调整连续行中的分配操作符。这将会导致像下面这样的格式:
|
||||||
|
# int aaaa = 12;
|
||||||
|
# int b = 23;
|
||||||
|
# int ccc = 23;
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
|
||||||
|
# 如果为假(false),移除分配操作符(=)前空格。
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
|
||||||
|
# 如果为真(true), 将会在字面量容器中插入空格(例如 OC和Javascript的数组和字典字面量)。
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
|
||||||
|
# 缩进case标签
|
||||||
|
IndentCaseLabels: true
|
||||||
|
|
||||||
|
# 如果表达式中包含函数调用,并且函数调用因为表达式太长被放到了下一行,是否缩进
|
||||||
|
IndentWrappedFunctionNames: true
|
||||||
|
|
||||||
|
# 如果为真(true), 保持块的起始空行。
|
||||||
|
# true: false:
|
||||||
|
# if (foo) { vs. if (foo) {
|
||||||
|
# bar();
|
||||||
|
# bar(); }
|
||||||
|
# }
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
|
||||||
|
# 允许所有参数都被放在下一行
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
|
||||||
|
# 使用C风格强制类型转换后,是否在中间添加一个空格
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
|
||||||
|
# 在模板定义后换行
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
|
||||||
|
# Tab长度
|
||||||
|
TabWidth: 4
|
||||||
|
|
||||||
|
# 是否使用Tab
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
# 在括号后对齐参数
|
||||||
|
# someLongFunction(argument1,
|
||||||
|
# argument2);
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
|
||||||
|
# 名字空间内部缩进
|
||||||
|
NamespaceIndentation: All
|
||||||
|
|
||||||
|
# 一行最长列数
|
||||||
|
ColumnLimit: 100
|
||||||
|
|
||||||
|
# 按层次缩进宏定义
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
|
||||||
|
# 预处理语句缩进为 2
|
||||||
|
PPIndentWidth: 2
|
||||||
|
|
||||||
|
# 数组元素对齐
|
||||||
|
AlignArrayOfStructures: Left
|
||||||
|
|
||||||
|
# 不对头文件排序
|
||||||
|
SortIncludes: Never
|
||||||
|
|
||||||
|
FixNamespaceComments: false
|
||||||
|
|
||||||
|
StatementMacros: ['__qas_attr__', '__qas_exclude__', '__qas_include__']
|
||||||
|
|
||||||
|
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE ]
|
||||||
98
libs/qwindowkit/qmsetup/.gitignore
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# This file is used to ignore files which are generated
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.log
|
||||||
|
*.autosave
|
||||||
|
*.a
|
||||||
|
*.core
|
||||||
|
*.moc
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*_pch.h.cpp
|
||||||
|
*_resource.rc
|
||||||
|
*.qm
|
||||||
|
.#*
|
||||||
|
*.*#
|
||||||
|
core
|
||||||
|
!core/
|
||||||
|
tags
|
||||||
|
.DS_Store
|
||||||
|
.directory
|
||||||
|
*.debug
|
||||||
|
Makefile*
|
||||||
|
*.prl
|
||||||
|
*.app
|
||||||
|
moc_*.cpp
|
||||||
|
ui_*.h
|
||||||
|
qrc_*.cpp
|
||||||
|
Thumbs.db
|
||||||
|
# *.res
|
||||||
|
# *.rc
|
||||||
|
/.qmake.cache
|
||||||
|
/.qmake.stash
|
||||||
|
|
||||||
|
# qtcreator generated files
|
||||||
|
*.pro.user*
|
||||||
|
|
||||||
|
# xemacs temporary files
|
||||||
|
*.flc
|
||||||
|
|
||||||
|
# Vim temporary files
|
||||||
|
.*.swp
|
||||||
|
|
||||||
|
# Visual Studio generated files
|
||||||
|
*.ib_pdb_index
|
||||||
|
*.idb
|
||||||
|
*.ilk
|
||||||
|
*.pdb
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.vcproj
|
||||||
|
*vcproj.*.*.user
|
||||||
|
*.ncb
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.vcxproj
|
||||||
|
*vcxproj.*
|
||||||
|
|
||||||
|
# MinGW generated files
|
||||||
|
*.Debug
|
||||||
|
*.Release
|
||||||
|
|
||||||
|
# Python byte code
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
# --------
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
*/.DS_Store
|
||||||
|
|
||||||
|
build-src*
|
||||||
|
build/
|
||||||
|
cmake-build*
|
||||||
|
*.user
|
||||||
|
*.lnk
|
||||||
|
_workingDir*
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
.cache
|
||||||
|
cache
|
||||||
|
.vs
|
||||||
|
out/
|
||||||
|
CMakeSettings.json
|
||||||
|
# /vcpkg
|
||||||
|
/data
|
||||||
|
/*.natvis
|
||||||
|
|
||||||
|
*.sublime-*
|
||||||
|
setup-vcpkg.json
|
||||||
|
setup-vcpkg-temp*
|
||||||
4
libs/qwindowkit/qmsetup/.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[submodule "syscmdline"]
|
||||||
|
path = src/syscmdline
|
||||||
|
url = ../../SineStriker/syscmdline.git
|
||||||
|
branch = main
|
||||||
46
libs/qwindowkit/qmsetup/CMakeLists.txt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
project(qmsetup VERSION 1.0.0.0)
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Configure Options
|
||||||
|
# ----------------------------------
|
||||||
|
option(QMSETUP_VCPKG_TOOLS_HINT "Install executables to tools directory" OFF)
|
||||||
|
option(QMSETUP_STATIC_RUNTIME "Static link runtime libraries on Windows" ON)
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# CMake Settings
|
||||||
|
# ----------------------------------
|
||||||
|
if(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /manifest:no")
|
||||||
|
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /manifest:no")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /manifest:no")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
|
||||||
|
set(CMAKE_DEBUG_POSTFIX "d")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Project Variables
|
||||||
|
# ----------------------------------
|
||||||
|
set(QMSETUP_VERSION ${PROJECT_VERSION})
|
||||||
|
set(QMSETUP_INSTALL_NAME ${PROJECT_NAME})
|
||||||
|
set(QMSETUP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
include(cmake/QMSetupAPI.cmake)
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
21
libs/qwindowkit/qmsetup/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) Stdware Collections
|
||||||
|
|
||||||
|
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.
|
||||||
252
libs/qwindowkit/qmsetup/README.md
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
# QMSetup
|
||||||
|
|
||||||
|
**QMSetup** is a set of CMake Modules and Basic Libraries for C/C++ projects.
|
||||||
|
|
||||||
|
**This project is independent from Qt and other 3rdparty libraries.** Due to the fact that it encompasses some tools that need to be compiled, it's strongly not suggested to be included as a subproject.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Helpful Functions
|
||||||
|
+ Path, Version functions
|
||||||
|
+ Target configuration functions
|
||||||
|
+ Qt related functions
|
||||||
|
|
||||||
|
### Generators
|
||||||
|
+ Generate Windows RC files, manifest files
|
||||||
|
+ Generate MacOS Bundle info files
|
||||||
|
+ Generate configuration header files
|
||||||
|
+ Generate Git information header files
|
||||||
|
|
||||||
|
### Filesystem Utilities
|
||||||
|
+ Reorganize header files
|
||||||
|
+ Copy files and directories after build
|
||||||
|
|
||||||
|
### Install Utilities
|
||||||
|
+ Deploy project dependencies and fix rpaths
|
||||||
|
|
||||||
|
### Extended Build Rules
|
||||||
|
+ Create translations with **Qt Linguist** tools
|
||||||
|
+ Create source files with **Protobuf** compiler
|
||||||
|
+ Create documentations with **Doxygen**
|
||||||
|
|
||||||
|
## Support Platforms
|
||||||
|
|
||||||
|
+ Microsoft Windows
|
||||||
|
+ Apple Macintosh
|
||||||
|
+ GNU/Linux
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
### Required Packages
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
|
||||||
|
Windows deploy command acquires the shared library paths by reading the PE files and searching the specified paths so that it doesn't depend on `dumpbin` tool.
|
||||||
|
|
||||||
|
#### Unix
|
||||||
|
|
||||||
|
Unix deploy command acquires the shared library paths by running `ldd`/`otool` command and fixes the *rpath*s by runing the `patchelf`/`install_name_tool` command, make sure you have installed them.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt install patchelf
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build System
|
||||||
|
|
||||||
|
+ C++ 17
|
||||||
|
+ CMake 3.19
|
||||||
|
|
||||||
|
### Open-Source Libraries
|
||||||
|
+ https://github.com/SineStriker/syscmdline
|
||||||
|
+ https://github.com/jothepro/doxygen-awesome-css
|
||||||
|
|
||||||
|
## Integrate
|
||||||
|
|
||||||
|
### Clone
|
||||||
|
|
||||||
|
Via Https
|
||||||
|
```sh
|
||||||
|
git clone --recursive https://github.com/stdware/qmsetup.git
|
||||||
|
```
|
||||||
|
Via SSH
|
||||||
|
```sh
|
||||||
|
git clone --recursive git@github.com:stdware/qmsetup.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Preinstall (Suggested)
|
||||||
|
|
||||||
|
#### Build & Install
|
||||||
|
```sh
|
||||||
|
cmake -B build -DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/path/to
|
||||||
|
cmake --build build --target all
|
||||||
|
cmake --build build --target install
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Import
|
||||||
|
```sh
|
||||||
|
cmake -Dqmsetup_DIR=/path/to/lib/cmake/qmsetup ...
|
||||||
|
```
|
||||||
|
```cmake
|
||||||
|
find_package(qmsetup REQUIRED)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sub-project
|
||||||
|
|
||||||
|
It still needs to be installed, but the installation occurs during the CMake Configure phase and is executed only once.
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
find_package(qmsetup QUIET)
|
||||||
|
|
||||||
|
if (NOT TARGET qmsetup::library)
|
||||||
|
# Modify this variable according to your project structure
|
||||||
|
set(_source_dir ${CMAKE_CURRENT_SOURCE_DIR}/qmsetup)
|
||||||
|
|
||||||
|
# Import install function
|
||||||
|
include("${_source_dir}/cmake/modules/private/InstallPackage.cmake")
|
||||||
|
|
||||||
|
# Install package in place
|
||||||
|
set(_package_path)
|
||||||
|
qm_install_package(qmsetup
|
||||||
|
SOURCE_DIR ${_source_dir}
|
||||||
|
BUILD_TYPE Release
|
||||||
|
RESULT_PATH _package_path
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find package again
|
||||||
|
find_package(qmsetup REQUIRED PATHS ${_package_path})
|
||||||
|
|
||||||
|
# Update import path
|
||||||
|
set(qmsetup_DIR ${_package_path} CACHE PATH "" FORCE)
|
||||||
|
endif()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
You can use the functions in this library to greatly simplify several kinds of common build rules.
|
||||||
|
|
||||||
|
#### Generate Configuration Header
|
||||||
|
```cmake
|
||||||
|
qm_import(Preprocess)
|
||||||
|
|
||||||
|
qm_add_definition(FOO false)
|
||||||
|
qm_add_definition(BAR 114514)
|
||||||
|
qm_add_definition(BAZ "ABC" STRING_LITERAL)
|
||||||
|
|
||||||
|
qm_generate_config(${CMAKE_BINARY_DIR}/conf.h)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Reorganize Include Directory
|
||||||
|
```cmake
|
||||||
|
qm_import(Preprocess)
|
||||||
|
|
||||||
|
qm_sync_include(src/core ${CMAKE_BINARY_DIR}/include/MyCore
|
||||||
|
INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}/MyCore
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Sync Resource Files After Build
|
||||||
|
```cmake
|
||||||
|
qm_import(Filesystem)
|
||||||
|
|
||||||
|
qm_add_copy_command(${PROJECT_NAME}
|
||||||
|
SOURCES
|
||||||
|
file.txt
|
||||||
|
dir_to_copy
|
||||||
|
dir_contents_to_copy/
|
||||||
|
DESTINATION .
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Deploy Project And All Dependencies
|
||||||
|
```cmake
|
||||||
|
qm_import(Deploy)
|
||||||
|
|
||||||
|
qm_deploy_directory("${CMAKE_INSTALL_PREFIX}"
|
||||||
|
COMMENT "Deploy project spectacularly"
|
||||||
|
PLUGINS "iconengines/qsvgicon" "bearer/qgenericbearer"
|
||||||
|
QML Qt QtQml
|
||||||
|
PLUGIN_DIR share/plugins
|
||||||
|
QML_DIR share/qml
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Add Qt Translations
|
||||||
|
```cmake
|
||||||
|
qm_import(Translate)
|
||||||
|
|
||||||
|
qm_find_qt(LinguistTools)
|
||||||
|
qm_add_translation(${PROJECT_NAME}_translations
|
||||||
|
LOCALES ja_JP zh_CN zh_TW
|
||||||
|
PREFIX ${PROJECT_NAME}
|
||||||
|
TARGETS ${PROJECT_NAME}
|
||||||
|
TS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/translations
|
||||||
|
QM_DIR ${CMAKE_CURRENT_BINARY_DIR}/translations
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Generate Protubuf Source Files
|
||||||
|
```cmake
|
||||||
|
qm_import(Protobuf)
|
||||||
|
|
||||||
|
find_package(Protobuf REQUIRED)
|
||||||
|
qm_create_protobuf(_proto_src
|
||||||
|
INPUT a.proto b.proto
|
||||||
|
INCLUDE_DIRECTORIES src/proto
|
||||||
|
OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/proto
|
||||||
|
)
|
||||||
|
target_sources(${PROJECT_NAME} PUBLIC ${_proto_src})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Generate Doxygen HTML Documentations
|
||||||
|
```cmake
|
||||||
|
qm_import(Doxygen)
|
||||||
|
|
||||||
|
find_package(Doxygen REQUIRED)
|
||||||
|
qm_setup_doxygen(${PROJECT_NAME}_RunDoxygen
|
||||||
|
NAME ${PROJECT_NAME}
|
||||||
|
DESCRIPTION "my project"
|
||||||
|
MDFILE "${CMAKE_SOURCE_DIR}/README.md"
|
||||||
|
OUTPUT_DIR "${CMAK_BINARY_DIR}/doc"
|
||||||
|
INPUT src
|
||||||
|
TARGETS ${PROJECT_NAME}
|
||||||
|
DEPENDS ${PROJECT_NAME}
|
||||||
|
NO_EXPAND_MACROS
|
||||||
|
Q_OBJECT
|
||||||
|
Q_GADGET
|
||||||
|
Q_DECLARE_TR_FUNCTIONS
|
||||||
|
COMPILE_DEFINITIONS
|
||||||
|
Q_SIGNALS=Q_SIGNALS
|
||||||
|
Q_SLOTS=Q_SLOTS
|
||||||
|
GENERATE_TAGFILE "${PROJECT_NAME}_tagfile.xml"
|
||||||
|
INSTALL_DIR "doc"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Find Modules
|
||||||
|
|
||||||
|
Use `qm_find_package` to find supported third-party packages.
|
||||||
|
|
||||||
|
+ YY-Thunks: https://github.com/Chuyu-Team/YY-Thunks
|
||||||
|
+ VC-LTL5: https://github.com/Chuyu-Team/VC-LTL5
|
||||||
|
|
||||||
|
### Detailed Documentations
|
||||||
|
|
||||||
|
+ [Core Command](docs/core-command.md)
|
||||||
|
|
||||||
|
The CMake Modules documentations is provided in the comments.
|
||||||
|
|
||||||
|
See `examples` to get detailed use cases.
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
+ [SineStriker](https://github.com/SineStriker)
|
||||||
|
+ [wangwenx190](https://github.com/wangwenx190)
|
||||||
|
+ [RigoLigoRLC](https://github.com/RigoLigoRLC)
|
||||||
|
+ [CrSjimo](https://github.com/CrSjimo)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
QMSetup is licensed under the MIT License.
|
||||||
1176
libs/qwindowkit/qmsetup/cmake/QMSetupAPI.cmake
Normal file
2867
libs/qwindowkit/qmsetup/cmake/doxygen/Doxyfile
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
Doxygen Awesome
|
||||||
|
https://github.com/jothepro/doxygen-awesome-css
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 - 2023 jothepro
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DoxygenAwesomeDarkModeToggle extends HTMLElement {
|
||||||
|
// SVG icons from https://fonts.google.com/icons
|
||||||
|
// Licensed under the Apache 2.0 license:
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
static lightModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FCBF00"><rect fill="none" height="24" width="24"/><circle cx="12" cy="12" opacity=".3" r="3"/><path d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg>`
|
||||||
|
static darkModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FE9700"><rect fill="none" height="24" width="24"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27 C17.45,17.19,14.93,19,12,19c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z" opacity=".3"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg>`
|
||||||
|
static title = "Toggle Light/Dark Mode"
|
||||||
|
|
||||||
|
static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
|
||||||
|
static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
|
||||||
|
|
||||||
|
static _staticConstructor = function() {
|
||||||
|
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference)
|
||||||
|
// Update the color scheme when the browsers preference changes
|
||||||
|
// without user interaction on the website.
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
|
||||||
|
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
|
||||||
|
})
|
||||||
|
// Update the color scheme when the tab is made visible again.
|
||||||
|
// It is possible that the appearance was changed in another tab
|
||||||
|
// while this tab was in the background.
|
||||||
|
document.addEventListener("visibilitychange", visibilityState => {
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}()
|
||||||
|
|
||||||
|
static init() {
|
||||||
|
$(function() {
|
||||||
|
$(document).ready(function() {
|
||||||
|
const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
|
||||||
|
toggleButton.title = DoxygenAwesomeDarkModeToggle.title
|
||||||
|
toggleButton.updateIcon()
|
||||||
|
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
|
||||||
|
toggleButton.updateIcon()
|
||||||
|
})
|
||||||
|
document.addEventListener("visibilitychange", visibilityState => {
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
toggleButton.updateIcon()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
|
||||||
|
})
|
||||||
|
$(window).resize(function(){
|
||||||
|
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.onclick=this.toggleDarkMode
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns `true` for dark-mode, `false` for light-mode system preference
|
||||||
|
*/
|
||||||
|
static get systemPreference() {
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns `true` for dark-mode, `false` for light-mode user preference
|
||||||
|
*/
|
||||||
|
static get userPreference() {
|
||||||
|
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
|
||||||
|
(DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
static set userPreference(userPreference) {
|
||||||
|
DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference
|
||||||
|
if(!userPreference) {
|
||||||
|
if(DoxygenAwesomeDarkModeToggle.systemPreference) {
|
||||||
|
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true)
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(!DoxygenAwesomeDarkModeToggle.systemPreference) {
|
||||||
|
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true)
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
static enableDarkMode(enable) {
|
||||||
|
if(enable) {
|
||||||
|
DoxygenAwesomeDarkModeToggle.darkModeEnabled = true
|
||||||
|
document.documentElement.classList.add("dark-mode")
|
||||||
|
document.documentElement.classList.remove("light-mode")
|
||||||
|
} else {
|
||||||
|
DoxygenAwesomeDarkModeToggle.darkModeEnabled = false
|
||||||
|
document.documentElement.classList.remove("dark-mode")
|
||||||
|
document.documentElement.classList.add("light-mode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static onSystemPreferenceChanged() {
|
||||||
|
DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
|
||||||
|
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
static onUserPreferenceChanged() {
|
||||||
|
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleDarkMode() {
|
||||||
|
DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference
|
||||||
|
this.updateIcon()
|
||||||
|
}
|
||||||
|
|
||||||
|
updateIcon() {
|
||||||
|
if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) {
|
||||||
|
this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon
|
||||||
|
} else {
|
||||||
|
this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle);
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
Doxygen Awesome
|
||||||
|
https://github.com/jothepro/doxygen-awesome-css
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 - 2023 jothepro
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
|
||||||
|
#MSearchBox {
|
||||||
|
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#MSearchField {
|
||||||
|
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height));
|
||||||
|
}
|
||||||
|
}
|
||||||
2530
libs/qwindowkit/qmsetup/cmake/doxygen/doxygen-awesome.css
Normal file
29
libs/qwindowkit/qmsetup/cmake/doxygen/extra-stylesheet.css
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
table.memname tr {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memname td {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memname tr:last-child:not(:first-child) {
|
||||||
|
margin-left: -0.75em
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
--external-link-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><path fill="%231779c4" d="M10.12,7.5H9.38A.38.38,0,0,0,9,7.88V10.5H1.5V3H4.88a.38.38,0,0,0,.37-.38V1.88a.38.38,0,0,0-.37-.38H1.12A1.12,1.12,0,0,0,0,2.62v8.26A1.12,1.12,0,0,0,1.12,12H9.38a1.12,1.12,0,0,0,1.12-1.12h0v-3A.38.38,0,0,0,10.12,7.5ZM11.44,0h-3A.56.56,0,0,0,8,1l.84.84L3.16,7.51a.56.56,0,0,0,0,.79h0l.54.53a.56.56,0,0,0,.79,0h0L10.2,3.12,11,4a.56.56,0,0,0,1-.4v-3A.56.56,0,0,0,11.44,0Z"/></svg>')
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
html:not(.light-mode) {
|
||||||
|
--external-link-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><path fill="%231982d2" d="M10.12,7.5H9.38A.38.38,0,0,0,9,7.88V10.5H1.5V3H4.88a.38.38,0,0,0,.37-.38V1.88a.38.38,0,0,0-.37-.38H1.12A1.12,1.12,0,0,0,0,2.62v8.26A1.12,1.12,0,0,0,1.12,12H9.38a1.12,1.12,0,0,0,1.12-1.12h0v-3A.38.38,0,0,0,10.12,7.5ZM11.44,0h-3A.56.56,0,0,0,8,1l.84.84L3.16,7.51a.56.56,0,0,0,0,.79h0l.54.53a.56.56,0,0,0,.79,0h0L10.2,3.12,11,4a.56.56,0,0,0,1-.4v-3A.56.56,0,0,0,11.44,0Z"/></svg>')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href^='http://'], a[href^='https://'] {
|
||||||
|
background-image: var(--external-link-icon);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center right;
|
||||||
|
background-size: 0.75em;
|
||||||
|
padding-right: 0.875em;
|
||||||
|
}
|
||||||
90
libs/qwindowkit/qmsetup/cmake/doxygen/header.html
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<!-- HTML header for doxygen 1.9.8-->
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=11" />
|
||||||
|
<meta name="generator" content="Doxygen $doxygenversion" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<!--BEGIN PROJECT_NAME-->
|
||||||
|
<title>$projectname: $title</title>
|
||||||
|
<!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME-->
|
||||||
|
<title>$title</title>
|
||||||
|
<!--END !PROJECT_NAME-->
|
||||||
|
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css" />
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var page_layout = 1;
|
||||||
|
</script>
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||||
|
$treeview $search $mathjax $darkmode
|
||||||
|
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" /> $extrastylesheet
|
||||||
|
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
DoxygenAwesomeDarkModeToggle.init()
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
||||||
|
<!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
|
||||||
|
<div id="top">
|
||||||
|
<!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
|
||||||
|
<!--BEGIN TITLEAREA-->
|
||||||
|
<div id="titlearea">
|
||||||
|
<table cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr id="projectrow">
|
||||||
|
<!--BEGIN PROJECT_LOGO-->
|
||||||
|
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo" /></td>
|
||||||
|
<!--END PROJECT_LOGO-->
|
||||||
|
<!--BEGIN PROJECT_NAME-->
|
||||||
|
<td id="projectalign">
|
||||||
|
<div id="projectname">$projectname
|
||||||
|
<!--BEGIN PROJECT_NUMBER--><span id="projectnumber"> $projectnumber</span>
|
||||||
|
<!--END PROJECT_NUMBER-->
|
||||||
|
</div>
|
||||||
|
<!--BEGIN PROJECT_BRIEF-->
|
||||||
|
<div id="projectbrief">$projectbrief</div>
|
||||||
|
<!--END PROJECT_BRIEF-->
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME-->
|
||||||
|
<!--BEGIN PROJECT_BRIEF-->
|
||||||
|
<td>
|
||||||
|
<div id="projectbrief">$projectbrief</div>
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_BRIEF-->
|
||||||
|
<!--END !PROJECT_NAME-->
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN SEARCHENGINE-->
|
||||||
|
<!--BEGIN !FULL_SIDEBAR-->
|
||||||
|
<td>$searchbox</td>
|
||||||
|
<!--END !FULL_SIDEBAR-->
|
||||||
|
<!--END SEARCHENGINE-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
</tr>
|
||||||
|
<!--BEGIN SEARCHENGINE-->
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">$searchbox</td>
|
||||||
|
</tr>
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
<!--END SEARCHENGINE-->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--END TITLEAREA-->
|
||||||
|
<!-- end header part -->
|
||||||
102
libs/qwindowkit/qmsetup/cmake/find-modules/VC-LTL.cmake
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# https://github.com/Chuyu-Team/VC-LTL5
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
if(NOT MSVC OR DEFINED __VC_LTL_CMAKE_INCLUDE_GUARD)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__VC_LTL_CMAKE_INCLUDE_GUARD 1)
|
||||||
|
|
||||||
|
#
|
||||||
|
# VC-LTL自动化加载配置,建议你将此文件单独复制到你的工程再使用,该文件能自动识别当前环境是否存在VC-LTL,并且自动应用。
|
||||||
|
#
|
||||||
|
# 使用方法:
|
||||||
|
# 1. 在“CMakeLists.txt” 添加 “include("VC-LTL helper for cmake.cmake")”。
|
||||||
|
#
|
||||||
|
# VC-LTL默认搜索顺序
|
||||||
|
# 1. “VC-LTL helper for cmake.cmake”所在根目录,即 ${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
# 2. 当前CMake根目录,即 ${CMAKE_CURRENT_SOURCE_DIR}/VC-LTL
|
||||||
|
# 3. 当前项目根目录,即 ${PROJECT_SOURCE_DIR}/VC-LTL
|
||||||
|
# 4. 当前CMake父目录,即 ${CMAKE_CURRENT_SOURCE_DIR}/../VC-LTL
|
||||||
|
# 5. 当前项目根目录,即 ${PROJECT_SOURCE_DIR}/../VC-LTL
|
||||||
|
# 6. 注册表HKEY_CURRENT_USER\Code\VC-LTL@Root
|
||||||
|
#
|
||||||
|
# 把VC-LTL放在其中一个位置即可,VC-LTL就能被自动引用。
|
||||||
|
#
|
||||||
|
# 如果你对默认搜索顺序不满,你可以修改此文件。你也可以直接指定${VC_LTL_Root}宏更加任性的去加载VC-LTL。
|
||||||
|
#
|
||||||
|
|
||||||
|
#####################################################################VC-LTL设置#####################################################################
|
||||||
|
|
||||||
|
#控制最小兼容系统版本,目前可用版本为5.1.2600.0 6.0.6000.0(默认) 6.2.9200.0 10.0.10240.0 10.0.19041.0
|
||||||
|
#注意:VC-LTL依赖YY-Thunks,否则可能无法兼容早期系统。如果需要支持Windows XP,该值必须为5.1.2600.0。
|
||||||
|
if(NOT DEFINED WindowsTargetPlatformMinVersion)
|
||||||
|
set(WindowsTargetPlatformMinVersion "10.0.19041.0" CACHE STRING "" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#VC-LTL使用的CRT模式,SupportLTL可能值为:
|
||||||
|
# * false:禁用VC_LTL
|
||||||
|
# * true:默认值,让VC-LTL自动适应。当最小兼容版本>=10.0时使用ucrt模式,其他系统使用msvcrt模式。
|
||||||
|
# * msvcrt:使用msvcrt.dll作为CRT。注意:msvcrt模式可能不完全支持所有ucrt的新功能。比如setloacl不支持UTF8。
|
||||||
|
# * ucrt:使用ucrtbase.dll作为CRT。注意:早期系统可能需要下载VC-LTL.Redist.Dlls.zip,感谢msvcr14x项目提供兼容XP系统的ucrtbase.dll。
|
||||||
|
#如果需要兼容XP时也使用ucrt,请指定SupportLTL=ucrt。
|
||||||
|
#set(SupportLTL "ucrt")
|
||||||
|
|
||||||
|
#(PR#70 引入),默认关,开启后将使用cmake `INTERFACE`能力,然后单独`target_link_directories(工程名称 VC_LTL)` 即可引用
|
||||||
|
#option(VC_LTL_EnableCMakeInterface "VC_LTL_EnableCMakeInterface" on)
|
||||||
|
####################################################################################################################################################
|
||||||
|
|
||||||
|
if(NOT VC_LTL_Root)
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/_msvcrt.h)
|
||||||
|
set(VC_LTL_Root ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT VC_LTL_Root)
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/VC-LTL/_msvcrt.h)
|
||||||
|
set(VC_LTL_Root ${CMAKE_CURRENT_SOURCE_DIR}/VC-LTL)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT VC_LTL_Root)
|
||||||
|
if(EXISTS ${PROJECT_SOURCE_DIR}/VC-LTL/_msvcrt.h)
|
||||||
|
set(VC_LTL_Root ${PROJECT_SOURCE_DIR}/VC-LTL)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT VC_LTL_Root)
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../VC-LTL/_msvcrt.h)
|
||||||
|
set(VC_LTL_Root ${CMAKE_CURRENT_SOURCE_DIR}/../VC-LTL)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT VC_LTL_Root)
|
||||||
|
if(EXISTS ${PROJECT_SOURCE_DIR}/../VC-LTL/_msvcrt.h)
|
||||||
|
set(VC_LTL_Root ${PROJECT_SOURCE_DIR}/../VC-LTL)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT VC_LTL_Root)
|
||||||
|
EXECUTE_PROCESS(COMMAND reg query "HKEY_CURRENT_USER\\Code\\VC-LTL" -v "Root"
|
||||||
|
OUTPUT_VARIABLE FOUND_FILE
|
||||||
|
ERROR_VARIABLE ERROR_INFO
|
||||||
|
)
|
||||||
|
|
||||||
|
string(REGEX MATCH "[a-zA-Z]:\\\\.+\\\\"
|
||||||
|
FOUND_LTL
|
||||||
|
${FOUND_FILE})
|
||||||
|
if (NOT ${FOUND_LTL} STREQUAL "")
|
||||||
|
set(VC_LTL_Root ${FOUND_LTL})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED VC_LTL_Root)
|
||||||
|
string(REGEX MATCH "\\\\\\\\.+\\\\" FOUND_LTL ${FOUND_FILE})
|
||||||
|
if (NOT ${FOUND_LTL} STREQUAL "")
|
||||||
|
set(VC_LTL_Root ${FOUND_LTL})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(VC_LTL_Root)
|
||||||
|
include("${VC_LTL_Root}\\config\\config.cmake")
|
||||||
|
endif()
|
||||||
102
libs/qwindowkit/qmsetup/cmake/find-modules/YY-Thunks.cmake
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (C) 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.
|
||||||
|
]]
|
||||||
|
|
||||||
|
# https://github.com/Chuyu-Team/YY-Thunks
|
||||||
|
|
||||||
|
if(NOT MSVC OR DEFINED __YY_THUNKS_CMAKE_INCLUDE_GUARD)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__YY_THUNKS_CMAKE_INCLUDE_GUARD 1)
|
||||||
|
|
||||||
|
if(NOT DEFINED YYTHUNKS_TARGET_OS)
|
||||||
|
set(YYTHUNKS_TARGET_OS "Vista" CACHE STRING "Supported values: Vista, WinXP" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(__yy_thunks_dir "")
|
||||||
|
if(DEFINED ENV{YYTHUNKS_INSTALL_DIR})
|
||||||
|
set(__env "$ENV{YYTHUNKS_INSTALL_DIR}")
|
||||||
|
if(NOT "x${__env}" STREQUAL "x" AND EXISTS "${__env}")
|
||||||
|
set(__yy_thunks_dir "${__env}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if("x${__yy_thunks_dir}" STREQUAL "x")
|
||||||
|
set(__yy_thunks_reg "")
|
||||||
|
cmake_host_system_information(RESULT __yy_thunks_reg
|
||||||
|
QUERY WINDOWS_REGISTRY "HKCU/Code/YY-Thunks"
|
||||||
|
VALUE "Root")
|
||||||
|
if(NOT "x${__yy_thunks_reg}" STREQUAL "x" AND EXISTS "${__yy_thunks_reg}")
|
||||||
|
set(__yy_thunks_dir "${__yy_thunks_reg}")
|
||||||
|
elseif(EXISTS "${CMAKE_CURRENT_LIST_DIR}/YY-Thunks")
|
||||||
|
set(__yy_thunks_dir "${CMAKE_CURRENT_LIST_DIR}/YY-Thunks")
|
||||||
|
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/YY-Thunks")
|
||||||
|
set(__yy_thunks_dir "${CMAKE_CURRENT_SOURCE_DIR}/YY-Thunks")
|
||||||
|
elseif(EXISTS "${PROJECT_SOURCE_DIR}/YY-Thunks")
|
||||||
|
set(__yy_thunks_dir "${PROJECT_SOURCE_DIR}/YY-Thunks")
|
||||||
|
elseif(EXISTS "${CMAKE_SOURCE_DIR}/YY-Thunks")
|
||||||
|
set(__yy_thunks_dir "${CMAKE_SOURCE_DIR}/YY-Thunks")
|
||||||
|
elseif(EXISTS "${CMAKE_SOURCE_DIR}/../YY-Thunks")
|
||||||
|
set(__yy_thunks_dir "${CMAKE_SOURCE_DIR}/../YY-Thunks")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT "x${__yy_thunks_dir}" STREQUAL "x")
|
||||||
|
cmake_path(NORMAL_PATH __yy_thunks_dir OUTPUT_VARIABLE __yy_thunks_dir)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT "x${__yy_thunks_dir}" STREQUAL "x" AND EXISTS "${__yy_thunks_dir}")
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(__yy_thunks_arch x64)
|
||||||
|
else()
|
||||||
|
set(__yy_thunks_arch x86)
|
||||||
|
endif()
|
||||||
|
set(__yy_thunks_obj "${__yy_thunks_dir}/objs/${__yy_thunks_arch}/YY_Thunks_for_${YYTHUNKS_TARGET_OS}.obj")
|
||||||
|
cmake_path(NORMAL_PATH __yy_thunks_obj OUTPUT_VARIABLE __yy_thunks_obj)
|
||||||
|
if(EXISTS "${__yy_thunks_obj}")
|
||||||
|
set(YYTHUNKS_FOUND TRUE CACHE BOOL "" FORCE)
|
||||||
|
set(YYTHUNKS_INSTALL_DIR "${__yy_thunks_dir}" CACHE STRING "" FORCE)
|
||||||
|
set(YYTHUNKS_ARCH "${__yy_thunks_arch}" CACHE STRING "" FORCE)
|
||||||
|
set(YYTHUNKS_OBJ_FILE "YY_Thunks_for_${YYTHUNKS_TARGET_OS}.obj" CACHE STRING "" FORCE)
|
||||||
|
set(YYTHUNKS_OBJ_PATH "${__yy_thunks_obj}" CACHE STRING "" FORCE)
|
||||||
|
add_link_options("${__yy_thunks_obj}")
|
||||||
|
message("###################################################################################################")
|
||||||
|
message("# #")
|
||||||
|
message("# ██ ██ ██ ██ ████████ ██ ██ ██ ██ ███ ██ ██ ██ ███████ #")
|
||||||
|
message("# ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ #")
|
||||||
|
message("# ████ ████ █████ ██ ███████ ██ ██ ██ ██ ██ █████ ███████ #")
|
||||||
|
message("# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ #")
|
||||||
|
message("# ██ ██ ██ ██ ██ ██████ ██ ████ ██ ██ ███████ #")
|
||||||
|
message("# #")
|
||||||
|
message("###################################################################################################")
|
||||||
|
message("")
|
||||||
|
message(" YY-Thunks install dir :" ${__yy_thunks_dir})
|
||||||
|
message(" YY-Thunks target platform :" ${YYTHUNKS_TARGET_OS})
|
||||||
|
message(" YY-Thunks obj file path :" ${__yy_thunks_obj})
|
||||||
|
message("")
|
||||||
|
else()
|
||||||
|
message(WARNING "YY-Thunks's obj file is missing!")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "Can't locate the YY-Thunks installation directory!")
|
||||||
|
endif()
|
||||||
238
libs/qwindowkit/qmsetup/cmake/modules/CompilerOptions.cmake
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Disable all possible warnings from the compiler.
|
||||||
|
|
||||||
|
qm_compiler_no_warnings()
|
||||||
|
]] #
|
||||||
|
macro(qm_compiler_no_warnings)
|
||||||
|
foreach(__lang C CXX)
|
||||||
|
if(NOT "x${CMAKE_${__lang}_FLAGS}" STREQUAL "x")
|
||||||
|
if(MSVC)
|
||||||
|
string(REGEX REPLACE " [/-]W[01234] " " " CMAKE_${__lang}_FLAGS ${CMAKE_${__lang}_FLAGS})
|
||||||
|
else()
|
||||||
|
string(REGEX REPLACE " -W(all)?(extra)? " " " CMAKE_${__lang}_FLAGS ${CMAKE_${__lang}_FLAGS})
|
||||||
|
string(REGEX REPLACE " -[W]?pedantic " " " CMAKE_${__lang}_FLAGS ${CMAKE_${__lang}_FLAGS})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
string(APPEND CMAKE_${__lang}_FLAGS " -w ")
|
||||||
|
endforeach()
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_definitions(-D_CRT_NON_CONFORMING_SWPRINTFS)
|
||||||
|
add_compile_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE)
|
||||||
|
add_compile_definitions(-D_CRT_NONSTDC_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
|
||||||
|
add_compile_definitions(-D_SCL_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_DEPRECATE)
|
||||||
|
add_compile_definitions(-D_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS)
|
||||||
|
else()
|
||||||
|
foreach(__lang C CXX)
|
||||||
|
string(APPEND CMAKE_${__lang}_FLAGS " -fpermissive ")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Enable all possible warnings from the compiler.
|
||||||
|
|
||||||
|
qm_compiler_max_warnings()
|
||||||
|
]] #
|
||||||
|
function(qm_compiler_max_warnings)
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_options(-W4)
|
||||||
|
elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
|
||||||
|
add_compile_options(-Weverything)
|
||||||
|
else()
|
||||||
|
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Treat all warnings as errors.
|
||||||
|
|
||||||
|
qm_compiler_warnings_are_errors()
|
||||||
|
]] #
|
||||||
|
function(qm_compiler_warnings_are_errors)
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_options(-WX)
|
||||||
|
else()
|
||||||
|
add_compile_options(-Werror)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Prevent the compiler from receiving unknown parameters.
|
||||||
|
|
||||||
|
qm_compiler_no_unknown_options()
|
||||||
|
]] #
|
||||||
|
function(qm_compiler_no_unknown_options)
|
||||||
|
if(MSVC)
|
||||||
|
if(MSVC_VERSION GREATER_EQUAL 1930) # Visual Studio 2022 version 17.0
|
||||||
|
add_compile_options(-options:strict)
|
||||||
|
endif()
|
||||||
|
add_link_options(-WX)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Remove all unused code from the final binary.
|
||||||
|
|
||||||
|
qm_compiler_eliminate_dead_code()
|
||||||
|
]] #
|
||||||
|
function(qm_compiler_eliminate_dead_code)
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_options(-Gw -Gy -Zc:inline)
|
||||||
|
add_link_options(-OPT:REF -OPT:ICF -OPT:LBR)
|
||||||
|
else()
|
||||||
|
add_compile_options(-ffunction-sections -fdata-sections)
|
||||||
|
if(APPLE)
|
||||||
|
add_link_options(-Wl,-dead_strip)
|
||||||
|
else()
|
||||||
|
add_link_options(-Wl,--as-needed -Wl,--strip-all -Wl,--gc-sections)
|
||||||
|
endif()
|
||||||
|
if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
|
||||||
|
add_link_options(-Wl,--icf=all)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Only export symbols which are marked to be exported, just like MSVC.
|
||||||
|
|
||||||
|
qm_compiler_dont_export_by_default()
|
||||||
|
]] #
|
||||||
|
macro(qm_compiler_dont_export_by_default)
|
||||||
|
set(CMAKE_C_VISIBILITY_PRESET "hidden")
|
||||||
|
set(CMAKE_CXX_VISIBILITY_PRESET "hidden")
|
||||||
|
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Enable all possible security issue mitigations from your compiler.
|
||||||
|
|
||||||
|
qm_compiler_enable_secure_code()
|
||||||
|
]] #
|
||||||
|
macro(qm_compiler_enable_secure_code)
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_options(-GS -sdl -guard:cf)
|
||||||
|
add_link_options(-DYNAMICBASE -FIXED:NO -NXCOMPAT -GUARD:CF)
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||||
|
add_link_options(-SAFESEH)
|
||||||
|
endif()
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
add_link_options(-HIGHENTROPYVA)
|
||||||
|
endif()
|
||||||
|
if(MSVC_VERSION GREATER_EQUAL 1920) # Visual Studio 2019 version 16.0
|
||||||
|
add_link_options(-CETCOMPAT)
|
||||||
|
endif()
|
||||||
|
if(MSVC_VERSION GREATER_EQUAL 1925) # Visual Studio 2019 version 16.5
|
||||||
|
add_compile_options(-Qspectre-load)
|
||||||
|
elseif(MSVC_VERSION GREATER_EQUAL 1912) # Visual Studio 2017 version 15.5
|
||||||
|
add_compile_options(-Qspectre)
|
||||||
|
endif()
|
||||||
|
if(MSVC_VERSION GREATER_EQUAL 1927) # Visual Studio 2019 version 16.7
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
add_compile_options(-guard:ehcont)
|
||||||
|
add_link_options(-guard:ehcont)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(MSVC_VERSION GREATER_EQUAL 1930) # Visual Studio 2022 version 17.0
|
||||||
|
add_compile_options(-Qspectre-jmp)
|
||||||
|
endif()
|
||||||
|
elseif(MINGW)
|
||||||
|
if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
|
||||||
|
add_compile_options(-mguard=cf)
|
||||||
|
add_link_options(-mguard=cf)
|
||||||
|
else()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
add_compile_options(-mshstk -ftrivial-auto-var-init=pattern
|
||||||
|
-fstack-protector-strong -fstack-clash-protection
|
||||||
|
-fcf-protection=full)
|
||||||
|
add_link_options(-Wl,-z,relro,-z,now)
|
||||||
|
if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
|
||||||
|
add_compile_options(-mretpoline -mspeculative-load-hardening)
|
||||||
|
if(NOT APPLE)
|
||||||
|
add_compile_options(-fsanitize=cfi -fsanitize-cfi-cross-dso)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Enable all possible Qt coding style policies.
|
||||||
|
|
||||||
|
qm_compiler_enable_strict_qt(
|
||||||
|
TARGETS <target1> <target2> ... <targetN>
|
||||||
|
[NO_DEPRECATED_API]
|
||||||
|
[ALLOW_KEYWORD]
|
||||||
|
[ALLOW_UNSAFE_FLAGS]
|
||||||
|
)
|
||||||
|
|
||||||
|
NO_DEPRECATED_API: Disable the use of any deprecated Qt APIs. Only has effect since Qt6.
|
||||||
|
ALLOW_KEYWORD: Allow the use of the traditional Qt keywords such as "signal" "slot" "emit".
|
||||||
|
ALLOW_UNSAFE_FLAGS: Allow the use of the unsafe QFlags (unsafe: can be implicitly cast to and from "int").
|
||||||
|
]] #
|
||||||
|
function(qm_compiler_enable_strict_qt)
|
||||||
|
cmake_parse_arguments(arg "NO_DEPRECATED_API;ALLOW_KEYWORD;ALLOW_UNSAFE_FLAGS" "" "TARGETS" ${ARGN})
|
||||||
|
if(NOT arg_TARGETS)
|
||||||
|
message(AUTHOR_WARNING "qm_compiler_enable_strict_qt: you need to specify at least one target!")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(arg_UNPARSED_ARGUMENTS)
|
||||||
|
message(AUTHOR_WARNING "qm_compiler_enable_strict_qt: Unrecognized arguments: ${arg_UNPARSED_ARGUMENTS}")
|
||||||
|
endif()
|
||||||
|
foreach(_target IN LISTS arg_TARGETS)
|
||||||
|
if(NOT TARGET ${_target})
|
||||||
|
message(AUTHOR_WARNING "qm_compiler_enable_strict_qt: ${_target} is not a valid CMake target!")
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
target_compile_definitions(${_target} PRIVATE
|
||||||
|
QT_NO_CAST_TO_ASCII
|
||||||
|
QT_NO_CAST_FROM_ASCII
|
||||||
|
QT_NO_CAST_FROM_BYTEARRAY
|
||||||
|
QT_NO_URL_CAST_FROM_STRING
|
||||||
|
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||||
|
QT_NO_JAVA_STYLE_ITERATORS
|
||||||
|
QT_NO_FOREACH QT_NO_QFOREACH
|
||||||
|
QT_NO_AS_CONST QT_NO_QASCONST
|
||||||
|
QT_NO_EXCHANGE QT_NO_QEXCHANGE
|
||||||
|
QT_NO_QPAIR
|
||||||
|
QT_NO_INTEGRAL_STRINGS
|
||||||
|
QT_NO_USING_NAMESPACE
|
||||||
|
QT_NO_CONTEXTLESS_CONNECT
|
||||||
|
QT_EXPLICIT_QFILE_CONSTRUCTION_FROM_PATH
|
||||||
|
QT_USE_NODISCARD_FILE_OPEN
|
||||||
|
QT_USE_QSTRINGBUILDER
|
||||||
|
QT_USE_FAST_OPERATOR_PLUS
|
||||||
|
QT_DEPRECATED_WARNINGS # Have no effect since 5.13
|
||||||
|
QT_DEPRECATED_WARNINGS_SINCE=0x0A0000 # Deprecated since 6.5
|
||||||
|
QT_WARN_DEPRECATED_UP_TO=0x0A0000 # Available since 6.5
|
||||||
|
)
|
||||||
|
if(arg_NO_DEPRECATED_API)
|
||||||
|
target_compile_definitions(${_target} PRIVATE
|
||||||
|
QT_DISABLE_DEPRECATED_BEFORE=0x0A0000 # Deprecated since 6.5
|
||||||
|
QT_DISABLE_DEPRECATED_UP_TO=0x0A0000 # Available since 6.5
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
# On Windows enabling this flag requires us re-compile Qt with this flag enabled,
|
||||||
|
# so only enable it on non-Windows platforms.
|
||||||
|
if(NOT WIN32)
|
||||||
|
target_compile_definitions(${_target} PRIVATE
|
||||||
|
QT_STRICT_ITERATORS
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
# We handle this flag specially because some Qt headers may still use the
|
||||||
|
# traditional keywords (especially some private headers).
|
||||||
|
if(NOT arg_ALLOW_KEYWORD)
|
||||||
|
target_compile_definitions(${_target} PRIVATE
|
||||||
|
QT_NO_KEYWORDS
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
# We handle this flag specially because some Qt headers may still use the
|
||||||
|
# unsafe flags (especially some QtQuick headers).
|
||||||
|
if(NOT arg_ALLOW_UNSAFE_FLAGS)
|
||||||
|
target_compile_definitions(${_target} PRIVATE
|
||||||
|
QT_TYPESAFE_FLAGS
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
421
libs/qwindowkit/qmsetup/cmake/modules/Deploy.cmake
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
#[[
|
||||||
|
Warning: This module depends on `qmcorecmd` after installation.
|
||||||
|
]] #
|
||||||
|
if(NOT QMSETUP_CORECMD_EXECUTABLE)
|
||||||
|
message(FATAL_ERROR "QMSETUP_CORECMD_EXECUTABLE not defined. Add find_package(qmsetup) to CMake first.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS)
|
||||||
|
set(QMSETUP_APPLOCAL_DEPS_PATHS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS_DEBUG)
|
||||||
|
set(QMSETUP_APPLOCAL_DEPS_PATHS_DEBUG ${QMSETUP_APPLOCAL_DEPS_PATHS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS_RELEASE)
|
||||||
|
set(QMSETUP_APPLOCAL_DEPS_PATHS_RELEASE ${QMSETUP_APPLOCAL_DEPS_PATHS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS_RELWITHDEBINFO)
|
||||||
|
set(QMSETUP_APPLOCAL_DEPS_PATHS_RELWITHDEBINFO ${QMSETUP_APPLOCAL_DEPS_PATHS_RELEASE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_APPLOCAL_DEPS_PATHS_MINSIZEREL)
|
||||||
|
set(QMSETUP_APPLOCAL_DEPS_PATHS_MINSIZEREL ${QMSETUP_APPLOCAL_DEPS_PATHS_RELEASE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Record searching paths for Windows Executables, must be called before calling `qm_win_applocal_deps`
|
||||||
|
or `qm_deploy_directory` if your project supports Windows.
|
||||||
|
|
||||||
|
WARNING: This function is deprecated.
|
||||||
|
|
||||||
|
qm_win_record_deps(<target>)
|
||||||
|
]] #
|
||||||
|
function(qm_win_record_deps _target)
|
||||||
|
if(NOT WIN32)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_paths)
|
||||||
|
get_target_property(_link_libraries ${_target} LINK_LIBRARIES)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS _link_libraries)
|
||||||
|
if(NOT TARGET ${_item})
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_target_property(_imported ${_item} IMPORTED)
|
||||||
|
|
||||||
|
if(_imported)
|
||||||
|
get_target_property(_path ${_item} LOCATION)
|
||||||
|
|
||||||
|
if(NOT _path OR NOT ${_path} MATCHES "\\.dll$")
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_path "$<TARGET_PROPERTY:${_item},LOCATION_$<CONFIG>>")
|
||||||
|
else()
|
||||||
|
get_target_property(_type ${_item} TYPE)
|
||||||
|
|
||||||
|
if(NOT ${_type} MATCHES "SHARED_LIBRARY")
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_path "$<TARGET_FILE:${_item}>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND _paths ${_path})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(NOT _paths)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_deps_file "${CMAKE_CURRENT_BINARY_DIR}/${_target}_deps_$<CONFIG>.txt")
|
||||||
|
file(GENERATE OUTPUT ${_deps_file} CONTENT "$<JOIN:${_paths},\n>")
|
||||||
|
set_target_properties(${_target} PROPERTIES QMSETUP_DEPENDENCIES_FILE ${_deps_file})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Automatically copy dependencies for Windows Executables after build.
|
||||||
|
|
||||||
|
qm_win_applocal_deps(<target>
|
||||||
|
[CUSTOM_TARGET <target>]
|
||||||
|
[FORCE] [VERBOSE]
|
||||||
|
[EXTRA_SEARCHING_PATHS <path...>]
|
||||||
|
[EXTRA_TARGETS <target...>]
|
||||||
|
[OUTPUT_DIR <dir>]
|
||||||
|
[EXCLUDE <pattern...>]
|
||||||
|
)
|
||||||
|
]] #
|
||||||
|
function(qm_win_applocal_deps _target)
|
||||||
|
if(NOT WIN32)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(options FORCE VERBOSE)
|
||||||
|
set(oneValueArgs TARGET CUSTOM_TARGET OUTPUT_DIR)
|
||||||
|
set(multiValueArgs EXTRA_SEARCHING_PATHS EXTRA_TARGETS EXCLUDE)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
# Get output directory and deploy target
|
||||||
|
set(_out_dir)
|
||||||
|
set(_deploy_target)
|
||||||
|
|
||||||
|
if(FUNC_CUSTOM_TARGET)
|
||||||
|
set(_deploy_target ${FUNC_CUSTOM_TARGET})
|
||||||
|
|
||||||
|
if(NOT TARGET ${_deploy_target})
|
||||||
|
add_custom_target(${_deploy_target})
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(_deploy_target ${_target})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_OUTPUT_DIR)
|
||||||
|
set(_out_dir ${FUNC_OUTPUT_DIR})
|
||||||
|
else()
|
||||||
|
set(_out_dir "$<TARGET_FILE_DIR:${_target}>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT _out_dir)
|
||||||
|
message(FATAL_ERROR "qm_win_applocal_deps: cannot determine output directory.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Get dep files
|
||||||
|
set(_dep_files)
|
||||||
|
_qm_win_get_all_dep_files(_dep_files ${_target})
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_EXTRA_TARGETS)
|
||||||
|
_qm_win_get_all_dep_files(_dep_files ${_item})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Prepare command
|
||||||
|
set(_args)
|
||||||
|
|
||||||
|
if(FUNC_FORCE)
|
||||||
|
list(APPEND _args -f)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_VERBOSE)
|
||||||
|
list(APPEND _args -V)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add extra searching paths
|
||||||
|
foreach(_item IN LISTS FUNC_EXTRA_SEARCHING_PATHS)
|
||||||
|
list(APPEND _args "-L${_item}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add global extra searching paths
|
||||||
|
if(CMAKE_BUILD_TYPE)
|
||||||
|
string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type_upper)
|
||||||
|
|
||||||
|
if(QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
|
||||||
|
foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
|
||||||
|
get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
list(APPEND _args "-L${_item}")
|
||||||
|
endforeach()
|
||||||
|
elseif(QMSETUP_APPLOCAL_DEPS_PATHS)
|
||||||
|
foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
|
||||||
|
get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
list(APPEND _args "-L${_item}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
|
||||||
|
get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
list(APPEND _args "-L${_item}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_item IN LISTS _dep_files)
|
||||||
|
list(APPEND _args "--linkdirs-file" "${_item}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_EXCLUDE)
|
||||||
|
list(APPEND _args -e ${_item})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
list(APPEND _args "$<TARGET_FILE:${_target}>")
|
||||||
|
|
||||||
|
add_custom_command(TARGET ${_deploy_target} POST_BUILD
|
||||||
|
COMMAND ${QMSETUP_CORECMD_EXECUTABLE} deploy ${_args}
|
||||||
|
WORKING_DIRECTORY ${_out_dir}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Add deploy command when install project, not available in debug mode.
|
||||||
|
|
||||||
|
qm_deploy_directory(<install_dir>
|
||||||
|
[FORCE] [STANDARD] [VERBOSE]
|
||||||
|
[LIBRARY_DIR <dir>]
|
||||||
|
[EXTRA_LIBRARIES <path>...]
|
||||||
|
[EXTRA_PLUGIN_PATHS <path>...]
|
||||||
|
[EXTRA_SEARCHING_PATHS <path>...]
|
||||||
|
|
||||||
|
[PLUGINS <plugin>...]
|
||||||
|
[PLUGIN_DIR <dir>]
|
||||||
|
|
||||||
|
[QML <qml>...]
|
||||||
|
[QML_DIR <dir>]
|
||||||
|
|
||||||
|
[WIN_TARGETS <target>...]
|
||||||
|
|
||||||
|
[COMMENT <comment>]
|
||||||
|
)
|
||||||
|
|
||||||
|
PLUGINS: Qt plugins, in format of `<category>/<name>`
|
||||||
|
PLUGIN_DIR: Qt plugins destination
|
||||||
|
EXTRA_PLUGIN_PATHS: Extra Qt plugins searching paths
|
||||||
|
QML: Qt qml directories
|
||||||
|
QML_DIR: Qt qml destination
|
||||||
|
LIBRARY_DIR: Library destination
|
||||||
|
EXTRA_LIBRARIES: Extra library names list to deploy
|
||||||
|
EXTRA_SEARCHING_PATHS: Extra library searching paths
|
||||||
|
]] #
|
||||||
|
function(qm_deploy_directory _install_dir)
|
||||||
|
set(options FORCE STANDARD VERBOSE)
|
||||||
|
set(oneValueArgs LIBRARY_DIR PLUGIN_DIR QML_DIR COMMENT)
|
||||||
|
set(multiValueArgs EXTRA_PLUGIN_PATHS PLUGINS QML WIN_TARGETS EXTRA_SEARCHING_PATHS EXTRA_LIBRARIES)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
# Get qmake
|
||||||
|
if((FUNC_PLUGINS OR FUNC_QML) AND NOT DEFINED QT_QMAKE_EXECUTABLE)
|
||||||
|
if(TARGET Qt${QT_VERSION_MAJOR}::qmake)
|
||||||
|
qm_get_executable_location(Qt${QT_VERSION_MAJOR}::qmake _qmake_path)
|
||||||
|
set(QT_QMAKE_EXECUTABLE "${_qmake_path}" CACHE FILEPATH "Path to qmake executable" FORCE)
|
||||||
|
elseif((FUNC_PLUGINS AND NOT FUNC_EXTRA_PLUGIN_PATHS) OR FUNC_QML)
|
||||||
|
message(FATAL_ERROR "qm_deploy_directory: qmake not defined. Add find_package(Qt5 COMPONENTS Core) to CMake to enable.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set values
|
||||||
|
qm_set_value(_lib_dir FUNC_LIBRARY_DIR "${_install_dir}/${QMSETUP_SHARED_LIBRARY_CATEGORY}")
|
||||||
|
qm_set_value(_plugin_dir FUNC_PLUGIN_DIR "${_install_dir}/plugins")
|
||||||
|
qm_set_value(_qml_dir FUNC_QML_DIR "${_install_dir}/qml")
|
||||||
|
|
||||||
|
# Prepare commands
|
||||||
|
set(_args
|
||||||
|
-i "${_install_dir}"
|
||||||
|
-m "${QMSETUP_CORECMD_EXECUTABLE}"
|
||||||
|
--plugindir "${_plugin_dir}"
|
||||||
|
--libdir "${_lib_dir}"
|
||||||
|
--qmldir "${_qml_dir}"
|
||||||
|
)
|
||||||
|
set(_searching_paths)
|
||||||
|
|
||||||
|
if(QT_QMAKE_EXECUTABLE)
|
||||||
|
list(APPEND _args --qmake "${QT_QMAKE_EXECUTABLE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add Qt plugins
|
||||||
|
foreach(_item IN LISTS FUNC_PLUGINS)
|
||||||
|
list(APPEND _args --plugin "${_item}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add QML modules
|
||||||
|
foreach(_item IN LISTS FUNC_QML)
|
||||||
|
list(APPEND _args --qml "${_item}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add extra plugin paths
|
||||||
|
foreach(_item IN LISTS FUNC_EXTRA_PLUGIN_PATHS)
|
||||||
|
list(APPEND _args --extra "${_item}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add extra searching paths
|
||||||
|
foreach(_item IN LISTS FUNC_EXTRA_SEARCHING_PATHS)
|
||||||
|
get_filename_component(_item ${_item} ABSOLUTE)
|
||||||
|
list(APPEND _searching_paths ${_item})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add global extra searching paths
|
||||||
|
if(CMAKE_BUILD_TYPE)
|
||||||
|
string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type_upper)
|
||||||
|
|
||||||
|
if(QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
|
||||||
|
foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS_${_build_type_upper})
|
||||||
|
get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
list(APPEND _searching_paths ${_item})
|
||||||
|
endforeach()
|
||||||
|
elseif(QMSETUP_APPLOCAL_DEPS_PATHS)
|
||||||
|
foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
|
||||||
|
get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
list(APPEND _searching_paths ${_item})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
foreach(_item IN LISTS QMSETUP_APPLOCAL_DEPS_PATHS)
|
||||||
|
get_filename_component(_item ${_item} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
list(APPEND _searching_paths ${_item})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_item IN LISTS _searching_paths)
|
||||||
|
list(APPEND _args -L "${_item}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(_dep_files)
|
||||||
|
|
||||||
|
if(FUNC_WIN_TARGETS)
|
||||||
|
_qm_win_get_all_dep_files(_dep_files ${FUNC_WIN_TARGETS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_item IN LISTS _dep_files)
|
||||||
|
list(APPEND _args "--linkdirs-file" "${_item}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(_script_quoted "cmd /c \"${QMSETUP_MODULES_DIR}/scripts/windeps.bat\"")
|
||||||
|
else()
|
||||||
|
set(_script_quoted "bash \"${QMSETUP_MODULES_DIR}/scripts/unixdeps.sh\"")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add extra libraries
|
||||||
|
foreach(_item IN LISTS _searching_paths)
|
||||||
|
foreach(_lib IN LISTS FUNC_EXTRA_LIBRARIES)
|
||||||
|
set(_path "${_item}/${_lib}")
|
||||||
|
|
||||||
|
if((EXISTS ${_path}) AND(NOT IS_DIRECTORY ${_path}))
|
||||||
|
list(APPEND _args --copy ${_path} ${_lib_dir})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add options
|
||||||
|
if(FUNC_FORCE)
|
||||||
|
list(APPEND _args "-f")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_STANDARD)
|
||||||
|
list(APPEND _args "-s")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_VERBOSE)
|
||||||
|
list(APPEND _args "-V")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_args_quoted)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS _args)
|
||||||
|
set(_args_quoted "${_args_quoted}\"${_item}\" ")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(_comment_code)
|
||||||
|
|
||||||
|
if(FUNC_COMMENT)
|
||||||
|
set(_comment_code "message(STATUS \"${FUNC_COMMENT}\")")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add install command
|
||||||
|
install(CODE "
|
||||||
|
${_comment_code}
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_script_quoted} ${_args_quoted}
|
||||||
|
WORKING_DIRECTORY \"${_install_dir}\"
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Private functions
|
||||||
|
# ----------------------------------
|
||||||
|
function(_qm_win_get_all_dep_files _out)
|
||||||
|
# Get searching paths
|
||||||
|
macro(get_recursive_dynamic_dependencies _current_target _result)
|
||||||
|
get_target_property(_deps ${_current_target} LINK_LIBRARIES)
|
||||||
|
|
||||||
|
if(_deps)
|
||||||
|
foreach(_dep IN LISTS _deps)
|
||||||
|
if(NOT TARGET ${_dep})
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_target_property(_type ${_dep} TYPE)
|
||||||
|
|
||||||
|
if(_type STREQUAL "SHARED_LIBRARY")
|
||||||
|
list(APPEND ${_result} ${_dep})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_recursive_dynamic_dependencies(${_dep} ${_result})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
set(_visited_targets ${ARGN})
|
||||||
|
|
||||||
|
foreach(_target ${ARGN})
|
||||||
|
set(_all_deps)
|
||||||
|
get_recursive_dynamic_dependencies(${_target} _all_deps)
|
||||||
|
|
||||||
|
foreach(_cur_dep IN LISTS _all_deps)
|
||||||
|
if(${_cur_dep} IN_LIST _visited_targets)
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND _visited_targets ${_cur_dep})
|
||||||
|
endforeach()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(_dep_files)
|
||||||
|
|
||||||
|
foreach(_target IN LISTS _visited_targets)
|
||||||
|
# Add file
|
||||||
|
get_target_property(_file ${_target} QMSETUP_DEPENDENCIES_FILE)
|
||||||
|
|
||||||
|
if(NOT _file)
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND _dep_files ${_file})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(${_out} ${_dep_files} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
235
libs/qwindowkit/qmsetup/cmake/modules/Doxygen.cmake
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Add Doxygen documentation generating target.
|
||||||
|
|
||||||
|
qm_setup_doxygen(<target>
|
||||||
|
[NAME <name>]
|
||||||
|
[VERSION <version>]
|
||||||
|
[DESCRIPTION <desc>]
|
||||||
|
[LOGO <file>]
|
||||||
|
[MDFILE <file>]
|
||||||
|
[OUTPUT_DIR <dir>]
|
||||||
|
[INSTALL_DIR <dir>]
|
||||||
|
|
||||||
|
[TAGFILES <file> ...]
|
||||||
|
[GENERATE_TAGFILE <file>]
|
||||||
|
|
||||||
|
[INPUT <file> ...]
|
||||||
|
[INCLUDE_DIRECTORIES <dir> ...]
|
||||||
|
[COMPILE_DEFINITIONS <NAME=VALUE> ...]
|
||||||
|
[TARGETS <target> ...]
|
||||||
|
[ENVIRONMENT_EXPORTS <key> ...]
|
||||||
|
[NO_EXPAND_MACROS <macro> ...]
|
||||||
|
[DEPENDS <dependency> ...]
|
||||||
|
)
|
||||||
|
]] #
|
||||||
|
function(qm_setup_doxygen _target)
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs NAME VERSION DESCRIPTION LOGO MDFILE OUTPUT_DIR INSTALL_DIR GENERATE_TAGFILE)
|
||||||
|
set(multiValueArgs INPUT TAGFILES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS TARGETS ENVIRONMENT_EXPORTS
|
||||||
|
NO_EXPAND_MACROS DEPENDS
|
||||||
|
)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT DOXYGEN_EXECUTABLE)
|
||||||
|
message(FATAL_ERROR "qm_setup_doxygen: DOXYGEN_EXECUTABLE not defined. Add find_package(Doxygen) to CMake to enable.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(DOXYGEN_FILE_DIR ${QMSETUP_MODULES_DIR}/doxygen)
|
||||||
|
|
||||||
|
if(FUNC_NAME)
|
||||||
|
set(_name ${FUNC_NAME})
|
||||||
|
else()
|
||||||
|
set(_name ${PROJECT_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_VERSION)
|
||||||
|
set(_version ${FUNC_VERSION})
|
||||||
|
else()
|
||||||
|
set(_version ${PROJECT_VERSION})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_DESCRIPTION)
|
||||||
|
set(_desc ${FUNC_DESCRIPTION})
|
||||||
|
elseif(PROJECT_DESCRIPTION)
|
||||||
|
set(_desc ${PROJECT_DESCRIPTION})
|
||||||
|
else()
|
||||||
|
set(_desc ${_name})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_LOGO)
|
||||||
|
set(_logo ${FUNC_LOGO})
|
||||||
|
else()
|
||||||
|
set(_logo)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_MDFILE)
|
||||||
|
set(_mdfile ${FUNC_MDFILE})
|
||||||
|
else()
|
||||||
|
set(_mdfile)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_GENERATE_TAGFILE)
|
||||||
|
set(_tagfile ${FUNC_GENERATE_TAGFILE})
|
||||||
|
else()
|
||||||
|
set(_tagfile)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_sep " \\\n ")
|
||||||
|
|
||||||
|
# Generate include file
|
||||||
|
set(_doxy_includes "${CMAKE_CURRENT_BINARY_DIR}/cmake/doxygen_${_target}_$<CONFIG>.inc")
|
||||||
|
set(_doxy_output_dir "${CMAKE_CURRENT_BINARY_DIR}/doxygen_${_target}")
|
||||||
|
|
||||||
|
set(_input "")
|
||||||
|
set(_tagfiles "")
|
||||||
|
set(_includes "")
|
||||||
|
set(_defines "")
|
||||||
|
set(_no_expand "")
|
||||||
|
|
||||||
|
if(FUNC_INPUT)
|
||||||
|
set(_input "INPUT = $<JOIN:${FUNC_INPUT},${_sep}>\n\n")
|
||||||
|
else()
|
||||||
|
set(_input "INPUT = \n\n")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_TAGFILES)
|
||||||
|
set(_tagfiles "TAGFILES = $<JOIN:${FUNC_TAGFILES},${_sep}>\n\n")
|
||||||
|
else()
|
||||||
|
set(_tagfiles "TAGFILES = \n\n")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_INCLUDE_DIRECTORIES)
|
||||||
|
set(_includes "INCLUDE_PATH = $<JOIN:${FUNC_INCLUDE_DIRECTORIES},${_sep}>\n\n")
|
||||||
|
else()
|
||||||
|
set(_includes "INCLUDE_PATH = \n\n")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_COMPILE_DEFINITIONS)
|
||||||
|
set(_defines "PREDEFINED = $<JOIN:${FUNC_COMPILE_DEFINITIONS},${_sep}>\n\n")
|
||||||
|
else()
|
||||||
|
set(_defines "PREDEFINED = \n\n")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_NO_EXPAND_MACROS)
|
||||||
|
set(_temp_list)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_NO_EXPAND_MACROS)
|
||||||
|
list(APPEND _temp_list "${_item}=")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(_no_expand "PREDEFINED += $<JOIN:${_temp_list},${_sep}>\n\n")
|
||||||
|
unset(_temp_list)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Extra
|
||||||
|
set(_extra_arguments)
|
||||||
|
|
||||||
|
if(FUNC_TARGETS)
|
||||||
|
foreach(item IN LISTS FUNC_TARGETS)
|
||||||
|
set(_extra_arguments
|
||||||
|
"${_extra_arguments}INCLUDE_PATH += $<JOIN:$<TARGET_PROPERTY:${item},INCLUDE_DIRECTORIES>,${_sep}>\n\n")
|
||||||
|
set(_extra_arguments
|
||||||
|
"${_extra_arguments}PREDEFINED += $<JOIN:$<TARGET_PROPERTY:${item},COMPILE_DEFINITIONS>,${_sep}>\n\n")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_OUTPUT_DIR)
|
||||||
|
set(_doxy_output_dir ${FUNC_OUTPUT_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_mdfile)
|
||||||
|
set(_extra_arguments "${_extra_arguments}INPUT += ${_mdfile}\n\n")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(GENERATE
|
||||||
|
OUTPUT "${_doxy_includes}"
|
||||||
|
CONTENT "${_input}${_tagfiles}${_includes}${_defines}${_extra_arguments}${_no_expand}"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_env)
|
||||||
|
|
||||||
|
foreach(_export IN LISTS FUNC_ENVIRONMENT_EXPORTS)
|
||||||
|
if(NOT DEFINED "${_export}")
|
||||||
|
message(FATAL_ERROR "qm_setup_doxygen: ${_export} is not known when trying to export it.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND _env "${_export}=${${_export}}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
list(APPEND _env "DOXY_FILE_DIR=${DOXYGEN_FILE_DIR}")
|
||||||
|
list(APPEND _env "DOXY_INCLUDE_FILE=${_doxy_includes}")
|
||||||
|
|
||||||
|
list(APPEND _env "DOXY_PROJECT_NAME=${_name}")
|
||||||
|
list(APPEND _env "DOXY_PROJECT_VERSION=${_version}")
|
||||||
|
list(APPEND _env "DOXY_PROJECT_BRIEF=${_desc}")
|
||||||
|
list(APPEND _env "DOXY_PROJECT_LOGO=${_logo}")
|
||||||
|
list(APPEND _env "DOXY_MAINPAGE_MD_FILE=${_mdfile}")
|
||||||
|
|
||||||
|
set(_build_command "${CMAKE_COMMAND}" "-E" "env"
|
||||||
|
${_env}
|
||||||
|
"DOXY_OUTPUT_DIR=${_doxy_output_dir}"
|
||||||
|
"DOXY_GENERATE_TAGFILE=${_tagfile}"
|
||||||
|
"${DOXYGEN_EXECUTABLE}"
|
||||||
|
"${DOXYGEN_FILE_DIR}/Doxyfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(FUNC_DEPENDS)
|
||||||
|
set(_dependencies DEPENDS ${FUNC_DEPENDS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_tagfile)
|
||||||
|
get_filename_component(_tagfile_dir ${_tagfile} ABSOLUTE)
|
||||||
|
get_filename_component(_tagfile_dir ${_tagfile_dir} DIRECTORY)
|
||||||
|
set(_make_tagfile_dir_cmd COMMAND ${CMAKE_COMMAND} -E make_directory ${_tagfile_dir})
|
||||||
|
else()
|
||||||
|
set(_make_tagfile_dir_cmd)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(${_target}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${_doxy_output_dir}
|
||||||
|
${_make_tagfile_dir_cmd}
|
||||||
|
COMMAND ${_build_command}
|
||||||
|
COMMENT "Building HTML documentation"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
VERBATIM
|
||||||
|
${_dependencies}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(FUNC_INSTALL_DIR)
|
||||||
|
set(_install_dir ${FUNC_INSTALL_DIR})
|
||||||
|
|
||||||
|
if(_tagfile)
|
||||||
|
get_filename_component(_name ${_tagfile} NAME)
|
||||||
|
set(_install_tagfile ${_name})
|
||||||
|
else()
|
||||||
|
set(_install_tagfile)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_install_command "${CMAKE_COMMAND}" "-E" "env"
|
||||||
|
${_env}
|
||||||
|
"DOXY_OUTPUT_DIR=\${_install_dir}"
|
||||||
|
"DOXY_GENERATE_TAGFILE=\${_install_dir}/${_install_tagfile}"
|
||||||
|
"${DOXYGEN_EXECUTABLE}"
|
||||||
|
"${DOXYGEN_FILE_DIR}/Doxyfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_install_command_quoted)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS _install_command)
|
||||||
|
set(_install_command_quoted "${_install_command_quoted}\"${_item}\" ")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
install(CODE "
|
||||||
|
message(STATUS \"Installing HTML documentation\")
|
||||||
|
get_filename_component(_install_dir \"${_install_dir}\" ABSOLUTE BASE_DIR \${CMAKE_INSTALL_PREFIX})
|
||||||
|
file(MAKE_DIRECTORY \${_install_dir})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_install_command_quoted}
|
||||||
|
WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"
|
||||||
|
OUTPUT_QUIET
|
||||||
|
)
|
||||||
|
")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
199
libs/qwindowkit/qmsetup/cmake/modules/Filesystem.cmake
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
if(NOT QMSETUP_MODULES_DIR)
|
||||||
|
get_filename_component(QMSETUP_MODULES_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Initialize the build output directories of targets and resources.
|
||||||
|
|
||||||
|
qm_init_directories()
|
||||||
|
]] #
|
||||||
|
macro(qm_init_directories)
|
||||||
|
if(NOT DEFINED QMSETUP_BUILD_DIR)
|
||||||
|
set(QMSETUP_BUILD_DIR "${CMAKE_BINARY_DIR}/out-$<LOWER_CASE:${CMAKE_SYSTEM_PROCESSOR}>-$<CONFIG>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${QMSETUP_BUILD_DIR}/bin)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${QMSETUP_BUILD_DIR}/lib)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${QMSETUP_BUILD_DIR}/lib)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_BUILD_SHARE_DIR)
|
||||||
|
set(CMAKE_BUILD_SHARE_DIR ${QMSETUP_BUILD_DIR}/share)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Add a resources copying command for whole project.
|
||||||
|
|
||||||
|
qm_add_copy_command(<target>
|
||||||
|
[CUSTOM_TARGET <target>]
|
||||||
|
[EXTRA_ARGS <args...>]
|
||||||
|
[DEPENDS <targets...>]
|
||||||
|
[VERBOSE] [SKIP_BUILD] [SKIP_INSTALL]
|
||||||
|
|
||||||
|
SOURCES <file/dir...> [DESTINATION <dir>] [INSTALL_DIR <dir>]
|
||||||
|
)
|
||||||
|
|
||||||
|
CUSTOM_TARGET: Use a custom target to control the copy command
|
||||||
|
EXTRA_ARGS: Extra arguments to pass to file(INSTALL) statement
|
||||||
|
DEPENDS: Targets that the copy command depends
|
||||||
|
|
||||||
|
SOURCES: Source files or directories, directories ending with "/" will have their contents copied
|
||||||
|
DESTINATION: Copy the source file to the destination path. If the given value is a relative path,
|
||||||
|
the base directory depends on the type of the target
|
||||||
|
- `$<TARGET_FILE_DIR>`: real target
|
||||||
|
- `QMSETUP_BUILD_DIR`: custom target
|
||||||
|
INSTALL_DIR: Install the source files into a subdirectory in the given path. The subdirectory is the
|
||||||
|
relative path from the `QMSETUP_BUILD_DIR` to `DESTINATION`.
|
||||||
|
]] #
|
||||||
|
function(qm_add_copy_command _target)
|
||||||
|
set(options VERBOSE SKIP_BUILD SKIP_INSTALL)
|
||||||
|
set(oneValueArgs CUSTOM_TARGET DESTINATION INSTALL_DIR)
|
||||||
|
set(multiValueArgs SOURCES EXTRA_ARGS DEPENDS)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT FUNC_SOURCES)
|
||||||
|
message(FATAL_ERROR "qm_add_copy_command: SOURCES not specified.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET ${_target})
|
||||||
|
add_custom_target(${_target})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Determine destination
|
||||||
|
set(_dest .)
|
||||||
|
|
||||||
|
if(FUNC_DESTINATION)
|
||||||
|
set(_dest ${FUNC_DESTINATION})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Determine destination base directory
|
||||||
|
get_target_property(_type ${_target} TYPE)
|
||||||
|
|
||||||
|
if(_type STREQUAL "UTILITY")
|
||||||
|
if(QMSETUP_BUILD_DIR)
|
||||||
|
set(_dest_base ${QMSETUP_BUILD_DIR})
|
||||||
|
else()
|
||||||
|
set(_dest_base ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(_dest_base "$<TARGET_FILE_DIR:${_target}>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set deploy target
|
||||||
|
if(FUNC_CUSTOM_TARGET)
|
||||||
|
set(_deploy_target ${FUNC_CUSTOM_TARGET})
|
||||||
|
|
||||||
|
if(NOT TARGET ${_deploy_target})
|
||||||
|
add_custom_target(${_deploy_target})
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(_deploy_target ${_target})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_DEPENDS)
|
||||||
|
add_dependencies(${_deploy_target} ${FUNC_DEPENDS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Prepare arguments
|
||||||
|
set(_extra_args)
|
||||||
|
set(_ignore_stdout)
|
||||||
|
|
||||||
|
if(FUNC_EXTRA_ARGS)
|
||||||
|
list(APPEND _extra_args -D "args=${FUNC_EXTRA_ARGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT FUNC_VERBOSE)
|
||||||
|
set(_ignore_stdout ${QMSETUP_IGNORE_STDOUT})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT FUNC_SKIP_BUILD)
|
||||||
|
# Build phase
|
||||||
|
add_custom_command(TARGET ${_deploy_target} POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-D "src=${FUNC_SOURCES}"
|
||||||
|
-D "dest=${_dest}"
|
||||||
|
-D "dest_base=${_dest_base}"
|
||||||
|
${_extra_args}
|
||||||
|
-P "${QMSETUP_MODULES_DIR}/scripts/copy.cmake" ${_ignore_stdout}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_INSTALL_DIR AND NOT FUNC_SKIP_INSTALL)
|
||||||
|
if(NOT QMSETUP_BUILD_DIR)
|
||||||
|
message(FATAL_ERROR "qm_add_copy_command: `QMSETUP_BUILD_DIR` not defined, the install directory cannot be determined.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Install phase
|
||||||
|
install(CODE "
|
||||||
|
set(_src \"${FUNC_SOURCES}\")
|
||||||
|
set(_extra_args \"${FUNC_EXTRA_ARGS}\")
|
||||||
|
|
||||||
|
# Calculate the relative path from build phase destination to build directory
|
||||||
|
get_filename_component(_build_dir \"${_dest}\" ABSOLUTE BASE_DIR \"${_dest_base}\")
|
||||||
|
file(RELATIVE_PATH _rel_path \"${QMSETUP_BUILD_DIR}\" \${_build_dir})
|
||||||
|
|
||||||
|
# Calculate real install directory
|
||||||
|
get_filename_component(_dest \"${FUNC_INSTALL_DIR}/\${_rel_path}\" ABSOLUTE BASE_DIR \${CMAKE_INSTALL_PREFIX})
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND \${CMAKE_COMMAND}
|
||||||
|
-D \"src=\${_src}\"
|
||||||
|
-D \"dest=\${_dest}\"
|
||||||
|
\${_extra_args}
|
||||||
|
-P \"${QMSETUP_MODULES_DIR}/scripts/copy.cmake\"
|
||||||
|
WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"
|
||||||
|
)
|
||||||
|
")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Add a custom command to run `configure_file`.
|
||||||
|
|
||||||
|
qm_future_configure_file(<_input> <output>
|
||||||
|
[FORCE]
|
||||||
|
[EXTRA_ARGS <args...>]
|
||||||
|
[DEPENDS <deps...>]
|
||||||
|
[VARIABLES <var...>]
|
||||||
|
)
|
||||||
|
]] #
|
||||||
|
function(qm_future_configure_file _input _output)
|
||||||
|
set(options FORCE)
|
||||||
|
set(oneValueArgs)
|
||||||
|
set(multiValueArgs VARIABLES EXTRA_ARGS DEPENDS)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
set(_options)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_VARIABLES)
|
||||||
|
list(APPEND _options -D "${_item}=${${_item}}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(FUNC_FORCE)
|
||||||
|
list(APPLE _options -D "force=TRUE")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT ${_output}
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-D "input=${_input}"
|
||||||
|
-D "output=${_output}"
|
||||||
|
-D "args=${FUNC_EXTRA_ARGS}"
|
||||||
|
${_options}
|
||||||
|
-P "${QMSETUP_MODULES_DIR}/scripts/configure_file.cmake"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
DEPENDS ${FUNC_DEPENDS}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
538
libs/qwindowkit/qmsetup/cmake/modules/Preprocess.cmake
Normal file
@@ -0,0 +1,538 @@
|
|||||||
|
#[[
|
||||||
|
Warning: This module depends on `qmcorecmd` after installation.
|
||||||
|
]] #
|
||||||
|
if(NOT QMSETUP_CORECMD_EXECUTABLE)
|
||||||
|
message(FATAL_ERROR "QMSETUP_CORECMD_EXECUTABLE not defined. Add find_package(qmsetup) to CMake first.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_DEFINITION_NUMERICAL)
|
||||||
|
set(QMSETUP_DEFINITION_NUMERICAL off)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_DEFINITION_SCOPE)
|
||||||
|
set(QMSETUP_DEFINITION_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_DEFINITION_PROPERTY)
|
||||||
|
set(QMSETUP_DEFINITION_PROPERTY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_SYNC_INCLUDE_STANDARD)
|
||||||
|
set(QMSETUP_SYNC_INCLUDE_STANDARD on)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Generate indirect reference files for header files to make the include statements more orderly.
|
||||||
|
The generated file has the same timestamp as the source file.
|
||||||
|
|
||||||
|
qm_sync_include(<src> <dest>
|
||||||
|
[STANDARD] [NO_STANDARD] [NO_ALL]
|
||||||
|
[INCLUDE <expr> <sub> ...]
|
||||||
|
[EXCLUDE <expr...>]
|
||||||
|
[INSTALL_DIR <dir>]
|
||||||
|
[FORCE] [VERBOSE]
|
||||||
|
)
|
||||||
|
|
||||||
|
STANDARD: Enable standard public-private pattern, can be forced to enable by enabling `QMSETUP_SYNC_INCLUDE_STANDARD`
|
||||||
|
NO_STANDARD: Disable standard public-private pattern, enable it to override `QMSETUP_SYNC_INCLUDE_STANDARD`
|
||||||
|
#]]
|
||||||
|
function(qm_sync_include _src_dir _dest_dir)
|
||||||
|
set(options FORCE VERBOSE NO_STANDARD NO_ALL)
|
||||||
|
set(oneValueArgs INSTALL_DIR)
|
||||||
|
set(multiValueArgs INCLUDE EXCLUDE)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT IS_ABSOLUTE ${_src_dir})
|
||||||
|
get_filename_component(_src_dir ${_src_dir} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
string(REPLACE "\\" "/" _src_dir ${_src_dir})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT IS_ABSOLUTE ${_dest_dir})
|
||||||
|
get_filename_component(_dest_dir ${_dest_dir} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
string(REPLACE "\\" "/" _dest_dir ${_dest_dir})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(IS_DIRECTORY ${_src_dir})
|
||||||
|
file(GLOB_RECURSE header_files ${_src_dir}/*.h ${_src_dir}/*.hpp)
|
||||||
|
|
||||||
|
set(_args)
|
||||||
|
|
||||||
|
if(FUNC_STANDARD OR(QMSETUP_SYNC_INCLUDE_STANDARD AND NOT FUNC_NO_STANDARD))
|
||||||
|
list(APPEND _args -s)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_NO_ALL)
|
||||||
|
list(APPEND _args -n)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_even off)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_INCLUDE)
|
||||||
|
if(_even)
|
||||||
|
set(_even off)
|
||||||
|
list(APPEND _args ${_item})
|
||||||
|
else()
|
||||||
|
set(_even on)
|
||||||
|
list(APPEND _args -i ${_item})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_EXCLUDE)
|
||||||
|
list(APPEND _args -e ${_item})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(FUNC_VERBOSE)
|
||||||
|
list(APPEND _args -V)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_FORCE OR NOT EXISTS ${_dest_dir})
|
||||||
|
if(EXISTS ${_dest_dir})
|
||||||
|
file(REMOVE_RECURSE ${_dest_dir})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${QMSETUP_CORECMD_EXECUTABLE} incsync ${_args} ${_src_dir} ${_dest_dir}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_INSTALL_DIR)
|
||||||
|
set(_install_dir ${FUNC_INSTALL_DIR})
|
||||||
|
set(_args_quoted)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS _args)
|
||||||
|
set(_args_quoted "${_args_quoted}\"${_item}\" ")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Get command output only and use file(INSTALL) to install files
|
||||||
|
install(CODE "
|
||||||
|
get_filename_component(_install_dir \"${_install_dir}\" ABSOLUTE BASE_DIR \${CMAKE_INSTALL_PREFIX})
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND \"${QMSETUP_CORECMD_EXECUTABLE}\" incsync -d
|
||||||
|
${_args_quoted} \"${_src_dir}\" \${_install_dir}
|
||||||
|
WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"
|
||||||
|
OUTPUT_VARIABLE _output_contents
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
string(REPLACE \"\\n\" \";\" _lines \"\${_output_contents}\")
|
||||||
|
|
||||||
|
foreach(_line IN LISTS _lines)
|
||||||
|
string(REGEX MATCH \"from \\\"([^\\\"]*)\\\" to \\\"([^\\\"]*)\\\"\" _ \${_line})
|
||||||
|
get_filename_component(_target_path \${CMAKE_MATCH_2} DIRECTORY)
|
||||||
|
file(INSTALL \${CMAKE_MATCH_1} DESTINATION \${_target_path})
|
||||||
|
endforeach()
|
||||||
|
")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "qm_sync_include: source directory doesn't exist.")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Add a definition to a property scope.
|
||||||
|
|
||||||
|
qm_add_definition( <key | key=value> | <key> <value>
|
||||||
|
[GLOBAL | TARGET <target> | SOURCE <file> | DIRECTORY <dir>]
|
||||||
|
[PROPERTY <prop>]
|
||||||
|
|
||||||
|
[CONDITION <cond...>]
|
||||||
|
[STRING_LITERAL] [NO_KEYWORD]
|
||||||
|
[NUMERICAL] [CLASSICAL]
|
||||||
|
)
|
||||||
|
|
||||||
|
STRING_LITERAL: Force quotes on values
|
||||||
|
NO_KEYWORD: Treat any keyword as string
|
||||||
|
NUMERICAL: Use 1/-1 as defined/undefined, can be forced to enable by enabling `QMSETUP_DEFINITION_NUMERICAL`
|
||||||
|
CLASSICAL: Use classical definition, enable it to override `QMSETUP_DEFINITION_NUMERICAL`
|
||||||
|
]] #
|
||||||
|
function(qm_add_definition _first)
|
||||||
|
set(options STRING_LITERAL NO_KEYWORD NUMERICAL CLASSICAL)
|
||||||
|
set(oneValueArgs TARGET SOURCE DIRECTORY PROPERTY)
|
||||||
|
set(multiValueArgs CONDITION)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
set(_result)
|
||||||
|
set(_is_pair off)
|
||||||
|
set(_defined off)
|
||||||
|
|
||||||
|
set(_list ${_first} ${FUNC_UNPARSED_ARGUMENTS})
|
||||||
|
list(LENGTH _list _len)
|
||||||
|
|
||||||
|
set(_cond on)
|
||||||
|
set(_numerical off)
|
||||||
|
|
||||||
|
if(NOT FUNC_CLASSICAL AND(QMSETUP_DEFINITION_NUMERICAL OR FUNC_NUMERICAL))
|
||||||
|
set(_numerical on)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_CONDITION)
|
||||||
|
if(NOT(${FUNC_CONDITION}))
|
||||||
|
set(_cond off)
|
||||||
|
endif()
|
||||||
|
elseif(DEFINED FUNC_CONDITION)
|
||||||
|
set(_cond off)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_len EQUAL 1)
|
||||||
|
set(_result ${_list})
|
||||||
|
set(_defined on)
|
||||||
|
|
||||||
|
if(NOT _cond)
|
||||||
|
set(_defined off)
|
||||||
|
endif()
|
||||||
|
elseif(_len EQUAL 2)
|
||||||
|
# Get key
|
||||||
|
list(POP_FRONT _list _key)
|
||||||
|
list(POP_FRONT _list _val)
|
||||||
|
|
||||||
|
if(FUNC_STRING_LITERAL AND NOT ${_val} MATCHES "\".+\"")
|
||||||
|
set(_val "\"${_val}\"")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Boolean
|
||||||
|
string(TOLOWER ${_val} _val_lower)
|
||||||
|
|
||||||
|
if(NOT FUNC_NO_KEYWORD AND(${_val_lower} STREQUAL "off" OR ${_val_lower} STREQUAL "false"))
|
||||||
|
set(_result ${_key})
|
||||||
|
set(_defined off)
|
||||||
|
|
||||||
|
if(NOT _cond)
|
||||||
|
set(_defined on)
|
||||||
|
endif()
|
||||||
|
elseif(NOT FUNC_NO_KEYWORD AND(${_val_lower} STREQUAL "on" OR ${_val_lower} STREQUAL "true"))
|
||||||
|
set(_result ${_key})
|
||||||
|
set(_defined on)
|
||||||
|
|
||||||
|
if(NOT _cond)
|
||||||
|
set(_defined off)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(_result "${_key}=${_val}")
|
||||||
|
set(_is_pair on)
|
||||||
|
set(_defined on)
|
||||||
|
|
||||||
|
if(NOT _cond)
|
||||||
|
set(_defined off)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "qm_add_definition: called with incorrect number of arguments")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_numerical AND NOT _is_pair)
|
||||||
|
if(_defined)
|
||||||
|
set(_result "${_result}=1")
|
||||||
|
else()
|
||||||
|
set(_result "${_result}=-1")
|
||||||
|
endif()
|
||||||
|
elseif(NOT _defined)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qm_calc_property_scope_helper(_scope _prop)
|
||||||
|
set_property(${_scope} APPEND PROPERTY ${_prop} "${_result}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Remove a definition from a property scope.
|
||||||
|
|
||||||
|
qm_remove_definition(<key>
|
||||||
|
[GLOBAL | TARGET <target> | SOURCE <file> | DIRECTORY <dir>]
|
||||||
|
[PROPERTY <prop>]
|
||||||
|
)
|
||||||
|
]] #
|
||||||
|
function(qm_remove_definition _key)
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs TARGET PROPERTY)
|
||||||
|
set(multiValueArgs)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(FUNC_TARGET)
|
||||||
|
get_target_property(_definitions ${FUNC_TARGET} ${_prop})
|
||||||
|
else()
|
||||||
|
get_property(_definitions GLOBAL PROPERTY ${_prop})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Filter
|
||||||
|
list(FILTER _definitions EXCLUDE REGEX "^${_key}(=.*)?$")
|
||||||
|
|
||||||
|
_qm_calc_property_scope_helper(_scope _prop)
|
||||||
|
set_property(${_scope} PROPERTY ${_prop} "${_definitions}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Generate a configuration header of a property scope. If the configuration has not changed,
|
||||||
|
the generated file's timestemp will not be updated when you reconfigure it.
|
||||||
|
|
||||||
|
qm_generate_config(<file>
|
||||||
|
[GLOBAL | TARGET <target> | SOURCE <file> | DIRECTORY <dir>]
|
||||||
|
[PROPERTY <prop>]
|
||||||
|
|
||||||
|
[PROJECT_NAME <name>]
|
||||||
|
[WARNING_FILE <file>]
|
||||||
|
[NO_WARNING]
|
||||||
|
[NO_HASH]
|
||||||
|
)
|
||||||
|
]] #
|
||||||
|
function(qm_generate_config _file)
|
||||||
|
set(options NO_WARNING NO_HASH)
|
||||||
|
set(oneValueArgs TARGET PROPERTY PROJECT_NAME WARNING_FILE)
|
||||||
|
set(multiValueArgs)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
_qm_calc_property_scope_helper(_scope _prop)
|
||||||
|
get_property(_definitions ${_scope} PROPERTY ${_prop})
|
||||||
|
|
||||||
|
if(NOT _definitions)
|
||||||
|
set(_definitions) # May be _-NOTFOUND
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qm_generate_config_helper()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Generate build info information header.
|
||||||
|
|
||||||
|
qm_generate_build_info(<file>
|
||||||
|
[REQUIRED]
|
||||||
|
[ROOT_DIRECTORY <dir>]
|
||||||
|
[PREFIX <prefix>]
|
||||||
|
[YEAR] [TIME]
|
||||||
|
|
||||||
|
[PROJECT_NAME <name>]
|
||||||
|
[WARNING_FILE <file>]
|
||||||
|
[NO_WARNING]
|
||||||
|
[NO_HASH]
|
||||||
|
)
|
||||||
|
|
||||||
|
file: Output file
|
||||||
|
|
||||||
|
REQUIRED: Abort if there's any error with git
|
||||||
|
ROOT_DIRECTORY: Repository root directory (CMake will try to run `git` at this directory)
|
||||||
|
PREFIX: Macros prefix, default to the upper case of `PROJECT_NAME`
|
||||||
|
]] #
|
||||||
|
function(qm_generate_build_info _file)
|
||||||
|
set(options NO_WARNING NO_HASH YEAR TIME REQUIRED)
|
||||||
|
set(oneValueArgs ROOT_DIRECTORY PREFIX PROJECT_NAME WARNING_FILE)
|
||||||
|
set(multiValueArgs)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(FUNC_PREFIX)
|
||||||
|
set(_prefix ${FUNC_PREFIX})
|
||||||
|
else()
|
||||||
|
string(TOUPPER "${PROJECT_NAME}" _prefix)
|
||||||
|
string(MAKE_C_IDENTIFIER ${_prefix} _prefix)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_dir)
|
||||||
|
qm_set_value(_dir FUNC_ROOT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
set(_git_branch "unknown")
|
||||||
|
set(_git_hash "unknown")
|
||||||
|
set(_git_commit_time "unknown")
|
||||||
|
set(_git_commit_author "unknown")
|
||||||
|
set(_git_commit_email "unknown")
|
||||||
|
set(_git_revision_id "0")
|
||||||
|
|
||||||
|
# Check `git` command
|
||||||
|
if(NOT GIT_EXECUTABLE)
|
||||||
|
find_package(Git)
|
||||||
|
|
||||||
|
if(NOT Git_FOUND)
|
||||||
|
if(FUNC_REQUIRED)
|
||||||
|
message(FATAL_ERROR "Git not found")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(GIT_EXECUTABLE)
|
||||||
|
# Branch
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} symbolic-ref --short -q HEAD
|
||||||
|
OUTPUT_VARIABLE _temp
|
||||||
|
ERROR_VARIABLE _err
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
WORKING_DIRECTORY ${_dir}
|
||||||
|
RESULT_VARIABLE _code
|
||||||
|
)
|
||||||
|
|
||||||
|
if(_code EQUAL 0)
|
||||||
|
set(_git_branch ${_temp})
|
||||||
|
elseif(FUNC_REQUIRED)
|
||||||
|
message(FATAL_ERROR "Error running git symbolic-ref: ${_err}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Hash
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} log -1 "--pretty=format:%H;%aI;%aN;%aE" # Use `;` as separator
|
||||||
|
OUTPUT_VARIABLE _temp
|
||||||
|
ERROR_VARIABLE _err
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
WORKING_DIRECTORY ${_dir}
|
||||||
|
RESULT_VARIABLE _code
|
||||||
|
)
|
||||||
|
|
||||||
|
if(_code EQUAL 0)
|
||||||
|
list(GET _temp 0 _git_hash)
|
||||||
|
list(GET _temp 1 _git_commit_time)
|
||||||
|
list(GET _temp 2 _git_commit_author)
|
||||||
|
list(GET _temp 3 _git_commit_email)
|
||||||
|
elseif(FUNC_REQUIRED)
|
||||||
|
message(FATAL_ERROR "Error running git log: ${_err}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Revision ID
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD
|
||||||
|
OUTPUT_VARIABLE _temp
|
||||||
|
ERROR_VARIABLE _err
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
WORKING_DIRECTORY ${_dir}
|
||||||
|
RESULT_VARIABLE _code
|
||||||
|
)
|
||||||
|
|
||||||
|
if(_code EQUAL 0)
|
||||||
|
set(_git_revision_id ${_temp})
|
||||||
|
elseif(FUNC_REQUIRED)
|
||||||
|
message(FATAL_ERROR "Error running git rev-list: ${_err}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
qm_set_value(_system_name CMAKE_SYSTEM_NAME unknown)
|
||||||
|
qm_set_value(_system_version CMAKE_SYSTEM_VERSION unknown)
|
||||||
|
qm_set_value(_system_processor CMAKE_SYSTEM_PROCESSOR unknown)
|
||||||
|
|
||||||
|
qm_set_value(_host_system_name CMAKE_HOST_SYSTEM_NAME unknown)
|
||||||
|
qm_set_value(_host_system_version CMAKE_HOST_SYSTEM_VERSION unknown)
|
||||||
|
qm_set_value(_host_system_processor CMAKE_HOST_SYSTEM_PROCESSOR unknown)
|
||||||
|
|
||||||
|
qm_set_value(_compiler_name CMAKE_CXX_COMPILER_ID unknown)
|
||||||
|
qm_set_value(_compiler_version CMAKE_CXX_COMPILER_VERSION unknown)
|
||||||
|
qm_set_value(_compiler_arch CMAKE_CXX_COMPILER_ARCHITECTURE_ID unknown)
|
||||||
|
qm_set_value(_compiler_abi CMAKE_CXX_COMPILER_ABI unknown)
|
||||||
|
|
||||||
|
set(_definitions)
|
||||||
|
|
||||||
|
set(_has_time off)
|
||||||
|
|
||||||
|
# year
|
||||||
|
if(FUNC_YEAR)
|
||||||
|
string(TIMESTAMP _build_year "%Y")
|
||||||
|
list(APPEND _definitions ${_prefix}_BUILD_YEAR=\"${_build_year}\")
|
||||||
|
set(_has_time on)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# time
|
||||||
|
if(FUNC_TIME)
|
||||||
|
string(TIMESTAMP _build_time UTC)
|
||||||
|
list(APPEND _definitions ${_prefix}_BUILD_TIME=\"${_build_time}\")
|
||||||
|
set(_has_time on)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_has_time)
|
||||||
|
list(APPEND _definitions "%")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# system
|
||||||
|
list(APPEND _definitions ${_prefix}_SYSTEM_NAME=\"${_system_name}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_SYSTEM_VERSION=\"${_system_version}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_SYSTEM_PROCESSOR=\"${_system_processor}\")
|
||||||
|
|
||||||
|
list(APPEND _definitions ${_prefix}_HOST_SYSTEM_NAME=\"${_host_system_name}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_HOST_SYSTEM_VERSION=\"${_host_system_version}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_HOST_SYSTEM_PROCESSOR=\"${_host_system_processor}\")
|
||||||
|
|
||||||
|
list(APPEND _definitions "%")
|
||||||
|
|
||||||
|
# compiler
|
||||||
|
list(APPEND _definitions ${_prefix}_COMPILER_ID=\"${_compiler_name}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_COMPILER_VERSION=\"${_compiler_version}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_COMPILER_ARCH=\"${_compiler_arch}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_COMPILER_ABI=\"${_compiler_abi}\")
|
||||||
|
|
||||||
|
list(APPEND _definitions "%")
|
||||||
|
|
||||||
|
# build time (deprecated)
|
||||||
|
# list(APPEND _definitions ${_prefix}_BUILD_DATE_TIME=\"${_build_time}\")
|
||||||
|
# list(APPEND _definitions ${_prefix}_BUILD_YEAR=\"${_build_year}\")
|
||||||
|
|
||||||
|
# list(APPEND _definitions "%")
|
||||||
|
|
||||||
|
# git info
|
||||||
|
list(APPEND _definitions ${_prefix}_GIT_BRANCH=\"${_git_branch}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_GIT_LAST_COMMIT_HASH=\"${_git_hash}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_GIT_LAST_COMMIT_TIME=\"${_git_commit_time}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_GIT_LAST_COMMIT_AUTHOR=\"${_git_commit_author}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_GIT_LAST_COMMIT_EMAIL=\"${_git_commit_email}\")
|
||||||
|
list(APPEND _definitions ${_prefix}_GIT_REVISION_ID=\"${_git_revision_id}\")
|
||||||
|
|
||||||
|
_qm_generate_config_helper()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Private functions
|
||||||
|
# ----------------------------------
|
||||||
|
function(_qm_calc_property_scope_helper _scope _prop)
|
||||||
|
if(FUNC_TARGET)
|
||||||
|
set(_scope TARGET ${FUNC_TARGET})
|
||||||
|
elseif(FUNC_SOURCE)
|
||||||
|
set(_scope SOURCE ${FUNC__SOURCE})
|
||||||
|
elseif(FUNC_DIRECTORY)
|
||||||
|
set(_scope DIRECTORY ${FUNC_DIRECTORY})
|
||||||
|
elseif(FUNC_GLOBAL)
|
||||||
|
set(_scope GLOBAL)
|
||||||
|
elseif(QMSETUP_DEFINITION_SCOPE)
|
||||||
|
set(_scope ${QMSETUP_DEFINITION_SCOPE})
|
||||||
|
else()
|
||||||
|
set(_scope GLOBAL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
qm_set_value(_prop FUNC_PROPERTY QMSETUP_DEFINITION_PROPERTY "CONFIG_DEFINITIONS")
|
||||||
|
|
||||||
|
set(_scope ${_scope} PARENT_SCOPE)
|
||||||
|
set(_prop ${_prop} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(_qm_generate_config_helper)
|
||||||
|
set(_args)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS _definitions)
|
||||||
|
list(APPEND _args "-D${_item}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(FUNC_PROJECT_NAME)
|
||||||
|
list(APPEND _args "-p" ${FUNC_PROJECT_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_NO_HASH)
|
||||||
|
list(APPEND _args "-f")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND _args ${_file})
|
||||||
|
|
||||||
|
if(NOT FUNC_NO_WARNING)
|
||||||
|
list(APPEND _args "-w")
|
||||||
|
|
||||||
|
if(FUNC_WARNING_FILE)
|
||||||
|
list(APPEND _args ${FUNC_WARNING_FILE})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(COMMAND ${QMSETUP_CORECMD_EXECUTABLE} configure ${_args}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
141
libs/qwindowkit/qmsetup/cmake/modules/Protobuf.cmake
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Add rules for creating Google Protobuf source files.
|
||||||
|
|
||||||
|
qm_create_protobuf(<OUT>
|
||||||
|
INPUT <files...>
|
||||||
|
[OUTPUT_DIR <dir>]
|
||||||
|
[TARGET <target>]
|
||||||
|
[INCLUDE_DIRECTORIES <dirs...>]
|
||||||
|
[OPTIONS <options...>]
|
||||||
|
[DEPENDS <deps...>]
|
||||||
|
[CREATE_ONCE]
|
||||||
|
)
|
||||||
|
|
||||||
|
INPUT: source files
|
||||||
|
OUTPUT_DIR: output directory
|
||||||
|
|
||||||
|
TARGET: add a custom target to run the generating command
|
||||||
|
|
||||||
|
INCLUDE_DIRECTORIES: extra include directories
|
||||||
|
OPTIONS: extra options passed to protobuf compiler
|
||||||
|
DEPENDS: dependencies
|
||||||
|
|
||||||
|
CREATE_ONCE: create proto code files at configure phase if not exist
|
||||||
|
|
||||||
|
OUT: output source file paths
|
||||||
|
#]]
|
||||||
|
function(qm_create_protobuf _out)
|
||||||
|
set(options CREATE_ONCE)
|
||||||
|
set(oneValueArgs OUTPUT_DIR TARGET)
|
||||||
|
set(multiValueArgs INPUT INCLUDE_DIRECTORIES OPTIONS DEPENDS)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
# Find `protoc`
|
||||||
|
if(NOT PROTOC_EXECUTABLE)
|
||||||
|
if(NOT TARGET protobuf::protoc)
|
||||||
|
message(FATAL_ERROR "qm_create_protobuf: protobuf compiler not found. Add find_package(Protobuf) to CMake to enable.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_target_property(PROTOC_EXECUTABLE protobuf::protoc LOCATION)
|
||||||
|
|
||||||
|
if(NOT PROTOC_EXECUTABLE)
|
||||||
|
message(FATAL_ERROR "qm_create_protobuf: failed to get the location of `protoc`, you could set PROTOC_EXECUTABLE manually.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Cache value
|
||||||
|
set(PROTOC_EXECUTABLE ${PROTOC_EXECUTABLE} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT FUNC_INPUT)
|
||||||
|
message(FATAL_ERROR "qm_create_protobuf: INPUT not specified.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_OUTPUT_DIR)
|
||||||
|
get_filename_component(_out_dir ${FUNC_OUTPUT_DIR} ABSOLUTE)
|
||||||
|
file(MAKE_DIRECTORY ${_out_dir})
|
||||||
|
else()
|
||||||
|
set(_out_dir ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect include paths and out files
|
||||||
|
set(_include_options)
|
||||||
|
set(_out_files)
|
||||||
|
set(_input_names)
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_INCLUDE_DIRECTORIES)
|
||||||
|
get_filename_component(_abs_path ${_item} ABSOLUTE)
|
||||||
|
list(APPEND _include_options -I${_abs_path})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_INPUT)
|
||||||
|
get_filename_component(_item ${_item} ABSOLUTE)
|
||||||
|
get_filename_component(_abs_path ${_item} DIRECTORY)
|
||||||
|
list(APPEND _include_options -I${_abs_path})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
list(REMOVE_DUPLICATES _include_options)
|
||||||
|
|
||||||
|
set(_create_once_warning)
|
||||||
|
set(_create_once_warning_printed off)
|
||||||
|
|
||||||
|
# Prepare for create once
|
||||||
|
if(FUNC_CREATE_ONCE)
|
||||||
|
# Check if options contain generator expressions
|
||||||
|
foreach(_opt IN LISTS _include_options LISTS FUNC_OPTIONS)
|
||||||
|
string(GENEX_STRIP "${_opt}" _no_genex)
|
||||||
|
|
||||||
|
if(NOT _no_genex STREQUAL _opt)
|
||||||
|
set(_create_once_warning "options contain generator expressions, skip generating source file now")
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_INPUT)
|
||||||
|
get_filename_component(_basename ${_item} NAME_WLE)
|
||||||
|
list(APPEND _out_files ${_out_dir}/${_basename}.pb.h ${_out_dir}/${_basename}.pb.cc)
|
||||||
|
|
||||||
|
get_filename_component(_name ${_item} NAME)
|
||||||
|
list(APPEND _input_names ${_name})
|
||||||
|
|
||||||
|
if(FUNC_CREATE_ONCE AND(NOT EXISTS ${_out_dir}/${_basename}.pb.h OR NOT EXISTS ${_out_dir}/${_basename}.pb.cc))
|
||||||
|
if(_create_once_warning)
|
||||||
|
if(NOT _create_once_warning_printed)
|
||||||
|
message(WARNING "qm_create_protobuf: ${_create_once_warning}")
|
||||||
|
set(_create_once_warning_printed on)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
get_filename_component(_abs_file ${_item} ABSOLUTE)
|
||||||
|
|
||||||
|
if(NOT EXISTS ${_abs_file})
|
||||||
|
message(WARNING "qm_create_protobuf: input file \"${_name}\" is not available, skip generating source file now")
|
||||||
|
else()
|
||||||
|
message(STATUS "Protoc: Generating ${_basename}.pb.h, ${_basename}.pb.cc")
|
||||||
|
execute_process(COMMAND
|
||||||
|
${PROTOC_EXECUTABLE} --cpp_out=${_out_dir} ${_include_options} ${FUNC_OPTIONS} ${_name}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${_out_dir}/${_basename}.pb.h ${_out_dir}/${_basename}.pb.cc
|
||||||
|
COMMAND ${PROTOC_EXECUTABLE} --cpp_out=${_out_dir} ${_include_options} ${FUNC_OPTIONS} ${_name}
|
||||||
|
DEPENDS ${_item} ${FUNC_DEPENDS}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(FUNC_TARGET)
|
||||||
|
if(NOT TARGET ${FUNC_TARGET})
|
||||||
|
add_custom_target(${FUNC_TARGET})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_dependencies(${FUNC_TARGET} ${_out_files})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_out} ${_out_files} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
96
libs/qwindowkit/qmsetup/cmake/modules/Qml.cmake
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Installs a QML module and its runtime loadable plugin, meta information, QML files, and resources.
|
||||||
|
The module is identified by the given target name.
|
||||||
|
|
||||||
|
The Qt version should be greater than or equal to 6.3.
|
||||||
|
|
||||||
|
qm_install_qml_modules(target
|
||||||
|
[PREFIX prefix]
|
||||||
|
)
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
PREFIX: install directory prefix (default: "qml")
|
||||||
|
|
||||||
|
Notice:
|
||||||
|
For static library backing targets, you should specify "OUTPUT_TARGETS" when calling "qt_add_qml_module()"
|
||||||
|
to collect the internally generated targets (mainly object libraries), and then install them by calling:
|
||||||
|
|
||||||
|
install(TARGETS ${_output_targets}
|
||||||
|
EXPORT <target set>
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
OBJECTS DESTINATION lib
|
||||||
|
)
|
||||||
|
|
||||||
|
See also: https://doc.qt.io/qt-6/qt-add-qml-module.html
|
||||||
|
|
||||||
|
]] #
|
||||||
|
function(qm_install_qml_modules _target)
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs PREFIX)
|
||||||
|
set(multiValueArgs)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
set(_prefix)
|
||||||
|
qm_set_value(_prefix FUNC_PREFIX "qml")
|
||||||
|
|
||||||
|
qt_query_qml_module(${_target}
|
||||||
|
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 _qml_files_deploy_paths
|
||||||
|
RESOURCES _module_resources
|
||||||
|
RESOURCES_DEPLOY_PATHS _resources_deploy_paths
|
||||||
|
)
|
||||||
|
|
||||||
|
# See also: https://doc.qt.io/qt-6/qt-query-qml-module.html#example
|
||||||
|
|
||||||
|
# Install the QML module runtime loadable plugin
|
||||||
|
set(_module_dir "${_prefix}/${_module_target_path}")
|
||||||
|
install(TARGETS "${_module_plugin_target}"
|
||||||
|
LIBRARY DESTINATION "${_module_dir}"
|
||||||
|
RUNTIME DESTINATION "${_module_dir}"
|
||||||
|
ARCHIVE DESTINATION "${_module_dir}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install the QML module meta information.
|
||||||
|
install(FILES "${_module_qmldir}" DESTINATION "${_module_dir}")
|
||||||
|
install(FILES "${_module_typeinfo}" DESTINATION "${_module_dir}")
|
||||||
|
|
||||||
|
# Install QML files, possibly renamed.
|
||||||
|
list(LENGTH _module_qml_files _num_files)
|
||||||
|
|
||||||
|
if(_num_files GREATER 0)
|
||||||
|
math(EXPR _last_index "${_num_files} - 1")
|
||||||
|
|
||||||
|
foreach(_i RANGE 0 ${_last_index})
|
||||||
|
list(GET _module_qml_files ${_i} _src_file)
|
||||||
|
list(GET _qml_files_deploy_paths ${_i} _deploy_path)
|
||||||
|
get_filename_component(_dest_name "${_deploy_path}" NAME)
|
||||||
|
get_filename_component(_dest_dir "${_deploy_path}" DIRECTORY)
|
||||||
|
install(FILES "${_src_file}" DESTINATION "${_module_dir}/${_dest_dir}" RENAME "${_dest_name}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Install resources, possibly renamed.
|
||||||
|
list(LENGTH _module_resources _num_files)
|
||||||
|
|
||||||
|
if(_num_files GREATER 0)
|
||||||
|
math(EXPR _last_index "${_num_files} - 1")
|
||||||
|
|
||||||
|
foreach(_i RANGE 0 ${_last_index})
|
||||||
|
list(GET _module_resources ${_i} _src_file)
|
||||||
|
list(GET _resources_deploy_paths ${_i} _deploy_path)
|
||||||
|
get_filename_component(_dest_name "${_deploy_path}" NAME)
|
||||||
|
get_filename_component(_dest_dir "${_deploy_path}" DIRECTORY)
|
||||||
|
install(FILES "${_src_file}" DESTINATION "${_module_dir}/${_dest_dir}" RENAME "${_dest_name}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
374
libs/qwindowkit/qmsetup/cmake/modules/Translate.cmake
Normal file
@@ -0,0 +1,374 @@
|
|||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Add qt translation target.
|
||||||
|
|
||||||
|
qm_add_translation(<target>
|
||||||
|
[LOCALES locales]
|
||||||
|
[PREFIX prefix]
|
||||||
|
[SOURCES files... | DIRECTORIES dirs... | TARGETS targets... | TS_FILES files...]
|
||||||
|
[TS_DIR dir]
|
||||||
|
[QM_DIR dir]
|
||||||
|
[TS_OPTIONS options...]
|
||||||
|
[QM_OPTIONS options...]
|
||||||
|
[TS_DEPENDS targets...]
|
||||||
|
[QM_DEPENDS targets...]
|
||||||
|
[CREATE_ONCE]
|
||||||
|
)
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
LOCALES: language names, e.g. zh_CN en_US, must specify if SOURCES or TARGETS is specified
|
||||||
|
PREFIX: translation file prefix, default to target name
|
||||||
|
|
||||||
|
SOURCES: source files
|
||||||
|
DIRECTORIES: source directories
|
||||||
|
TARGETS: target names, the source files of which will be collected
|
||||||
|
TS_FILES: ts file names, add the specified ts file
|
||||||
|
|
||||||
|
TS_DIR: ts files destination, default to `CMAKE_CURRENT_SOURCE_DIR`
|
||||||
|
QM_DIR: qm files destination, default to `CMAKE_CURRENT_BINARY_DIR`
|
||||||
|
|
||||||
|
TS_DEPENDS: add lupdate task as a dependency to the given targets
|
||||||
|
QM_DEPENDS: add lrelease task as a dependency to the given targets
|
||||||
|
|
||||||
|
CREATE_ONCE: create translations at configure phase if not exist
|
||||||
|
|
||||||
|
]] #
|
||||||
|
function(qm_add_translation _target)
|
||||||
|
set(options CREATE_ONCE)
|
||||||
|
set(oneValueArgs PREFIX TS_DIR QM_DIR)
|
||||||
|
set(multiValueArgs LOCALES SOURCES DIRECTORIES TARGETS TS_FILES TS_OPTIONS QM_OPTIONS TS_DEPENDS QM_DEPENDS)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
# Get linguist tools
|
||||||
|
if(NOT TARGET Qt${QT_VERSION_MAJOR}::lupdate OR NOT TARGET Qt${QT_VERSION_MAJOR}::lrelease)
|
||||||
|
message(FATAL_ERROR "qm_add_translation: linguist tools not defined. Add find_package(Qt\${QT_VERSION_MAJOR} COMPONENTS LinguistTools) to CMake to enable.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_src_files)
|
||||||
|
set(_include_dirs)
|
||||||
|
|
||||||
|
# Collect source files
|
||||||
|
if(FUNC_SOURCES)
|
||||||
|
list(APPEND _src_files ${FUNC_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect source files
|
||||||
|
if(FUNC_TARGETS)
|
||||||
|
foreach(_item IN LISTS FUNC_TARGETS)
|
||||||
|
get_target_property(_type ${_item} TYPE)
|
||||||
|
|
||||||
|
if((_type STREQUAL "UTILITY") OR(_type STREQUAL "INTERFACE_LIBRARY"))
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_tmp_files)
|
||||||
|
get_target_property(_tmp_files ${_item} SOURCES)
|
||||||
|
set(_qml_files)
|
||||||
|
get_target_property(_qml_files ${_item} QT_QML_MODULE_QML_FILES)
|
||||||
|
if (NOT _qml_files STREQUAL ${_item}-NOTFOUND)
|
||||||
|
list(APPEND _tmp_files ${_qml_files})
|
||||||
|
endif()
|
||||||
|
list(FILTER _tmp_files INCLUDE REGEX ".+\\.(h|hh|hpp|hxx|c|cc|cpp|cxx|m|mm|qml|js|mjs)$")
|
||||||
|
list(FILTER _tmp_files EXCLUDE REGEX "^(qasc|moc)_.+")
|
||||||
|
|
||||||
|
# Need to convert to absolute path
|
||||||
|
get_target_property(_target_dir ${_item} SOURCE_DIR)
|
||||||
|
|
||||||
|
foreach(_file IN LISTS _tmp_files)
|
||||||
|
get_filename_component(_abs_file ${_file} ABSOLUTE BASE_DIR ${_target_dir})
|
||||||
|
list(APPEND _src_files ${_abs_file})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
unset(_tmp_files)
|
||||||
|
|
||||||
|
get_target_property(_tmp_dirs ${_item} INCLUDE_DIRECTORIES)
|
||||||
|
list(APPEND _include_dirs ${_tmp_dirs})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect source directories
|
||||||
|
if(FUNC_DIRECTORIES)
|
||||||
|
foreach(_item IN LISTS FUNC_DIRECTORIES)
|
||||||
|
file(GLOB _tmp
|
||||||
|
${_item}/*.h ${_item}/*.hpp
|
||||||
|
${_item}/*.hh ${_item}/*.hxx
|
||||||
|
${_item}/*.cpp ${_item}/*.cxx
|
||||||
|
${_item}/*.c ${_item}/*.cc
|
||||||
|
${_item}/*.m ${_item}/*.mm
|
||||||
|
)
|
||||||
|
list(APPEND _src_files ${_tmp})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_src_files)
|
||||||
|
if(NOT FUNC_LOCALES)
|
||||||
|
message(FATAL_ERROR "qm_add_translation: source files collected but LOCALES not specified!")
|
||||||
|
endif()
|
||||||
|
elseif(NOT FUNC_TS_FILES)
|
||||||
|
message(FATAL_ERROR "qm_add_translation: no source files or ts files collected!")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(${_target})
|
||||||
|
|
||||||
|
set(_qm_depends)
|
||||||
|
|
||||||
|
if(FUNC_TS_OPTIONS)
|
||||||
|
set(_ts_options ${FUNC_TS_OPTIONS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_QM_OPTIONS)
|
||||||
|
set(_qm_options ${FUNC_QM_OPTIONS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_src_files)
|
||||||
|
if(FUNC_PREFIX)
|
||||||
|
set(_prefix ${FUNC_PREFIX})
|
||||||
|
else()
|
||||||
|
set(_prefix ${_target})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_TS_DIR)
|
||||||
|
set(_ts_dir ${FUNC_TS_DIR})
|
||||||
|
else()
|
||||||
|
set(_ts_dir ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_ts_files)
|
||||||
|
|
||||||
|
foreach(_loc IN LISTS FUNC_LOCALES)
|
||||||
|
list(APPEND _ts_files ${_ts_dir}/${_prefix}_${_loc}.ts)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Include options
|
||||||
|
set(_include_options)
|
||||||
|
|
||||||
|
foreach(_inc IN LISTS _include_dirs)
|
||||||
|
list(APPEND _include_options "-I${_inc}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# May be an lupdate bug, so we skip passing include directories
|
||||||
|
# list(APPEND _ts_options ${_include_options})
|
||||||
|
if(_ts_options)
|
||||||
|
list(PREPEND _ts_options OPTIONS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_create_once)
|
||||||
|
|
||||||
|
if(FUNC_CREATE_ONCE)
|
||||||
|
set(_create_once CREATE_ONCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qm_add_lupdate_target(${_target}_lupdate
|
||||||
|
INPUT ${_src_files}
|
||||||
|
OUTPUT ${_ts_files}
|
||||||
|
${_ts_options}
|
||||||
|
${_create_once}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add update dependencies
|
||||||
|
# add_dependencies(${_target} ${_target}_lupdate)
|
||||||
|
foreach(_item IN LISTS FUNC_TS_DEPENDS)
|
||||||
|
add_dependencies(${_item} ${_target}_lupdate)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# list(APPEND _qm_depends DEPENDS ${_target}_lupdate)
|
||||||
|
else()
|
||||||
|
if(FUNC_PREFIX)
|
||||||
|
message(WARNING "qm_add_translation: no source files collected, PREFIX ignored")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_TS_DIR)
|
||||||
|
message(WARNING "qm_add_translation: no source files collected, TS_DIR ignored")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_TS_DEPENDS)
|
||||||
|
message(WARNING "qm_add_translation: no source files collected, TS_DEPENDS ignored")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_QM_DIR)
|
||||||
|
set(_qm_dir ${FUNC_QM_DIR})
|
||||||
|
else()
|
||||||
|
set(_qm_dir ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_qm_target)
|
||||||
|
|
||||||
|
if(_qm_options)
|
||||||
|
list(PREPEND _qm_options OPTIONS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
_qm_add_lrelease_target(${_target}_lrelease
|
||||||
|
INPUT ${_ts_files} ${FUNC_TS_FILES}
|
||||||
|
DESTINATION ${_qm_dir}
|
||||||
|
${_qm_options}
|
||||||
|
${_qm_depends}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(${_target} ${_target}_lrelease)
|
||||||
|
|
||||||
|
# Add release dependencies
|
||||||
|
if(FUNC_TARGETS)
|
||||||
|
foreach(_item IN LISTS FUNC_TARGETS)
|
||||||
|
add_dependencies(${_item} ${_target}_lrelease)
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_item IN LISTS FUNC_QM_DEPENDS)
|
||||||
|
add_dependencies(${_item} ${_target}_lrelease)
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# ----------------------------------
|
||||||
|
# Private functions
|
||||||
|
# ----------------------------------
|
||||||
|
# Input: cxx source files
|
||||||
|
# Output: target ts files
|
||||||
|
function(_qm_add_lupdate_target _target)
|
||||||
|
set(options CREATE_ONCE)
|
||||||
|
set(oneValueArgs)
|
||||||
|
set(multiValueArgs INPUT OUTPUT OPTIONS DEPENDS)
|
||||||
|
|
||||||
|
cmake_parse_arguments(_LUPDATE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
set(_lupdate_deps ${_LUPDATE_DEPENDS})
|
||||||
|
|
||||||
|
set(_my_sources ${_LUPDATE_INPUT})
|
||||||
|
set(_my_tsfiles ${_LUPDATE_OUTPUT})
|
||||||
|
|
||||||
|
add_custom_target(${_target} DEPENDS ${_lupdate_deps})
|
||||||
|
qm_get_executable_location(Qt${QT_VERSION_MAJOR}::lupdate _lupdate_exe)
|
||||||
|
|
||||||
|
set(_create_once_warning)
|
||||||
|
set(_create_once_warning_printed off)
|
||||||
|
|
||||||
|
# Prepare for create once
|
||||||
|
if(_LUPDATE_CREATE_ONCE)
|
||||||
|
# Check if all src files are available
|
||||||
|
foreach(_file IN LISTS _my_sources)
|
||||||
|
get_filename_component(_abs_file ${_file} ABSOLUTE)
|
||||||
|
|
||||||
|
if(NOT EXISTS ${_abs_file})
|
||||||
|
get_filename_component(_file ${_file} NAME)
|
||||||
|
set(_create_once_warning "source file \"${_file}\" is not available, skip generating ts file now")
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Check if options contain generator expressions
|
||||||
|
if(NOT _create_once_warning)
|
||||||
|
foreach(_opt IN LISTS _LUPDATE_OPTIONS)
|
||||||
|
string(GENEX_STRIP "${_opt}" _no_genex)
|
||||||
|
|
||||||
|
if(NOT _no_genex STREQUAL _opt)
|
||||||
|
set(_create_once_warning "lupdate options contain generator expressions, skip generating ts file now")
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(_ts_file IN LISTS _my_tsfiles)
|
||||||
|
# make a list file to call lupdate on, so we don't make our commands too
|
||||||
|
# long for some systems
|
||||||
|
get_filename_component(_ts_name ${_ts_file} NAME)
|
||||||
|
set(_ts_lst_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lst_file")
|
||||||
|
set(_lst_file_srcs)
|
||||||
|
|
||||||
|
foreach(_lst_file_src IN LISTS _my_sources)
|
||||||
|
set(_lst_file_srcs "${_lst_file_src}\n${_lst_file_srcs}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES)
|
||||||
|
|
||||||
|
foreach(_pro_include IN LISTS _inc_DIRS)
|
||||||
|
get_filename_component(_abs_include "${_pro_include}" ABSOLUTE)
|
||||||
|
set(_lst_file_srcs "-I${_pro_include}\n${_lst_file_srcs}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
file(WRITE ${_ts_lst_file} "${_lst_file_srcs}")
|
||||||
|
|
||||||
|
get_filename_component(_ts_abs ${_ts_file} ABSOLUTE)
|
||||||
|
|
||||||
|
if(_LUPDATE_CREATE_ONCE AND NOT EXISTS ${_ts_abs})
|
||||||
|
if(_create_once_warning)
|
||||||
|
if(NOT _create_once_warning_printed)
|
||||||
|
message(WARNING "qm_add_translation: ${_create_once_warning}")
|
||||||
|
set(_create_once_warning_printed on)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS "Lupdate: Generating ${_ts_name}")
|
||||||
|
get_filename_component(_abs_file ${_ts_file} ABSOLUTE)
|
||||||
|
get_filename_component(_dir ${_abs_file} DIRECTORY)
|
||||||
|
file(MAKE_DIRECTORY ${_dir})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${_lupdate_exe} ${_LUPDATE_OPTIONS} "@${_ts_lst_file}" -ts ${_ts_file}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
OUTPUT_QUIET
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${_target} POST_BUILD
|
||||||
|
COMMAND ${_lupdate_exe}
|
||||||
|
ARGS ${_LUPDATE_OPTIONS} "@${_ts_lst_file}" -ts ${_ts_file}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
BYPRODUCTS ${_ts_lst_file}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Input: ts files
|
||||||
|
# Output: list to append qm files
|
||||||
|
function(_qm_add_lrelease_target _target)
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs DESTINATION OUTPUT)
|
||||||
|
set(multiValueArgs INPUT OPTIONS DEPENDS)
|
||||||
|
|
||||||
|
cmake_parse_arguments(_LRELEASE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
set(_lrelease_files ${_LRELEASE_INPUT})
|
||||||
|
set(_lrelease_deps ${_LRELEASE_DEPENDS})
|
||||||
|
|
||||||
|
qm_get_executable_location(Qt${QT_VERSION_MAJOR}::lrelease _lrelease_exe)
|
||||||
|
|
||||||
|
set(_qm_files)
|
||||||
|
|
||||||
|
foreach(_file IN LISTS _lrelease_files)
|
||||||
|
get_filename_component(_abs_FILE ${_file} ABSOLUTE)
|
||||||
|
get_filename_component(_qm_file ${_file} NAME)
|
||||||
|
|
||||||
|
# everything before the last dot has to be considered the file name (including other dots)
|
||||||
|
string(REGEX REPLACE "\\.[^.]*$" "" FILE_NAME ${_qm_file})
|
||||||
|
get_source_file_property(output_location ${_abs_FILE} OUTPUT_LOCATION)
|
||||||
|
|
||||||
|
if(output_location)
|
||||||
|
set(_out_dir ${output_location})
|
||||||
|
elseif(_LRELEASE_DESTINATION)
|
||||||
|
set(_out_dir ${_LRELEASE_DESTINATION})
|
||||||
|
else()
|
||||||
|
set(_out_dir ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_qm_file "${_out_dir}/${FILE_NAME}.qm")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${_qm_file}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${_out_dir}
|
||||||
|
COMMAND ${_lrelease_exe} ARGS ${_LRELEASE_OPTIONS} ${_abs_FILE} -qm ${_qm_file}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
DEPENDS ${_lrelease_files}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND _qm_files ${_qm_file})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
add_custom_target(${_target} ALL DEPENDS ${_lrelease_deps} ${_qm_files})
|
||||||
|
|
||||||
|
if(_LRELEASE_OUTPUT)
|
||||||
|
set(${_LRELEASE_OUTPUT} ${_qm_files} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
68
libs/qwindowkit/qmsetup/cmake/modules/private/Generate.cmake
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#[[
|
||||||
|
Warning: This module is private, may be modified or removed in the future, please use with caution.
|
||||||
|
]] #
|
||||||
|
|
||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Create the names of output files preserving relative dirs. (Ported from MOC command)
|
||||||
|
|
||||||
|
qm_make_output_file(<infile> <prefix> <ext> <OUT>)
|
||||||
|
|
||||||
|
OUT: output source file paths
|
||||||
|
#]]
|
||||||
|
function(qm_make_output_file _infile _prefix _ext _out)
|
||||||
|
string(LENGTH ${CMAKE_CURRENT_BINARY_DIR} _binlength)
|
||||||
|
string(LENGTH ${_infile} _infileLength)
|
||||||
|
set(_checkinfile ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
if(_infileLength GREATER _binlength)
|
||||||
|
string(SUBSTRING "${_infile}" 0 ${_binlength} _checkinfile)
|
||||||
|
|
||||||
|
if(_checkinfile STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
file(RELATIVE_PATH _name ${CMAKE_CURRENT_BINARY_DIR} ${_infile})
|
||||||
|
else()
|
||||||
|
file(RELATIVE_PATH _name ${CMAKE_CURRENT_SOURCE_DIR} ${_infile})
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
file(RELATIVE_PATH _name ${CMAKE_CURRENT_SOURCE_DIR} ${_infile})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_HOST_WIN32 AND _name MATCHES "^([a-zA-Z]):(.*)$") # absolute path
|
||||||
|
set(_name "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${_name}")
|
||||||
|
string(REPLACE ".." "__" _outfile ${_outfile})
|
||||||
|
get_filename_component(_outpath ${_outfile} PATH)
|
||||||
|
get_filename_component(_outfile ${_outfile} NAME_WLE)
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY ${_outpath})
|
||||||
|
set(${_out} ${_outpath}/${_prefix}${_outfile}.${_ext} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Create a custom command to run `xxd`.
|
||||||
|
|
||||||
|
qm_add_binary_resource(<input> <output>)
|
||||||
|
#]]
|
||||||
|
function(qm_add_binary_resource _input _output)
|
||||||
|
find_program(_xxd "xxd")
|
||||||
|
if(NOT _xxd)
|
||||||
|
get_filename_component(_name ${_output} NAME)
|
||||||
|
string(MAKE_C_IDENTIFIER ${_name} _name)
|
||||||
|
set(_cmd "${CMAKE_COMMAND}"
|
||||||
|
-D "input=${_input}"
|
||||||
|
-D "output=${_output}"
|
||||||
|
-D "name=${_name}"
|
||||||
|
-P "${QMSETUP_MODULES_DIR}/scripts/xxd.cmake")
|
||||||
|
else()
|
||||||
|
set(_cmd "${_xxd}" "-i" "${_input}" "${_output}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${_output}
|
||||||
|
COMMAND ${_cmd}
|
||||||
|
DEPENDS ${_input}
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
#[[
|
||||||
|
Warning: This module is private, may be modified or removed in the future, please use with caution.
|
||||||
|
]] #
|
||||||
|
|
||||||
|
if(NOT DEFINED QMSETUP_PACKAGE_BUILD_TYPE)
|
||||||
|
set(QMSETUP_PACKAGE_BUILD_TYPE "Release")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
#[[
|
||||||
|
Install external package at configuration phase.
|
||||||
|
|
||||||
|
qm_install_package(<name>
|
||||||
|
[SOURCE_DIR <dir>]
|
||||||
|
[BUILD_TREE_DIR <dir>]
|
||||||
|
[INSTALL_DIR <dir>]
|
||||||
|
[CMAKE_PACKAGE_SUBDIR <subdir>]
|
||||||
|
|
||||||
|
[BUILD_TYPE <type>]
|
||||||
|
[CONFIGURE_ARGS <arg...>]
|
||||||
|
|
||||||
|
[RESULT_PATH <VAR>]
|
||||||
|
)
|
||||||
|
]] #
|
||||||
|
function(qm_install_package _name)
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs SOURCE_DIR BUILD_TREE_DIR INSTALL_DIR CMAKE_PACKAGE_SUBDIR BUILD_TYPE RESULT_PATH)
|
||||||
|
set(multiValueArgs CONFIGURE_ARGS)
|
||||||
|
cmake_parse_arguments(FUNC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
# Directories
|
||||||
|
if(NOT FUNC_SOURCE_DIR)
|
||||||
|
message(FATAL_ERROR "pre_install_package: SOURCE_DIR is not spefified")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_src_dir ${FUNC_SOURCE_DIR})
|
||||||
|
|
||||||
|
if(FUNC_BUILD_TREE_DIR)
|
||||||
|
set(_build_tree_dir ${FUNC_BUILD_TREE_DIR})
|
||||||
|
else()
|
||||||
|
set(_build_tree_dir ${CMAKE_BINARY_DIR}/_build)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_INSTALL_DIR)
|
||||||
|
set(_install_dir ${FUNC_INSTALL_DIR})
|
||||||
|
else()
|
||||||
|
set(_install_dir ${CMAKE_BINARY_DIR}/_install)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_CMAKE_PACKAGE_SUBDIR)
|
||||||
|
set(_cmake_subdir ${FUNC_CMAKE_PACKAGE_SUBDIR})
|
||||||
|
else()
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
set(_cmake_subdir "${CMAKE_INSTALL_LIBDIR}/cmake/${_name}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Build types
|
||||||
|
if(FUNC_BUILD_TYPE)
|
||||||
|
set(_build_type -DCMAKE_BUILD_TYPE=${FUNC_BUILD_TYPE})
|
||||||
|
elseif(CMAKE_BUILD_TYPE)
|
||||||
|
set(_build_type -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})
|
||||||
|
elseif(NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
|
set(_build_type -DCMAKE_BUILD_TYPE=${QMSETUP_PACKAGE_BUILD_TYPE})
|
||||||
|
else()
|
||||||
|
set(_build_type)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_BUILD_TYPE)
|
||||||
|
set(_build_types ${FUNC_BUILD_TYPE})
|
||||||
|
else()
|
||||||
|
set(_build_types ${QMSETUP_PACKAGE_BUILD_TYPE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Do it
|
||||||
|
set(_install_cmake_dir ${_install_dir}/${_cmake_subdir})
|
||||||
|
set(_build_dir ${_build_tree_dir}/${_name})
|
||||||
|
|
||||||
|
if(NOT IS_DIRECTORY ${_install_cmake_dir})
|
||||||
|
# Determine generator
|
||||||
|
set(_extra_args)
|
||||||
|
|
||||||
|
if(CMAKE_GENERATOR)
|
||||||
|
set(_extra_args -G "${CMAKE_GENERATOR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_GENERATOR_PLATFORM)
|
||||||
|
set(_extra_args -A "${CMAKE_GENERATOR_PLATFORM}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Remove old build directory
|
||||||
|
if(IS_DIRECTORY ${_build_dir})
|
||||||
|
file(REMOVE_RECURSE ${_build_dir})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY ${_build_tree_dir})
|
||||||
|
|
||||||
|
# Configure
|
||||||
|
message(STATUS "Configuring ${_name}...")
|
||||||
|
set(_log_file ${_build_tree_dir}/${_name}_configure.log)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -S ${_src_dir} -B ${_build_dir}
|
||||||
|
${_extra_args} ${_build_type}
|
||||||
|
# Pass through CMAKE_INSTALL_LIBDIR to ensure the package uses the same
|
||||||
|
# lib directory convention (e.g., lib vs lib64) as the parent project.
|
||||||
|
# Without this, packages using GNUInstallDirs may default to a different
|
||||||
|
# directory structure than expected.
|
||||||
|
"-DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR}"
|
||||||
|
"-DCMAKE_INSTALL_PREFIX=${_install_dir}" ${FUNC_CONFIGURE_ARGS}
|
||||||
|
OUTPUT_FILE ${_log_file}
|
||||||
|
ERROR_FILE ${_log_file}
|
||||||
|
RESULT_VARIABLE _code
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT ${_code} EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Configure failed, check \"${_log_file}\"")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Build
|
||||||
|
foreach(_item IN LISTS _build_types)
|
||||||
|
message(STATUS "Building ${_name} (${_item})...")
|
||||||
|
set(_log_file ${_build_tree_dir}/${_name}_build-${_item}.log)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} --build ${_build_dir} --config ${_item} --parallel
|
||||||
|
OUTPUT_FILE ${_log_file}
|
||||||
|
ERROR_FILE ${_log_file}
|
||||||
|
RESULT_VARIABLE _code
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT ${_code} EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Build failed, check \"${_log_file}\"")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Install
|
||||||
|
foreach(_item IN LISTS _build_types)
|
||||||
|
message(STATUS "Installing ${_name} (${_item})...")
|
||||||
|
set(_log_file ${_build_tree_dir}/${_name}_install-${_item}.log)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} --build ${_build_dir} --config ${_item} --target install
|
||||||
|
OUTPUT_FILE ${_log_file}
|
||||||
|
ERROR_FILE ${_log_file}
|
||||||
|
RESULT_VARIABLE _code
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT ${_code} EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Install failed, check \"${_log_file}\"")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FUNC_RESULT_PATH)
|
||||||
|
set(${FUNC_RESULT_PATH} ${_install_cmake_dir} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
include_guard(DIRECTORY)
|
||||||
|
|
||||||
|
function(qm_get_windows_proxy _out)
|
||||||
|
if(NOT WIN32)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND reg query "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings" /v ProxyEnable
|
||||||
|
OUTPUT_VARIABLE _proxy_enable_output
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT _proxy_enable_output MATCHES "ProxyEnable[ \t\r\n]+REG_DWORD[ \t\r\n]+0x1")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND reg query "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings" /v ProxyServer
|
||||||
|
OUTPUT_VARIABLE _proxy_server_output
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT _proxy_server_output MATCHES "ProxyServer[ \t\r\n]+REG_SZ[ \t\r\n]+(.*)")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_out} ${CMAKE_MATCH_1} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
macro(qm_set_proxy_env _proxy)
|
||||||
|
set(ENV{HTTP_PROXY} "http://${_proxy}")
|
||||||
|
set(ENV{HTTPS_PROXY} "http://${_proxy}")
|
||||||
|
set(ENV{ALL_PROXY} "http://${_proxy}")
|
||||||
|
endmacro()
|
||||||
19
libs/qwindowkit/qmsetup/cmake/scripts/configure_file.cmake
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# MIT License
|
||||||
|
# Copyright (c) 2023 SineStriker
|
||||||
|
|
||||||
|
# Description:
|
||||||
|
# Command that executes `configure_file`.
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# cmake
|
||||||
|
# -D input=<file>
|
||||||
|
# -D output=<file>
|
||||||
|
# -D force=TRUE/FALSE
|
||||||
|
# [-D args=<args...>]
|
||||||
|
# -P configure_file.cmake
|
||||||
|
|
||||||
|
if(force AND EXISTS ${_output})
|
||||||
|
file(REMOVE ${_output})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(${input} ${output} ${args})
|
||||||
64
libs/qwindowkit/qmsetup/cmake/scripts/copy.cmake
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# MIT License
|
||||||
|
# Copyright (c) 2023 SineStriker
|
||||||
|
|
||||||
|
# Description:
|
||||||
|
# Copy file or directory to destination if different.
|
||||||
|
# Mainly use `file(INSTALL)` to implement.
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# cmake
|
||||||
|
# -D src=<files/dirs...>
|
||||||
|
# -D dest=<dir>
|
||||||
|
# [-D dest_base=<dir>]
|
||||||
|
# [-D args=<args...>]
|
||||||
|
# -P copy.cmake
|
||||||
|
|
||||||
|
# Check required arguments
|
||||||
|
if(NOT src)
|
||||||
|
message(FATAL_ERROR "src not defined.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT dest)
|
||||||
|
message(FATAL_ERROR "dest not defined.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Calculate destination
|
||||||
|
if(dest_base)
|
||||||
|
set(_dest_base ${dest_base})
|
||||||
|
else()
|
||||||
|
set(_dest_base ${CMAKE_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_filename_component(_dest ${dest} ABSOLUTE BASE_DIR ${_dest_base})
|
||||||
|
|
||||||
|
# Copy
|
||||||
|
foreach(_file IN LISTS src)
|
||||||
|
# Avoid using `get_filename_component` to keep the trailing slash
|
||||||
|
set(_path ${_file})
|
||||||
|
|
||||||
|
if(NOT IS_ABSOLUTE ${_path})
|
||||||
|
set(_path "${CMAKE_BINARY_DIR}/${_path}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(IS_DIRECTORY ${_path})
|
||||||
|
file(INSTALL DESTINATION ${_dest}
|
||||||
|
TYPE DIRECTORY
|
||||||
|
FILES ${_path}
|
||||||
|
${args}
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
set(_paths)
|
||||||
|
|
||||||
|
if(${_path} MATCHES "\\*\\*")
|
||||||
|
file(GLOB_RECURSE _paths ${_path})
|
||||||
|
else()
|
||||||
|
file(GLOB _paths ${_path})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(INSTALL DESTINATION ${_dest}
|
||||||
|
TYPE FILE
|
||||||
|
FILES ${_paths}
|
||||||
|
${args}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
245
libs/qwindowkit/qmsetup/cmake/scripts/unixdeps.sh
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# MIT License
|
||||||
|
# Copyright (c) 2023 SineStriker
|
||||||
|
|
||||||
|
# Description: This script calls `qmcorecmd` to deploy dependencies on Mac/Linux.
|
||||||
|
|
||||||
|
# Show usage
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $(basename $0) -i <dir> -m <path>"
|
||||||
|
echo " --plugindir <plugin_dir> --libdir <lib_dir> --qmldir <qml_dir>"
|
||||||
|
echo " [--qmake <qmake_path>] [--extra <extra_path>]..."
|
||||||
|
echo " [--qml <qml_module>]... [--plugin <plugin>]... [--copy <src> <dest>]..."
|
||||||
|
echo " [-f] [-s] [-V] [-h]"
|
||||||
|
echo " -i <input_dir> Directory containing binaries and libraries"
|
||||||
|
echo " -m <corecmd_path> Path to corecmd"
|
||||||
|
echo " --plugindir <plugin_dir> Output directory for plugins"
|
||||||
|
echo " --libdir <lib_dir> Output directory for libraries"
|
||||||
|
echo " --qmldir <qml_dir> Output directory for QML files"
|
||||||
|
echo " --qmake <qmake_path> Path to qmake (optional)"
|
||||||
|
echo " --extra <extra_path> Extra plugin searching path (repeatable)"
|
||||||
|
echo " --qml <qml_module> Relative path to QML directory (repeatable)"
|
||||||
|
echo " --plugin <plugin> Specify a Qt plugin to deploy (repeatable)"
|
||||||
|
echo " --copy <src> <dest> Specify additional binary file to copy and its destination directory (repeatable)"
|
||||||
|
echo " --linkdirs-file Add library searching paths from a list file"
|
||||||
|
echo " -L Add a library searching path"
|
||||||
|
echo " -f Force overwrite existing files"
|
||||||
|
echo " -s Ignore C/C++ runtime and system libraries"
|
||||||
|
echo " -V Show verbose output"
|
||||||
|
echo " -h Show this help message"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize arguments
|
||||||
|
EXTRA_PLUGIN_PATHS=()
|
||||||
|
QML_REL_PATHS=()
|
||||||
|
ARGS=()
|
||||||
|
VERBOSE=""
|
||||||
|
PLUGINS=()
|
||||||
|
FILES=""
|
||||||
|
|
||||||
|
# Parse command line
|
||||||
|
while (( "$#" )); do
|
||||||
|
case "$1" in
|
||||||
|
-i) INPUT_DIR="$2"; shift 2;;
|
||||||
|
-m) CORECMD_PATH="$2"; shift 2;;
|
||||||
|
-L) ARGS+=("-L \"$2\""); shift 2;;
|
||||||
|
--linkdirs-file) ARGS+=("--linkdirs-file \"$2\""); shift 2;;
|
||||||
|
--plugindir) PLUGIN_DIR="$2"; shift 2;;
|
||||||
|
--libdir) LIB_DIR="$2"; shift 2;;
|
||||||
|
--qmldir) QML_DIR="$2"; shift 2;;
|
||||||
|
--qmake) QMAKE_PATH="$2"; shift 2;;
|
||||||
|
--extra) EXTRA_PLUGIN_PATHS+=("$2"); shift 2;;
|
||||||
|
--plugin) PLUGINS+=("$2"); shift 2;;
|
||||||
|
--qml) QML_REL_PATHS+=("$2"); shift 2;;
|
||||||
|
--copy) ARGS+=("-c \"$2\" \"$3\""); shift 3;;
|
||||||
|
-f|-s) ARGS+=("$1"); shift;;
|
||||||
|
-V) VERBOSE="-V"; shift;;
|
||||||
|
-h) usage; exit 0;;
|
||||||
|
*) echo "Error: Unsupported argument $1"; usage; exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check required arguments
|
||||||
|
for arg in INPUT_DIR PLUGIN_DIR LIB_DIR QML_DIR CORECMD_PATH; do
|
||||||
|
if [[ -z ${!arg} ]]; then
|
||||||
|
echo "Error: Missing required argument '$arg'"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Get Qt plugin and QML paths
|
||||||
|
PLUGIN_PATHS=()
|
||||||
|
QML_PATH=""
|
||||||
|
if [[ -n "$QMAKE_PATH" ]]; then
|
||||||
|
QMAKE_PLUGIN_PATH=$($QMAKE_PATH -query QT_INSTALL_PLUGINS)
|
||||||
|
PLUGIN_PATHS+=("$QMAKE_PLUGIN_PATH")
|
||||||
|
|
||||||
|
QML_PATH=$($QMAKE_PATH -query QT_INSTALL_QML)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add extra plugin searching paths
|
||||||
|
PLUGIN_PATHS+=("${EXTRA_PLUGIN_PATHS[@]}")
|
||||||
|
|
||||||
|
# Ensure that the QML search path is not empty
|
||||||
|
# when the QML related path is specified (qmake needs to be specified)
|
||||||
|
if [[ ${#QML_REL_PATHS[@]} -gt 0 && -z "$QML_PATH" ]]; then
|
||||||
|
echo "Error: qmake path must be specified when QML paths are provided"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Search input directory
|
||||||
|
search_input_dir() {
|
||||||
|
local path="$1"
|
||||||
|
for item in "$path"/*; do
|
||||||
|
if [ -d "$item" ]; then
|
||||||
|
# Check if the directory is mac .framework
|
||||||
|
if [[ "OSTYPE" == "darwin"* ]] && [[ "$item" == *.framework ]]; then
|
||||||
|
FILES="$FILES \"$item\""
|
||||||
|
else
|
||||||
|
search_input_dir "$item"
|
||||||
|
fi
|
||||||
|
elif [ -f "$item" ]; then
|
||||||
|
if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
|
||||||
|
# On Windows, search for.exe and.dll files
|
||||||
|
FILES="$FILES \"$item\""
|
||||||
|
else
|
||||||
|
# On Unix, traverse all files, using the file command to
|
||||||
|
# check for executable binary files
|
||||||
|
file_type=$(file -b "$item")
|
||||||
|
if [[ ($file_type == "ELF"* || $file_type == "Mach-O"*) && -x "$item" ]]; then
|
||||||
|
FILES="$FILES \"$item\""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
search_input_dir "$INPUT_DIR"
|
||||||
|
|
||||||
|
# Find the full path to the Qt plugin
|
||||||
|
for plugin_path in "${PLUGINS[@]}"; do
|
||||||
|
# Check format
|
||||||
|
if [[ $plugin_path == */* ]]; then
|
||||||
|
IFS='/' read -r -a plugin_parts <<< "$plugin_path"
|
||||||
|
|
||||||
|
# Extracts the category and name
|
||||||
|
category=${plugin_parts[0]}
|
||||||
|
name=${plugin_parts[1]}
|
||||||
|
|
||||||
|
# Calculate destination directory
|
||||||
|
dest_dir="${PLUGIN_DIR}/${category}"
|
||||||
|
|
||||||
|
# Initialize an array to store found plugins
|
||||||
|
found_plugins=""
|
||||||
|
|
||||||
|
# Traverse the path and find the specific plug-in files
|
||||||
|
for search_path in "${PLUGIN_PATHS[@]}"; do
|
||||||
|
while IFS= read -r plugin; do
|
||||||
|
# Get name
|
||||||
|
plugin_name=$(basename "$plugin")
|
||||||
|
|
||||||
|
# Check if the plugin was already found to avoid duplicates
|
||||||
|
if [[ ! $found_plugins =~ $plugin_name ]]; then
|
||||||
|
found_plugins+="$plugin_name "
|
||||||
|
ARGS+=("-c \"$plugin\" \"$dest_dir\"")
|
||||||
|
fi
|
||||||
|
done < <(find "${search_path}/${category}" -name "lib${name}.*" ! -name "*debug*" ! -type d -print)
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#found_plugins[@]} -eq 0 ]; then
|
||||||
|
echo "Error: Plugin '${plugin_path}' not found in any search paths."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Error: Invalid plugin format '${plugin_path}'. Expected format: <category>/<name>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Process QML item
|
||||||
|
handle_qml_file() {
|
||||||
|
local file="$1"
|
||||||
|
local rel_path="${file#$QML_PATH/}"
|
||||||
|
|
||||||
|
local target="$QML_DIR/$rel_path"
|
||||||
|
local target_dir="$(dirname "$target")"
|
||||||
|
|
||||||
|
# Directory: must be mac framework
|
||||||
|
if [ -d "$file" ]; then
|
||||||
|
ARGS+=("-c \"$file\" \"$target_dir\"")
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ignore specific files
|
||||||
|
if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
|
||||||
|
if [[ "$file" == *.pdb ]] || [[ "$file" == *d.dll ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ "$file" == *_debug.dylib ]] || [[ "$file" == *.so.debug ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine whether it is an executable binary file and handle it accordingly
|
||||||
|
if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OSTYPE" == "cygwin"* ]]; then
|
||||||
|
if [[ "$file" == *.dll || "$file" == *.exe ]]; then
|
||||||
|
ARGS+=("-c \"$file\" \"$target_dir\"")
|
||||||
|
else
|
||||||
|
mkdir -p "$target_dir"
|
||||||
|
cp "$file" "$target"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
file_type=$(file -b "$file")
|
||||||
|
if [[ ($file_type == "ELF"* || $file_type == "Mach-O"*) && -x "$file" ]]; then
|
||||||
|
ARGS+=("-c \"$file\" \"$target_dir\"")
|
||||||
|
else
|
||||||
|
mkdir -p "$target_dir"
|
||||||
|
cp "$file" "$target"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Search QML directory
|
||||||
|
search_qml_dir() {
|
||||||
|
local path="$1"
|
||||||
|
for item in "$path"/*; do
|
||||||
|
if [ -d "$item" ]; then
|
||||||
|
# Check if the path is mac .framework
|
||||||
|
if [[ "OSTYPE" == "darwin"* ]] && [[ "$item" == *.framework ]]; then
|
||||||
|
handle_qml_file "$item"
|
||||||
|
else
|
||||||
|
search_qml_dir "$item"
|
||||||
|
fi
|
||||||
|
elif [ -f "$item" ]; then
|
||||||
|
handle_qml_file "$item"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Process QML directories
|
||||||
|
for qml_rel_path in "${QML_REL_PATHS[@]}"; do
|
||||||
|
full_path="$QML_PATH/$qml_rel_path"
|
||||||
|
if [[ -d "$full_path" ]]; then
|
||||||
|
# Directory
|
||||||
|
search_qml_dir "$full_path"
|
||||||
|
elif [[ -f "$full_path" ]]; then
|
||||||
|
# File
|
||||||
|
handle_qml_file "$full_path" "$QML_DIR"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Build and execute the deploy command
|
||||||
|
DEPLOY_CMD="$CORECMD_PATH deploy $FILES ${ARGS[@]} -o \"$LIB_DIR\" $VERBOSE"
|
||||||
|
if [[ "$VERBOSE" == "-V" ]]; then
|
||||||
|
echo "Executing: $DEPLOY_CMD"
|
||||||
|
fi
|
||||||
|
eval $DEPLOY_CMD
|
||||||
|
|
||||||
|
# Check the deployment result
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
294
libs/qwindowkit/qmsetup/cmake/scripts/windeps.bat
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
:: MIT License
|
||||||
|
:: Copyright (c) 2023 SineStriker
|
||||||
|
|
||||||
|
:: Description: This script calls `qmcorecmd` to deploy dependencies on Windows.
|
||||||
|
|
||||||
|
@echo off
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
:: Initialize arguments
|
||||||
|
set "INPUT_DIR="
|
||||||
|
set "PLUGIN_DIR="
|
||||||
|
set "LIB_DIR="
|
||||||
|
set "QML_DIR="
|
||||||
|
set "QMAKE_PATH="
|
||||||
|
set "CORECMD_PATH="
|
||||||
|
set "VERBOSE="
|
||||||
|
set "FILES="
|
||||||
|
set "EXTRA_PLUGIN_PATHS="
|
||||||
|
set "PLUGINS=" & set /a "PLUGIN_COUNT=0"
|
||||||
|
set "QML_REL_PATHS="
|
||||||
|
set "ARGS=" & set /a "ARG_COUNT=0"
|
||||||
|
|
||||||
|
:: Parse command line
|
||||||
|
:parse_args
|
||||||
|
if "%~1"=="" goto :end_parse_args
|
||||||
|
if "%1"=="-i" set "INPUT_DIR=%~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="-m" set "CORECMD_PATH=%~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="--plugindir" set "PLUGIN_DIR=%~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="--libdir" set "LIB_DIR=%~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="--qmldir" set "QML_DIR=%~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="--qmake" set "QMAKE_PATH=%~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="--extra" set "EXTRA_PLUGIN_PATHS=!EXTRA_PLUGIN_PATHS! %~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="--plugin" set /a "PLUGIN_COUNT+=1" & set "PLUGINS[!PLUGIN_COUNT!]=%~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="--qml" set "QML_REL_PATHS=!QML_REL_PATHS! %~2" & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="--copy" call :push_args -c %~2 %~3 & shift & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="-f" call :push_args -f & shift & goto :parse_args
|
||||||
|
if "%1"=="-s" call :push_args -s & shift & goto :parse_args
|
||||||
|
if "%1"=="-V" set "VERBOSE=-V" & shift & goto :parse_args
|
||||||
|
if "%1"=="-h" call :usage & exit /b
|
||||||
|
|
||||||
|
if "%1"=="--linkdirs-file" call :push_args --linkdirs-file %~2 & shift & shift & goto :parse_args
|
||||||
|
if "%1"=="-L" call :push_args -L %~2 & shift & shift & goto :parse_args
|
||||||
|
|
||||||
|
shift
|
||||||
|
goto :parse_args
|
||||||
|
:end_parse_args
|
||||||
|
|
||||||
|
:: Check required arguments
|
||||||
|
if not defined INPUT_DIR echo Error: Missing required argument 'INPUT_DIR' & call :usage & exit /b
|
||||||
|
if not defined PLUGIN_DIR echo Error: Missing required argument 'PLUGIN_DIR' & call :usage & exit /b
|
||||||
|
if not defined LIB_DIR echo Error: Missing required argument 'LIB_DIR' & call :usage & exit /b
|
||||||
|
if not defined QML_DIR echo Error: Missing required argument 'QML_DIR' & call :usage & exit /b
|
||||||
|
if not defined CORECMD_PATH echo Error: Missing required argument 'CORECMD_PATH' & call :usage & exit /b
|
||||||
|
|
||||||
|
:: Normalize
|
||||||
|
set "INPUT_DIR=!INPUT_DIR:/=\!"
|
||||||
|
set "PLUGIN_DIR=!PLUGIN_DIR:/=\!"
|
||||||
|
set "LIB_DIR=!LIB_DIR:/=\!"
|
||||||
|
set "QML_DIR=!QML_DIR:/=\!"
|
||||||
|
set "CORECMD_PATH=!CORECMD_PATH:/=\!"
|
||||||
|
|
||||||
|
:: Get Qt plugin and QML paths
|
||||||
|
set "PLUGIN_PATHS="
|
||||||
|
set "QML_PATH="
|
||||||
|
if defined QMAKE_PATH (
|
||||||
|
for /f "tokens=*" %%a in ('!QMAKE_PATH! -query QT_INSTALL_PLUGINS') do set "QMAKE_PLUGIN_PATH=%%a"
|
||||||
|
set "PLUGIN_PATHS=!QMAKE_PLUGIN_PATH!"
|
||||||
|
for /f "tokens=*" %%a in ('!QMAKE_PATH! -query QT_INSTALL_QML') do set "QML_PATH=%%a"
|
||||||
|
set "QML_PATH=!QML_PATH:/=\!"
|
||||||
|
|
||||||
|
:: Add Qt bin directory
|
||||||
|
for /f "tokens=*" %%a in ('!QMAKE_PATH! -query QT_INSTALL_BINS') do set "QT_BIN_PATH=%%a"
|
||||||
|
call :push_args -L !QT_BIN_PATH!
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Add extra plugin searching paths
|
||||||
|
set "PLUGIN_PATHS=!PLUGIN_PATHS! !EXTRA_PLUGIN_PATHS!"
|
||||||
|
|
||||||
|
:: Ensure that the QML search path is not empty
|
||||||
|
:: when the QML related path is specified (qmake needs to be specified)
|
||||||
|
if not "%QML_REL_PATHS%"=="" (
|
||||||
|
if "%QML_PATH%"=="" (
|
||||||
|
echo Error: qmake path must be specified when QML paths are provided
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
:: The type of file to be searched depends on the operating system
|
||||||
|
:: On Windows, search for.exe and.dll files
|
||||||
|
for /r "%INPUT_DIR%" %%f in (*.exe *.dll) do (
|
||||||
|
set "FILES=!FILES! %%f"
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Find the full path to the Qt plugin
|
||||||
|
for /L %%i in (1,1,%PLUGIN_COUNT%) do (
|
||||||
|
set "plugin_path=!PLUGINS[%%i]!"
|
||||||
|
|
||||||
|
:: Check format
|
||||||
|
echo !plugin_path! | findstr /R "[^/]*\/[^/]*" >nul
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo Error: Invalid plugin format '!plugin_path!'. Expected format: ^<category^>/^<name^>
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Extracts the category and name
|
||||||
|
for /f "tokens=1,2 delims=/" %%a in ("!plugin_path!") do (
|
||||||
|
set "category=%%a"
|
||||||
|
set "name=%%b"
|
||||||
|
|
||||||
|
:: Calculate destination directory
|
||||||
|
set "DESTINATION_DIR=!PLUGIN_DIR!\!category!"
|
||||||
|
set "DESTINATION_DIR=!DESTINATION_DIR:/=\!"
|
||||||
|
|
||||||
|
:: Traverse the path and find the specific plug-in file
|
||||||
|
set "FOUND_PLUGINS="
|
||||||
|
call :search_plugin
|
||||||
|
if not defined FOUND_PLUGINS (
|
||||||
|
echo Error: Plugin '!plugin_path!' not found in any search paths.
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Process QML directories
|
||||||
|
for %%q in (%QML_REL_PATHS%) do (
|
||||||
|
call :search_qml_dir "%%q"
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Build and execute the deploy
|
||||||
|
set "ARGS_FILE=windeps_args.txt"
|
||||||
|
if exist "%ARGS_FILE%" del %ARGS_FILE%
|
||||||
|
for %%a in (!FILES!) do (
|
||||||
|
echo %%a >> %ARGS_FILE%
|
||||||
|
)
|
||||||
|
for /L %%i in (1,1,%ARG_COUNT%) do (
|
||||||
|
echo !ARGS[%%i]! >> %ARGS_FILE%
|
||||||
|
)
|
||||||
|
echo -o >> %ARGS_FILE%
|
||||||
|
echo !LIB_DIR! >> %ARGS_FILE%
|
||||||
|
echo !VERBOSE! >> %ARGS_FILE%
|
||||||
|
set "DEPLOY_CMD=!CORECMD_PATH! deploy @!ARGS_FILE!"
|
||||||
|
call !DEPLOY_CMD!
|
||||||
|
|
||||||
|
:: Check the deployment result
|
||||||
|
if %errorlevel% neq 0 exit /b
|
||||||
|
del %ARGS_FILE%
|
||||||
|
exit /b
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
:: Add args
|
||||||
|
:push_args
|
||||||
|
for %%x in (%*) do set /a "ARG_COUNT+=1" & set "ARGS[!ARG_COUNT!]=%%x"
|
||||||
|
exit /b
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
:: Search plugins
|
||||||
|
:search_plugin
|
||||||
|
for %%d in (!PLUGIN_PATHS!) do (
|
||||||
|
for %%f in ("%%d\!category!\!name!.dll") do (
|
||||||
|
if exist "%%f" (
|
||||||
|
call :check_debug "%%f"
|
||||||
|
if "!ok!"=="0" (
|
||||||
|
call :add_plugin "%%f"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
exit /b
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
:: Add plugin if not already found
|
||||||
|
:add_plugin
|
||||||
|
set "plugin=%~1"
|
||||||
|
set "plugin_name=%~nx1"
|
||||||
|
for %%i in (!FOUND_PLUGINS!) do (
|
||||||
|
if "%%i"=="!plugin_name!" (
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
)
|
||||||
|
set "FOUND_PLUGINS=!FOUND_PLUGINS! !plugin_name!"
|
||||||
|
call :push_args -c !plugin! !DESTINATION_DIR!
|
||||||
|
exit /b
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
:: Search QML directory
|
||||||
|
:search_qml_dir
|
||||||
|
set "full_path=%QML_PATH%\%~1"
|
||||||
|
if exist "%full_path%\" (
|
||||||
|
:: Directory
|
||||||
|
for /r "%full_path%" %%f in (*) do (
|
||||||
|
call :handle_qml_file "%%f"
|
||||||
|
)
|
||||||
|
) else if exist "%full_path%" (
|
||||||
|
:: File
|
||||||
|
call :handle_qml_file "%full_path%"
|
||||||
|
)
|
||||||
|
exit /b
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
:: Check debug version of a dll
|
||||||
|
:check_debug
|
||||||
|
set "ok=1"
|
||||||
|
set "file_path=%~1"
|
||||||
|
if "!file_path:~-4!"==".pdb" exit /b
|
||||||
|
if "!file_path:~-10!"==".dll.debug" exit /b
|
||||||
|
if "!file_path:~-5!" == "d.dll" (
|
||||||
|
set "prefix=!file_path:~0,-5!"
|
||||||
|
if exist "!prefix!.dll" (
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
)
|
||||||
|
set "ok=0"
|
||||||
|
exit /b
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
:: Copy or add to a deployment command
|
||||||
|
:handle_qml_file
|
||||||
|
set "file=%~1"
|
||||||
|
set "file=!file:/=\!"
|
||||||
|
|
||||||
|
:: Ignore specific files (example)
|
||||||
|
call :check_debug "%file%"
|
||||||
|
if "!ok!"=="1" (
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Computes target file and folder in a very stupid way
|
||||||
|
set "rel_path=!file:%QML_PATH%\=!"
|
||||||
|
set "target=%QML_DIR%\%rel_path%"
|
||||||
|
for %%I in ("!file!") do (
|
||||||
|
set "file_dir=%%~dpI"
|
||||||
|
)
|
||||||
|
set "rel_dir_path=!file_dir:%QML_PATH%\=!"
|
||||||
|
set "target_dir=%QML_DIR%\%rel_dir_path%"
|
||||||
|
|
||||||
|
:: Determine whether it is an executable binary file and handle it accordingly
|
||||||
|
if "%file:~-4%"==".dll" (
|
||||||
|
call :push_args -c !file! !target_dir!
|
||||||
|
) else if "%file:~-4%"==".exe" (
|
||||||
|
call :push_args -c !file! !target_dir!
|
||||||
|
) else (
|
||||||
|
if not exist "%target%" (
|
||||||
|
mkdir "%target_dir%" >nul 2>&1
|
||||||
|
)
|
||||||
|
copy /Y "%file%" "%target%" >nul 2>&1
|
||||||
|
)
|
||||||
|
|
||||||
|
exit /b
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
|
:: Show usage
|
||||||
|
:usage
|
||||||
|
echo Usage: %~n0 -i ^<dir^> -m ^<path^>
|
||||||
|
echo --plugindir ^<plugin_dir^> --libdir ^<lib_dir^> --qmldir ^<qml_dir^>
|
||||||
|
echo [--qmake ^<qmake_path^>] [--extra ^<extra_path^>]...
|
||||||
|
echo [--qml ^<qml_module^>]... [--plugin ^<plugin^>]... [--copy ^<src^> ^<dest^>]...
|
||||||
|
echo [--linkdirs-file ^<file^>]... [-L ^<path^>]...
|
||||||
|
echo [-f] [-s] [-V] [-h]
|
||||||
|
exit /b
|
||||||
|
:: ----------------------------------------------------------------------------------
|
||||||
23
libs/qwindowkit/qmsetup/cmake/scripts/xxd.cmake
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
if(NOT DEFINED input)
|
||||||
|
message(FATAL_ERROR "input not defined")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED output)
|
||||||
|
message(FATAL_ERROR "output not defined")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED name)
|
||||||
|
message(FATAL_ERROR "name not defined")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_filename_component(_output_dir ${output} DIRECTORY)
|
||||||
|
if(NOT EXISTS ${_output_dir})
|
||||||
|
file(MAKE_DIRECTORY ${_output_dir})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(READ ${input} _file_content HEX)
|
||||||
|
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " _hex_content ${_file_content})
|
||||||
|
file(WRITE ${output}
|
||||||
|
"unsigned char ${name}[] = {${_hex_content}};\n"
|
||||||
|
"unsigned int ${name}_len = sizeof(${name});\n"
|
||||||
|
)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
Set oWS = WScript.CreateObject("WScript.Shell")
|
||||||
|
sLinkFile = "@SHORTCUT_PATH@"
|
||||||
|
Set oLink = oWS.CreateShortcut(sLinkFile)
|
||||||
|
oLink.TargetPath = "@SHORTCUT_TARGET_PATH@"
|
||||||
|
oLink.WorkingDirectory = "@SHORTCUT_WORKING_DIRECOTRY@"
|
||||||
|
oLink.Description = "@SHORTCUT_DESCRIPTION@"
|
||||||
|
oLink.IconLocation = "@SHORTCUT_ICON_LOCATION@"
|
||||||
|
oLink.Save
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<description>@MANIFEST_DESCRIPTION@</description>
|
||||||
|
<assemblyIdentity
|
||||||
|
version="@MANIFEST_VERSION@"
|
||||||
|
name="@MANIFEST_IDENTIFIER@"
|
||||||
|
type="win32"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
@MANIFEST_PRIVILEGES@
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="Microsoft.Windows.Common-Controls"
|
||||||
|
version="6.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
publicKeyToken="6595b64144ccf1df"
|
||||||
|
language="*"
|
||||||
|
/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- XAML Island won't work without the maxversiontested list -->
|
||||||
|
<!-- Windows 10 Version 1809 (October 2018 Update) -->
|
||||||
|
<maxversiontested Id="10.0.17763.0"/>
|
||||||
|
<!-- Windows 10 Version 1903 (May 2019 Update) -->
|
||||||
|
<maxversiontested Id="10.0.18362.0"/>
|
||||||
|
<!-- Windows 10 Version 1909 (November 2019 Update) -->
|
||||||
|
<maxversiontested Id="10.0.18363.0"/>
|
||||||
|
<!-- Windows 10 Version 2004 (May 2020 Update) -->
|
||||||
|
<maxversiontested Id="10.0.19041.0"/>
|
||||||
|
<!-- Windows 10 Version 20H2 (October 2020 Update) -->
|
||||||
|
<maxversiontested Id="10.0.19042.0"/>
|
||||||
|
<!-- Windows 10 Version 21H1 (May 2021 Update) -->
|
||||||
|
<maxversiontested Id="10.0.19043.0"/>
|
||||||
|
<!-- Windows 10 Version 21H2 (November 2021 Update) -->
|
||||||
|
<maxversiontested Id="10.0.19044.0"/>
|
||||||
|
<!-- Windows 10 Version 22H2 -->
|
||||||
|
<maxversiontested Id="10.0.19045.0"/>
|
||||||
|
<!-- Windows 11 Version 21H2 -->
|
||||||
|
<maxversiontested Id="10.0.22000.0"/>
|
||||||
|
<!-- Windows 11 Version 22H2 -->
|
||||||
|
<maxversiontested Id="10.0.22621.0"/>
|
||||||
|
<!-- Windows 11 Version 23H2 -->
|
||||||
|
<maxversiontested Id="10.0.22631.0"/>
|
||||||
|
<!-- Windows 11 Version 24H2 -->
|
||||||
|
<maxversiontested Id="10.0.26100.0"/>
|
||||||
|
<!-- Windows 11 Version 25H2 -->
|
||||||
|
<maxversiontested Id="10.0.26200.0"/>
|
||||||
|
<!-- Windows Vista and Windows Server 2008 -->
|
||||||
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||||
|
<!-- Windows 7 and Windows Server 2008 R2 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||||
|
<!-- Windows 8 and Windows Server 2012 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||||
|
<!-- Windows 8.1 and Windows Server 2012 R2 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||||
|
<!-- Windows 10 and Windows 11 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
|
||||||
|
<printerDriverIsolation xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">True</printerDriverIsolation>
|
||||||
|
<disableWindowFiltering xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">True</disableWindowFiltering>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
||||||
|
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">True</longPathAware>
|
||||||
|
<heapType xmlns="http://schemas.microsoft.com/SMI/2020/WindowsSettings">SegmentHeap</heapType>
|
||||||
|
@MANIFEST_UTF8@
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
</assembly>
|
||||||
29
libs/qwindowkit/qmsetup/cmake/windows/WinResource.rc.in
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifndef VS_VERSION_INFO
|
||||||
|
#define VS_VERSION_INFO 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@RC_ICON_COMMENT@ IDI_ICON1 ICON DISCARDABLE "@RC_ICON_PATH@"
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION @RC_VERSION@
|
||||||
|
PRODUCTVERSION @RC_VERSION@
|
||||||
|
{
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
{
|
||||||
|
// U.S. English - Windows, Multilingual
|
||||||
|
BLOCK "040904E4"
|
||||||
|
{
|
||||||
|
VALUE "FileDescription", "@RC_DESCRIPTION@"
|
||||||
|
VALUE "FileVersion", "@RC_VERSION_STRING@"
|
||||||
|
VALUE "ProductName", "@RC_APPLICATION_NAME@"
|
||||||
|
VALUE "ProductVersion", "@RC_VERSION_STRING@"
|
||||||
|
VALUE "LegalCopyright", "@RC_COPYRIGHT@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
{
|
||||||
|
VALUE "Translation", 0x409, 1252 // 1252 = 0x04E4
|
||||||
|
}
|
||||||
|
}
|
||||||
38
libs/qwindowkit/qmsetup/cmake/windows/WinResource2.rc.in
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
@RC_ICONS@
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION @RC_VERSION@
|
||||||
|
PRODUCTVERSION @RC_VERSION@
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS VS_FF_DEBUG
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS VOS_NT_WINDOWS32
|
||||||
|
FILETYPE @RC_FILE_TYPE@
|
||||||
|
FILESUBTYPE VFT2_UNKNOWN
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Comments", "@RC_COMMENTS@"
|
||||||
|
VALUE "CompanyName", "@RC_COMPANY@"
|
||||||
|
VALUE "FileDescription", "@RC_DESCRIPTION@"
|
||||||
|
VALUE "FileVersion", "@RC_VERSION_STRING@"
|
||||||
|
VALUE "InternalName", "@RC_INTERNAL_NAME@"
|
||||||
|
VALUE "LegalCopyright", "@RC_COPYRIGHT@"
|
||||||
|
VALUE "LegalTrademarks", "@RC_TRADEMARK@"
|
||||||
|
VALUE "OriginalFilename", "@RC_ORIGINAL_FILENAME@"
|
||||||
|
VALUE "ProductName", "@RC_APPLICATION_NAME@"
|
||||||
|
VALUE "ProductVersion", "@RC_VERSION_STRING@"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
56
libs/qwindowkit/qmsetup/docs/core-command.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Core Command
|
||||||
|
|
||||||
|
`qmcorecmd` is an executable written by C++. It is designed to provide a set of solutions that are fixed in form and that CMake scripts cannot implement due to insufficient features or inefficiencies.
|
||||||
|
|
||||||
|
`qmcorecmd` uses `syscmdline` to parse command line arguments and have multiple subcommands.
|
||||||
|
|
||||||
|
You can refer to the help message of each command to acquire more usage information, since this document provides only a brief introduction.
|
||||||
|
|
||||||
|
## Filesystem Commands
|
||||||
|
|
||||||
|
### Copy
|
||||||
|
|
||||||
|
Copies a file or folder. If the given folder path ends with the separator, copies the contents of the folder.
|
||||||
|
|
||||||
|
+ Read timestamp to determine whether to overwrite an existing object file.
|
||||||
|
+ Support ignoring specific files specified by regular expressions.
|
||||||
|
|
||||||
|
### Rmdir
|
||||||
|
|
||||||
|
Recursively deletes all empty directories.
|
||||||
|
|
||||||
|
Since CMake copies all directories unconditionally when executing the `install(DIRECTORY ...)` command, even if the directory is empty. This command can be used to fix this unreasonable phenomenon.
|
||||||
|
|
||||||
|
### Touch
|
||||||
|
|
||||||
|
Since Microsoft Windows does not provide a native command for handling file timestamps, this command is designed to copy or update a file's time stamp.
|
||||||
|
|
||||||
|
Only some of the functionality of Unix `touch` command is implemented.
|
||||||
|
|
||||||
|
## Buildsystem Commands
|
||||||
|
|
||||||
|
### Configure
|
||||||
|
|
||||||
|
Generates configuration header files.
|
||||||
|
|
||||||
|
It allows users to add macro definitions via the `-D` option, which are directly written into the generated header file. Additionally, users can specify a warning file with the `-w` option, the contents of which are added as comments at the top of the header file.
|
||||||
|
|
||||||
|
A key feature of this command is its ability to compute the SHA-256 hash of the definitions and embed it in the generated file, facilitating the tracking of configuration changes.
|
||||||
|
|
||||||
|
### Incsync
|
||||||
|
|
||||||
|
Reorganizes header files in include directories.
|
||||||
|
|
||||||
|
It supports defining path patterns and corresponding subdirectories through the `-i` option, reorganizing header files by writing relative reference statement or copying directly. The `-e` option can be used to exclude files matching certain patterns.
|
||||||
|
|
||||||
|
While processing header files, `incsync` considers the last modified time to determine whether to copy or update files.
|
||||||
|
|
||||||
|
### Deploy
|
||||||
|
|
||||||
|
Resolves and deploys a binary's shared library dependencies.
|
||||||
|
|
||||||
|
It analyzes dependencies of specified files and copies these dependencies to a designated output directory. Moreover, it handles details like fixing RPATH or dealing with Windows-specific library search paths.
|
||||||
|
|
||||||
|
The `-s` option is provided to ignore standard C/C++ runtime and system libraries, reducing unnecessary dependency copying.
|
||||||
|
|
||||||
|
All shared libraries that are deployed must have different file names.
|
||||||
12
libs/qwindowkit/qmsetup/include/qmsetup/qmsetup_global.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef QMSETUP_GLOBAL_H
|
||||||
|
#define QMSETUP_GLOBAL_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define QMSETUP_DECL_EXPORT __declspec(dllexport)
|
||||||
|
# define QMSETUP_DECL_IMPORT __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
# define QMSETUP_DECL_EXPORT __attribute__((visibility("default")))
|
||||||
|
# define QMSETUP_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // QMSETUP_GLOBAL_H
|
||||||
79
libs/qwindowkit/qmsetup/src/CMakeLists.txt
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
include(GNUInstallDirs)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
if(QMSETUP_STATIC_RUNTIME)
|
||||||
|
# To avoid a command execution that can't find the library, we choose to link compiler runtime statically
|
||||||
|
if(MINGW)
|
||||||
|
add_link_options(-static -static-libgcc -static-libstdc++)
|
||||||
|
elseif(MSVC)
|
||||||
|
add_compile_options(/MT)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Get syscmdline
|
||||||
|
find_package(syscmdline QUIET)
|
||||||
|
|
||||||
|
if(NOT TARGET syscmdline::syscmdline)
|
||||||
|
set(SYSCMDLINE_INSTALL off)
|
||||||
|
add_subdirectory(syscmdline)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add subdirectories
|
||||||
|
add_subdirectory(corecmd)
|
||||||
|
|
||||||
|
# Add headers
|
||||||
|
set(_corelib_name library)
|
||||||
|
add_library(${_corelib_name} INTERFACE)
|
||||||
|
target_include_directories(${_corelib_name} INTERFACE
|
||||||
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>"
|
||||||
|
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||||
|
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${QMSETUP_INSTALL_NAME}>"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS ${_corelib_name}
|
||||||
|
EXPORT ${QMSETUP_INSTALL_NAME}Targets
|
||||||
|
)
|
||||||
|
|
||||||
|
if(TRUE)
|
||||||
|
# Add install target
|
||||||
|
set(_install_dir ${CMAKE_INSTALL_LIBDIR}/cmake/${QMSETUP_INSTALL_NAME})
|
||||||
|
|
||||||
|
# Add version file
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${QMSETUP_INSTALL_NAME}ConfigVersion.cmake"
|
||||||
|
VERSION ${QMSETUP_VERSION}
|
||||||
|
COMPATIBILITY AnyNewerVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add configuration file
|
||||||
|
configure_package_config_file(
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/${QMSETUP_INSTALL_NAME}Config.cmake.in
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${QMSETUP_INSTALL_NAME}Config.cmake"
|
||||||
|
INSTALL_DESTINATION ${_install_dir}
|
||||||
|
NO_CHECK_REQUIRED_COMPONENTS_MACRO
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install cmake files
|
||||||
|
install(FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${QMSETUP_INSTALL_NAME}Config.cmake"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${QMSETUP_INSTALL_NAME}ConfigVersion.cmake"
|
||||||
|
DESTINATION ${_install_dir}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install cmake targets files
|
||||||
|
install(EXPORT ${QMSETUP_INSTALL_NAME}Targets
|
||||||
|
FILE "${QMSETUP_INSTALL_NAME}Targets.cmake"
|
||||||
|
NAMESPACE qmsetup::
|
||||||
|
DESTINATION ${_install_dir}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install headers
|
||||||
|
install(DIRECTORY ../include/
|
||||||
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install cmake modules
|
||||||
|
install(DIRECTORY ../cmake/
|
||||||
|
DESTINATION ${_install_dir}/cmake
|
||||||
|
)
|
||||||
|
endif()
|
||||||
89
libs/qwindowkit/qmsetup/src/corecmd/CMakeLists.txt
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
project(qmcorecmd VERSION ${QMSETUP_VERSION})
|
||||||
|
|
||||||
|
string(TIMESTAMP _year "%Y")
|
||||||
|
set(RC_COPYRIGHT "Copyright 2023-${_year} Stdware Collections")
|
||||||
|
set(RC_DESCRIPTION "QMSetup Core Utility Command")
|
||||||
|
|
||||||
|
set(_src
|
||||||
|
main.cpp
|
||||||
|
sha-256.h
|
||||||
|
sha-256.cpp
|
||||||
|
utils.h
|
||||||
|
utils.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND _src utils_win.cpp)
|
||||||
|
else()
|
||||||
|
list(APPEND _src utils_unix.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME} ${_src})
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE syscmdline::syscmdline)
|
||||||
|
|
||||||
|
# Add features
|
||||||
|
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20 cxx_std_17)
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
|
CXX_EXTENSIONS OFF
|
||||||
|
CXX_STANDARD 17
|
||||||
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
)
|
||||||
|
|
||||||
|
# Compat with gcc 8
|
||||||
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9")
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE stdc++fs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE shlwapi)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
qm_add_win_rc(${PROJECT_NAME}
|
||||||
|
COPYRIGHT ${RC_COPYRIGHT}
|
||||||
|
DESCRIPTION ${RC_DESCRIPTION}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Make sure Windows UAC does not believe it is an installer
|
||||||
|
qm_add_win_manifest(${PROJECT_NAME}
|
||||||
|
DESCRIPTION ${RC_DESCRIPTION}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE TOOL_DESC="${RC_DESCRIPTION}, Version ${QMSETUP_VERSION}")
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE TOOL_COPYRIGHT="${RC_COPYRIGHT}, checkout https://github.com/stdware/qmsetup")
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE TOOL_VERSION="${QMSETUP_VERSION}")
|
||||||
|
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES EXPORT_NAME corecmd)
|
||||||
|
|
||||||
|
# Vcpkg requires the binary to be installed in "tools/${PORT}" directory
|
||||||
|
if(QMSETUP_VCPKG_TOOLS_HINT)
|
||||||
|
set(_tools_dir tools/${QMSETUP_INSTALL_NAME})
|
||||||
|
else()
|
||||||
|
set(_tools_dir ${CMAKE_INSTALL_BINDIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS ${PROJECT_NAME}
|
||||||
|
EXPORT ${QMSETUP_INSTALL_NAME}Targets
|
||||||
|
RUNTIME DESTINATION "${_tools_dir}" OPTIONAL
|
||||||
|
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" OPTIONAL
|
||||||
|
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" OPTIONAL
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check patchelf
|
||||||
|
if (NOT WIN32 AND NOT APPLE)
|
||||||
|
execute_process(
|
||||||
|
COMMAND patchelf --version
|
||||||
|
OUTPUT_VARIABLE _patchelf_version_output
|
||||||
|
ERROR_QUIET
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT "${_patchelf_version_output}" MATCHES "patchelf")
|
||||||
|
message(WARNING "Patchelf not found, the deploy feature won't work.")
|
||||||
|
else()
|
||||||
|
string(REGEX REPLACE "patchelf (.+)" "\\1" _patchelf_version ${_patchelf_version_output})
|
||||||
|
message(STATUS "Found patchelf, version ${_patchelf_version}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
1629
libs/qwindowkit/qmsetup/src/corecmd/main.cpp
Normal file
210
libs/qwindowkit/qmsetup/src/corecmd/sha-256.cpp
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
#include "sha-256.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
static constexpr const auto CHUNK_SIZE = 64;
|
||||||
|
static constexpr const auto TOTAL_LEN_LEN = 8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ABOUT bool: this file does not use bool in order to be as pre-C99 compatible as possible.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are reproduced here.
|
||||||
|
* When useful for clarification, portions of the pseudo-code are reproduced here too.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize array of round constants:
|
||||||
|
* (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
|
||||||
|
*/
|
||||||
|
static constexpr const uint32_t k[] = {
|
||||||
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||||
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||||
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||||
|
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||||
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||||
|
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||||
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||||
|
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buffer_state {
|
||||||
|
const uint8_t * p;
|
||||||
|
size_t len;
|
||||||
|
size_t total_len;
|
||||||
|
int single_one_delivered; /* bool */
|
||||||
|
int total_len_delivered; /* bool */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline constexpr uint32_t right_rot(uint32_t value, unsigned int count)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Defined behaviour in standard C for all count where 0 < count < 32,
|
||||||
|
* which is what we need here.
|
||||||
|
*/
|
||||||
|
return value >> count | value << (32 - count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_buf_state(struct buffer_state * state, const void * input, size_t len)
|
||||||
|
{
|
||||||
|
state->p = static_cast<const uint8_t*>(input);
|
||||||
|
state->len = len;
|
||||||
|
state->total_len = len;
|
||||||
|
state->single_one_delivered = 0;
|
||||||
|
state->total_len_delivered = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return value: bool */
|
||||||
|
static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state)
|
||||||
|
{
|
||||||
|
size_t space_in_chunk;
|
||||||
|
|
||||||
|
if (state->total_len_delivered) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->len >= CHUNK_SIZE) {
|
||||||
|
std::memcpy(chunk, state->p, CHUNK_SIZE);
|
||||||
|
state->p += CHUNK_SIZE;
|
||||||
|
state->len -= CHUNK_SIZE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(chunk, state->p, state->len);
|
||||||
|
chunk += state->len;
|
||||||
|
space_in_chunk = CHUNK_SIZE - state->len;
|
||||||
|
state->p += state->len;
|
||||||
|
state->len = 0;
|
||||||
|
|
||||||
|
/* If we are here, space_in_chunk is one at minimum. */
|
||||||
|
if (!state->single_one_delivered) {
|
||||||
|
*chunk++ = 0x80;
|
||||||
|
space_in_chunk -= 1;
|
||||||
|
state->single_one_delivered = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now:
|
||||||
|
* - either there is enough space left for the total length, and we can conclude,
|
||||||
|
* - or there is too little space left, and we have to pad the rest of this chunk with zeroes.
|
||||||
|
* In the latter case, we will conclude at the next invokation of this function.
|
||||||
|
*/
|
||||||
|
if (space_in_chunk >= TOTAL_LEN_LEN) {
|
||||||
|
const size_t left = space_in_chunk - TOTAL_LEN_LEN;
|
||||||
|
size_t len = state->total_len;
|
||||||
|
int i;
|
||||||
|
std::memset(chunk, 0x00, left);
|
||||||
|
chunk += left;
|
||||||
|
|
||||||
|
/* Storing of len * 8 as a big endian 64-bit without overflow. */
|
||||||
|
chunk[7] = (uint8_t) (len << 3);
|
||||||
|
len >>= 5;
|
||||||
|
for (i = 6; i >= 0; i--) {
|
||||||
|
chunk[i] = (uint8_t) len;
|
||||||
|
len >>= 8;
|
||||||
|
}
|
||||||
|
state->total_len_delivered = 1;
|
||||||
|
} else {
|
||||||
|
std::memset(chunk, 0x00, space_in_chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limitations:
|
||||||
|
* - Since input is a pointer in RAM, the data to hash should be in RAM, which could be a problem
|
||||||
|
* for large data sizes.
|
||||||
|
* - SHA algorithms theoretically operate on bit strings. However, this implementation has no support
|
||||||
|
* for bit string lengths that are not multiples of eight, and it really operates on arrays of bytes.
|
||||||
|
* In particular, the len parameter is a number of bytes.
|
||||||
|
*/
|
||||||
|
void calc_sha_256(uint8_t hash[32], const void * input, size_t len)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Note 1: All integers (expect indexes) are 32-bit unsigned integers and addition is calculated modulo 2^32.
|
||||||
|
* Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 = i = 63
|
||||||
|
* Note 3: The compression function uses 8 working variables, a through h
|
||||||
|
* Note 4: Big-endian convention is used when expressing the constants in this pseudocode,
|
||||||
|
* and when parsing message block data from bytes to words, for example,
|
||||||
|
* the first word of the input message "abc" after padding is 0x61626380
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize hash values:
|
||||||
|
* (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
|
||||||
|
*/
|
||||||
|
uint32_t h[] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* 512-bit chunks is what we will operate on. */
|
||||||
|
uint8_t chunk[64];
|
||||||
|
|
||||||
|
struct buffer_state state;
|
||||||
|
|
||||||
|
init_buf_state(&state, input, len);
|
||||||
|
|
||||||
|
while (calc_chunk(chunk, &state)) {
|
||||||
|
uint32_t ah[8];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create a 64-entry message schedule array w[0..63] of 32-bit words
|
||||||
|
* (The initial values in w[0..63] don't matter, so many implementations zero them here)
|
||||||
|
* copy chunk into first 16 words w[0..15] of the message schedule array
|
||||||
|
*/
|
||||||
|
uint32_t w[64];
|
||||||
|
const uint8_t *p = chunk;
|
||||||
|
|
||||||
|
std::memset(w, 0x00, sizeof w);
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
w[i] = (uint32_t) p[0] << 24 | (uint32_t) p[1] << 16 |
|
||||||
|
(uint32_t) p[2] << 8 | (uint32_t) p[3];
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: */
|
||||||
|
for (i = 16; i < 64; i++) {
|
||||||
|
const uint32_t s0 = right_rot(w[i - 15], 7) ^ right_rot(w[i - 15], 18) ^ (w[i - 15] >> 3);
|
||||||
|
const uint32_t s1 = right_rot(w[i - 2], 17) ^ right_rot(w[i - 2], 19) ^ (w[i - 2] >> 10);
|
||||||
|
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize working variables to current hash value: */
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
ah[i] = h[i];
|
||||||
|
|
||||||
|
/* Compression function main loop: */
|
||||||
|
for (i = 0; i < 64; i++) {
|
||||||
|
const uint32_t s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25);
|
||||||
|
const uint32_t ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]);
|
||||||
|
const uint32_t temp1 = ah[7] + s1 + ch + k[i] + w[i];
|
||||||
|
const uint32_t s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22);
|
||||||
|
const uint32_t maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]);
|
||||||
|
const uint32_t temp2 = s0 + maj;
|
||||||
|
|
||||||
|
ah[7] = ah[6];
|
||||||
|
ah[6] = ah[5];
|
||||||
|
ah[5] = ah[4];
|
||||||
|
ah[4] = ah[3] + temp1;
|
||||||
|
ah[3] = ah[2];
|
||||||
|
ah[2] = ah[1];
|
||||||
|
ah[1] = ah[0];
|
||||||
|
ah[0] = temp1 + temp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the compressed chunk to the current hash value: */
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
h[i] += ah[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Produce the final hash value (big-endian): */
|
||||||
|
for (i = 0, j = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
hash[j++] = (uint8_t) (h[i] >> 24);
|
||||||
|
hash[j++] = (uint8_t) (h[i] >> 16);
|
||||||
|
hash[j++] = (uint8_t) (h[i] >> 8);
|
||||||
|
hash[j++] = (uint8_t) h[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
19
libs/qwindowkit/qmsetup/src/corecmd/sha-256.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef SHA_256_H
|
||||||
|
#define SHA_256_H
|
||||||
|
|
||||||
|
// https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/MISC/sha2
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void calc_sha_256(uint8_t hash[32], const void *input, size_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // SHA_256_H
|
||||||
31
libs/qwindowkit/qmsetup/src/corecmd/utils.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define _TSTR(X) L##X
|
||||||
|
# define tstrcmp wcscmp
|
||||||
|
#else
|
||||||
|
# define _TSTR(X) X
|
||||||
|
# define tstrcmp strcmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
|
||||||
|
std::filesystem::path cleanPath(const std::filesystem::path &path) {
|
||||||
|
fs::path result;
|
||||||
|
for (const auto &part : path) {
|
||||||
|
if (part == _TSTR("..")) {
|
||||||
|
if (!result.empty() && result.filename() != _TSTR("..")) {
|
||||||
|
result = result.parent_path();
|
||||||
|
} else {
|
||||||
|
result /= part;
|
||||||
|
}
|
||||||
|
} else if (part != _TSTR(".")) {
|
||||||
|
result /= part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||