From c05b7b631556c59d065362ad455d3fcef769c8de Mon Sep 17 00:00:00 2001 From: jamgroga Date: Sun, 31 Oct 2021 13:04:48 +0000 Subject: [PATCH] Add window support for Windows. --- apps/gui-main-win.cpp | 100 ++++----- src/audio/CMakeLists.txt | 29 ++- .../audio_interfaces/WasapiInterface.cpp | 207 ++++++++++++++++++ src/audio/audio_interfaces/WasapiInterface.h | 36 +++ src/client/GuiApplication.cpp | 20 ++ src/console/MainApplication.cpp | 10 +- src/console/MainApplication.h | 17 +- src/core/AbstractApp.h | 26 +++ src/core/CMakeLists.txt | 1 + src/core/CommandLineArgs.cpp | 5 + src/core/CommandLineArgs.h | 2 + src/core/StringUtils.cpp | 24 ++ src/core/StringUtils.h | 1 + src/core/loggers/FileLogger.cpp | 11 +- src/core/loggers/FileLogger.h | 14 +- src/ui_elements/CMakeLists.txt | 4 + src/windows/CMakeLists.txt | 15 +- src/windows/managers/DesktopManager.cpp | 9 +- src/windows/managers/DesktopManager.h | 8 +- .../ui_interfaces/win32/Win32UIInterface.cpp | 40 ++++ .../ui_interfaces/win32/Win32UIInterface.h | 29 +++ .../ui_interfaces/win32/Win32Window.cpp | 139 ++++++++++++ src/windows/ui_interfaces/win32/Win32Window.h | 42 ++++ .../win32/Win32WindowInterface.cpp | 32 +++ .../win32/Win32WindowInterface.h | 29 +++ test/CMakeLists.txt | 4 +- test/audio/TestAudioWriter.cpp | 24 +- 27 files changed, 783 insertions(+), 95 deletions(-) create mode 100644 src/audio/audio_interfaces/WasapiInterface.cpp create mode 100644 src/audio/audio_interfaces/WasapiInterface.h create mode 100644 src/core/AbstractApp.h create mode 100644 src/windows/ui_interfaces/win32/Win32UIInterface.cpp create mode 100644 src/windows/ui_interfaces/win32/Win32UIInterface.h create mode 100644 src/windows/ui_interfaces/win32/Win32Window.cpp create mode 100644 src/windows/ui_interfaces/win32/Win32Window.h create mode 100644 src/windows/ui_interfaces/win32/Win32WindowInterface.cpp create mode 100644 src/windows/ui_interfaces/win32/Win32WindowInterface.h diff --git a/apps/gui-main-win.cpp b/apps/gui-main-win.cpp index 54fb73c..ef4beb6 100644 --- a/apps/gui-main-win.cpp +++ b/apps/gui-main-win.cpp @@ -2,72 +2,66 @@ #define UNICODE #endif +#include "MainApplication.h" +#include "GuiApplication.h" +#include "CommandLineArgs.h" +#include "Win32WindowInterface.h" +#include "FileLogger.h" +#include "StringUtils.h" + #include "windows.h" -LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +#include +#include +#include + +void initializeCommandLineArgs(CommandLineArgs* args) +{ + int nArgs{ 0 }; + auto szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs); + if (szArglist == nullptr) + { + return; + } + + std::vector windowsArgs(nArgs); + for (int idx = 0; idx < nArgs; idx++) + { + windowsArgs[idx] = StringUtils::convert(szArglist[idx]); + } + LocalFree(szArglist); + + args->Process(windowsArgs); +} int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { - // Register the window class. - const wchar_t CLASS_NAME[] = L"Sample Window Class"; + std::ofstream out("out.txt"); + std::cout.rdbuf(out.rdbuf()); - WNDCLASS wc = { }; + auto args = CommandLineArgs::CreateUnique(); + initializeCommandLineArgs(args.get()); + args->RecordLaunchPath(); - wc.lpfnWndProc = WindowProc; - wc.hInstance = hInstance; - wc.lpszClassName = CLASS_NAME; + // Start the main app + auto main_app = MainApplication::Create(); - RegisterClass(&wc); + auto applicationContext = std::make_unique(); + applicationContext->hInstance = reinterpret_cast(hInstance); + applicationContext->nCmdShow = nCmdShow; - HWND hwnd = CreateWindowEx( - 0, // Optional window styles. - CLASS_NAME, // Window class - L"Learn to Program Windows", // Window text - WS_OVERLAPPEDWINDOW, // Window style + main_app->Initialize(std::move(args), std::move(applicationContext)); - // Size and position - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + MLOG_INFO("Creating GUI Application"); - NULL, // Parent window - NULL, // Menu - hInstance, // Instance handle - NULL // Additional application data - ); + // Start the gui application + auto gui_app = GuiApplication(); + gui_app.SetMainApplication(main_app); - if (hwnd == NULL) - { - return 0; - } - ShowWindow(hwnd, nCmdShow); + MLOG_INFO("Running GUI Application"); + gui_app.Run(); - // Run the message loop. - MSG msg = { }; - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } + main_app->ShutDown(); return 0; } -LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - - FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1)); - - EndPaint(hwnd, &ps); - } - - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} \ No newline at end of file diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index fc73d2a..7ce05f2 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -3,17 +3,24 @@ set(platform_HEADERS "") set(platform_INCLUDES "") if (UNIX) -find_package(ALSA REQUIRED) -list(APPEND platform_HEADERS - audio_interfaces/AlsaInterface.h - ${ALSA_INCLUDE_DIRS} -) -list(APPEND platform_INCLUDES - audio_interfaces/AlsaInterface.cpp -) -list(APPEND platform_LIBS - ${ALSA_LIBRARIES} -) + find_package(ALSA REQUIRED) + list(APPEND platform_HEADERS + audio_interfaces/AlsaInterface.h + ${ALSA_INCLUDE_DIRS} + ) + list(APPEND platform_INCLUDES + audio_interfaces/AlsaInterface.cpp + ) + list(APPEND platform_LIBS + ${ALSA_LIBRARIES} + ) +else() + list(APPEND platform_HEADERS + audio_interfaces/WasapiInterface.h + ) + list(APPEND platform_INCLUDES + audio_interfaces/WasapiInterface.cpp + ) endif (UNIX) list(APPEND audio_HEADERS diff --git a/src/audio/audio_interfaces/WasapiInterface.cpp b/src/audio/audio_interfaces/WasapiInterface.cpp new file mode 100644 index 0000000..3c911a5 --- /dev/null +++ b/src/audio/audio_interfaces/WasapiInterface.cpp @@ -0,0 +1,207 @@ +#include "WasapiInterface.h" +#include "FileLogger.h" + +#include "AudioSynth.h" + +#include +#include + +#include +#include +#include +#include + +WasapiInterface::WasapiInterface() +{ + +} + +WasapiInterface::~WasapiInterface() +{ + +} + +std::unique_ptr WasapiInterface::Create() +{ + return std::make_unique(); +} + +void WasapiInterface::OpenDevice(const AudioDevicePtr& device) +{ + +} + +void WasapiInterface::SetAccessType(const AudioDevicePtr& device) +{ + +} + +void WasapiInterface::SetSampleFormat(const AudioDevicePtr& device) +{ + +} + +void WasapiInterface::SetSampleRate(const AudioDevicePtr& device) +{ + +} + +void WasapiInterface::SetPeriod(const AudioDevicePtr& device) +{ + +} + +void WasapiInterface::SetBufferSize(const AudioDevicePtr& device) +{ + +} + +void WasapiInterface::SetChannelNumber(const AudioDevicePtr& device) +{ + +} + +// REFERENCE_TIME time units per second and per millisecond +#define REFTIMES_PER_SEC 10000000 +#define REFTIMES_PER_MILLISEC 10000 + +#define EXIT_ON_ERROR(hres) \ + if (FAILED(hres)) { goto Exit; } +#define SAFE_RELEASE(punk) \ + if ((punk) != NULL) \ + { (punk)->Release(); (punk) = NULL; } + +const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); +const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); +const IID IID_IAudioClient = __uuidof(IAudioClient); +const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); + +void WasapiInterface::Play(const AudioDevicePtr& device) +{ + std::cout << "Into wasapi play" << std::endl; + IMMDeviceEnumerator* pEnumerator = nullptr; + auto hr = CoCreateInstance(CLSID_MMDeviceEnumerator, + nullptr, + CLSCTX_ALL, + IID_IMMDeviceEnumerator, + (void**)&pEnumerator); + if (FAILED(hr)) + { + std::cout << "Failed to create enumerator" << std::endl; + return; + } + + IMMDevice* pDevice = nullptr; + hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice); + if (FAILED(hr)) + { + return; + } + std::cout << "Got default endpoint" << std::endl; + + IPropertyStore* pPropertyStore{ nullptr }; + hr = pDevice->OpenPropertyStore(STGM_READ, &pPropertyStore); + + DWORD propCount{ 0 }; + pPropertyStore->GetCount(&propCount); + + PROPVARIANT deviceName; + PropVariantInit(&deviceName); + // hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &deviceName); + hr = pPropertyStore->GetValue(PKEY_DeviceInterface_FriendlyName, &deviceName); + //PKEY_Device_FriendlyName + std::cout << "Device name: " << deviceName.pwszVal << std::endl; + + pPropertyStore->Release(); + + + IAudioClient* pAudioClient = nullptr; + hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void**)&pAudioClient); + std::cout << "Activated audio device" << std::endl; + if (FAILED(hr)) + { + return; + } + + WAVEFORMATEX* pwfx = nullptr; + hr = pAudioClient->GetMixFormat(&pwfx); + if (FAILED(hr)) + { + return; + } + std::cout << "formatTag: " << pwfx->wFormatTag << std::endl; + std::cout << "nChannels: " << pwfx->nChannels << std::endl; + std::cout << "nSamplesPerSec: " << pwfx->nSamplesPerSec << std::endl; + std::cout << "nAvgBytesPerSec: " << pwfx->nAvgBytesPerSec << std::endl; // nSamplesPerSec*nBlockAlign + std::cout << "nBlockAlign: " << pwfx->nBlockAlign << std::endl; //nChannels *wBitsPerSample/8 (bytes) + std::cout << "wBitsPerSample: " << pwfx->wBitsPerSample << std::endl; + std::cout << "cbSize: " << pwfx->cbSize << std::endl; + + //REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC; + //hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, + // hnsRequestedDuration, + // 0, pwfx, nullptr); + //if (FAILED(hr)) + //{ + // return; + //} + + //// Tell the audio source which format to use. + //// hr = pMySource->SetFormat(pwfx); + + //// Get the actual size of the allocated buffer. + //UINT32 bufferFrameCount; + //hr = pAudioClient->GetBufferSize(&bufferFrameCount); + + //IAudioRenderClient* pRenderClient = nullptr; + //hr = pAudioClient->GetService(IID_IAudioRenderClient, (void**)&pRenderClient); + + //// Grab the entire buffer for the initial fill operation. + //BYTE* pData; + //hr = pRenderClient->GetBuffer(bufferFrameCount, &pData); + + //// Load the initial data into the shared buffer. + //DWORD flags = 0; + //// hr = pMySource->LoadData(bufferFrameCount, pData, &flags); + + //hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags); + + //// Calculate the actual duration of the allocated buffer. + //auto hnsActualDuration = (double)REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec; + + //hr = pAudioClient->Start(); // Start playing. + + //// Each loop fills about half of the shared buffer. + //while (flags != AUDCLNT_BUFFERFLAGS_SILENT) + //{ + // // Sleep for half the buffer duration. + // Sleep((DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2)); + + // // See how much buffer space is available. + // UINT32 numFramesPadding; + // hr = pAudioClient->GetCurrentPadding(&numFramesPadding); + + // auto numFramesAvailable = bufferFrameCount - numFramesPadding; + + // // Grab all the available space in the shared buffer. + // hr = pRenderClient->GetBuffer(numFramesAvailable, &pData); + + // // Get next 1/2-second of data from the audio source. + // // hr = pMySource->LoadData(numFramesAvailable, pData, &flags); + + // hr = pRenderClient->ReleaseBuffer(numFramesAvailable, flags); + //} + // + //// Wait for last data in buffer to play before stopping. + //Sleep((DWORD)(hnsActualDuration / REFTIMES_PER_MILLISEC / 2)); + + //hr = pAudioClient->Stop(); // Stop playing. + + //CoTaskMemFree(pwfx); + //SAFE_RELEASE(pEnumerator) + //SAFE_RELEASE(pDevice) + //SAFE_RELEASE(pAudioClient) + //SAFE_RELEASE(pRenderClient) + + return; +} diff --git a/src/audio/audio_interfaces/WasapiInterface.h b/src/audio/audio_interfaces/WasapiInterface.h new file mode 100644 index 0000000..168e175 --- /dev/null +++ b/src/audio/audio_interfaces/WasapiInterface.h @@ -0,0 +1,36 @@ +#pragma once + +#include "IAudioInterface.h" +#include "AudioDevice.h" + +#include + +class WasapiInterface : public IAudioInterface +{ + +public: + + WasapiInterface(); + + ~WasapiInterface(); + + static std::unique_ptr Create(); + + void OpenDevice(const AudioDevicePtr& device) override; + + void SetAccessType(const AudioDevicePtr& device); + + void SetSampleFormat(const AudioDevicePtr& device); + + void SetSampleRate(const AudioDevicePtr& device); + + void SetPeriod(const AudioDevicePtr& device); + + void SetBufferSize(const AudioDevicePtr& device); + + void SetChannelNumber(const AudioDevicePtr& device); + + void Play(const AudioDevicePtr& device) override; +}; + +using AlsaInterfacePtr = std::shared_ptr; diff --git a/src/client/GuiApplication.cpp b/src/client/GuiApplication.cpp index 45f6d4e..39cc9d6 100644 --- a/src/client/GuiApplication.cpp +++ b/src/client/GuiApplication.cpp @@ -1,8 +1,12 @@ #include "GuiApplication.h" #include "Widget.h" +#ifdef __linux__ #include "XcbInterface.h" #include "XcbKeyboard.h" +#else +#include "Win32UiInterface.h" +#endif #include "Window.h" #include "TextElement.h" #include "WindowManager.h" @@ -14,6 +18,7 @@ #include "TopBar.h" #include "StatusBar.h" #include "HorizontalSpacer.h" +#include "FileLogger.h" #include @@ -33,6 +38,7 @@ GuiApplication::~GuiApplication() void GuiApplication::SetMainApplication(MainApplicationPtr app) { mMainApplication = app; + mDesktopManager->SetMainApp(app); } void GuiApplication::SetUpWidget() @@ -75,6 +81,7 @@ void GuiApplication::Run() auto mainWindow = mDesktopManager->GetWindowManager()->GetMainWindow(); SetUpWidget(); +#ifdef __linux__ mDesktopManager->SetKeyboard(XcbKeyboard::Create()); bool useOpenGl = true; @@ -89,4 +96,17 @@ void GuiApplication::Run() } window_interface.Loop(mDesktopManager.get()); window_interface.ShutDown(); +#else + mDesktopManager->SetKeyboard(Keyboard::Create()); + + MLOG_INFO("Creating Window Interface"); + Win32UIInterface window_interface; + window_interface.AddWindow(mainWindow, mDesktopManager.get()); + + window_interface.ShowWindow(mainWindow); + + window_interface.Loop(mDesktopManager.get()); + window_interface.ShutDown(); + MLOG_INFO("Window Interface Shut Down"); +#endif } diff --git a/src/console/MainApplication.cpp b/src/console/MainApplication.cpp index 8e41a55..12714a9 100644 --- a/src/console/MainApplication.cpp +++ b/src/console/MainApplication.cpp @@ -23,8 +23,13 @@ MainApplication::~MainApplication() } -void MainApplication::Initialize(CommandLineArgsUPtr commandLineArgs) +void MainApplication::Initialize(CommandLineArgsUPtr commandLineArgs, std::unique_ptr applicationContext) { + if (applicationContext) + { + mApplicationContext = std::move(applicationContext); + } + mCommandLineArgs = std::move(commandLineArgs); const auto launch_path = mCommandLineArgs->GetLaunchPath().string(); @@ -34,10 +39,13 @@ void MainApplication::Initialize(CommandLineArgsUPtr commandLineArgs) mDatabaseManager = DatabaseManager::Create(); mDatabaseManager->CreateDatabase(launch_path + "/database.db"); + MLOG_INFO("Created DB"); mNetworkManager = NetworkManager::Create(); + MLOG_INFO("Created Network Manager"); mAudioManager = AudioManager::Create(); + MLOG_INFO("Created Audio Manager"); } void MainApplication::Run() diff --git a/src/console/MainApplication.h b/src/console/MainApplication.h index dbfcb6a..327f527 100644 --- a/src/console/MainApplication.h +++ b/src/console/MainApplication.h @@ -3,28 +3,22 @@ #include #include +#include "AbstractApp.h" #include "AudioManager.h" #include "FileLogger.h" #include "DatabaseManager.h" #include "NetworkManager.h" #include "CommandLineArgs.h" -class MainApplication +class MainApplication : public AbstractApp { -private: - - CommandLineArgsUPtr mCommandLineArgs; - DatabaseManagerPtr mDatabaseManager; - NetworkManagerUPtr mNetworkManager; - AudioManagerUPtr mAudioManager; - public: MainApplication(); ~MainApplication(); - void Initialize(CommandLineArgsUPtr commandLineArgs); + void Initialize(CommandLineArgsUPtr commandLineArgs, std::unique_ptr applicationContext=nullptr); void Run(); @@ -40,6 +34,11 @@ private: void PlayAudio(); void ConvertDocument(const std::string& inputPath, const std::string& outputPath); + + CommandLineArgsUPtr mCommandLineArgs; + DatabaseManagerPtr mDatabaseManager; + NetworkManagerUPtr mNetworkManager; + AudioManagerUPtr mAudioManager; }; using MainApplicationPtr = std::shared_ptr; diff --git a/src/core/AbstractApp.h b/src/core/AbstractApp.h new file mode 100644 index 0000000..ab34aa4 --- /dev/null +++ b/src/core/AbstractApp.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +class IApplicationContext +{ +public: + IApplicationContext() = default; + virtual ~IApplicationContext() = default; +}; + +class AbstractApp +{ +public: + AbstractApp() = default; + + virtual ~AbstractApp() = default; + IApplicationContext* GetApplicationContext() const + { + return mApplicationContext.get(); + } +protected: + std::unique_ptr mApplicationContext{ nullptr }; +}; + +using AbstractAppPtr = std::unique_ptr; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ea34f7e..c19faf8 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,4 +1,5 @@ list(APPEND core_HEADERS + AbstractApp.h Event.h Color.h CommandLineArgs.h diff --git a/src/core/CommandLineArgs.cpp b/src/core/CommandLineArgs.cpp index 336b971..80eaa6f 100644 --- a/src/core/CommandLineArgs.cpp +++ b/src/core/CommandLineArgs.cpp @@ -30,6 +30,11 @@ void CommandLineArgs::Process(int argc, char *argv[]) } } +void CommandLineArgs::Process(const std::vector& args) +{ + mArugments = args; +} + std::size_t CommandLineArgs::GetNumberOfArgs() const { return mArugments.size(); diff --git a/src/core/CommandLineArgs.h b/src/core/CommandLineArgs.h index b4b3306..865b8e8 100644 --- a/src/core/CommandLineArgs.h +++ b/src/core/CommandLineArgs.h @@ -21,6 +21,8 @@ public: void Process(int argc, char *argv[]); + void Process(const std::vector& args); + std::size_t GetNumberOfArgs() const; std::string GetArg(std::size_t index) const; diff --git a/src/core/StringUtils.cpp b/src/core/StringUtils.cpp index 434c6e4..547f2a7 100644 --- a/src/core/StringUtils.cpp +++ b/src/core/StringUtils.cpp @@ -2,6 +2,10 @@ #include #include +#ifdef _WIN32 +#include "Windows.h" +#endif + bool StringUtils::IsAlphaNumeric(char c) { std::locale loc; @@ -21,3 +25,23 @@ std::string StringUtils::ToLower(const std::string& s) [](unsigned char c){ return std::tolower(c); }); return ret; } + +std::string StringUtils::convert(const std::wstring& input) +{ + if (input.empty()) + { + return std::string(); + } + +#ifdef _WIN32 + const auto size = ::WideCharToMultiByte(CP_UTF8, 0, &input[0], + (int)input.size(), nullptr, 0, nullptr, nullptr); + + std::string result(size, 0); + ::WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(), + &result[0], size, nullptr, nullptr); + return result; +#else + throw std::logic_error("Not implemented"); +#endif +} diff --git a/src/core/StringUtils.h b/src/core/StringUtils.h index 2dc305f..2a70f79 100644 --- a/src/core/StringUtils.h +++ b/src/core/StringUtils.h @@ -17,4 +17,5 @@ public: static bool IsAlphaNumeric(char c); static bool IsSpace(char c); static std::string ToLower(const std::string& s); + static std::string convert(const std::wstring& input); }; diff --git a/src/core/loggers/FileLogger.cpp b/src/core/loggers/FileLogger.cpp index e93b32b..6d7da28 100644 --- a/src/core/loggers/FileLogger.cpp +++ b/src/core/loggers/FileLogger.cpp @@ -1,7 +1,7 @@ #include "FileLogger.h" #include #include - +#include FileLogger::~FileLogger() { @@ -28,12 +28,12 @@ void FileLogger::Close() mFileStream.close(); } -void FileLogger::LogLine(const std::string& line) +void FileLogger::LogLine(const std::ostringstream& line) { - mFileStream << line << std::endl; + mFileStream << line.str() << std::endl; } -void FileLogger::LogLine(const std::string& logType, const std::string& line, const std::string& fileName, const std::string& functionName, int lineNumber) +void FileLogger::LogLine(const std::string& logType, const std::ostringstream& line, const std::string& fileName, const std::string& functionName, int lineNumber) { std::time_t t = std::time(nullptr); const std::string cleanedFileName = fileName.substr(fileName.find_last_of("/\\") + 1); @@ -43,5 +43,6 @@ void FileLogger::LogLine(const std::string& logType, const std::string& line, co #else gmtime_r(&t, &time_buf); #endif - mFileStream << logType << "|" << std::put_time(&time_buf, "%T") << "|" << cleanedFileName << "::" << functionName << "::" << lineNumber << "|" << line << std::endl; + std::cout << logType << "|" << std::put_time(&time_buf, "%T") << "|" << cleanedFileName << "::" << functionName << "::" << lineNumber << "|" << line.str() << std::endl; + mFileStream << logType << "|" << std::put_time(&time_buf, "%T") << "|" << cleanedFileName << "::" << functionName << "::" << lineNumber << "|" << line.str() << std::endl; } diff --git a/src/core/loggers/FileLogger.h b/src/core/loggers/FileLogger.h index bc149d6..b30c84f 100644 --- a/src/core/loggers/FileLogger.h +++ b/src/core/loggers/FileLogger.h @@ -1,10 +1,16 @@ #pragma once -#define MLOG_INFO(msg) FileLogger::GetInstance().LogLine("Info", msg, __FILE__, __FUNCTION__, __LINE__); -#define MLOG_ERROR(msg) FileLogger::GetInstance().LogLine("Error", msg, __FILE__, __FUNCTION__, __LINE__); + +#define MLOG_ALL(msg, level) {std::ostringstream mt_logstream;\ + mt_logstream << msg; \ + FileLogger::GetInstance().LogLine(level, mt_logstream, __FILE__, __FUNCTION__, __LINE__);}; + +#define MLOG_INFO(msg) MLOG_ALL(msg, "Info"); +#define MLOG_ERROR(msg) MLOG_ALL(msg, "Error"); #include #include #include +#include class FileLogger { @@ -41,9 +47,9 @@ public: void Close(); - void LogLine(const std::string& line); + void LogLine(const std::ostringstream& line); - void LogLine(const std::string& logType, const std::string& line, const std::string& fileName = "", const std::string& functionName = "", int lineNumber=-1); + void LogLine(const std::string& logType, const std::ostringstream& line, const std::string& fileName = "", const std::string& functionName = "", int lineNumber=-1); }; diff --git a/src/ui_elements/CMakeLists.txt b/src/ui_elements/CMakeLists.txt index 8c77056..b0bc14d 100644 --- a/src/ui_elements/CMakeLists.txt +++ b/src/ui_elements/CMakeLists.txt @@ -8,6 +8,10 @@ list(APPEND ui_elements_LIB_INCLUDES ui_events/MouseEvent.cpp ui_events/UiEvent.cpp ui_events/PaintEvent.cpp + ui_events/KeyboardEvent.h + ui_events/MouseEvent.h + ui_events/UiEvent.h + ui_events/PaintEvent.h widgets/Widget.cpp widgets/Button.cpp widgets/Label.cpp diff --git a/src/windows/CMakeLists.txt b/src/windows/CMakeLists.txt index 82e3773..302a948 100644 --- a/src/windows/CMakeLists.txt +++ b/src/windows/CMakeLists.txt @@ -12,9 +12,18 @@ list(APPEND platform_INCLUDES ui_interfaces/x11/XcbTextInterface.cpp ui_interfaces/x11/XcbKeyboard.cpp ui_interfaces/x11/GlxInterface.cpp) - + list(APPEND platform_LIBS - X11 X11-xcb xcb ) + X11 X11-xcb xcb ) +else() +list(APPEND platform_INCLUDES + ui_interfaces/win32/Win32UIInterface.h + ui_interfaces/win32/Win32UIInterface.cpp + ui_interfaces/win32/Win32WindowInterface.h + ui_interfaces/win32/Win32WindowInterface.cpp + ui_interfaces/win32/Win32Window.h + ui_interfaces/win32/Win32Window.cpp + ) endif() list(APPEND windows_LIB_INCLUDES @@ -29,6 +38,8 @@ target_include_directories(windows PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/managers" "${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/x11" + "${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32" + "${PROJECT_SOURCE_DIR}/src/core" "${PROJECT_SOURCE_DIR}/src/geometry" "${PROJECT_SOURCE_DIR}/src/graphics" "${PROJECT_SOURCE_DIR}/src/ui_elements" diff --git a/src/windows/managers/DesktopManager.cpp b/src/windows/managers/DesktopManager.cpp index 94c0828..045f4ef 100644 --- a/src/windows/managers/DesktopManager.cpp +++ b/src/windows/managers/DesktopManager.cpp @@ -1,5 +1,7 @@ #include "DesktopManager.h" +#include "FileLogger.h" + DesktopManager::DesktopManager() : mScreens(), mWindowManager(WindowManager::Create()), @@ -28,6 +30,7 @@ void DesktopManager::ClearEvents() void DesktopManager::OnKeyboardEvent(const KeyboardEvent* event) { + MLOG_INFO("Got key event: " << event->GetKeyString()); GetWindowManager()->OnKeyboardEvent(event); } @@ -97,14 +100,14 @@ void DesktopManager::SetKeyboard(KeyboardUPtr keyboard) mKeyboard = std::move(keyboard); } -void DesktopManager::SetMainApp(AbstractDesktopAppPtr mainApp) +void DesktopManager::SetMainApp(std::shared_ptr mainApp) { mMainApplication = mainApp; } -AbstractDesktopAppPtr DesktopManager::GetMainApp() +AbstractApp* DesktopManager::GetMainApp() { - return mMainApplication; + return mMainApplication.get(); } void DesktopManager::AddScreen(ScreenPtr screen) diff --git a/src/windows/managers/DesktopManager.h b/src/windows/managers/DesktopManager.h index ee27ca5..e43c817 100644 --- a/src/windows/managers/DesktopManager.h +++ b/src/windows/managers/DesktopManager.h @@ -10,7 +10,7 @@ #include "MouseEvent.h" #include "WindowManager.h" #include "UiEvent.h" -#include "AbstractDesktopApp.h" +#include "AbstractApp.h" #include "EventManager.h" class DesktopManager @@ -25,9 +25,9 @@ public: void SetWindowManager(WindowManagerUPtr windowManager); - void SetMainApp(AbstractDesktopAppPtr mainApp); + void SetMainApp(std::shared_ptr mainApp); - AbstractDesktopAppPtr GetMainApp(); + AbstractApp* GetMainApp(); WindowManager* GetWindowManager() const; @@ -58,7 +58,7 @@ private: WindowManagerUPtr mWindowManager; KeyboardUPtr mKeyboard; EventManagerUPtr mEventManager; - AbstractDesktopAppPtr mMainApplication; + std::shared_ptr mMainApplication; bool mModified; }; diff --git a/src/windows/ui_interfaces/win32/Win32UIInterface.cpp b/src/windows/ui_interfaces/win32/Win32UIInterface.cpp new file mode 100644 index 0000000..d44b354 --- /dev/null +++ b/src/windows/ui_interfaces/win32/Win32UIInterface.cpp @@ -0,0 +1,40 @@ +#include "Win32UIInterface.h" + +#include + +Win32UIInterface::Win32UIInterface() + : mWindowInterface(std::make_unique()) +{ + +} + +void Win32UIInterface::Initialize(DesktopManager* desktopManager) +{ + +} + +void Win32UIInterface::Loop(DesktopManager* desktopManager) +{ + // Run the message loop. + MSG msg = { }; + while (::GetMessage(&msg, NULL, 0, 0)) + { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } +} + +void Win32UIInterface::ShutDown() +{ + +} + +void Win32UIInterface::ShowWindow(mt::Window* window) +{ + mWindowInterface->Show(window); +} + +void Win32UIInterface::AddWindow(mt::Window* window, DesktopManager* desktopManager) +{ + mWindowInterface->Add(window, desktopManager); +} \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32UIInterface.h b/src/windows/ui_interfaces/win32/Win32UIInterface.h new file mode 100644 index 0000000..c2cf822 --- /dev/null +++ b/src/windows/ui_interfaces/win32/Win32UIInterface.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Window.h" + +#include "Win32WindowInterface.h" + +class DesktopManager; + +class Win32UIInterface +{ +public: + Win32UIInterface(); + + ~Win32UIInterface() = default; + + void Initialize(DesktopManager* desktopManager); + + void Loop(DesktopManager* desktopManager); + + void ShutDown(); + + void ShowWindow(mt::Window* window); + + void AddWindow(mt::Window* window, DesktopManager* desktopManager); + +private: + + Win32WindowInterfacePtr mWindowInterface; +}; \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32Window.cpp b/src/windows/ui_interfaces/win32/Win32Window.cpp new file mode 100644 index 0000000..4dd1eb0 --- /dev/null +++ b/src/windows/ui_interfaces/win32/Win32Window.cpp @@ -0,0 +1,139 @@ +#include "Win32Window.h" + +#include "Win32WindowInterface.h" + +#include +#include "FileLogger.h" +#include "StringUtils.h" + +#include "ui_events\KeyboardEvent.h" +#include "DesktopManager.h" + +LRESULT CALLBACK FreeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +Win32Window::Win32Window() +{ + +} + +std::unique_ptr Win32Window::Create() +{ + return std::make_unique(); +} + +HWND Win32Window::GetHandle() const +{ + return mHandle; +} + +void Win32Window::CreateNative(Win32ApplicationContext* context, DesktopManager* desktopManager) +{ + mDesktopManager = desktopManager; + + const char CLASS_NAME[] = "Sample Window Class"; + + auto hInstance = reinterpret_cast(context->hInstance); + WNDCLASS wc = { }; + wc.lpfnWndProc = FreeWindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = CLASS_NAME; + + RegisterClass(&wc); + + MLOG_INFO("Request window create"); + mHandle = CreateWindowEx( + 0, // Optional window styles. + CLASS_NAME, // Window class + "Media Tool", // Window text + WS_OVERLAPPEDWINDOW, // Window style + + // Size and position + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + + nullptr, // Parent window + nullptr, // Menu + hInstance, // Instance handle + this // Additional application data + ); + + if (mHandle == nullptr) + { + LPVOID lpMsgBuf; + auto dw = ::GetLastError(); + + ::FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, dw,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); + + MLOG_INFO("Request window failed: " << dw); + + LocalFree(lpMsgBuf); + } + MLOG_INFO("Request window create got handle: " << "0x" << mHandle); +} + +LRESULT CALLBACK Win32Window::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_DESTROY: + { + PostQuitMessage(0); + return 0; + } + + case WM_CHAR: + { + auto key_event = std::make_unique(); + key_event->SetAction(KeyboardEvent::Action::Pressed); + + auto keyChar = (wchar_t)wParam; + key_event->SetKeyString(StringUtils::convert(std::wstring(1, keyChar))); + mDesktopManager->OnUiEvent(std::move(key_event)); + } + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(mHandle, &ps); + + FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1)); + + auto text = L"Hello World"; + auto val = DrawText(hdc, (LPCSTR)(&text[0]), -1, &ps.rcPaint, 0); + + EndPaint(mHandle, &ps); + } + } + return DefWindowProc(mHandle, message, wParam, lParam); +} + +static LRESULT CALLBACK FreeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + Win32Window* window; + + if (uMsg == WM_NCCREATE) + { + CREATESTRUCT* cs = (CREATESTRUCT*)lParam; + window = (Win32Window*)cs->lpCreateParams; + + SetLastError(0); + if (::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)window) == 0) + { + if (GetLastError() != 0) + return FALSE; + } + } + else + { + window = (Win32Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + } + + if (window) + { + window->SetHandle(hwnd); + return window->WindowProc(uMsg, wParam, lParam); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32Window.h b/src/windows/ui_interfaces/win32/Win32Window.h new file mode 100644 index 0000000..ea0dd75 --- /dev/null +++ b/src/windows/ui_interfaces/win32/Win32Window.h @@ -0,0 +1,42 @@ +#pragma once + +#include "IPlatformWindow.h" +#include + +class Win32ApplicationContext; +class DesktopManager; + +class Win32Window : public IPlatformWindow +{ +public: + Win32Window(); + virtual ~Win32Window() = default; + + static std::unique_ptr Create(); + + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + + HWND GetHandle() const; + + void SetHandle(HWND handle) + { + mHandle = handle; + } + + int GetCmdShow() const + { + return mCmdShow; + } + + void SetCmdShow(int cmdShow) + { + mCmdShow = cmdShow; + } + + void CreateNative(Win32ApplicationContext* context, DesktopManager* desktopManager); + +private: + HWND mHandle{ 0 }; + int mCmdShow{ 0 }; + DesktopManager* mDesktopManager; +}; \ No newline at end of file diff --git a/src/windows/ui_interfaces/win32/Win32WindowInterface.cpp b/src/windows/ui_interfaces/win32/Win32WindowInterface.cpp new file mode 100644 index 0000000..e284fe7 --- /dev/null +++ b/src/windows/ui_interfaces/win32/Win32WindowInterface.cpp @@ -0,0 +1,32 @@ +#include "Win32WindowInterface.h" + +#include "Win32Window.h" + +#include + +#include "DesktopManager.h" + +#include "FileLogger.h" + +Win32WindowInterface::Win32WindowInterface() +{ + +} + +void Win32WindowInterface::Show(mt::Window* window) +{ + auto platformWindow = dynamic_cast(window->GetPlatformWindow()); + MLOG_INFO("Showing platform window: " << platformWindow->GetHandle()); + ::ShowWindow(platformWindow->GetHandle(), platformWindow->GetCmdShow()); +} + +void Win32WindowInterface::Add(mt::Window* window, DesktopManager* desktopManager) +{ + auto context = dynamic_cast(desktopManager->GetMainApp()->GetApplicationContext()); + + auto win32_window = Win32Window::Create(); + win32_window->CreateNative(context, desktopManager); + win32_window->SetCmdShow(context->nCmdShow); + window->SetPlatformWindow(std::move(win32_window)); +} + diff --git a/src/windows/ui_interfaces/win32/Win32WindowInterface.h b/src/windows/ui_interfaces/win32/Win32WindowInterface.h new file mode 100644 index 0000000..027c0b1 --- /dev/null +++ b/src/windows/ui_interfaces/win32/Win32WindowInterface.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Window.h" +#include "AbstractApp.h" + +#include + +#include + +class DesktopManager; + +class Win32ApplicationContext : public IApplicationContext +{ +public: + void* hInstance{ nullptr }; + int nCmdShow{ 0 }; +}; + +class Win32WindowInterface +{ +public: + Win32WindowInterface(); + + void Add(mt::Window* window, DesktopManager* desktopManager); + + void Show(mt::Window* window); +}; + +using Win32WindowInterfacePtr = std::unique_ptr; \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6d13ebd..111c845 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(test_utils SHARED +add_library(test_utils STATIC test_utils/TestCase.h test_utils/TestCaseRunner.cpp ) @@ -18,7 +18,7 @@ list(APPEND TestNames TestOpenGlRendering) foreach(TestFile TestName IN ZIP_LISTS TestFiles TestNames) - add_executable(${TestName} ${TestFile}) + add_executable(${TestName} ${TestFile}) target_link_libraries(${TestName} PUBLIC core network database geometry audio graphics web client test_utils) endforeach() diff --git a/test/audio/TestAudioWriter.cpp b/test/audio/TestAudioWriter.cpp index 28a1dd6..12c8ba4 100644 --- a/test/audio/TestAudioWriter.cpp +++ b/test/audio/TestAudioWriter.cpp @@ -1,12 +1,15 @@ #include "AudioSample.h" #include "AudioSynth.h" #include "AudioWriter.h" +#include "WasapiInterface.h" #include "TestCase.h" #include "TestCaseRunner.h" #include #include +#include +#include class TestWriteWav : public TestCase { @@ -24,11 +27,30 @@ public: } }; +class TestAudioRender : public TestCase +{ +public: + bool Run() override + { + WasapiInterface audio_interface; + auto device = AudioDevice::Create(); + audio_interface.Play(device); + return true; + } +}; + +//int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) int main() { + CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + std::cout << "into entry point" << std::endl; TestCaseRunner runner; - runner.AddTestCase("TestWriteNav", std::make_unique()); + //runner.AddTestCase("TestWriteNav", std::make_unique()); + runner.AddTestCase("TestAudioRender", std::make_unique()); const auto testsPassed = runner.Run(); return testsPassed ? 0 : -1; + + CoUninitialize(); }