diff --git a/CMakeLists.txt b/CMakeLists.txt index 07e955a..c344219 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,20 @@ else() message(STATUS "Vulkan support disabled") endif() +# Generate version header from template (for C++ code) +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/version.h" + @ONLY +) + +# Generate version shell script from template (for shell scripts) +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/version.sh.in" + "${CMAKE_CURRENT_SOURCE_DIR}/version.sh" + @ONLY +) + # Common source files set(SOURCES src/main.cpp @@ -187,6 +201,11 @@ add_executable(${PROJECT_NAME} ${HEADERS} ) +# Include build directory for generated version.h +target_include_directories(${PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} +) + # Link Qt5 libraries target_link_libraries(${PROJECT_NAME} Qt5::Core diff --git a/make_deb.sh b/make_deb.sh index d9703a2..6483112 100755 --- a/make_deb.sh +++ b/make_deb.sh @@ -12,13 +12,24 @@ NC='\033[0m' # No Color # 配置变量 APP_NAME="ScreenLockDetector" PACKAGE_NAME="ScreenLockDetector" -# 从 CMakeLists.txt 中提取版本号 -VERSION=$(grep -oP '(?<=project\(ScreenLockDetector VERSION )[0-9.]+' CMakeLists.txt) -if [ -z "$VERSION" ]; then - echo -e "${RED}错误: 无法从 CMakeLists.txt 中提取版本号${NC}" + +# 从自动生成的 version.sh 中读取版本号 +if [ ! -f "version.sh" ]; then + echo -e "${RED}错误: version.sh 文件不存在${NC}" + echo -e "${YELLOW}请先运行 ./build.sh 生成版本文件${NC}" exit 1 fi -echo -e "${GREEN}✓ 从 CMakeLists.txt 读取版本号: ${VERSION}${NC}" + +# Source version.sh to get APP_VERSION +source version.sh + +if [ -z "$APP_VERSION" ]; then + echo -e "${RED}错误: 无法从 version.sh 中读取版本号${NC}" + exit 1 +fi + +VERSION="$APP_VERSION" +echo -e "${GREEN}✓ 从 version.sh 读取版本号: ${VERSION}${NC}" ARCH="amd64" QT_DIR="$HOME/sdk/qt-5.15.2" LINUXDEPLOYQT="${LINUXDEPLOYQT:-$HOME/tools/sunvpack-py/bin/linuxdeployqt}" diff --git a/src/version.h.in b/src/version.h.in new file mode 100644 index 0000000..7eb4e3e --- /dev/null +++ b/src/version.h.in @@ -0,0 +1,15 @@ +#ifndef VERSION_H +#define VERSION_H + +// Auto-generated version information from CMakeLists.txt +// DO NOT EDIT THIS FILE MANUALLY - Edit CMakeLists.txt instead + +#define APP_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ +#define APP_VERSION_MINOR @PROJECT_VERSION_MINOR@ +#define APP_VERSION_PATCH @PROJECT_VERSION_PATCH@ +#define APP_VERSION_STRING "@PROJECT_VERSION@" + +// Vulkan version macros +#define APP_VK_VERSION VK_MAKE_VERSION(APP_VERSION_MAJOR, APP_VERSION_MINOR, APP_VERSION_PATCH) + +#endif // VERSION_H diff --git a/src/vulkanwidget.cpp b/src/vulkanwidget.cpp index aff8e66..bfa38f0 100644 --- a/src/vulkanwidget.cpp +++ b/src/vulkanwidget.cpp @@ -1,5 +1,6 @@ #include "vulkanwidget.h" #include "vulkanrenderer.h" +#include "version.h" #include #include #include @@ -68,7 +69,7 @@ VulkanWidget::VulkanWidget(QWidget *parent) // Create render timer m_renderTimer = new QTimer(this); connect(m_renderTimer, &QTimer::timeout, this, &VulkanWidget::onRenderTimer); - + // Initialize FPS calculation m_frameTimes.reserve(FPS_SAMPLE_COUNT); @@ -111,7 +112,7 @@ void VulkanWidget::setRenderingEnabled(bool enabled) if (m_renderingEnabled) { qDebug() << "Vulkan rendering ENABLED - Resuming animations"; - + // Check if device was lost (e.g., after wake from sleep) if (m_deviceLost) { qDebug() << "Device lost detected on resume, attempting recovery..."; @@ -121,7 +122,7 @@ void VulkanWidget::setRenderingEnabled(bool enabled) return; } } - + // 恢复渲染时,重新启动定时器(锁屏时已停止) if (!m_renderTimer->isActive()) { m_renderTimer->start(16); // ~60 FPS @@ -291,7 +292,7 @@ bool VulkanWidget::createInstance() VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "VulkanWidget"; - appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.applicationVersion = APP_VK_VERSION; // Auto-generated from CMakeLists.txt appInfo.pEngineName = "No Engine"; appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.apiVersion = VK_API_VERSION_1_0; @@ -344,7 +345,7 @@ bool VulkanWidget::createSurface() #elif defined(__linux__) VkXlibSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - + // Reuse existing X11 display or open a new one Display* x11Display = static_cast(m_x11Display); if (!x11Display) { @@ -358,7 +359,7 @@ bool VulkanWidget::createSurface() } else { qDebug() << "Reusing existing X11 display"; } - + createInfo.dpy = x11Display; createInfo.window = static_cast(window->winId()); @@ -772,7 +773,7 @@ void VulkanWidget::renderFrame() if (!m_initialized || m_isClosing) { return; } - + // Don't render if device is lost (recovery will be attempted on next enable) if (m_deviceLost) { return; @@ -785,14 +786,14 @@ void VulkanWidget::renderFrame() QDateTime currentTime = QDateTime::currentDateTime(); qint64 frameTimeUs = m_lastFrameTime.msecsTo(currentTime) * 1000; // Convert to microseconds m_lastFrameTime = currentTime; - + if (frameTimeUs > 0) { // Add frame time to circular buffer if (m_frameTimes.size() >= FPS_SAMPLE_COUNT) { m_frameTimes.erase(m_frameTimes.begin()); } m_frameTimes.push_back(frameTimeUs); - + // Calculate average FPS from recent frames if (!m_frameTimes.empty()) { qint64 totalTimeUs = 0; @@ -857,7 +858,7 @@ void VulkanWidget::renderFrame() result = vkQueueSubmit(m_queue, 1, &submitInfo, m_inFlightFences[m_currentFrame]); if (result != VK_SUCCESS) { qDebug() << "Failed to submit draw command buffer! Error code = " << result; - + // Handle device lost error (e.g., after wake from sleep/hibernation) if (result == VK_ERROR_DEVICE_LOST || result == -4) { qDebug() << "VK_ERROR_DEVICE_LOST detected! Attempting to recover device..."; @@ -957,7 +958,7 @@ void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t i // Calculate elapsed time in seconds QDateTime now = QDateTime::currentDateTime(); qint64 elapsedTime = m_startTime.secsTo(now); - + m_renderer->recordCommandBuffer(commandBuffer, imageIndex, imageView, m_frameCount, static_cast(elapsedTime), m_currentFps, @@ -1083,7 +1084,7 @@ void VulkanWidget::cleanupVulkan() if (m_surface != VK_NULL_HANDLE) { vkDestroySurfaceKHR(m_instance, m_surface, nullptr); } - + // Close X11 display if it was opened (Linux only) #ifdef __linux__ if (m_x11Display) { @@ -1228,13 +1229,13 @@ std::vector VulkanWidget::getRequiredDeviceExtensions() bool VulkanWidget::handleDeviceLost() { qDebug() << "=== Handling device lost error ==="; - + // Stop rendering timer to prevent more render attempts during recovery if (m_renderTimer && m_renderTimer->isActive()) { m_renderTimer->stop(); qDebug() << "Render timer stopped for device recovery"; } - + // Wait for any pending operations to complete (may fail, but try anyway) if (m_device != VK_NULL_HANDLE) { VkResult result = vkDeviceWaitIdle(m_device); @@ -1242,14 +1243,14 @@ bool VulkanWidget::handleDeviceLost() qDebug() << "vkDeviceWaitIdle failed (expected with device lost), continuing recovery..."; } } - + // Attempt to recreate the device and all resources bool success = recreateDevice(); - + if (success) { m_deviceLost = false; qDebug() << "Device recovery successful!"; - + // Restart rendering timer if rendering was enabled if (m_renderingEnabled && m_renderTimer && !m_renderTimer->isActive()) { m_renderTimer->start(16); // ~60 FPS @@ -1258,21 +1259,21 @@ bool VulkanWidget::handleDeviceLost() } else { qDebug() << "Device recovery failed!"; } - + return success; } bool VulkanWidget::recreateDevice() { qDebug() << "=== Recreating Vulkan device ==="; - + // Clean up renderer first if (m_renderer) { delete m_renderer; m_renderer = nullptr; qDebug() << "Renderer cleaned up"; } - + // Clean up sync objects if (m_device != VK_NULL_HANDLE) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { @@ -1288,16 +1289,16 @@ bool VulkanWidget::recreateDevice() } qDebug() << "Sync objects cleaned up"; } - + m_renderFinishedSemaphores.clear(); m_imageAvailableSemaphores.clear(); m_inFlightFences.clear(); - + // Clean up command objects if (m_device != VK_NULL_HANDLE && m_commandPool != VK_NULL_HANDLE) { if (!m_commandBuffers.empty()) { - vkFreeCommandBuffers(m_device, m_commandPool, - static_cast(m_commandBuffers.size()), + vkFreeCommandBuffers(m_device, m_commandPool, + static_cast(m_commandBuffers.size()), m_commandBuffers.data()); m_commandBuffers.clear(); } @@ -1305,10 +1306,10 @@ bool VulkanWidget::recreateDevice() m_commandPool = VK_NULL_HANDLE; qDebug() << "Command objects cleaned up"; } - + // Clean up swapchain cleanupSwapchain(); - + // Destroy logical device if (m_device != VK_NULL_HANDLE) { vkDestroyDevice(m_device, nullptr); @@ -1316,14 +1317,14 @@ bool VulkanWidget::recreateDevice() m_queue = VK_NULL_HANDLE; qDebug() << "Logical device destroyed"; } - + // Destroy surface if (m_surface != VK_NULL_HANDLE) { vkDestroySurfaceKHR(m_instance, m_surface, nullptr); m_surface = VK_NULL_HANDLE; qDebug() << "Surface destroyed"; } - + // Close and reset X11 display (Linux only) - will be reopened when creating new surface #ifdef __linux__ if (m_x11Display) { @@ -1332,21 +1333,21 @@ bool VulkanWidget::recreateDevice() qDebug() << "X11 display closed for recreation"; } #endif - + // Now recreate everything from surface onwards - + // Important: Add a small delay to let the GPU driver fully reset // This prevents VK_ERROR_SURFACE_LOST_KHR on some systems qDebug() << "Waiting for GPU driver to stabilize..."; QThread::msleep(200); // 200ms delay - + // Step 1: Recreate surface if (!createSurface()) { setError("Failed to recreate surface after device lost"); return false; } qDebug() << "Surface recreated"; - + // Verify the physical device still supports this surface VkBool32 surfaceSupported = VK_FALSE; vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, m_queueFamilyIndex, m_surface, &surfaceSupported); @@ -1356,14 +1357,14 @@ bool VulkanWidget::recreateDevice() return false; } qDebug() << "Surface support verified"; - + // Step 2: Recreate logical device if (!createDevice()) { setError("Failed to recreate device after device lost"); return false; } qDebug() << "Logical device recreated"; - + // Step 3: Recreate swapchain // Query surface capabilities again to ensure they're current VkSurfaceCapabilitiesKHR surfaceCaps; @@ -1374,31 +1375,31 @@ bool VulkanWidget::recreateDevice() return false; } qDebug() << "Surface capabilities validated"; - + if (!createSwapchain()) { setError("Failed to recreate swapchain after device lost"); return false; } qDebug() << "Swapchain recreated"; - + // Step 4: Recreate command objects if (!createCommandObjects()) { setError("Failed to recreate command objects after device lost"); return false; } qDebug() << "Command objects recreated"; - + // Step 5: Recreate synchronization objects if (!createSyncObjects()) { setError("Failed to recreate sync objects after device lost"); return false; } qDebug() << "Sync objects recreated"; - + // Step 6: Recreate VulkanRenderer if (m_surfaceWidth >= 100 && m_surfaceHeight >= 100) { m_renderer = new VulkanRenderer(); - + // Get swapchain format VkSurfaceFormatKHR surfaceFormat; uint32_t formatCount = 0; @@ -1408,7 +1409,7 @@ bool VulkanWidget::recreateDevice() vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data()); surfaceFormat = formats[0]; } - + // Initialize renderer if (!m_renderer->initialize(m_device, m_physicalDevice, m_queue, m_queueFamilyIndex, @@ -1419,13 +1420,13 @@ bool VulkanWidget::recreateDevice() m_renderer = nullptr; return false; } - + qDebug() << "VulkanRenderer recreated successfully!"; } - + // Reset frame counter m_currentFrame = 0; - + qDebug() << "=== Device recreation complete ==="; return true; } diff --git a/version.sh b/version.sh new file mode 100644 index 0000000..91fb0a8 --- /dev/null +++ b/version.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Auto-generated version information from CMakeLists.txt +# DO NOT EDIT THIS FILE MANUALLY - Edit CMakeLists.txt instead +# This file is sourced by shell scripts to get version information + +APP_VERSION_MAJOR=1 +APP_VERSION_MINOR=3 +APP_VERSION_PATCH=0 +APP_VERSION="1.3.0" + +# Export for use in other scripts +export APP_VERSION_MAJOR +export APP_VERSION_MINOR +export APP_VERSION_PATCH +export APP_VERSION diff --git a/version.sh.in b/version.sh.in new file mode 100644 index 0000000..c93c748 --- /dev/null +++ b/version.sh.in @@ -0,0 +1,16 @@ +#!/bin/bash + +# Auto-generated version information from CMakeLists.txt +# DO NOT EDIT THIS FILE MANUALLY - Edit CMakeLists.txt instead +# This file is sourced by shell scripts to get version information + +APP_VERSION_MAJOR=@PROJECT_VERSION_MAJOR@ +APP_VERSION_MINOR=@PROJECT_VERSION_MINOR@ +APP_VERSION_PATCH=@PROJECT_VERSION_PATCH@ +APP_VERSION="@PROJECT_VERSION@" + +# Export for use in other scripts +export APP_VERSION_MAJOR +export APP_VERSION_MINOR +export APP_VERSION_PATCH +export APP_VERSION