From cf4ed9d9dc6f370260616e1a1c60b15e631f2dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 11 Jun 2024 16:41:57 +0800 Subject: [PATCH] Media (Windows): finalize Windows support --- .github/workflows/ci.yml | 4 +- CMakeLists.txt | 79 ++++++++++++----------- src/detection/media/media_windows.c | 38 +++++++++++ src/detection/media/media_windows.cpp | 65 ------------------- src/detection/media/media_windows.dll.cpp | 53 +++++++++++++++ src/detection/media/media_windows.dll.h | 15 +++++ 6 files changed, 148 insertions(+), 106 deletions(-) create mode 100644 src/detection/media/media_windows.c delete mode 100644 src/detection/media/media_windows.cpp create mode 100644 src/detection/media/media_windows.dll.cpp create mode 100644 src/detection/media/media_windows.dll.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 776f2af0d..f7614a2e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -460,7 +460,7 @@ jobs: with: msystem: CLANG64 update: true - install: git mingw-w64-clang-x86_64-7zip mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-vulkan-headers mingw-w64-clang-x86_64-opencl-icd + install: git mingw-w64-clang-x86_64-7zip mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-vulkan-headers mingw-w64-clang-x86_64-opencl-icd mingw-w64-clang-x86_64-cppwinrt - name: print msys version run: uname -a @@ -522,7 +522,7 @@ jobs: with: msystem: CLANG32 update: true - install: git p7zip mingw-w64-clang-i686-cmake mingw-w64-clang-i686-clang mingw-w64-clang-i686-vulkan-loader mingw-w64-clang-i686-vulkan-headers mingw-w64-clang-i686-opencl-icd + install: git p7zip mingw-w64-clang-i686-cmake mingw-w64-clang-i686-clang mingw-w64-clang-i686-vulkan-loader mingw-w64-clang-i686-vulkan-headers mingw-w64-clang-i686-opencl-icd mingw-w64-clang-i686-cppwinrt - name: print msys version run: uname -a diff --git a/CMakeLists.txt b/CMakeLists.txt index c8560919b..b530f8223 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,14 +115,9 @@ set(WARNING_FLAGS "-Wall -Wextra -Wconversion -Werror=uninitialized -Werror=retu set(CMAKE_C_STANDARD 11) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=incompatible-pointer-types -Werror=implicit-function-declaration -Werror=int-conversion") -if(WIN32) - set(CMAKE_CXX_STANDARD 20) -elseif(ENABLE_DIRECTX_HEADERS) - set(CMAKE_CXX_STANDARD 17) -endif() - if(WIN32 OR ENABLE_DIRECTX_HEADERS) enable_language(CXX) + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS} -fno-exceptions -fno-rtti") endif() @@ -700,7 +695,7 @@ elseif(WIN32) src/detection/locale/locale_windows.c src/detection/localip/localip_windows.c src/detection/gamepad/gamepad_windows.c - src/detection/media/media_windows.cpp + src/detection/media/media_windows.c src/detection/memory/memory_windows.c src/detection/physicalmemory/physicalmemory_linux.c src/detection/monitor/monitor_windows.c @@ -1040,7 +1035,6 @@ elseif(WIN32) PRIVATE "setupapi" PRIVATE "hid" PRIVATE "wtsapi32" - PRIVATE "RuntimeObject" ) elseif(BSD) target_link_libraries(libfastfetch @@ -1073,6 +1067,39 @@ target_link_libraries(libfastfetch PRIVATE ${CMAKE_DL_LIBS} ) +if(WIN32) + set(CMAKE_CXX_STANDARD 20) + include(CheckIncludeFileCXX) + CHECK_INCLUDE_FILE_CXX("winrt/Windows.Media.Control.h" HAVE_WINRT) + if(HAVE_WINRT) + add_library(ffwinrt SHARED src/detection/media/media_windows.dll.cpp) + target_link_libraries(ffwinrt PRIVATE "RuntimeObject") + + include(CheckCXXSymbolExists) + if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(header version) + else() + set(header ciso646) + endif() + + check_cxx_symbol_exists(_LIBCPP_VERSION ${header} LIBCPP) + if(LIBCPP) + target_link_libraries(ffwinrt + PRIVATE "libc++.a" + ) + endif() + + check_cxx_symbol_exists(__GLIBCXX__ ${header} GLIBCXX) + if(GLIBCXX) + target_link_libraries(ffwinrt + PRIVATE "libstdc++.a" + ) + endif() + else() + set(CMAKE_CXX_STANDARD 17) + endif() +endif() + ###################### # Executable targets # ###################### @@ -1097,34 +1124,11 @@ target_link_libraries(flashfetch PRIVATE libfastfetch ) -if(NOT WIN32) - # Prevent fastfetch from linking to libstdc++ - set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") - set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "") - set_target_properties(fastfetch PROPERTIES LINKER_LANGUAGE C) - set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C) -else() - include(CheckCXXSymbolExists) - if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES) - set(header version) - else() - set(header ciso646) - endif() - - check_cxx_symbol_exists(_LIBCPP_VERSION ${header} LIBCPP) - if(LIBCPP) - target_link_libraries(libfastfetch - PRIVATE "libc++.a" - ) - endif() - - check_cxx_symbol_exists(__GLIBCXX__ ${header} GLIBCXX) - if(GLIBCXX) - target_link_libraries(libfastfetch - PRIVATE "libstdc++.a" - ) - endif() -endif() +# Prevent fastfetch from linking to libstdc++ +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") +set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "") +set_target_properties(fastfetch PROPERTIES LINKER_LANGUAGE C) +set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C) if(yyjson_FOUND) target_compile_definitions(fastfetch PRIVATE FF_USE_SYSTEM_YYJSON) @@ -1134,12 +1138,9 @@ if(yyjson_FOUND) endif() if(WIN32) - set(TARGET_NAME fastfetch) target_sources(fastfetch PRIVATE src/util/windows/version.rc ) - - set(TARGET_NAME flashfetch) target_sources(flashfetch PRIVATE src/util/windows/version.rc ) diff --git a/src/detection/media/media_windows.c b/src/detection/media/media_windows.c new file mode 100644 index 000000000..ed0ed97ce --- /dev/null +++ b/src/detection/media/media_windows.c @@ -0,0 +1,38 @@ +#include "common/library.h" +#include "util/windows/unicode.h" +#include "media.h" +#include "media_windows.dll.h" + +static const char* getMedia(FFMediaResult* media) +{ + FF_LIBRARY_LOAD(libffwinrt, NULL, "dlopen libffwinrt" FF_LIBRARY_EXTENSION " failed", "libffwinrt" FF_LIBRARY_EXTENSION, 0) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libffwinrt, ffWinrtDetectMedia) + libffwinrt = NULL; // Don't close libffwinrt or it may crash + + FFWinrtMediaResult result = {}; + + const char* error = ffffWinrtDetectMedia(&result); + if (error) + { + ffStrbufSetStatic(&media->error, error); + return NULL; + } + + ffStrbufSetWS(&media->playerId, result.playerId); + ffStrbufSet(&media->player, &media->playerId); + if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe")) + ffStrbufSubstrBefore(&media->player, media->player.length - 4); + else + ffStrbufSubstrAfterFirstC(&media->player, '!'); // UWP ID + ffStrbufSetWS(&media->song, result.song); + ffStrbufSetWS(&media->artist, result.artist); + ffStrbufSetWS(&media->album, result.album); + ffStrbufSetStatic(&media->status, result.status); + return NULL; +} + +void ffDetectMediaImpl(FFMediaResult* media) +{ + const char* error = getMedia(media); + ffStrbufAppendS(&media->error, error); +} diff --git a/src/detection/media/media_windows.cpp b/src/detection/media/media_windows.cpp deleted file mode 100644 index 1e67dd680..000000000 --- a/src/detection/media/media_windows.cpp +++ /dev/null @@ -1,65 +0,0 @@ -extern "C" -{ - #include "media.h" - #include "util/windows/unicode.h" -} - -#include -#include -#include - -extern "C" -{ -static const char* getMedia(FFMediaResult* media) -{ - using namespace winrt::Windows::Media::Control; - auto manager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync().get(); - if (!manager) - return "GlobalSystemMediaTransportControlsSessionManager::RequestAsync() failed"; - - auto session = manager.GetCurrentSession(); - if (!session) - return "GetCurrentSession() failed"; - - auto mediaProps = session - .TryGetMediaPropertiesAsync() - .get(); - if (!mediaProps) - return "TryGetMediaPropertiesAsync() failed"; - - if (auto playbackInfo = session.GetPlaybackInfo()) - { - switch (playbackInfo.PlaybackStatus()) - { -#define FF_MEDIA_SET_STATUS(status_code) \ -case GlobalSystemMediaTransportControlsSessionPlaybackStatus::status_code: ffStrbufSetStatic(&media->status, #status_code); break - FF_MEDIA_SET_STATUS(Closed); - FF_MEDIA_SET_STATUS(Opened); - FF_MEDIA_SET_STATUS(Changing); - FF_MEDIA_SET_STATUS(Stopped); - FF_MEDIA_SET_STATUS(Playing); - FF_MEDIA_SET_STATUS(Paused); -#undef FF_MEDIA_SET_STATUS - } - } - - ffStrbufSetNWS(&media->playerId, session.SourceAppUserModelId().size(), session.SourceAppUserModelId().data()); - ffStrbufSet(&media->player, &media->playerId); - if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe")) - ffStrbufSubstrBefore(&media->player, media->player.length - 4); - else - ffStrbufSubstrAfterFirstC(&media->player, '!'); // UWP ID - - ffStrbufSetNWS(&media->song, mediaProps.Title().size(), mediaProps.Title().data()); - ffStrbufSetNWS(&media->artist, mediaProps.Artist().size(), mediaProps.Artist().data()); - ffStrbufSetNWS(&media->album, mediaProps.AlbumTitle().size(), mediaProps.AlbumTitle().data()); - return NULL; -} - -void ffDetectMediaImpl(FFMediaResult* media) -{ - const char* error = getMedia(media); - ffStrbufAppendS(&media->error, error); -} - -} diff --git a/src/detection/media/media_windows.dll.cpp b/src/detection/media/media_windows.dll.cpp new file mode 100644 index 000000000..53877d29f --- /dev/null +++ b/src/detection/media/media_windows.dll.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +extern "C" +{ +#include "media_windows.dll.h" + +const char* ffWinrtDetectMedia(FFWinrtMediaResult* result) +{ + // C++/WinRT requires Windows 8.1 or later and C++ runtime (std::string and other stuff) + // Make it a separate dll in order not to break Windows 7 support + using namespace winrt::Windows::Media::Control; + + auto manager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync().get(); + if (!manager) + return "winrt: GlobalSystemMediaTransportControlsSessionManager::RequestAsync() failed"; + + auto session = manager.GetCurrentSession(); + if (!session) + return "winrt: GetCurrentSession() failed"; + + auto mediaProps = session + .TryGetMediaPropertiesAsync() + .get(); + if (!mediaProps) + return "winrt: TryGetMediaPropertiesAsync() failed"; + + if (auto playbackInfo = session.GetPlaybackInfo()) + { + switch (playbackInfo.PlaybackStatus()) + { +#define FF_MEDIA_SET_STATUS(status_code) \ +case GlobalSystemMediaTransportControlsSessionPlaybackStatus::status_code: result->status = #status_code; break + FF_MEDIA_SET_STATUS(Closed); + FF_MEDIA_SET_STATUS(Opened); + FF_MEDIA_SET_STATUS(Changing); + FF_MEDIA_SET_STATUS(Stopped); + FF_MEDIA_SET_STATUS(Playing); + FF_MEDIA_SET_STATUS(Paused); +#undef FF_MEDIA_SET_STATUS + } + } + + ::wcsncpy(result->playerId, session.SourceAppUserModelId().data(), FF_MEDIA_WIN_RESULT_BUFLEN); + ::wcsncpy(result->song, mediaProps.Title().data(), FF_MEDIA_WIN_RESULT_BUFLEN); + ::wcsncpy(result->artist, mediaProps.Artist().data(), FF_MEDIA_WIN_RESULT_BUFLEN); + ::wcsncpy(result->album, mediaProps.AlbumTitle().data(), FF_MEDIA_WIN_RESULT_BUFLEN); + + return NULL; +} + +} // extern "C" diff --git a/src/detection/media/media_windows.dll.h b/src/detection/media/media_windows.dll.h new file mode 100644 index 000000000..045976c2e --- /dev/null +++ b/src/detection/media/media_windows.dll.h @@ -0,0 +1,15 @@ +#pragma once + +#define FF_MEDIA_WIN_RESULT_BUFLEN 256 + +typedef struct FFWinrtMediaResult +{ + wchar_t playerId[FF_MEDIA_WIN_RESULT_BUFLEN]; + wchar_t song[FF_MEDIA_WIN_RESULT_BUFLEN]; + wchar_t artist[FF_MEDIA_WIN_RESULT_BUFLEN]; + wchar_t album[FF_MEDIA_WIN_RESULT_BUFLEN]; + const char* status; +} FFWinrtMediaResult; + +__attribute__((__dllexport__)) +const char* ffWinrtDetectMedia(FFWinrtMediaResult* result);