From 027122452a25191b81fef8fe35f5b54768d435f2 Mon Sep 17 00:00:00 2001 From: Sine Striker <trueful@163.com> Date: 周六, 02 12月 2023 01:54:24 +0800 Subject: [PATCH] Add windows implementations --- src/quick/quickwindowagent.h | 2 src/core/contexts/abstractwindowcontext.cpp | 0 examples/mainwindow/CMakeLists.txt | 15 +++ examples/mainwindow/main.cpp | 10 ++ src/core/contexts/abstractwindowcontext_p.h | 2 examples/mainwindow/mainwindow.h | 12 ++ CMakeLists.txt | 8 + src/core/contexts/qtwindowcontext_p.h | 3 src/core/contexts/win32windowcontext.cpp | 65 +++++++++++++ src/core/corewindowagent.cpp | 24 +++- src/core/corewindowagent_p.h | 4 src/core/qwkcoreglobal.h | 9 + /dev/null | 17 --- src/core/contexts/win32windowcontext_p.h | 27 +++++ src/widgets/widgetwindowagent.cpp | 13 +- src/core/CMakeLists.txt | 14 +- src/CMakeLists.txt | 5 src/core/qwindowkit_windows.h | 13 ++ src/core/qwindowkit_windows.cpp | 22 ++++ src/core/contexts/qtwindowcontext.cpp | 4 src/widgets/widgetwindowagent.h | 2 examples/mainwindow/mainwindow.cpp | 15 +++ examples/CMakeLists.txt | 1 src/quick/quickwindowagent.cpp | 13 +- 24 files changed, 252 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11bfc38..484a03b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ set(QWINDOWKIT_INSTALL_NAME ${PROJECT_NAME}) # ---------------------------------- -# Main Project +# Find basic dependencies # ---------------------------------- find_package(qmsetup QUIET) @@ -65,6 +65,12 @@ set(qmsetup_DIR ${_package_path} CACHE PATH "" FORCE) endif() +qm_import(Filesystem) +qm_init_directories() + +# ---------------------------------- +# Add source modules +# ---------------------------------- add_subdirectory(src) if(QWINDOWKIT_BUILD_EXAMPLES) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e69de29..c6a5640 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(mainwindow) \ No newline at end of file diff --git a/examples/mainwindow/CMakeLists.txt b/examples/mainwindow/CMakeLists.txt new file mode 100644 index 0000000..f981f1a --- /dev/null +++ b/examples/mainwindow/CMakeLists.txt @@ -0,0 +1,15 @@ +project(QWKExample_MainWindow) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +file(GLOB _src *.h *.cpp) + +add_executable(${PROJECT_NAME}) + +qm_configure_target(${PROJECT_NAME} + SOURCES ${_src} + QT_LINKS Core Gui Widgets + LINKS QWKWidgets +) \ No newline at end of file diff --git a/examples/mainwindow/main.cpp b/examples/mainwindow/main.cpp new file mode 100644 index 0000000..c68f59f --- /dev/null +++ b/examples/mainwindow/main.cpp @@ -0,0 +1,10 @@ +#include <QApplication> + +#include "mainwindow.h" + +int main(int argc, char *argv[]) { + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} \ No newline at end of file diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp new file mode 100644 index 0000000..f551a7f --- /dev/null +++ b/examples/mainwindow/mainwindow.cpp @@ -0,0 +1,15 @@ +#include "mainwindow.h" + +#include <QtCore/QDebug> + +#include <QWKWidgets/widgetwindowagent.h> + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { + auto agent = new QWK::WidgetWindowAgent(this); + if (!agent->setup(this)) { + qDebug() << "Frameless handle failed to initialize."; + } +} + +MainWindow::~MainWindow() { +} diff --git a/examples/mainwindow/mainwindow.h b/examples/mainwindow/mainwindow.h new file mode 100644 index 0000000..c0d595d --- /dev/null +++ b/examples/mainwindow/mainwindow.h @@ -0,0 +1,12 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QtWidgets/QMainWindow> + +class MainWindow : public QMainWindow { +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); +}; + +#endif // MAINWINDOW_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b0c2943..3dd7697 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,4 @@ -qm_import(Filesystem Preprocess) -qm_init_directories() +qm_import(Preprocess) set(QWINDOWKIT_PROJECT_DESCRIPTION "Cross-platform window customization framework") set(QWINDOWKIT_PROJECT_COPYRIGHT "Copyright 2023 Stdware Collections") @@ -106,7 +105,7 @@ if(NOT FUNC_NO_SYNC_INCLUDE) # Generate a standard include directory in build directory qm_sync_include(. "${QWINDOWKIT_GENERATED_INCLUDE_DIR}/${_inc_name}" ${_install_options} - ${FUNC_SYNC_INCLUDE_OPTIONS} + ${FUNC_SYNC_INCLUDE_OPTIONS} FORCE ) target_include_directories(${_target} PUBLIC "$<BUILD_INTERFACE:${QWINDOWKIT_GENERATED_INCLUDE_DIR}>" diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 03fa2dd..7b3d4a4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -9,20 +9,21 @@ corewindowagent_p.h corewindowagent.cpp windowitemdelegate.h - handler/abstractwindowcontext_p.h - handler/abstractwindowcontext.cpp + contexts/abstractwindowcontext_p.h + contexts/abstractwindowcontext.cpp ) if(WIN32) list(APPEND _src qwindowkit_windows.h - handler/win32windowcontext_p.h - handler/win32windowcontext.cpp + qwindowkit_windows.cpp + contexts/win32windowcontext_p.h + contexts/win32windowcontext.cpp ) else() list(APPEND _src - handler/qtwindowcontext_p.h - handler/qtwindowcontext.cpp + contexts/qtwindowcontext_p.h + contexts/qtwindowcontext.cpp ) if(APPLE) # add files @@ -38,6 +39,7 @@ LINKS QT_LINKS Core Gui QT_INCLUDE_PRIVATE Core Gui + INCLUDE_PRIVATE contexts PREFIX QWK_CORE ) diff --git a/src/core/handler/abstractwindowcontext.cpp b/src/core/contexts/abstractwindowcontext.cpp similarity index 100% rename from src/core/handler/abstractwindowcontext.cpp rename to src/core/contexts/abstractwindowcontext.cpp diff --git a/src/core/handler/abstractwindowcontext_p.h b/src/core/contexts/abstractwindowcontext_p.h similarity index 97% rename from src/core/handler/abstractwindowcontext_p.h rename to src/core/contexts/abstractwindowcontext_p.h index 6b908e6..fd3a445 100644 --- a/src/core/handler/abstractwindowcontext_p.h +++ b/src/core/contexts/abstractwindowcontext_p.h @@ -19,6 +19,8 @@ ~AbstractWindowContext(); public: + virtual bool setup() = 0; + inline QWindow *window() const; void setupWindow(QWindow *window); diff --git a/src/core/handler/qtwindowcontext.cpp b/src/core/contexts/qtwindowcontext.cpp similarity index 96% rename from src/core/handler/qtwindowcontext.cpp rename to src/core/contexts/qtwindowcontext.cpp index 1716fb2..a9740f1 100644 --- a/src/core/handler/qtwindowcontext.cpp +++ b/src/core/contexts/qtwindowcontext.cpp @@ -47,6 +47,10 @@ QtWindowContext::~QtWindowContext() { } + bool QtWindowContext::setup() { + return false; + } + bool QtWindowContext::eventFilter(QObject *obj, QEvent *event) { return AbstractWindowContext::eventFilter(obj, event); } diff --git a/src/core/handler/qtwindowcontext_p.h b/src/core/contexts/qtwindowcontext_p.h similarity index 90% rename from src/core/handler/qtwindowcontext_p.h rename to src/core/contexts/qtwindowcontext_p.h index c856da2..6daccb8 100644 --- a/src/core/handler/qtwindowcontext_p.h +++ b/src/core/contexts/qtwindowcontext_p.h @@ -11,6 +11,9 @@ QtWindowContext(QWindow *window, WindowItemDelegate *delegate); ~QtWindowContext(); + public: + bool setup() override; + protected: bool eventFilter(QObject *obj, QEvent *event) override; }; diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp new file mode 100644 index 0000000..a5dd7f7 --- /dev/null +++ b/src/core/contexts/win32windowcontext.cpp @@ -0,0 +1,65 @@ +#include "win32windowcontext_p.h" + +#include <QtCore/QHash> + +namespace QWK { + + using WndProcHash = QHash<HWND, Win32WindowContext *>; + Q_GLOBAL_STATIC(WndProcHash, g_wndProcHash); + + Win32WindowContext::Win32WindowContext(QWindow *window, WindowItemDelegate *delegate) + : AbstractWindowContext(window, delegate), windowId(0), qtWindowProc(nullptr) { + } + + Win32WindowContext::~Win32WindowContext() { + auto hWnd = reinterpret_cast<HWND>(windowId); + g_wndProcHash->remove(hWnd); + } + + bool Win32WindowContext::setup() { + auto winId = m_windowHandle->winId(); + Q_ASSERT(winId); + if (!winId) { + return false; + } + + // Install window hook + auto hWnd = reinterpret_cast<HWND>(winId); + auto orgWndProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hWnd, GWLP_WNDPROC)); + Q_ASSERT(orgWndProc); + if (!orgWndProc) { + QWK_WARNING << winLastErrorMessage(); + return false; + } + + if (::SetWindowLongPtrW(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(windowProc)) == 0) { + QWK_WARNING << winLastErrorMessage(); + return false; + } + + windowId = winId; + qtWindowProc = orgWndProc; // Store original window proc + g_wndProcHash->insert(hWnd, this); // Save window handle mapping + return true; + } + + LRESULT Win32WindowContext::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + Q_ASSERT(hWnd); + if (!hWnd) { + return FALSE; + } + + const auto *ctx = g_wndProcHash->value(hWnd); + if (!ctx) { + return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + + auto winId = reinterpret_cast<WId>(hWnd); + + // Further procedure + Q_UNUSED(winId) + + return ::CallWindowProcW(ctx->qtWindowProc, hWnd, uMsg, wParam, lParam); + } + +} \ No newline at end of file diff --git a/src/core/contexts/win32windowcontext_p.h b/src/core/contexts/win32windowcontext_p.h new file mode 100644 index 0000000..f1ab71e --- /dev/null +++ b/src/core/contexts/win32windowcontext_p.h @@ -0,0 +1,27 @@ +#ifndef WIN32WINDOWCONTEXT_P_H +#define WIN32WINDOWCONTEXT_P_H + +#include <QWKCore/qwindowkit_windows.h> +#include <QWKCore/private/abstractwindowcontext_p.h> + +namespace QWK { + + class QWK_CORE_EXPORT Win32WindowContext : public AbstractWindowContext { + Q_OBJECT + public: + Win32WindowContext(QWindow *window, WindowItemDelegate *delegate); + ~Win32WindowContext(); + + public: + bool setup() override; + + protected: + WId windowId; + WNDPROC qtWindowProc; // Original Qt window proc function + + static LRESULT windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + }; + +} + +#endif // WIN32WINDOWCONTEXT_P_H diff --git a/src/core/corewindowagent.cpp b/src/core/corewindowagent.cpp index a4e4ac4..54b081c 100644 --- a/src/core/corewindowagent.cpp +++ b/src/core/corewindowagent.cpp @@ -2,28 +2,40 @@ #include "corewindowagent_p.h" #ifdef Q_OS_WINDOWS -# include "handler/win32windowcontext_p.h" +# include "win32windowcontext_p.h" #else -# include "handler/qtwindowcontext_p.h" +# include "qtwindowcontext_p.h" #endif + +Q_LOGGING_CATEGORY(qWindowKitLog, "qwindowkit") namespace QWK { - CoreWindowAgentPrivate::CoreWindowAgentPrivate() { + CoreWindowAgentPrivate::CoreWindowAgentPrivate() : m_eventHandler(nullptr) { } CoreWindowAgentPrivate::~CoreWindowAgentPrivate() { + delete m_eventHandler; } void CoreWindowAgentPrivate::init() { } - void CoreWindowAgentPrivate::setup(QWindow *window, WindowItemDelegate *delegate) { + bool CoreWindowAgentPrivate::setup(QWindow *window, WindowItemDelegate *delegate) { + auto handler = #ifdef Q_OS_WINDOWS - m_eventHandler = new Win32WindowContext(window, delegate); + new Win32WindowContext(window, delegate) #else - m_eventHandler = new QtWindowContext(window, delegate); + new QtWindowContext(window, delegate) #endif + ; + + if (!handler->setup()) { + delete handler; + return false; + } + m_eventHandler = handler; + return true; } CoreWindowAgent::~CoreWindowAgent() { diff --git a/src/core/corewindowagent_p.h b/src/core/corewindowagent_p.h index c30cdbd..5276145 100644 --- a/src/core/corewindowagent_p.h +++ b/src/core/corewindowagent_p.h @@ -16,9 +16,9 @@ CoreWindowAgent *q_ptr; // no need to initialize - void setup(QWindow *window, WindowItemDelegate *delegate); + bool setup(QWindow *window, WindowItemDelegate *delegate); - AbstractWindowContext *m_eventHandler{}; + AbstractWindowContext *m_eventHandler; }; } diff --git a/src/core/handler/win32windowcontext.cpp b/src/core/handler/win32windowcontext.cpp deleted file mode 100644 index 0311532..0000000 --- a/src/core/handler/win32windowcontext.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "win32windowcontext_p.h" - -#include <windows.h> - -namespace QWK { - - static LRESULT CALLBACK QWK_WindowsWndProc(const HWND hWnd, const UINT uMsg, - const WPARAM wParam, const LPARAM lParam) { - // Implement - return 0; - } - - static bool hookWindowProc(QObject *window, WId windowId) { - Q_ASSERT(windowId); - if (!windowId) { - return false; - } - - const auto hwnd = reinterpret_cast<HWND>(windowId); - if (!extraData->qtWindowProc) { - ::SetLastError(ERROR_SUCCESS); - const auto qtWindowProc = - reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hwnd, GWLP_WNDPROC)); - Q_ASSERT(qtWindowProc); - if (!qtWindowProc) { - WARNING << getSystemErrorMessage(kGetWindowLongPtrW); - return false; - } - extraData->qtWindowProc = qtWindowProc; - } - if (!extraData->windowProcHooked) { - ::SetLastError(ERROR_SUCCESS); - if (::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, - reinterpret_cast<LONG_PTR>(QWK_WindowsWndProc)) == 0) { - WARNING << getSystemErrorMessage(kSetWindowLongPtrW); - return false; - } - extraData->windowProcHooked = true; - } - return true; - } - - Win32WindowContext::Win32WindowContext(QWindow *window, WindowItemDelegate *delegate) - : AbstractWindowContext(window, delegate) { - // Install windows window hook - } - - Win32WindowContext::~Win32WindowContext() { - } - -} \ No newline at end of file diff --git a/src/core/handler/win32windowcontext_p.h b/src/core/handler/win32windowcontext_p.h deleted file mode 100644 index 7d0b415..0000000 --- a/src/core/handler/win32windowcontext_p.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef WIN32WINDOWCONTEXT_P_H -#define WIN32WINDOWCONTEXT_P_H - -#include <QWKCore/private/abstractwindowcontext_p.h> - -namespace QWK { - - class QWK_CORE_EXPORT Win32WindowContext : public AbstractWindowContext { - Q_OBJECT - public: - Win32WindowContext(QWindow *window, WindowItemDelegate *delegate); - ~Win32WindowContext(); - }; - -} - -#endif // WIN32WINDOWCONTEXT_P_H diff --git a/src/core/qwindowkit_windows.cpp b/src/core/qwindowkit_windows.cpp new file mode 100644 index 0000000..aeb2954 --- /dev/null +++ b/src/core/qwindowkit_windows.cpp @@ -0,0 +1,22 @@ +#include "qwindowkit_windows.h" + +namespace QWK { + + QString winErrorMessage(DWORD code) { + LPWSTR buf = nullptr; + if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast<LPWSTR>(&buf), 0, nullptr) == 0) { + return {}; + } + const QString &errorText = QString::fromWCharArray(buf).trimmed(); + ::LocalFree(buf); + return errorText; + } + + QString winLastErrorMessage() { + return winErrorMessage(::GetLastError()); + } + +} \ No newline at end of file diff --git a/src/core/qwindowkit_windows.h b/src/core/qwindowkit_windows.h index 8a013ce..6462e0b 100644 --- a/src/core/qwindowkit_windows.h +++ b/src/core/qwindowkit_windows.h @@ -1,5 +1,18 @@ #ifndef QWINDOWKIT_WINDOWS_H #define QWINDOWKIT_WINDOWS_H +#include <windows.h> + +#include <QString> + +#include <QWKCore/qwkcoreglobal.h> + +namespace QWK { + + QWK_CORE_EXPORT QString winErrorMessage(DWORD code); + + QWK_CORE_EXPORT QString winLastErrorMessage(); + +} #endif // QWINDOWKIT_WINDOWS_H diff --git a/src/core/qwkcoreglobal.h b/src/core/qwkcoreglobal.h index 7cba597..7c6b936 100644 --- a/src/core/qwkcoreglobal.h +++ b/src/core/qwkcoreglobal.h @@ -1,7 +1,7 @@ #ifndef QWKCOREGLOBAL_H #define QWKCOREGLOBAL_H -#include <QtGlobal> +#include <QLoggingCategory> #ifndef QWK_CORE_EXPORT # ifdef QWK_CORE_STATIC @@ -15,4 +15,11 @@ # endif #endif +QWK_CORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(qWindowKitLog) + +#define QWK_INFO qCInfo(qWindowKitLog) +#define QWK_DEBUG qCDebug(qWindowKitLog) +#define QWK_WARNING qCWarning(qWindowKitLog) +#define QWK_CRITICAL qCCritical(qWindowKitLog) + #endif // QWKCOREGLOBAL_H diff --git a/src/quick/quickwindowagent.cpp b/src/quick/quickwindowagent.cpp index d7f283d..a1bbeb6 100644 --- a/src/quick/quickwindowagent.cpp +++ b/src/quick/quickwindowagent.cpp @@ -23,19 +23,22 @@ QuickWindowAgent::~QuickWindowAgent() { } - void QuickWindowAgent::setup(QQuickWindow *window) { + bool QuickWindowAgent::setup(QQuickWindow *window) { Q_ASSERT(window); if (!window) { - return; + return false; } Q_D(QuickWindowAgent); if (d->host) { - return; + return false; + } + + if (!d->setup(window, new QuickItemDelegate())) { + return true; } d->host = window; - - d->setup(window, new QuickItemDelegate()); + return true; } bool QuickWindowAgent::isHitTestVisible(QQuickItem *item) const { diff --git a/src/quick/quickwindowagent.h b/src/quick/quickwindowagent.h index 7c004e4..0df2794 100644 --- a/src/quick/quickwindowagent.h +++ b/src/quick/quickwindowagent.h @@ -19,7 +19,7 @@ ~QuickWindowAgent(); public: - void setup(QQuickWindow *window); + bool setup(QQuickWindow *window); bool isHitTestVisible(QQuickItem *item) const; void setHitTestVisible(QQuickItem *item, bool visible); diff --git a/src/widgets/widgetwindowagent.cpp b/src/widgets/widgetwindowagent.cpp index d3200a7..9726e4b 100644 --- a/src/widgets/widgetwindowagent.cpp +++ b/src/widgets/widgetwindowagent.cpp @@ -21,20 +21,23 @@ WidgetWindowAgent::~WidgetWindowAgent() { } - void WidgetWindowAgent::setup(QWidget *w) { + bool WidgetWindowAgent::setup(QWidget *w) { Q_ASSERT(w); if (!w) { - return; + return false; } Q_D(WidgetWindowAgent); if (d->host) { - return; + return false; } - d->host = w; std::ignore = w->winId(); // Make sure the window handle is created - d->setup(w->windowHandle(), new WidgetItemDelegate()); + if (!d->setup(w->windowHandle(), new WidgetItemDelegate())) { + return true; + } + d->host = w; + return true; } bool WidgetWindowAgent::isHitTestVisible(QWidget *w) const { diff --git a/src/widgets/widgetwindowagent.h b/src/widgets/widgetwindowagent.h index 32df976..81e454c 100644 --- a/src/widgets/widgetwindowagent.h +++ b/src/widgets/widgetwindowagent.h @@ -18,7 +18,7 @@ ~WidgetWindowAgent(); public: - void setup(QWidget *w); + bool setup(QWidget *w); bool isHitTestVisible(QWidget *w) const; void setHitTestVisible(QWidget *w, bool visible); -- Gitblit v1.9.1