UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2023 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "pch.h" 30 31 #include "toolkit.h" 32 33 #include <cx/allocator.h> 34 #include <cx/mempool.h> 35 36 #include "../common/context.h" 37 #include "../common/document.h" 38 #include "../common/toolbar.h" 39 #include "../common/properties.h" 40 41 #include "icons.h" 42 43 #include "MainWindow.xaml.h" 44 45 #include "App.xaml.h" 46 47 using namespace winrt; 48 using namespace Microsoft::UI::Xaml; 49 using namespace Microsoft::UI::Xaml::Controls; 50 using namespace Microsoft::UI::Xaml::XamlTypeInfo; 51 using namespace Microsoft::UI::Xaml::Markup; 52 using namespace Windows::UI::Xaml::Interop; 53 using namespace winrt::Windows::Foundation; 54 using namespace Windows::UI::Core; 55 56 static const char* application_name; 57 58 static ui_callback startup_func; 59 static void* startup_data; 60 61 static ui_callback open_func; 62 void* open_data; 63 64 static ui_callback exit_func; 65 void* exit_data; 66 67 static ui_callback appclose_fnc; 68 69 static void* appclose_udata; 70 71 72 static UiObject* active_window; 73 74 static winrt::Microsoft::UI::Dispatching::DispatcherQueue uiDispatcherQueue = { nullptr }; 75 76 void ui_app_run_startup() { 77 uiDispatcherQueue = winrt::Microsoft::UI::Dispatching::DispatcherQueue::GetForCurrentThread(); 78 79 if (startup_func) { 80 startup_func(NULL, startup_data); 81 } 82 } 83 84 class App : public ApplicationT<App, IXamlMetadataProvider> { 85 public: 86 void OnLaunched(LaunchActivatedEventArgs const&) { 87 Resources().MergedDictionaries().Append(XamlControlsResources()); 88 if (startup_func) { 89 startup_func(NULL, startup_data); 90 } 91 92 //auto window = make<winui::implementation::MainWindow>(); 93 //window.Activate(); 94 } 95 IXamlType GetXamlType(TypeName const& type) { 96 return provider.GetXamlType(type); 97 } 98 IXamlType GetXamlType(hstring const& fullname) { 99 return provider.GetXamlType(fullname); 100 } 101 com_array<XmlnsDefinition> GetXmlnsDefinitions() { 102 return provider.GetXmlnsDefinitions(); 103 } 104 private: 105 XamlControlsXamlMetaDataProvider provider; 106 }; 107 108 UiWidget::UiWidget(winrt::Microsoft::UI::Xaml::UIElement& elm) : uielement(elm) {} 109 110 extern "C" void destroy_ui_window_wrapper(void* ptr) { 111 UiWindow* win = (UiWindow*)ptr; 112 delete win; 113 } 114 115 extern "C" void destroy_ui_widget_wrapper(void* ptr) { 116 UiWidget* widget = (UiWidget*)ptr; 117 delete widget; 118 } 119 120 extern "C" void destroy_ui_container_wrapper(void* ptr) { 121 UiContainer* ctn = (UiContainer*)ptr; 122 delete ctn; 123 } 124 125 void ui_context_add_window_destructor(UiContext* ctx, UiWindow* win) { 126 cxMempoolRegister(ctx->mp, win, destroy_ui_window_wrapper); 127 } 128 129 void ui_context_add_widget_destructor(UiContext* ctx, UiWidget* widget) { 130 cxMempoolRegister(ctx->mp, widget, destroy_ui_widget_wrapper); 131 } 132 133 void ui_context_add_container_destructor(UiContext* ctx, UiContainer *container) { 134 cxMempoolRegister(ctx->mp, container, destroy_ui_container_wrapper); 135 } 136 137 138 UiEvent ui_create_int_event(UiObject* obj, int64_t i) { 139 UiEvent evt; 140 evt.obj = obj; 141 evt.window = obj->window; 142 evt.document = obj->ctx->document; 143 evt.eventdata = nullptr; 144 evt.intval = i; 145 return evt; 146 } 147 148 149 #include <MddBootstrap.h> 150 151 void ui_appsdk_bootstrap(void) { 152 const UINT32 majorMinorVersion{ 0x00010002 }; 153 PCWSTR versionTag{ ""L }; 154 const PACKAGE_VERSION minVersion{}; 155 156 const HRESULT hr = MddBootstrapInitialize(majorMinorVersion, versionTag, minVersion); 157 if (FAILED(hr)) { 158 exit(102); 159 } 160 } 161 162 void ui_init(const char* appname, int argc, char** argv) { 163 application_name = appname; 164 165 //ui_appsdk_bootstrap(); 166 167 uic_init_global_context(); 168 uic_docmgr_init(); 169 uic_menu_init(); 170 uic_toolbar_init(); 171 172 uic_load_app_properties(); 173 } 174 175 const char* ui_appname() { 176 return application_name; 177 } 178 179 void ui_onstartup(ui_callback f, void* userdata) { 180 startup_func = f; 181 startup_data = userdata; 182 } 183 184 void ui_onopen(ui_callback f, void* userdata) { 185 open_func = f; 186 open_data = userdata; 187 } 188 189 void ui_onexit(ui_callback f, void* userdata) { 190 exit_func = f; 191 exit_data = userdata; 192 } 193 194 void ui_main() { 195 /* 196 init_apartment(); 197 //Application::Start([](auto&&) {make<App>(); }); 198 199 ::winrt::Microsoft::UI::Xaml::Application::Start( 200 [](auto&&) 201 { 202 ::winrt::make<::winrt::winui::implementation::App>(); 203 }); 204 */ 205 { 206 void (WINAPI * pfnXamlCheckProcessRequirements)(); 207 auto module = ::LoadLibrary("Microsoft.ui.xaml.dll"L); 208 if (module) 209 { 210 pfnXamlCheckProcessRequirements = reinterpret_cast<decltype(pfnXamlCheckProcessRequirements)>(GetProcAddress(module, "XamlCheckProcessRequirements")); 211 if (pfnXamlCheckProcessRequirements) 212 { 213 (*pfnXamlCheckProcessRequirements)(); 214 } 215 216 ::FreeLibrary(module); 217 } 218 } 219 220 winrt::init_apartment(winrt::apartment_type::single_threaded); 221 ::winrt::Microsoft::UI::Xaml::Application::Start( 222 [](auto&&) 223 { 224 ::winrt::make<::winrt::winui::implementation::App>(); 225 }); 226 } 227 228 class UiWin { 229 public: 230 Window window; 231 }; 232 233 void ui_show(UiObject* obj) { 234 if (obj->wobj) { 235 obj->wobj->window.Activate(); 236 } else if(obj->widget && obj->widget->Show) { 237 obj->widget->Show(); 238 } 239 } 240 241 void ui_close(UiObject* obj) { 242 if (obj->wobj) { 243 obj->wobj->window.Close(); 244 } 245 } 246 247 static void ui_job_thread(UiJob* job) { 248 if (!job->job_func(job->job_data) && job->finish_callback) { 249 bool isQueued = uiDispatcherQueue.TryEnqueue([job]() 250 { 251 UiEvent event; 252 event.obj = job->obj; 253 event.window = job->obj->window; 254 event.document = job->obj->ctx->document; 255 event.intval = 0; 256 event.eventdata = NULL; 257 job->finish_callback(&event, job->finish_data); 258 delete job; 259 }); 260 if (!isQueued) { 261 // TODO: error or try again? 262 exit(-1); 263 } 264 } 265 else { 266 delete job; 267 } 268 } 269 270 UIEXPORT void ui_job(UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { 271 UiJob* job = new UiJob; 272 job->obj = obj; 273 job->job_func = tf; 274 job->job_data = td; 275 job->finish_callback = f; 276 job->finish_data = fd; 277 278 std::thread jobThread(ui_job_thread, job); 279 jobThread.detach(); 280 } 281 282 UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td) { 283 bool isQueued = uiDispatcherQueue.TryEnqueue([tf, td]() 284 { 285 (void)tf(td); 286 }); 287 if (!isQueued) { 288 // TODO: error or try again? 289 exit(-1); 290 } 291 } 292 293 static UiJob kill_job; // &kill_job indicates to stop the thread 294 295 static void ui_threadpool_run(UiThreadpool* pool) { 296 for (;;) { 297 UiJob* job = pool->GetJob(); 298 if (job == &kill_job) { 299 return; 300 } 301 else if (job) { 302 ui_job_thread(job); 303 } 304 } 305 } 306 307 UiThreadpool::UiThreadpool(int nthreads) { 308 for (int i = 0; i < nthreads; i++) { 309 std::thread thread(ui_threadpool_run, this); 310 thread.detach(); 311 } 312 } 313 314 void UiThreadpool::EnqueueJob(UiJob* job) 315 { 316 std::unique_lock<std::mutex> lock(mutex); 317 queue.push(job); 318 lock.unlock(); 319 condition.notify_one(); 320 } 321 322 UiJob* UiThreadpool::GetJob() { 323 std::unique_lock<std::mutex> lock(mutex); 324 325 UiJob* job = nullptr; 326 while (!job) { 327 if (queue.empty()) { 328 condition.wait(lock); 329 continue; 330 } 331 else 332 { 333 job = queue.front(); 334 queue.pop(); 335 } 336 } 337 338 return job; 339 } 340 341 UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads) { 342 return new UiThreadpool(nthreads); 343 } 344 345 UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool) { 346 // TODO 347 } 348 349 UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { 350 UiJob* job = new UiJob; 351 job->obj = obj; 352 job->job_func = tf; 353 job->job_data = td; 354 job->finish_callback = f; 355 job->finish_data = fd; 356 pool->EnqueueJob(job); 357 } 358 359 360 361 void ui_set_widget_groups(UiContext *ctx, UIWIDGET widget, const int *groups) { 362 if(!groups) { 363 return; 364 } 365 size_t ngroups = uic_group_array_size(groups); 366 ui_set_widget_ngroups(ctx, widget, groups, ngroups); 367 } 368 369 void ui_set_widget_ngroups(UiContext *ctx, UIWIDGET widget, const int *groups, size_t ngroups) { 370 if(ngroups > 0) { 371 uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); 372 ui_set_enabled(widget, FALSE); 373 } 374 } 375 376 377 UIEXPORT void ui_set_enabled(UIWIDGET widget, int enabled) { 378 Control ctrl = widget->uielement.as<Control>(); 379 if (ctrl) { 380 ctrl.IsEnabled(enabled); 381 } 382 } 383