diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65b033c..c727527 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,13 +20,13 @@ jobs: steps: - name: Add debug repositories run: | - printf "[core-debug]\nInclude = /etc/pacman.d/mirrorlist\n[extra-debug]\nInclude = /etc/pacman.d/mirrorlist\n[community-debug]\nInclude = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf + printf "[core-debug]\nInclude = /etc/pacman.d/mirrorlist\n[extra-debug]\nInclude = /etc/pacman.d/mirrorlist\n[multilib-debug]\nInclude = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf printf 'Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch\n%s\n' "$(cat /etc/pacman.d/mirrorlist)" > /etc/pacman.d/mirrorlist - name: Install dependencies run: pacman --noconfirm -Syu base-devel glibc-debug git valgrind libglvnd libsndfile libx11 libxrandr freetype2 cairo - uses: actions/checkout@v3 - name: Configure project - run: make config TEST=1 + run: make config TEST=1 STRICT=1 - name: Fetch project dependencies run: make fetch - name: Build project @@ -46,13 +46,13 @@ jobs: steps: - name: Add debug repositories run: | - printf "[core-debug]\nInclude = /etc/pacman.d/mirrorlist\n[extra-debug]\nInclude = /etc/pacman.d/mirrorlist\n[community-debug]\nInclude = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf + printf "[core-debug]\nInclude = /etc/pacman.d/mirrorlist\n[extra-debug]\nInclude = /etc/pacman.d/mirrorlist\n[multilib-debug]\nInclude = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf printf 'Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch\n%s\n' "$(cat /etc/pacman.d/mirrorlist)" > /etc/pacman.d/mirrorlist - name: Install dependencies run: pacman --noconfirm -Syu base-devel glibc-debug git valgrind libglvnd libsndfile libx11 libxrandr freetype2 cairo - uses: actions/checkout@v3 - name: Configure project - run: make config TEST=1 DEBUG=1 + run: make config TEST=1 STRICT=1 DEBUG=1 - name: Fetch project dependencies run: make fetch - name: Build project @@ -74,7 +74,7 @@ jobs: run: zypper --non-interactive --no-gpg-checks in tar gzip git make valgrind gcc gcc-c++ libX11-devel libXrandr-devel libglvnd-devel Mesa-libGL-devel libsndfile-devel freetype2-devel cairo-devel - uses: actions/checkout@v3 - name: Configure project - run: make config TEST=1 + run: make config TEST=1 STRICT=1 - name: Fetch project dependencies run: make fetch - name: Build project @@ -96,7 +96,7 @@ jobs: run: zypper --non-interactive --no-gpg-checks in tar gzip git make valgrind gcc gcc-c++ libstdc++-devel clang libX11-devel libXrandr-devel libglvnd-devel Mesa-libGL-devel libsndfile-devel freetype2-devel cairo-devel - uses: actions/checkout@v3 - name: Configure project - run: make config TEST=1 CC=clang CXX=clang++ + run: make config TEST=1 STRICT=1 CC=clang CXX=clang++ - name: Fetch project dependencies run: make fetch - name: Build project @@ -120,7 +120,7 @@ jobs: run: apt-get -y install git make pkg-config valgrind gcc g++ libgl-dev libsndfile1-dev libx11-dev libxrandr-dev libfreetype6-dev libcairo2-dev - uses: actions/checkout@v3 - name: Configure project - run: make config TEST=1 + run: make config TEST=1 STRICT=1 - name: Fetch project dependencies run: make fetch - name: Build project @@ -152,7 +152,7 @@ jobs: - uses: actions/checkout@v3 - name: Configure project shell: msys2 {0} - run: make config TEST=1 + run: make config TEST=1 STRICT=1 - name: Fetch project dependencies shell: msys2 {0} run: make fetch diff --git a/CHANGELOG b/CHANGELOG index 132693b..57cd704 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,12 @@ * RECENT CHANGES ******************************************************************************* +=== 1.0.12 === +* Fixed bug in the ws::ft::FontManager which could yield memory corrption after + complete font manager cleanup. +* Updated build scripts. +* Updated module versions in dependencies. + === 1.0.11 === * Fixed clang build error. diff --git a/include/lsp-plug.in/ws/IDisplay.h b/include/lsp-plug.in/ws/IDisplay.h index ad2a418..c5ef756 100644 --- a/include/lsp-plug.in/ws/IDisplay.h +++ b/include/lsp-plug.in/ws/IDisplay.h @@ -100,6 +100,7 @@ namespace lsp r3d::factory_t *p3DFactory; // Pointer to the factory object ssize_t nCurrent3D; // Current 3D backend ssize_t nPending3D; // Pending 3D backend + size_t nIdleInterval; // Idle interval in milliseconds protected: friend class IR3DBackend; @@ -109,7 +110,6 @@ namespace lsp status_t switch_r3d_backend(r3d_lib_t *backend); status_t commit_r3d_factory(const LSPString *path, r3d::factory_t *factory, const version_t *mversion); void detach_r3d_backends(); - void call_main_task(timestamp_t time); status_t process_pending_tasks(timestamp_t time); static void drop_r3d_lib(r3d_lib_t *lib); bool check_duplicate(const r3d_lib_t *lib); @@ -515,7 +515,20 @@ namespace lsp * @param count number of actual monitors enumerated * @return pointer to enumerated monitors or error. */ - virtual const MonitorInfo *enum_monitors(size_t *count); + virtual const MonitorInfo *enum_monitors(size_t *count); + + /** + * Get the typical idle interval for the display + * @return the typical idle interval (default 50 ms or 20 FPS) + */ + virtual size_t idle_interval(); + + /** + * Set the typical idle interval for the display + * @param interval idle interval in millisecionds + * @return previous value of the idle interval + */ + size_t set_idle_interval(size_t interval); }; } /* namespace ws */ diff --git a/include/lsp-plug.in/ws/version.h b/include/lsp-plug.in/ws/version.h index f310eb3..662841d 100644 --- a/include/lsp-plug.in/ws/version.h +++ b/include/lsp-plug.in/ws/version.h @@ -24,7 +24,7 @@ #define LSP_WS_LIB_MAJOR 1 #define LSP_WS_LIB_MINOR 0 -#define LSP_WS_LIB_MICRO 11 +#define LSP_WS_LIB_MICRO 12 #if defined(LSP_WS_LIB_PUBLISHER) #define LSP_WS_LIB_PUBLIC LSP_EXPORT_MODIFIER diff --git a/include/private/win/WinDisplay.h b/include/private/win/WinDisplay.h index 34db99d..5883c8a 100644 --- a/include/private/win/WinDisplay.h +++ b/include/private/win/WinDisplay.h @@ -68,10 +68,6 @@ namespace lsp friend class WinWindow; friend class WinDDSurface; - public: - static const WCHAR *WINDOW_CLASS_NAME; - static const WCHAR *CLIPBOARD_CLASS_NAME; - protected: typedef struct font_t { @@ -118,6 +114,9 @@ namespace lsp lltl::parray vClipMemory; // Memory chunks allocated for the clipboard WinWindow *pDragWindow; // Window which is currently acting in Drag&Drop action ipc::Thread *pPingThread; // Pinger thread + volatile timestamp_t nLastIdleCall; // The time of last idle call + LSPString sWindowClassName; // Window class name + LSPString sClipboardClassName; // Clipboard window class name protected: void do_destroy(); diff --git a/include/private/win/WinWindow.h b/include/private/win/WinWindow.h index 8256abe..dec20a1 100644 --- a/include/private/win/WinWindow.h +++ b/include/private/win/WinWindow.h @@ -77,6 +77,7 @@ namespace lsp WinDisplay *pWinDisplay; // Pointer to the display HWND hWindow; // The identifier of the wrapped window HWND hParent; // The identifier of parent window + HWND hTransientFor; // The transient window WinDDSurface *pSurface; // Drawing surface WinDNDTarget *pDNDTarget; // Drag&Drop target LONG_PTR pOldUserData; // Old user data @@ -84,6 +85,7 @@ namespace lsp bool bWrapper; // Indicates that window is a wrapper bool bMouseInside; // Flag that indicates that mouse is inside of the window bool bGrabbing; // Grabbing mouse and keyboard events + bool bTransientOn; // The transient window status size_t nMouseCapture; // Flag for capturing mouse rectangle_t sSize; // Size of the window size_limit_t sConstraints; // Window constraints diff --git a/include/private/x11/X11Display.h b/include/private/x11/X11Display.h index 857ef23..d86d24a 100644 --- a/include/private/x11/X11Display.h +++ b/include/private/x11/X11Display.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 10 окт. 2016 г. diff --git a/make/configure.mk b/make/configure.mk index dd063a5..6441722 100644 --- a/make/configure.mk +++ b/make/configure.mk @@ -117,7 +117,7 @@ define _modconfig = $(if $($(name)_TEST),, $(eval $(name)_TEST := $($(name)_PATH)/test)) $(if $($(name)_TESTING),, $(eval $(name)_TESTING := 0)) $(if $($(name)_BIN),, $(eval $(name)_BIN := $(TARGET_BUILDDIR)/$($(name)_NAME))) - $(if $($(name)_CFLAGS),, $(eval $(name)_CFLAGS := "-I\"$($(name)_INC)\"" -D$(name)_BUILTIN$(if $(publisher), -D$(name)_PUBLISHER))) + $(if $($(name)_CFLAGS),, $(eval $(name)_CFLAGS := "$(if $($(name)_INC_OPT),$($(name)_INC_OPT) ,-I )\"$($(name)_INC)\"" -D$(name)_BUILTIN$(if $(publisher), -D$(name)_PUBLISHER))) $(if $($(name)_LDLAGS),, $(eval $(name)_LDFLAGS :=)) $(if $($(name)_OBJ),, $(eval $(name)_OBJ := "$($(name)_BIN)/$($(name)_NAME).o")) $(if $($(name)_OBJ_TEST),, $(eval $(name)_OBJ_TEST := "$($(name)_BIN)/$($(name)_NAME)-test.o")) @@ -129,7 +129,7 @@ define _modconfig = $(if $(HOST_$(name)_TEST),, $(eval HOST_$(name)_TEST := $(HOST_$(name)_PATH)/test)) $(if $(HOST_$(name)_TESTING),, $(eval HOST_$(name)_TESTING := 0)) $(if $(HOST_$(name)_BIN),, $(eval HOST_$(name)_BIN := $(HOST_BUILDDIR)/$($(name)_NAME))) - $(if $(HOST_$(name)_CFLAGS),, $(eval HOST_$(name)_CFLAGS := "-I\"$($(name)_INC)\"" -D$(name)_BUILTIN$(if $(publisher), -D$(name)_PUBLISHER))) + $(if $(HOST_$(name)_CFLAGS),, $(eval HOST_$(name)_CFLAGS := "$(if $($(name)_INC_OPT),$($(name)_INC_OPT) ,-I )\"$($(name)_INC)\"" -D$(name)_BUILTIN$(if $(publisher), -D$(name)_PUBLISHER))) $(if $(HOST_$(name)_LDLAGS),, $(eval HOST_$(name)_LDFLAGS :=)) $(if $(HOST_$(name)_OBJ),, $(eval HOST_$(name)_OBJ := "$(HOST_$(name)_BIN)/$($(name)_NAME).o")) $(if $(HOST_$(name)_OBJ_TEST),,$(eval HOST_$(name)_OBJ_TEST:= "$(HOST_$(name)_BIN)/$($(name)_NAME)-test.o")) @@ -158,13 +158,13 @@ define hdrconfig = $(if $($(name)_PATH),, $(eval $(name)_PATH := $(MODULES)/$($(name)_NAME))) $(if $($(name)_INC),, $(eval $(name)_INC := $($(name)_PATH)/include)) $(if $($(name)_TESTING),, $(eval $(name)_TESTING := 0)) - $(if $($(name)_CFLAGS),, $(eval $(name)_CFLAGS := "-I\"$($(name)_INC)\""$(if $(publisher), "-D$(name)_PUBLISHER"))) + $(if $($(name)_CFLAGS),, $(eval $(name)_CFLAGS := "$(if $($(name)_INC_OPT),$($(name)_INC_OPT) ,-I )\"$($(name)_INC)\""$(if $(publisher), "-D$(name)_PUBLISHER"))) $(if $($(name)_MFLAGS),, $(eval $(name)_MFLAGS := "-D$(name)_BUILTIN -fvisibility=hidden")) $(if $(HOST_$(name)_PATH),, $(eval HOST_$(name)_PATH := $(MODULES)/$($(name)_NAME))) $(if $(HOST_$(name)_INC),, $(eval HOST_$(name)_INC := $(HOST_$(name)_PATH)/include)) $(if $(HOST_$(name)_TESTING),, $(eval HOST_$(name)_TESTING := 0)) - $(if $(HOST_$(name)_CFLAGS),, $(eval HOST_$(name)_CFLAGS := "-I\"$(HOST_$(name)_INC)\""$(if $(publisher), "-D$(name)_PUBLISHER"))) + $(if $(HOST_$(name)_CFLAGS),, $(eval HOST_$(name)_CFLAGS := "$(if $($(name)_INC_OPT),$($(name)_INC_OPT) ,-I )\"$(HOST_$(name)_INC)\""$(if $(publisher), "-D$(name)_PUBLISHER"))) $(if $(HOST_$(name)_MFLAGS),, $(eval HOST_$(name)_MFLAGS := "-D$(name)_BUILTIN -fvisibility=hidden")) endef diff --git a/make/system.mk b/make/system.mk index 4949812..5796e89 100644 --- a/make/system.mk +++ b/make/system.mk @@ -192,6 +192,7 @@ COMMON_VARS = \ ROOT_ARTIFACT_ID \ PROFILE \ STATICLIB_EXT \ + STRICT \ TEST \ TRACE @@ -216,6 +217,7 @@ sysvars: echo " PLATFORM target software platform to perform build" echo " PROFILE build with profile options" echo " STATICLIB_EXT file extension for static library files" + echo " STRICT strict compilation: treat compilation warnings as errors" echo " SUB_FEATURES list of features disabled in the build as a subtraction of default" echo " TEST use test build" echo " TRACE compile with additional trace information output" diff --git a/make/tools.mk b/make/tools.mk index 9dee60e..e3b1c47 100644 --- a/make/tools.mk +++ b/make/tools.mk @@ -102,6 +102,11 @@ ifeq ($(TRACE),1) CXXFLAGS_EXT += -DLSP_TRACE endif +ifeq ($(STRICT),1) + CFLAGS_EXT += -Werror + CXXFLAGS_EXT += -Werror +endif + ifeq ($(TEST),1) CFLAGS_EXT += -DLSP_TESTING CXXFLAGS_EXT += -DLSP_TESTING diff --git a/modules.mk b/modules.mk index 9980081..dbe357c 100644 --- a/modules.mk +++ b/modules.mk @@ -20,55 +20,55 @@ #------------------------------------------------------------------------------ # Variables that describe source code dependencies -LSP_COMMON_LIB_VERSION := 1.0.28 +LSP_COMMON_LIB_VERSION := 1.0.29 LSP_COMMON_LIB_NAME := lsp-common-lib LSP_COMMON_LIB_TYPE := src LSP_COMMON_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_COMMON_LIB_NAME).git LSP_COMMON_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_COMMON_LIB_NAME).git -LSP_DSP_LIB_VERSION := 1.0.12 +LSP_DSP_LIB_VERSION := 1.0.13 LSP_DSP_LIB_NAME := lsp-dsp-lib LSP_DSP_LIB_TYPE := src LSP_DSP_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_DSP_LIB_NAME).git LSP_DSP_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_DSP_LIB_NAME).git -LSP_LLTL_LIB_VERSION := 1.0.11 +LSP_LLTL_LIB_VERSION := 1.0.12 LSP_LLTL_LIB_NAME := lsp-lltl-lib LSP_LLTL_LIB_TYPE := src LSP_LLTL_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_LLTL_LIB_NAME).git LSP_LLTL_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_LLTL_LIB_NAME).git -LSP_R3D_BASE_LIB_VERSION := 1.0.11 +LSP_R3D_BASE_LIB_VERSION := 1.0.12 LSP_R3D_BASE_LIB_NAME := lsp-r3d-base-lib LSP_R3D_BASE_LIB_TYPE := src LSP_R3D_BASE_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_R3D_BASE_LIB_NAME).git LSP_R3D_BASE_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_R3D_BASE_LIB_NAME).git -LSP_R3D_GLX_LIB_VERSION := 1.0.11 +LSP_R3D_GLX_LIB_VERSION := 1.0.12 LSP_R3D_GLX_LIB_NAME := lsp-r3d-glx-lib LSP_R3D_GLX_LIB_TYPE := src LSP_R3D_GLX_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_R3D_GLX_LIB_NAME).git LSP_R3D_GLX_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_R3D_GLX_LIB_NAME).git -LSP_R3D_IFACE_VERSION := 1.0.11 +LSP_R3D_IFACE_VERSION := 1.0.12 LSP_R3D_IFACE_NAME := lsp-r3d-iface LSP_R3D_IFACE_TYPE := src LSP_R3D_IFACE_URL_RO := https://github.com/lsp-plugins/$(LSP_R3D_IFACE_NAME).git LSP_R3D_IFACE_URL_RW := git@github.com:lsp-plugins/$(LSP_R3D_IFACE_NAME).git -LSP_R3D_WGL_LIB_VERSION := 1.0.6 +LSP_R3D_WGL_LIB_VERSION := 1.0.7 LSP_R3D_WGL_LIB_NAME := lsp-r3d-wgl-lib LSP_R3D_WGL_LIB_TYPE := src LSP_R3D_WGL_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_R3D_WGL_LIB_NAME).git LSP_R3D_WGL_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_R3D_WGL_LIB_NAME).git -LSP_RUNTIME_LIB_VERSION := 1.0.14 +LSP_RUNTIME_LIB_VERSION := 1.0.15 LSP_RUNTIME_LIB_NAME := lsp-runtime-lib LSP_RUNTIME_LIB_TYPE := src LSP_RUNTIME_LIB_URL_RO := https://github.com/lsp-plugins/$(LSP_RUNTIME_LIB_NAME).git LSP_RUNTIME_LIB_URL_RW := git@github.com:lsp-plugins/$(LSP_RUNTIME_LIB_NAME).git -LSP_TEST_FW_VERSION := 1.0.20 +LSP_TEST_FW_VERSION := 1.0.21 LSP_TEST_FW_NAME := lsp-test-fw LSP_TEST_FW_TYPE := src LSP_TEST_FW_URL_RO := https://github.com/lsp-plugins/$(LSP_TEST_FW_NAME).git diff --git a/project.mk b/project.mk index 2d7a9e5..2a6b67b 100644 --- a/project.mk +++ b/project.mk @@ -23,5 +23,5 @@ ARTIFACT_ID = LSP_WS_LIB ARTIFACT_NAME = lsp-ws-lib ARTIFACT_DESC = LSP window subsystem core library ARTIFACT_HEADERS = lsp-plug.in -ARTIFACT_VERSION = 1.0.11 +ARTIFACT_VERSION = 1.0.12 diff --git a/src/main/IDisplay.cpp b/src/main/IDisplay.cpp index ddf0b78..7b5a161 100644 --- a/src/main/IDisplay.cpp +++ b/src/main/IDisplay.cpp @@ -105,6 +105,7 @@ namespace lsp sMainTask.nTime = 0; sMainTask.pHandler = NULL; sMainTask.pArg = NULL; + nIdleInterval = 50; } IDisplay::~IDisplay() @@ -484,18 +485,30 @@ namespace lsp } } - void IDisplay::call_main_task(timestamp_t time) - { - if (sMainTask.pHandler != NULL) - sMainTask.pHandler(time, time, sMainTask.pArg); - } - void IDisplay::task_queue_changed() { } status_t IDisplay::process_pending_tasks(timestamp_t time) { + // Sync backends + if (nCurrent3D != nPending3D) + { + r3d_lib_t *lib = s3DLibs.get(nPending3D); + if (lib != NULL) + { + if (switch_r3d_backend(lib) == STATUS_OK) + nCurrent3D = nPending3D; + } + else + nPending3D = nCurrent3D; + } + + // Call the main task + if (sMainTask.pHandler != NULL) + sMainTask.pHandler(time, time, sMainTask.pArg); + + // Execute all other pending tasks dtask_t task; status_t result = STATUS_OK; @@ -706,19 +719,6 @@ namespace lsp status_t IDisplay::main_iteration() { - // Sync backends - if (nCurrent3D != nPending3D) - { - r3d_lib_t *lib = s3DLibs.get(nPending3D); - if (lib != NULL) - { - if (switch_r3d_backend(lib) == STATUS_OK) - nCurrent3D = nPending3D; - } - else - nPending3D = nCurrent3D; - } - return STATUS_SUCCESS; } @@ -993,6 +993,19 @@ namespace lsp *count = 0; return NULL; } - } + + size_t IDisplay::idle_interval() + { + return nIdleInterval; + } + + size_t IDisplay::set_idle_interval(size_t interval) + { + size_t old = nIdleInterval; + nIdleInterval = interval; + return old; + } + + } /* namespace ws */ } /* namespace lsp */ diff --git a/src/main/freetype/FontManger.cpp b/src/main/freetype/FontManger.cpp index 67713a3..f659989 100644 --- a/src/main/freetype/FontManger.cpp +++ b/src/main/freetype/FontManger.cpp @@ -392,6 +392,7 @@ namespace lsp } } vAliases.flush(); + sLRU.clear(); return STATUS_OK; } diff --git a/src/main/freetype/LRUCache.cpp b/src/main/freetype/LRUCache.cpp index e239cfb..002af27 100644 --- a/src/main/freetype/LRUCache.cpp +++ b/src/main/freetype/LRUCache.cpp @@ -75,7 +75,7 @@ namespace lsp if (pTail != NULL) pTail->lru_next = NULL; else - pHead = NULL; + pHead = NULL; // Clear links to other glyphs glyph->lru_prev = NULL; @@ -91,14 +91,14 @@ namespace lsp glyph->lru_next = pHead; glyph->lru_prev = NULL; pHead->lru_prev = glyph; - pHead = glyph; + pHead = glyph; return glyph; } glyph->lru_next = NULL; glyph->lru_prev = NULL; - pHead = glyph; - pTail = glyph; + pHead = glyph; + pTail = glyph; return glyph; } diff --git a/src/main/win/WinDisplay.cpp b/src/main/win/WinDisplay.cpp index 469e5b5..e29c738 100644 --- a/src/main/win/WinDisplay.cpp +++ b/src/main/win/WinDisplay.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include // Define the placement-new for our construction/destruction tricks @@ -58,10 +59,10 @@ namespace lsp //----------------------------------------------------------------- static const BYTE none_cursor_and[] = { 0xff }; static const BYTE none_cursor_xor[] = { 0 }; + static const char *WINDOW_CLASS_NAME = "lsp-ws-lib::window"; + static const char *CLIPBOARD_CLASS_NAME = "lsp-ws-lib::clipboard"; //----------------------------------------------------------------- - const WCHAR *WinDisplay::WINDOW_CLASS_NAME = L"lsp-ws-lib window"; - const WCHAR *WinDisplay::CLIPBOARD_CLASS_NAME = L"lsp-ws-lib clipboard window"; volatile atomic_t WinDisplay::hLock = 0; volatile DWORD WinDisplay::nThreadId = 0; WinDisplay *WinDisplay::pHandlers = NULL; @@ -72,12 +73,12 @@ namespace lsp WinDisplay::WinDisplay(): IDisplay() { - bExit = false; - pD2D1Factroy = NULL; - pWICFactory = NULL; - pDWriteFactory = NULL; - hWindowClass = 0; - hClipClass = 0; + bExit = false; + pD2D1Factroy = NULL; + pWICFactory = NULL; + pDWriteFactory = NULL; + hWindowClass = 0; + hClipClass = 0; bzero(&sPendingMessage, sizeof(sPendingMessage)); sPendingMessage.message = WM_NULL; @@ -85,11 +86,12 @@ namespace lsp for (size_t i=0; i<__MP_COUNT; ++i) vCursors[i] = NULL; - pNextHandler = NULL; - hClipWnd = NULL; - pClipData = NULL; - pDragWindow = NULL; - pPingThread = NULL; + pNextHandler = NULL; + hClipWnd = NULL; + pClipData = NULL; + pDragWindow = NULL; + pPingThread = NULL; + nLastIdleCall = 0; } WinDisplay::~WinDisplay() @@ -108,12 +110,13 @@ namespace lsp bExit = false; - // Register window class - bzero(&wc, sizeof(wc)); + // Register window classes + sWindowClassName.fmt_ascii("%s", WINDOW_CLASS_NAME, this); + bzero(&wc, sizeof(wc)); wc.lpfnWndProc = window_proc; wc.hInstance = GetModuleHandleW(NULL); - wc.lpszClassName = WINDOW_CLASS_NAME; + wc.lpszClassName = sWindowClassName.get_utf16(); if (!(hWindowClass = RegisterClassW(&wc))) { @@ -122,11 +125,12 @@ namespace lsp } // Register clipboard window class - bzero(&wc, sizeof(wc)); + sClipboardClassName.fmt_ascii("%s", CLIPBOARD_CLASS_NAME, this); + bzero(&wc, sizeof(wc)); wc.lpfnWndProc = clipboard_proc; wc.hInstance = GetModuleHandleW(NULL); - wc.lpszClassName = CLIPBOARD_CLASS_NAME; + wc.lpszClassName = sClipboardClassName.get_utf16(); if (!(hClipClass = RegisterClassW(&wc))) { @@ -179,14 +183,14 @@ namespace lsp // Create invisible clipboard window hClipWnd = CreateWindowExW( 0, // dwExStyle - WinDisplay::CLIPBOARD_CLASS_NAME, // lpClassName + sClipboardClassName.get_utf16(), // lpClassName L"Clipboard", // lpWindowName WS_OVERLAPPEDWINDOW, // dwStyle 0, // X 0, // Y 1, // nWidth 1, // nHeight - NULL, // hWndParent + HWND_MESSAGE, // hWndParent NULL, // hMenu GetModuleHandleW(NULL), // hInstance this); // lpCreateParam @@ -195,6 +199,7 @@ namespace lsp lsp_error("Error creating clipboard window: %ld", long(GetLastError())); return STATUS_UNKNOWN_ERR; } + lsp_trace("Created clipboard window hWND=%p", hClipWnd); // Create pinging thread pPingThread = new ipc::Thread(ping_proc, this); @@ -230,12 +235,12 @@ namespace lsp // Unregister window classes if (hWindowClass != 0) { - UnregisterClassW(WINDOW_CLASS_NAME, GetModuleHandleW(NULL)); + UnregisterClassW(sWindowClassName.get_utf16(), GetModuleHandleW(NULL)); hWindowClass = 0; } if (hClipClass != 0) { - UnregisterClassW(CLIPBOARD_CLASS_NAME, GetModuleHandleW(NULL)); + UnregisterClassW(sClipboardClassName.get_utf16(), GetModuleHandleW(NULL)); hClipClass = 0; } @@ -275,11 +280,15 @@ namespace lsp status_t WinDisplay::ping_proc(void *arg) { - WinDisplay *_this = static_cast(arg); + WinDisplay *self = static_cast(arg); while (!ipc::Thread::is_cancelled()) { - PostMessageW(_this->hClipWnd, WM_USER, 0, 0); + // Post message if there was no idle loop for a long time + timestamp_t ts = system::get_time_millis(); + if (ts >= (self->nLastIdleCall + self->idle_interval())) + PostMessageW(self->hClipWnd, WM_USER, 0, 0); + ipc::Thread::sleep(20); } @@ -300,12 +309,20 @@ namespace lsp // Obtain the "this" pointer WinWindow *wnd = reinterpret_cast(GetWindowLongPtrW(hwnd, GWLP_USERDATA)); -// lsp_trace("Received event: this=%p, hwnd=%p, uMsg=%d(0x%x), wParam=%d(0x%x), lParam=%p", -// _this, hwnd, int(uMsg), int(uMsg), int(wParam), int(wParam), lParam); if (wnd == NULL) return DefWindowProcW(hwnd, uMsg, wParam, lParam); - timestamp_t ts = GetMessageTime(); + // Do the idle stuff if required + WinDisplay *self = wnd->pWinDisplay; + if (self != NULL) + { + timestamp_t ts = system::get_time_millis(); + if (ts >= (self->nLastIdleCall + self->idle_interval())) + { + self->process_pending_tasks(ts); + self->nLastIdleCall = ts; + } + } // // Debug // switch (uMsg) @@ -335,7 +352,7 @@ namespace lsp // Do not deliver several events to the window handler if it is grabbing events at this moment via hook if (is_hookable_event(uMsg)) { - if (wnd->pWinDisplay->has_grabbing_events()) + if (self->has_grabbing_events()) { if (!wnd->is_grabbing_events()) return 0; @@ -343,7 +360,8 @@ namespace lsp } // Deliver event to the window - return wnd->process_event(uMsg, wParam, lParam, ts, false); + timestamp_t msg_time = GetMessageTime(); + return wnd->process_event(uMsg, wParam, lParam, msg_time, false); } status_t WinDisplay::main() @@ -352,7 +370,7 @@ namespace lsp { // Get current time timestamp_t xts = system::get_time_millis(); - int wtime = compute_poll_delay(xts, 50); // How many milliseconds to wait + int wtime = compute_poll_delay(xts, idle_interval()); // How many milliseconds to wait // Poll for the new message if (wtime > 0) @@ -405,16 +423,11 @@ namespace lsp // At this moment, we don't have any pending messages for processing sPendingMessage.message = WM_NULL; - // Do main iteration - status_t result = IDisplay::main_iteration(); - if (result == STATUS_OK) - result = process_pending_tasks(ts); - - // Call for main task - call_main_task(ts); + // Process all pending tasks + status_t res = process_pending_tasks(ts); + nLastIdleCall = ts; - // Return number of processed events - return result; + return res; } status_t WinDisplay::main_iteration() @@ -438,7 +451,7 @@ namespace lsp MSG message; timestamp_t xts = system::get_time_millis(); - int wtime = compute_poll_delay(xts, 50); // How many milliseconds to wait + int wtime = compute_poll_delay(xts, idle_interval()); // How many milliseconds to wait // Poll for the new message if (wtime <= 0) @@ -472,12 +485,12 @@ namespace lsp IWindow *WinDisplay::create_window(void *handle) { - return new WinWindow(this, reinterpret_cast(handle), NULL, true); + return new WinWindow(this, reinterpret_cast(handle), NULL, false); } IWindow *WinDisplay::wrap_window(void *handle) { - return new WinWindow(this, reinterpret_cast(handle), NULL, false); + return new WinWindow(this, reinterpret_cast(handle), NULL, true); } ISurface *WinDisplay::create_surface(size_t width, size_t height) @@ -1756,18 +1769,33 @@ namespace lsp LRESULT CALLBACK WinDisplay::clipboard_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - WinDisplay *dpy = reinterpret_cast(GetWindowLongPtrW(hwnd, GWLP_USERDATA)); + WinDisplay *dpy; + + // Handle WM_CREATE in a bit another way + if (uMsg == WM_CREATE) + { + CREATESTRUCTW *create = reinterpret_cast(lParam); + dpy = reinterpret_cast(create->lpCreateParams); + SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast(dpy)); + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + // Check that display is present + dpy = reinterpret_cast(GetWindowLongPtrW(hwnd, GWLP_USERDATA)); + if (dpy == NULL) + return DefWindowProc(hwnd, uMsg, wParam, lParam); + + // Do the idle stuff if required + timestamp_t ts = system::get_time_millis(); + if (ts >= (dpy->nLastIdleCall + dpy->idle_interval())) + { + dpy->process_pending_tasks(ts); + dpy->nLastIdleCall = ts; + } + + // Process the message switch (uMsg) { - case WM_CREATE: - { - CREATESTRUCTW *create = reinterpret_cast(lParam); - dpy = reinterpret_cast(create->lpCreateParams); - if (dpy != NULL) - SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast(dpy)); - break; - } case WM_RENDERFORMAT: { // wParam - The clipboard format to be rendered. diff --git a/src/main/win/WinWindow.cpp b/src/main/win/WinWindow.cpp index 45711bc..0d15088 100644 --- a/src/main/win/WinWindow.cpp +++ b/src/main/win/WinWindow.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 1 июл. 2022 г. @@ -57,13 +57,15 @@ namespace lsp hWindow = INVALID_HWND; hParent = wnd; } + hTransientFor = NULL; pSurface = NULL; pDNDTarget = NULL; pOldUserData = reinterpret_cast(reinterpret_cast(NULL)); - pOldProc = reinterpret_cast(NULL); + pOldProc = static_cast(NULL); bWrapper = wrapper; bMouseInside = false; bGrabbing = false; + bTransientOn = false; nMouseCapture = 0; sSize.nLeft = 0; @@ -115,18 +117,18 @@ namespace lsp { // Create new window hWindow = CreateWindowExW( - 0, // dwExStyle - WinDisplay::WINDOW_CLASS_NAME, // lpClassName - L"", // lpWindowName - WS_OVERLAPPEDWINDOW, // dwStyle - sSize.nLeft, // X - sSize.nTop, // Y - sSize.nWidth, // nWidth - sSize.nHeight, // nHeight - hParent, // hWndParent - NULL, // hMenu - GetModuleHandleW(NULL), // hInstance - this // lpCreateParam + 0, // dwExStyle + pWinDisplay->sWindowClassName.get_utf16(), // lpClassName + L"", // lpWindowName + (hParent != NULL) ? WS_CHILD : WS_OVERLAPPEDWINDOW, // dwStyle + sSize.nLeft, // X + sSize.nTop, // Y + sSize.nWidth, // nWidth + sSize.nHeight, // nHeight + hParent, // hWndParent + NULL, // hMenu + GetModuleHandleW(NULL), // hInstance + this // lpCreateParam ); if (hWindow == NULL) @@ -134,6 +136,7 @@ namespace lsp lsp_error("Error creating window: %ld", long(GetLastError())); return STATUS_UNKNOWN_ERR; } + lsp_trace("Created window hWND=%p", hWindow); commit_border_style(enBorderStyle, nActions); } @@ -143,6 +146,8 @@ namespace lsp pOldProc = reinterpret_cast( SetWindowLongPtrW(hWindow, GWLP_WNDPROC, reinterpret_cast(WinDisplay::window_proc))); pOldUserData = SetWindowLongPtrW(hWindow, GWLP_USERDATA, reinterpret_cast(this)); + + lsp_trace("pOldProc = %p, pOldUserData = 0x%lx", pOldProc, pOldUserData); } // Create Surface @@ -602,6 +607,34 @@ namespace lsp return 0; } + case WM_WINDOWPOSCHANGING: + { + if ((hTransientFor == NULL) || (hTransientFor == HWND_TOP)) + break; + + HWND hPrev = GetTopWindow(GetDesktopWindow()); + while (hPrev != NULL) + { + HWND hCurr = GetWindow(hPrev, GW_HWNDNEXT); + + // We are already at the top? + if (hCurr == hWindow) + break; + if (hCurr == hTransientFor) + { + WINDOWPOS *p = reinterpret_cast(lParam); + p->hwndInsertAfter = hPrev; + p->flags &= ~SWP_NOZORDER; + break; + } + + // Update pointer + hPrev = hCurr; + } + + break; + } + // case WM_CHAR: // lsp_trace("WM_CHAR code=0x%x", wParam); // return 0; @@ -621,8 +654,11 @@ namespace lsp return DefWindowProcW(hWindow, uMsg, wParam, lParam); // If message has not been processed, update context and call previous wrappers + lsp_trace("pOldProc = %p, pOldUserData=0x%lx", pOldProc, pOldUserData); + SetWindowLongPtrW(hWindow, GWLP_USERDATA, pOldUserData); SetWindowLongPtrW(hWindow, GWLP_WNDPROC, reinterpret_cast(pOldProc)); + LRESULT res = (pOldProc != NULL) ? pOldProc(hWindow, uMsg, wParam, lParam) : DefWindowProcW(hWindow, uMsg, wParam, lParam); @@ -834,6 +870,8 @@ namespace lsp status_t WinWindow::hide() { + lsp_trace("Hide window this=%p", this); + if (hWindow == NULL) return STATUS_BAD_STATE; @@ -843,27 +881,39 @@ namespace lsp bGrabbing = false; } + if ((hTransientFor != HWND_TOP) && (hTransientFor != NULL)) + { + EnableWindow(hTransientFor, bTransientOn); + hTransientFor = NULL; + } ShowWindow(hWindow, SW_HIDE); return STATUS_OK; } status_t WinWindow::show() { + lsp_trace("Show window this=%p, hWindow=%p", this, hWindow); if (hWindow == NULL) return STATUS_BAD_STATE; + hTransientFor = NULL; ShowWindow(hWindow, SW_SHOW); return STATUS_OK; } status_t WinWindow::show(IWindow *over) { + lsp_trace("Show window this=%p, hWindow=%p over=%p", this, hWindow, over); + if (hWindow == NULL) return STATUS_BAD_STATE; - HWND hTransientFor = HWND_TOP; + hTransientFor = HWND_TOP; if (over != NULL) - hTransientFor = reinterpret_cast(over->handle()); + { + hTransientFor = reinterpret_cast(over->handle()); + bTransientOn = !EnableWindow(hTransientFor, FALSE); + } SetWindowPos( hWindow, // hWnd @@ -1085,49 +1135,59 @@ namespace lsp status_t WinWindow::commit_border_style(border_style_t bs, size_t wa) { - border_style_t xbs = (has_parent()) ? BS_NONE : bs; - size_t style = 0; - size_t ex_style = 0; + size_t style = 0; + size_t ex_style = 0; + HMENU sysmenu = NULL; - switch (xbs) + if (has_parent()) { - case BS_DIALOG: - style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU; - ex_style = WS_EX_ACCEPTFILES; - break; - case BS_SINGLE: - style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU; - if (wa & WA_MINIMIZE) - style |= WS_MINIMIZEBOX; - if (wa & WA_MAXIMIZE) - style |= WS_MAXIMIZEBOX; - ex_style = WS_EX_ACCEPTFILES; - break; - case BS_SIZEABLE: - style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU; - if (wa & WA_MINIMIZE) - style |= WS_MINIMIZEBOX; - if (wa & WA_MAXIMIZE) - style |= WS_MAXIMIZEBOX; - ex_style = WS_EX_ACCEPTFILES; - break; - case BS_POPUP: - case BS_COMBO: - case BS_DROPDOWN: - style = WS_POPUP; - ex_style = WS_EX_TOPMOST | WS_EX_TOOLWINDOW; - break; - case BS_NONE: - default: - style = WS_OVERLAPPED; - ex_style = WS_EX_ACCEPTFILES; - break; + style = WS_CHILD; + ex_style = WS_EX_ACCEPTFILES; + sysmenu = NULL; + } + else + { + sysmenu = GetSystemMenu(hWindow, FALSE); + + switch (bs) + { + case BS_DIALOG: + style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU; + ex_style = WS_EX_ACCEPTFILES; + break; + case BS_SINGLE: + style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU; + if (wa & WA_MINIMIZE) + style |= WS_MINIMIZEBOX; + if (wa & WA_MAXIMIZE) + style |= WS_MAXIMIZEBOX; + ex_style = WS_EX_ACCEPTFILES; + break; + case BS_SIZEABLE: + style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU; + if (wa & WA_MINIMIZE) + style |= WS_MINIMIZEBOX; + if (wa & WA_MAXIMIZE) + style |= WS_MAXIMIZEBOX; + ex_style = WS_EX_ACCEPTFILES; + break; + case BS_POPUP: + case BS_COMBO: + case BS_DROPDOWN: + style = WS_POPUP; + ex_style = WS_EX_TOPMOST | WS_EX_TOOLWINDOW; + break; + case BS_NONE: + default: + style = WS_OVERLAPPED; + ex_style = WS_EX_ACCEPTFILES; + break; + } } SetWindowLongW(hWindow, GWL_STYLE, LONG(style)); SetWindowLongW(hWindow, GWL_EXSTYLE, LONG(ex_style)); - HMENU sysmenu = (hParent == NULL) ? GetSystemMenu(hWindow, FALSE) : NULL; if (sysmenu != NULL) { #define COMMIT(id, flag) \ @@ -1304,6 +1364,7 @@ namespace lsp { if (hWindow == NULL) return false; + HWND wnd = GetParent(hWindow); return wnd != NULL; diff --git a/src/main/x11/X11Display.cpp b/src/main/x11/X11Display.cpp index 8b1557d..84305af 100644 --- a/src/main/x11/X11Display.cpp +++ b/src/main/x11/X11Display.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2023 Linux Studio Plugins Project + * (C) 2023 Vladimir Sadovnikov * * This file is part of lsp-ws-lib * Created on: 10 окт. 2016 г. @@ -483,7 +483,7 @@ namespace lsp timestamp_t xts = (timestamp_t(ts.seconds) * 1000) + (ts.nanos / 1000000); // Compute how many milliseconds to wait for the event - int wtime = (::XPending(pDisplay) > 0) ? 0 : compute_poll_delay(xts, 50); + int wtime = (::XPending(pDisplay) > 0) ? 0 : compute_poll_delay(xts, idle_interval()); // Try to poll input data for a specified period x11_poll.fd = x11_fd; @@ -576,21 +576,13 @@ namespace lsp handle_event(&event); } - // Call parent class for iteration - status_t result = IDisplay::main_iteration(); - if (result != STATUS_OK) - return result; - // Process pending tasks - result = process_pending_tasks(ts); + status_t result = process_pending_tasks(ts); // Flush & sync display ::XFlush(pDisplay); // XSync(pDisplay, False); - // Call for main task - call_main_task(ts); - // Perform garbage collection for the font manager #ifdef USE_LIBFREETYPE sFontManager.gc(); diff --git a/src/main/x11/X11Window.cpp b/src/main/x11/X11Window.cpp index 23d62ba..7603a31 100644 --- a/src/main/x11/X11Window.cpp +++ b/src/main/x11/X11Window.cpp @@ -691,6 +691,7 @@ namespace lsp case BS_COMBO: case BS_DROPDOWN: atoms[n_items++] = a.X11__NET_WM_STATE_ABOVE; + atoms[n_items++] = a.X11__NET_WM_STATE_SKIP_TASKBAR; break; case BS_SINGLE: // Not resizable; minimize/maximize menu diff --git a/src/test/mtest/display/async_tasks.cpp b/src/test/mtest/display/async_tasks.cpp index 2d84e1a..48117a6 100644 --- a/src/test/mtest/display/async_tasks.cpp +++ b/src/test/mtest/display/async_tasks.cpp @@ -73,11 +73,11 @@ MTEST_BEGIN("ws.display", async_tasks) float *x = new float[NUM_POINTS+1]; if (!x) return STATUS_NO_MEM; - lsp_finally { delete x; }; + lsp_finally { delete[] x; }; float *y = new float[NUM_POINTS+1]; if (!y) return STATUS_NO_MEM; - lsp_finally { delete y; }; + lsp_finally { delete[] y; }; // Draw lissajous figure for (size_t i=0; i <= NUM_POINTS; ++i)