From 34ba90376b48fad91d194e2fc73a940e918696bc Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Mon, 12 Dec 2022 17:46:44 +0800 Subject: [PATCH] linux: remove the build-time dependency of libxcb and libgtk We can load them dynamically at run-time. Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- README.md | 2 - .../Core/FramelessHelper_Linux | 1 + .../Core/framelesshelper_linux.h | 350 ++++++++++++++++++ .../Core/private/sysapiloader_p.h | 26 +- qmake/core.pri | 9 +- src/core/CMakeLists.txt | 28 +- src/core/framelesshelpercore_global.cpp | 6 +- src/core/platformsupport_linux.cpp | 282 ++++++++++++++ src/core/utils_linux.cpp | 65 +--- 9 files changed, 675 insertions(+), 94 deletions(-) create mode 100644 include/FramelessHelper/Core/FramelessHelper_Linux create mode 100644 include/FramelessHelper/Core/framelesshelper_linux.h create mode 100644 src/core/platformsupport_linux.cpp diff --git a/README.md b/README.md index 1dd106c..d05b0cf 100644 --- a/README.md +++ b/README.md @@ -127,8 +127,6 @@ cmake --build . --config Release --target all --parallel cmake --install . --config Release --strip ``` -**IMPORTANT NOTE**: On Linux you need to install the _GTK3_ and _X11_ development packages first. - Once the compilation and installation is done, you will be able to use the `find_package(FramelessHelper REQUIRED COMPONENTS Core Widgets Quick)` command to find and link to the FramelessHelper library. But before doing that, please make sure CMake knows where to find FramelessHelper, by passing the `CMAKE_PREFIX_PATH` variable to it. For example: `-DCMAKE_PREFIX_PATH=C:/my-cmake-packages;C:/my-toolchain;etc...`. Build FramelessHelper as a sub-directory of your CMake project is of course also supported. The supported FramelessHelper target names are `FramelessHelper::FramelessHelperCore`, `FramelessHelper::FramelessHelperWidgets` and `FramelessHelper::FramelessHelperQuick`. ## Use diff --git a/include/FramelessHelper/Core/FramelessHelper_Linux b/include/FramelessHelper/Core/FramelessHelper_Linux new file mode 100644 index 0000000..de95d4e --- /dev/null +++ b/include/FramelessHelper/Core/FramelessHelper_Linux @@ -0,0 +1 @@ +#include diff --git a/include/FramelessHelper/Core/framelesshelper_linux.h b/include/FramelessHelper/Core/framelesshelper_linux.h new file mode 100644 index 0000000..720d2a5 --- /dev/null +++ b/include/FramelessHelper/Core/framelesshelper_linux.h @@ -0,0 +1,350 @@ +/* + * 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. + */ + +#pragma once + +#include + +/* + * Copyright (C) 2001-2006 Bart Massey, Jamey Sharp, and Josh Triplett. + * All Rights Reserved. + * + * 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 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. + * + * Except as contained in this notice, the names of the authors or their + * institutions shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization from the authors. + */ + +using Display = struct _XDisplay; +using xcb_connection_t = struct xcb_connection_t; + +using xcb_button_t = uint8_t; +using xcb_window_t = uint32_t; +using xcb_timestamp_t = uint32_t; +using xcb_atom_t = uint32_t; + +using xcb_generic_error_t = struct xcb_generic_error_t +{ + uint8_t response_type; + uint8_t error_code; + uint16_t sequence; + uint32_t resource_id; + uint16_t minor_code; + uint8_t major_code; + uint8_t pad0; + uint32_t pad[5]; + uint32_t full_sequence; +}; + +using xcb_client_message_data_t = union xcb_client_message_data_t +{ + uint8_t data8[20]; + uint16_t data16[10]; + uint32_t data32[5]; +}; + +using xcb_button_press_event_t = struct xcb_button_press_event_t +{ + uint8_t response_type; + xcb_button_t detail; + uint16_t sequence; + xcb_timestamp_t time; + xcb_window_t root; + xcb_window_t event; + xcb_window_t child; + int16_t root_x; + int16_t root_y; + int16_t event_x; + int16_t event_y; + uint16_t state; + uint8_t same_screen; + uint8_t pad0; +}; +using xcb_button_release_event_t = xcb_button_press_event_t; + +using xcb_void_cookie_t = struct xcb_void_cookie_t +{ + unsigned int sequence; +}; + +using xcb_intern_atom_cookie_t = struct xcb_intern_atom_cookie_t +{ + unsigned int sequence; +}; + +using xcb_intern_atom_reply_t = struct xcb_intern_atom_reply_t +{ + uint8_t response_type; + uint8_t pad0; + uint16_t sequence; + uint32_t length; + xcb_atom_t atom; +}; + +using xcb_client_message_event_t = struct xcb_client_message_event_t +{ + uint8_t response_type; + uint8_t format; + uint16_t sequence; + xcb_window_t window; + xcb_atom_t type; + xcb_client_message_data_t data; +}; + +[[maybe_unused]] inline constexpr const auto XCB_BUTTON_RELEASE = 5; +[[maybe_unused]] inline constexpr const auto XCB_CLIENT_MESSAGE = 33; +[[maybe_unused]] inline constexpr const auto XCB_BUTTON_INDEX_1 = 1; +[[maybe_unused]] inline constexpr const auto XCB_EVENT_MASK_STRUCTURE_NOTIFY = 131072; +[[maybe_unused]] inline constexpr const auto XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT = 1048576; +[[maybe_unused]] inline constexpr const auto XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY = 524288; + +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_TOP = 1; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_RIGHT = 3; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_BOTTOM = 5; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_LEFT = 7; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_MOVE = 8; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_SIZE_KEYBOARD = 9; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_MOVE_KEYBOARD = 10; +[[maybe_unused]] inline constexpr const auto _NET_WM_MOVERESIZE_CANCEL = 11; + +[[maybe_unused]] inline constexpr const char _NET_WM_MOVERESIZE_ATOM_NAME[] = "_NET_WM_MOVERESIZE"; + +extern "C" +{ + +FRAMELESSHELPER_CORE_API xcb_void_cookie_t +xcb_send_event( + xcb_connection_t *connection, + uint8_t propagate, + xcb_window_t destination, + uint32_t event_mask, + const char *event +); + +FRAMELESSHELPER_CORE_API int +xcb_flush( + xcb_connection_t *connection +); + +FRAMELESSHELPER_CORE_API xcb_intern_atom_cookie_t +xcb_intern_atom( + xcb_connection_t *connection, + uint8_t only_if_exists, + uint16_t name_len, + const char *name +); + +FRAMELESSHELPER_CORE_API xcb_intern_atom_reply_t * +xcb_intern_atom_reply( + xcb_connection_t *connection, + xcb_intern_atom_cookie_t cookie, + xcb_generic_error_t **error +); + +FRAMELESSHELPER_CORE_API xcb_void_cookie_t +xcb_ungrab_pointer( + xcb_connection_t *connection, + xcb_timestamp_t time +); + +} // extern "C" + + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#define G_VALUE_INIT { 0, { { 0 } } } +#define g_signal_connect(instance, detailed_signal, c_handler, data) \ + g_signal_connect_data((instance), (detailed_signal), (c_handler), (data), nullptr, G_CONNECT_DEFAULT) + +using gint = int; +using glong = long; +using gshort = short; +using gboolean = int; +using gushort = unsigned short; +using guint = unsigned int; +using gulong = unsigned long; +using gfloat = float; +using gdouble = double; +using gchar = char; +using guchar = unsigned char; +using gchararray = char *; +using gpointer = void *; +using gint64 = int64_t; +using guint64 = uint64_t; +using gsize = unsigned long; + +using GType = gsize; +using GValue = struct _GValue; +using GObject = struct _GObject; +using GClosure = struct _GClosure; +using GtkSettings = struct _GtkSettings; + +using GConnectFlags = enum GConnectFlags +{ + G_CONNECT_DEFAULT = 0, + G_CONNECT_AFTER = 1 << 0, + G_CONNECT_SWAPPED = 1 << 1 +}; + +using GCallback = void(*)(void); +using GClosureNotify = void(*)(gpointer data, GClosure *closure); + +struct _GValue +{ + GType g_type; + + union + { + gint v_int; + guint v_uint; + glong v_long; + gulong v_ulong; + gint64 v_int64; + guint64 v_uint64; + gfloat v_float; + gdouble v_double; + gpointer v_pointer; + } data[2]; +}; + +[[maybe_unused]] inline constexpr const char GTK_THEME_NAME_ENV_VAR[] = "GTK_THEME"; +[[maybe_unused]] inline constexpr const char GTK_THEME_NAME_PROP[] = "gtk-theme-name"; +[[maybe_unused]] inline constexpr const char GTK_THEME_PREFER_DARK_PROP[] = "gtk-application-prefer-dark-theme"; + +extern "C" +{ + +FRAMELESSHELPER_CORE_API void +gtk_init( + int *argc, + char ***argv +); + +FRAMELESSHELPER_CORE_API GValue * +g_value_init( + GValue *value, + GType g_type +); + +FRAMELESSHELPER_CORE_API GValue * +g_value_reset( + GValue *value +); + +FRAMELESSHELPER_CORE_API void +g_value_unset( + GValue *value +); + +FRAMELESSHELPER_CORE_API gboolean +g_value_get_boolean( + const GValue *value +); + +FRAMELESSHELPER_CORE_API const gchar * +g_value_get_string( + const GValue *value +); + +FRAMELESSHELPER_CORE_API GtkSettings * +gtk_settings_get_default( + void +); + +FRAMELESSHELPER_CORE_API void +g_object_get_property( + GObject *object, + const gchar *property_name, + GValue *value +); + +FRAMELESSHELPER_CORE_API gulong +g_signal_connect_data( + gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags +); + +FRAMELESSHELPER_CORE_API void +g_free( + gpointer mem +); + +FRAMELESSHELPER_CORE_API void +g_object_unref( + GObject *object +); + +FRAMELESSHELPER_CORE_API void +g_clear_object( + GObject **object_ptr +); + +} // extern "C" diff --git a/include/FramelessHelper/Core/private/sysapiloader_p.h b/include/FramelessHelper/Core/private/sysapiloader_p.h index 9b8ac0e..90112a7 100644 --- a/include/FramelessHelper/Core/private/sysapiloader_p.h +++ b/include/FramelessHelper/Core/private/sysapiloader_p.h @@ -58,17 +58,8 @@ FRAMELESSHELPER_END_NAMESPACE Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(SysApiLoader)) -#ifdef Q_OS_WINDOWS -# define API_WIN_AVAILABLE(lib, func) \ +#define API_AVAILABLE(lib, func) \ (FRAMELESSHELPER_PREPEND_NAMESPACE(SysApiLoader)::instance()->isAvailable(k##lib, k##func)) -# define API_USER_AVAILABLE(func) API_WIN_AVAILABLE(user32, func) -# define API_THEME_AVAILABLE(func) API_WIN_AVAILABLE(uxtheme, func) -# define API_DWM_AVAILABLE(func) API_WIN_AVAILABLE(dwmapi, func) -# define API_SHCORE_AVAILABLE(func) API_WIN_AVAILABLE(shcore, func) -# define API_WINMM_AVAILABLE(func) API_WIN_AVAILABLE(winmm, func) -# define API_D2D_AVAILABLE(func) API_WIN_AVAILABLE(d2d1, func) -# define API_NT_AVAILABLE(func) API_WIN_AVAILABLE(ntdll, func) -#endif #define API_CALL_FUNCTION(func, ...) \ ((FRAMELESSHELPER_PREPEND_NAMESPACE(SysApiLoader)::instance()->get(k##func))(__VA_ARGS__)) @@ -82,3 +73,18 @@ Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(SysApiLoader)) #define API_CALL_FUNCTION4(func, ...) API_CALL_FUNCTION3(_##func, func, __VA_ARGS__) #define API_CALL_FUNCTION5(func, ...) API_CALL_FUNCTION3(func##2, func, __VA_ARGS__) + +#ifdef Q_OS_WINDOWS +# define API_USER_AVAILABLE(func) API_AVAILABLE(user32, func) +# define API_THEME_AVAILABLE(func) API_AVAILABLE(uxtheme, func) +# define API_DWM_AVAILABLE(func) API_AVAILABLE(dwmapi, func) +# define API_SHCORE_AVAILABLE(func) API_AVAILABLE(shcore, func) +# define API_WINMM_AVAILABLE(func) API_AVAILABLE(winmm, func) +# define API_D2D_AVAILABLE(func) API_AVAILABLE(d2d1, func) +# define API_NT_AVAILABLE(func) API_AVAILABLE(ntdll, func) +#endif // Q_OS_WINDOWS + +#ifdef Q_OS_LINUX +# define API_XCB_AVAILABLE(func) API_AVAILABLE(libxcb, func) +# define API_GTK_AVAILABLE(func) API_AVAILABLE(libgtk, func) +#endif // Q_OS_LINUX diff --git a/qmake/core.pri b/qmake/core.pri index 91b3b53..54cf9c6 100644 --- a/qmake/core.pri +++ b/qmake/core.pri @@ -64,10 +64,11 @@ win32 { } unix:!macx { - CONFIG += link_pkgconfig - PKGCONFIG += gtk+-3.0 xcb - DEFINES += GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6 - SOURCES += $$CORE_SRC_DIR/utils_linux.cpp + HEADERS += \ + $$CORE_PUB_INC_DIR/framelesshelper_linux.h + SOURCES += \ + $$CORE_SRC_DIR/utils_linux.cpp \ + $$CORE_SRC_DIR/platformsupport_linux.cpp } macx { diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 675209e..938a82a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -22,12 +22,6 @@ SOFTWARE. ]] -if(UNIX AND NOT APPLE) - find_package(PkgConfig REQUIRED) - find_package(X11 REQUIRED) - pkg_search_module(GTK3 REQUIRED gtk+-3.0) -endif() - set(SUB_MOD_NAME Core) set(SUB_PROJ_NAME ${PROJECT_NAME}${SUB_MOD_NAME}) set(SUB_PROJ_PATH ${PROJECT_NAME}/${SUB_MOD_NAME}) @@ -102,7 +96,16 @@ if(WIN32) elseif(APPLE) list(APPEND SOURCES utils_mac.mm) elseif(UNIX) - list(APPEND SOURCES utils_linux.cpp) + list(APPEND PUBLIC_HEADERS + ${INCLUDE_PREFIX}/framelesshelper_linux.h + ) + list(APPEND PUBLIC_HEADERS_ALIAS + ${INCLUDE_PREFIX}/FramelessHelper_Linux + ) + list(APPEND SOURCES + utils_linux.cpp + platformsupport_linux.cpp + ) endif() if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC) @@ -175,17 +178,6 @@ if(APPLE) "-framework Cocoa" "-framework AppKit" ) -elseif(UNIX) - target_compile_definitions(${SUB_PROJ_NAME} PRIVATE - GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6 - ) - target_link_libraries(${SUB_PROJ_NAME} PRIVATE - ${GTK3_LIBRARIES} - X11::xcb - ) - target_include_directories(${SUB_PROJ_NAME} PRIVATE - ${GTK3_INCLUDE_DIRS} - ) endif() if(FRAMELESSHELPER_NO_PRIVATE) diff --git a/src/core/framelesshelpercore_global.cpp b/src/core/framelesshelpercore_global.cpp index cbea4d8..c2744b2 100644 --- a/src/core/framelesshelpercore_global.cpp +++ b/src/core/framelesshelpercore_global.cpp @@ -25,9 +25,6 @@ #include "framelesshelpercore_global.h" #include "utils.h" #include "framelessmanager.h" -#ifdef Q_OS_WINDOWS -# include "framelesshelper_win.h" -#endif #include "framelesshelper_qt.h" #include "chromepalette.h" #include "micamaterial.h" @@ -39,10 +36,11 @@ #include "micamaterial_p.h" #include "windowborderpainter_p.h" #ifdef Q_OS_WINDOWS +# include "framelesshelper_win.h" # include "registrykey_p.h" #endif #ifdef Q_OS_LINUX -# include +# include "framelesshelper_linux.h" #endif #include #include diff --git a/src/core/platformsupport_linux.cpp b/src/core/platformsupport_linux.cpp new file mode 100644 index 0000000..0dc65d9 --- /dev/null +++ b/src/core/platformsupport_linux.cpp @@ -0,0 +1,282 @@ +/* + * 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. + */ + +#include "sysapiloader_p.h" +#include "framelesshelper_linux.h" + +#define GTK_SETTINGS(Name, Type, ...) \ + Type Name(const gchar *property) \ + { \ + Q_ASSERT(property); \ + if (!property) { \ + return {}; \ + } \ + GtkSettings *settings = gtk_settings_get_default(); \ + Q_ASSERT(settings); \ + if (!settings) { \ + return {}; \ + } \ + GValue value = G_VALUE_INIT; \ + g_object_get_property(reinterpret_cast(settings), property, &value); \ + __VA_ARGS__ \ + g_value_unset(&value); \ + return result; \ + } + +FRAMELESSHELPER_STRING_CONSTANT(libxcb) +FRAMELESSHELPER_STRING_CONSTANT2(libgtk, "libgtk-3") + +FRAMELESSHELPER_STRING_CONSTANT(xcb_send_event) +FRAMELESSHELPER_STRING_CONSTANT(xcb_flush) +FRAMELESSHELPER_STRING_CONSTANT(xcb_intern_atom) +FRAMELESSHELPER_STRING_CONSTANT(xcb_intern_atom_reply) +FRAMELESSHELPER_STRING_CONSTANT(xcb_ungrab_pointer) + +FRAMELESSHELPER_STRING_CONSTANT(gtk_init) +FRAMELESSHELPER_STRING_CONSTANT(g_value_init) +FRAMELESSHELPER_STRING_CONSTANT(g_value_reset) +FRAMELESSHELPER_STRING_CONSTANT(g_value_unset) +FRAMELESSHELPER_STRING_CONSTANT(g_value_get_boolean) +FRAMELESSHELPER_STRING_CONSTANT(g_value_get_string) +FRAMELESSHELPER_STRING_CONSTANT(gtk_settings_get_default) +FRAMELESSHELPER_STRING_CONSTANT(g_object_get_property) +FRAMELESSHELPER_STRING_CONSTANT(g_signal_connect_data) +FRAMELESSHELPER_STRING_CONSTANT(g_free) +FRAMELESSHELPER_STRING_CONSTANT(g_object_unref) +FRAMELESSHELPER_STRING_CONSTANT(g_clear_object) + +////////////////////////////////////////////// +// XCB + +extern "C" xcb_void_cookie_t +xcb_send_event( + xcb_connection_t *connection, + uint8_t propagate, + xcb_window_t destination, + uint32_t event_mask, + const char *event +) +{ + if (!API_XCB_AVAILABLE(xcb_send_event)) { + return {}; + } + return API_CALL_FUNCTION(xcb_send_event, connection, propagate, destination, event_mask, event); +} + +extern "C" int +xcb_flush( + xcb_connection_t *connection +) +{ + if (!API_XCB_AVAILABLE(xcb_flush)) { + return 0; + } + return API_CALL_FUNCTION(xcb_flush, connection); +} + +extern "C" xcb_intern_atom_cookie_t +xcb_intern_atom( + xcb_connection_t *connection, + uint8_t only_if_exists, + uint16_t name_len, + const char *name +) +{ + if (!API_XCB_AVAILABLE(xcb_intern_atom)) { + return {}; + } + return API_CALL_FUNCTION(xcb_intern_atom, connection, only_if_exists, name_len, name); +} + +extern "C" xcb_intern_atom_reply_t * +xcb_intern_atom_reply( + xcb_connection_t *connection, + xcb_intern_atom_cookie_t cookie, + xcb_generic_error_t **error +) +{ + if (!API_XCB_AVAILABLE(xcb_intern_atom_reply)) { + return nullptr; + } + return API_CALL_FUNCTION(xcb_intern_atom_reply, connection, cookie, error); +} + +extern "C" xcb_void_cookie_t +xcb_ungrab_pointer( + xcb_connection_t *connection, + xcb_timestamp_t time +) +{ + if (!API_XCB_AVAILABLE(xcb_ungrab_pointer)) { + return {}; + } + return API_CALL_FUNCTION(xcb_ungrab_pointer, connection, time); +} + +/////////////////////////////////////////////////// +// GTK + +extern "C" void +gtk_init( + int *argc, + char ***argv +) +{ + if (!API_GTK_AVAILABLE(gtk_init)) { + return; + } + API_CALL_FUNCTION(gtk_init, argc, argv); +} + +extern "C" GValue * +g_value_init( + GValue *value, + GType g_type +) +{ + if (!API_GTK_AVAILABLE(g_value_init)) { + return nullptr; + } + return API_CALL_FUNCTION(g_value_init, value, g_type); +} + +extern "C" GValue * +g_value_reset( + GValue *value +) +{ + if (!API_GTK_AVAILABLE(g_value_reset)) { + return nullptr; + } + return API_CALL_FUNCTION(g_value_reset, value); +} + +extern "C" void +g_value_unset( + GValue *value +) +{ + if (!API_GTK_AVAILABLE(g_value_unset)) { + return; + } + API_CALL_FUNCTION(g_value_unset, value); +} + +extern "C" gboolean +g_value_get_boolean( + const GValue *value +) +{ + if (!API_GTK_AVAILABLE(g_value_get_boolean)) { + return false; + } + return API_CALL_FUNCTION(g_value_get_boolean, value); +} + +extern "C" const gchar * +g_value_get_string( + const GValue *value +) +{ + if (!API_GTK_AVAILABLE(g_value_get_string)) { + return nullptr; + } + return API_CALL_FUNCTION(g_value_get_string, value); +} + +extern "C" GtkSettings * +gtk_settings_get_default( + void +) +{ + if (!API_GTK_AVAILABLE(gtk_settings_get_default)) { + return nullptr; + } + return API_CALL_FUNCTION(gtk_settings_get_default); +} + +extern "C" void +g_object_get_property( + GObject *object, + const gchar *property_name, + GValue *value +) +{ + if (!API_GTK_AVAILABLE(g_object_get_property)) { + return; + } + API_CALL_FUNCTION(g_object_get_property, object, property_name, value); +} + +extern "C" gulong +g_signal_connect_data( + gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags +) +{ + if (!API_GTK_AVAILABLE(g_signal_connect_data)) { + return 0; + } + return API_CALL_FUNCTION(g_signal_connect_data, instance, detailed_signal, c_handler, data, destroy_data, connect_flags); +} + +extern "C" void +g_free( + gpointer mem +) +{ + if (!API_GTK_AVAILABLE(g_free)) { + return; + } + API_CALL_FUNCTION(g_free, mem); +} + +extern "C" void +g_object_unref( + GObject *object +) +{ + if (!API_GTK_AVAILABLE(g_object_unref)) { + return; + } + API_CALL_FUNCTION(g_object_unref, object); +} + +extern "C" void +g_clear_object( + GObject **object_ptr +) +{ + if (!API_GTK_AVAILABLE(g_clear_object)) { + return; + } + API_CALL_FUNCTION(g_clear_object, object_ptr); +} + +GTK_SETTINGS(GTK_bool, bool, const bool result = g_value_get_boolean(&value);) +GTK_SETTINGS(GTK_str, QString, const QString result = QUtf8String(g_value_get_string(&value));) diff --git a/src/core/utils_linux.cpp b/src/core/utils_linux.cpp index 1d14f38..0619f85 100644 --- a/src/core/utils_linux.cpp +++ b/src/core/utils_linux.cpp @@ -23,6 +23,7 @@ */ #include "utils.h" +#include "framelesshelper_linux.h" #include "framelessconfig_p.h" #include "framelessmanager.h" #include "framelessmanager_p.h" @@ -39,8 +40,9 @@ # include # endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #endif // FRAMELESSHELPER_CORE_NO_PRIVATE -#include -#include + +extern bool GTK_bool(const gchar *); +extern QString GTK_str(const gchar *); FRAMELESSHELPER_BEGIN_NAMESPACE @@ -60,27 +62,6 @@ Q_LOGGING_CATEGORY(lcUtilsLinux, "wangwenx190.framelesshelper.core.utils.linux") using namespace Global; -using Display = struct _XDisplay; - -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0; -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_SIZE_TOP = 1; -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2; -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_SIZE_RIGHT = 3; -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4; -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_SIZE_BOTTOM = 5; -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6; -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_SIZE_LEFT = 7; -[[maybe_unused]] static constexpr const auto _NET_WM_MOVERESIZE_MOVE = 8; - -[[maybe_unused]] static constexpr const char _NET_WM_MOVERESIZE_ATOM_NAME[] = "_NET_WM_MOVERESIZE"; - -[[maybe_unused]] static constexpr const auto _NET_WM_SENDEVENT_MASK = - (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY); - -[[maybe_unused]] static constexpr const char GTK_THEME_NAME_ENV_VAR[] = "GTK_THEME"; -[[maybe_unused]] static constexpr const char GTK_THEME_NAME_PROP[] = "gtk-theme-name"; -[[maybe_unused]] static constexpr const char GTK_THEME_PREFER_DARK_PROP[] = "gtk-application-prefer-dark-theme"; - FRAMELESSHELPER_STRING_CONSTANT(dark) FRAMELESSHELPER_BYTEARRAY_CONSTANT(rootwindow) @@ -92,35 +73,6 @@ FRAMELESSHELPER_BYTEARRAY_CONSTANT(startupid) FRAMELESSHELPER_BYTEARRAY_CONSTANT(display) FRAMELESSHELPER_BYTEARRAY_CONSTANT(connection) -template -[[nodiscard]] static inline T gtkSetting(const gchar *propertyName) -{ - Q_ASSERT(propertyName); - if (!propertyName) { - return {}; - } - GtkSettings * const settings = gtk_settings_get_default(); - Q_ASSERT(settings); - if (!settings) { - return {}; - } - T result = {}; - g_object_get(settings, propertyName, &result, nullptr); - return result; -} - -[[nodiscard]] static inline QString gtkSetting(const gchar *propertyName) -{ - Q_ASSERT(propertyName); - if (!propertyName) { - return {}; - } - const auto propertyValue = gtkSetting(propertyName); - const QString result = QUtf8String(propertyValue); - g_free(propertyValue); - return result; -} - [[maybe_unused]] [[nodiscard]] static inline int qtEdgesToWmMoveOrResizeOperation(const Qt::Edges edges) { @@ -415,8 +367,9 @@ static inline void // First we need to ungrab the pointer that may have been // automatically grabbed by Qt on ButtonPressEvent. xcb_ungrab_pointer(connection, x11_appTime()); - xcb_send_event(connection, false, rootWindow, _NET_WM_SENDEVENT_MASK, - reinterpret_cast(&xev)); + xcb_send_event(connection, false, rootWindow, + (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY), + reinterpret_cast(&xev)); xcb_flush(connection); } @@ -525,7 +478,7 @@ bool Utils::shouldAppsUseDarkMode_linux() gtk-theme-name provides both light and dark variants. We can save a regex check by testing this property first. */ - const auto preferDark = gtkSetting(GTK_THEME_PREFER_DARK_PROP); + const bool preferDark = GTK_bool(GTK_THEME_PREFER_DARK_PROP); if (preferDark) { return true; } @@ -533,7 +486,7 @@ bool Utils::shouldAppsUseDarkMode_linux() /* https://docs.gtk.org/gtk3/property.Settings.gtk-theme-name.html */ - const QString curThemeName = gtkSetting(GTK_THEME_NAME_PROP); + const QString curThemeName = GTK_str(GTK_THEME_NAME_PROP); if (!curThemeName.isEmpty()) { return curThemeName.contains(kdark, Qt::CaseInsensitive); }