ui/winui/toolkit.cpp

changeset 431
bb7da585debc
parent 388
473c03f85197
equal deleted inserted replaced
169:fe49cff3c571 431:bb7da585debc
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(L"Microsoft.ui.xaml.dll");
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 }

mercurial