#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);
}
}
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;
uic_init_global_context();
uic_docmgr_init();
uic_menu_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() {
{
void (
WINAPI * pfnXamlCheckProcessRequirements)();
auto module = ::LoadLibrary(
"Microsoft.ui.xaml.dll"L);
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) {
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) {
exit(-
1);
}
}
static UiJob kill_job;
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) {
}
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);
}
}