Fri, 15 Nov 2024 21:25:35 +0100
add ui_dialog_window reference counting (GTK)
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2023 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "pch.h" #include "toolkit.h" #include <cx/allocator.h> #include <cx/mempool.h> #include "../common/context.h" #include "../common/document.h" #include "../common/toolbar.h" #include "../common/properties.h" #include "icons.h" #include "MainWindow.xaml.h" #include "App.xaml.h" using namespace winrt; using namespace Microsoft::UI::Xaml; using namespace Microsoft::UI::Xaml::Controls; using namespace Microsoft::UI::Xaml::XamlTypeInfo; using namespace Microsoft::UI::Xaml::Markup; using namespace Windows::UI::Xaml::Interop; using namespace winrt::Windows::Foundation; using namespace Windows::UI::Core; static const char* application_name; static ui_callback startup_func; static void* startup_data; static ui_callback open_func; void* open_data; static ui_callback exit_func; void* exit_data; static ui_callback appclose_fnc; static void* appclose_udata; static UiObject* active_window; static winrt::Microsoft::UI::Dispatching::DispatcherQueue uiDispatcherQueue = { nullptr }; void ui_app_run_startup() { uiDispatcherQueue = winrt::Microsoft::UI::Dispatching::DispatcherQueue::GetForCurrentThread(); if (startup_func) { startup_func(NULL, startup_data); } } class App : public ApplicationT<App, IXamlMetadataProvider> { public: void OnLaunched(LaunchActivatedEventArgs const&) { Resources().MergedDictionaries().Append(XamlControlsResources()); if (startup_func) { startup_func(NULL, startup_data); } //auto window = make<winui::implementation::MainWindow>(); //window.Activate(); } IXamlType GetXamlType(TypeName const& type) { return provider.GetXamlType(type); } IXamlType GetXamlType(hstring const& fullname) { return provider.GetXamlType(fullname); } com_array<XmlnsDefinition> GetXmlnsDefinitions() { return provider.GetXmlnsDefinitions(); } private: XamlControlsXamlMetaDataProvider provider; }; UiWidget::UiWidget(winrt::Microsoft::UI::Xaml::UIElement& elm) : uielement(elm) {} extern "C" void destroy_ui_window_wrapper(void* ptr) { UiWindow* win = (UiWindow*)ptr; delete win; } extern "C" void destroy_ui_widget_wrapper(void* ptr) { UiWidget* widget = (UiWidget*)ptr; delete widget; } extern "C" void destroy_ui_container_wrapper(void* ptr) { UiContainer* ctn = (UiContainer*)ptr; delete ctn; } void ui_context_add_window_destructor(UiContext* ctx, UiWindow* win) { cxMempoolRegister(ctx->mp, win, destroy_ui_window_wrapper); } void ui_context_add_widget_destructor(UiContext* ctx, UiWidget* widget) { cxMempoolRegister(ctx->mp, widget, destroy_ui_widget_wrapper); } void ui_context_add_container_destructor(UiContext* ctx, UiContainer *container) { cxMempoolRegister(ctx->mp, container, destroy_ui_container_wrapper); } UiEvent ui_create_int_event(UiObject* obj, int64_t i) { UiEvent evt; evt.obj = obj; evt.window = obj->window; evt.document = obj->ctx->document; evt.eventdata = nullptr; evt.intval = i; return evt; } #include <MddBootstrap.h> void ui_appsdk_bootstrap(void) { const UINT32 majorMinorVersion{ 0x00010002 }; PCWSTR versionTag{ L"" }; const PACKAGE_VERSION minVersion{}; const HRESULT hr = MddBootstrapInitialize(majorMinorVersion, versionTag, minVersion); if (FAILED(hr)) { exit(102); } } void ui_init(const char* appname, int argc, char** argv) { application_name = appname; //ui_appsdk_bootstrap(); uic_init_global_context(); uic_docmgr_init(); uic_toolbar_init(); uic_load_app_properties(); } const char* ui_appname() { return application_name; } void ui_onstartup(ui_callback f, void* userdata) { startup_func = f; startup_data = userdata; } void ui_onopen(ui_callback f, void* userdata) { open_func = f; open_data = userdata; } void ui_onexit(ui_callback f, void* userdata) { exit_func = f; exit_data = userdata; } void ui_main() { /* init_apartment(); //Application::Start([](auto&&) {make<App>(); }); ::winrt::Microsoft::UI::Xaml::Application::Start( [](auto&&) { ::winrt::make<::winrt::winui::implementation::App>(); }); */ { void (WINAPI * pfnXamlCheckProcessRequirements)(); auto module = ::LoadLibrary(L"Microsoft.ui.xaml.dll"); if (module) { pfnXamlCheckProcessRequirements = reinterpret_cast<decltype(pfnXamlCheckProcessRequirements)>(GetProcAddress(module, "XamlCheckProcessRequirements")); if (pfnXamlCheckProcessRequirements) { (*pfnXamlCheckProcessRequirements)(); } ::FreeLibrary(module); } } winrt::init_apartment(winrt::apartment_type::single_threaded); ::winrt::Microsoft::UI::Xaml::Application::Start( [](auto&&) { ::winrt::make<::winrt::winui::implementation::App>(); }); } class UiWin { public: Window window; }; void ui_show(UiObject* obj) { if (obj->wobj) { obj->wobj->window.Activate(); } else if(obj->widget && obj->widget->Show) { obj->widget->Show(); } } void ui_close(UiObject* obj) { if (obj->wobj) { obj->wobj->window.Close(); } } static void ui_job_thread(UiJob* job) { if (!job->job_func(job->job_data) && job->finish_callback) { bool isQueued = uiDispatcherQueue.TryEnqueue([job]() { UiEvent event; event.obj = job->obj; event.window = job->obj->window; event.document = job->obj->ctx->document; event.intval = 0; event.eventdata = NULL; job->finish_callback(&event, job->finish_data); delete job; }); if (!isQueued) { // TODO: error or try again? exit(-1); } } else { delete job; } } UIEXPORT void ui_job(UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { UiJob* job = new UiJob; job->obj = obj; job->job_func = tf; job->job_data = td; job->finish_callback = f; job->finish_data = fd; std::thread jobThread(ui_job_thread, job); jobThread.detach(); } UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td) { bool isQueued = uiDispatcherQueue.TryEnqueue([tf, td]() { (void)tf(td); }); if (!isQueued) { // TODO: error or try again? exit(-1); } } static UiJob kill_job; // &kill_job indicates to stop the thread static void ui_threadpool_run(UiThreadpool* pool) { for (;;) { UiJob* job = pool->GetJob(); if (job == &kill_job) { return; } else if (job) { ui_job_thread(job); } } } UiThreadpool::UiThreadpool(int nthreads) { for (int i = 0; i < nthreads; i++) { std::thread thread(ui_threadpool_run, this); thread.detach(); } } void UiThreadpool::EnqueueJob(UiJob* job) { std::unique_lock<std::mutex> lock(mutex); queue.push(job); lock.unlock(); condition.notify_one(); } UiJob* UiThreadpool::GetJob() { std::unique_lock<std::mutex> lock(mutex); UiJob* job = nullptr; while (!job) { if (queue.empty()) { condition.wait(lock); continue; } else { job = queue.front(); queue.pop(); } } return job; } UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads) { return new UiThreadpool(nthreads); } UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool) { // TODO } UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { UiJob* job = new UiJob; job->obj = obj; job->job_func = tf; job->job_data = td; job->finish_callback = f; job->finish_data = fd; pool->EnqueueJob(job); } void ui_set_widget_groups(UiContext *ctx, UIWIDGET widget, const int *groups) { if(!groups) { return; } size_t ngroups = uic_group_array_size(groups); ui_set_widget_ngroups(ctx, widget, groups, ngroups); } void ui_set_widget_ngroups(UiContext *ctx, UIWIDGET widget, const int *groups, size_t ngroups) { if(ngroups > 0) { uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); ui_set_enabled(widget, FALSE); } } UIEXPORT void ui_set_enabled(UIWIDGET widget, int enabled) { Control ctrl = widget->uielement.as<Control>(); if (ctrl) { ctrl.IsEnabled(enabled); } }