diff --git a/Import/GacUI.UnitTest.UI.cpp b/Import/GacUI.UnitTest.UI.cpp index 916f07dc..736f80b2 100644 --- a/Import/GacUI.UnitTest.UI.cpp +++ b/Import/GacUI.UnitTest.UI.cpp @@ -48,8 +48,8 @@ Helper Functions } void InstallDom( - const remoteprotocol::RenderingTrace& trace, - const remoteprotocol::RenderingFrame& frame, + const remoteprotocol::UnitTest_RenderingTrace& trace, + const remoteprotocol::UnitTest_RenderingFrame& frame, GuiGraphicsComposition* container, vint x, vint y, @@ -59,17 +59,17 @@ Helper Functions auto bounds = new GuiBoundsComposition; container->AddChild(bounds); - bounds->SetExpectedBounds(Rect({ dom->bounds.x1 - x,dom->bounds.y1 - y }, { dom->bounds.Width(),dom->bounds.Height() })); + bounds->SetExpectedBounds(Rect({ dom->content.bounds.x1 - x,dom->content.bounds.y1 - y }, { dom->content.bounds.Width(),dom->content.bounds.Height() })); - auto cursor = dom->cursor; - if (dom->cursor) + auto cursor = dom->content.cursor; + if (dom->content.cursor) { cursorCounter++; } - if (dom->hitTestResult && cursorCounter == 0) + if (dom->content.hitTestResult && cursorCounter == 0) { - switch (dom->hitTestResult.Value()) + switch (dom->content.hitTestResult.Value()) { case INativeWindowListener::BorderLeft: case INativeWindowListener::BorderRight: @@ -104,9 +104,9 @@ Helper Functions bounds->SetAssociatedCursor(GetCurrentController()->ResourceService()->GetSystemCursor(cursor.Value())); } - if (dom->element) + if (dom->content.element) { - switch (trace.createdElements->Get(dom->element.Value())) + switch (trace.createdElements->Get(dom->content.element.Value())) { case remoteprotocol::RendererType::FocusRectangle: { @@ -118,7 +118,7 @@ Helper Functions { auto element = Ptr(GuiSolidBorderElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetColor(desc.borderColor); element->SetShape(desc.shape); @@ -128,7 +128,7 @@ Helper Functions { auto element = Ptr(Gui3DBorderElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetColors(desc.leftTopColor, desc.rightBottomColor); } @@ -137,7 +137,7 @@ Helper Functions { auto element = Ptr(Gui3DSplitterElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetColors(desc.leftTopColor, desc.rightBottomColor); element->SetDirection(desc.direction); @@ -147,7 +147,7 @@ Helper Functions { auto element = Ptr(GuiSolidBackgroundElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetColor(desc.backgroundColor); element->SetShape(desc.shape); @@ -157,7 +157,7 @@ Helper Functions { auto element = Ptr(GuiGradientBackgroundElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetColors(desc.leftTopColor, desc.rightBottomColor); element->SetDirection(desc.direction); @@ -168,7 +168,7 @@ Helper Functions { auto element = Ptr(GuiInnerShadowElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetColor(desc.shadowColor); element->SetThickness(desc.thickness); @@ -178,7 +178,7 @@ Helper Functions { auto element = Ptr(GuiSolidLabelElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetColor(desc.textColor); element->SetAlignments(GetAlignment(desc.horizontalAlignment), GetAlignment(desc.verticalAlignment)); @@ -194,7 +194,7 @@ Helper Functions { auto element = Ptr(GuiPolygonElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetSize(desc.size); element->SetBorderColor(desc.borderColor); @@ -210,7 +210,7 @@ Helper Functions { auto element = Ptr(GuiImageFrameElement::Create()); bounds->SetOwnedElement(element); - auto& desc = frame.elements->Get(dom->element.Value()).Get(); + auto& desc = frame.elements->Get(dom->content.element.Value()).Get(); element->SetAlignments(GetAlignment(desc.horizontalAlignment), GetAlignment(desc.verticalAlignment)); element->SetStretch(desc.stretch); @@ -238,17 +238,17 @@ Helper Functions { for (auto child : *dom->children.Obj()) { - InstallDom(trace, frame, bounds, dom->bounds.x1, dom->bounds.y1, child, cursorCounter); + InstallDom(trace, frame, bounds, dom->content.bounds.x1, dom->content.bounds.y1, child, cursorCounter); } } - if (dom->cursor) + if (dom->content.cursor) { cursorCounter--; } } - GuiBoundsComposition* BuildRootComposition(const remoteprotocol::RenderingTrace& trace, const remoteprotocol::RenderingFrame& frame) + GuiBoundsComposition* BuildRootComposition(const remoteprotocol::UnitTest_RenderingTrace& trace, const remoteprotocol::UnitTest_RenderingFrame& frame) { vint w = frame.windowSize.clientBounds.Width().value; vint h = frame.windowSize.clientBounds.Height().value; @@ -373,24 +373,6 @@ Closures //------------------------------------------------------------------- - __vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_::__vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0) - :__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0)) - { - } - - void __vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const - { - auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings(); - auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerStringsStrings>>(__vwsn_value_); - if ((__vwsn_old_.Obj() == __vwsn_new_.Obj())) - { - return; - } - ::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_); - } - - //------------------------------------------------------------------- - __vwsnf1_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_::__vwsnf1_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0) :__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0)) { @@ -491,13 +473,13 @@ Closures void __vwsnf8_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const { - auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_22)->GetText(); + auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetText(); auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_); if ((__vwsn_old_ == __vwsn_new_)) { return; } - ::vl::__vwsn::This(__vwsnthis_0->__vwsn_precompile_22)->SetText(__vwsn_new_); + ::vl::__vwsn::This(__vwsnthis_0->self)->SetText(__vwsn_new_); } //------------------------------------------------------------------- @@ -509,13 +491,13 @@ Closures void __vwsnf9_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_::operator()(const ::vl::reflection::description::Value& __vwsn_value_) const { - auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetText(); - auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::WString>(__vwsn_value_); - if ((__vwsn_old_ == __vwsn_new_)) + auto __vwsn_old_ = ::vl::__vwsn::This(__vwsnthis_0->self)->GetStrings(); + auto __vwsn_new_ = ::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerStringsStrings>>(__vwsn_value_); + if ((__vwsn_old_.Obj() == __vwsn_new_.Obj())) { return; } - ::vl::__vwsn::This(__vwsnthis_0->self)->SetText(__vwsn_new_); + ::vl::__vwsn::This(__vwsnthis_0->self)->SetStrings(__vwsn_new_); } //------------------------------------------------------------------- @@ -665,7 +647,7 @@ Closures void __vwsnc3_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_() { - auto __vwsn_bind_activator_result_ = [&](){ try{ return ::vl::__vwsn::This(::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IUnitTestSnapshotFrame>>(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetSelectedItem()).Obj())->GetCommandsAsJsonText(); } catch(...){ return ::vl::WString::Unmanaged(L""); } }(); + auto __vwsn_bind_activator_result_ = [&](){ try{ return ::vl::__vwsn::This(::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IUnitTestSnapshotFrame>>(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetSelectedItem()).Obj())->GetElementsAsJsonText(); } catch(...){ return ::vl::WString::Unmanaged(L""); } }(); ::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_)); } @@ -715,10 +697,11 @@ Closures //------------------------------------------------------------------- - __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0) - :__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0)) + __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0) + :__vwsn_this_(__vwsnctor___vwsn_this_) + , __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0)) { - this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiBindableTextList*>(nullptr); + this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::UnitTestSnapshotViewerWindow*>(nullptr); this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>(); this->__vwsn_bind_opened_ = false; this->__vwsn_bind_closed_ = false; @@ -726,11 +709,11 @@ Closures void __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_() { - auto __vwsn_bind_activator_result_ = [&](){ try{ return ::vl::__vwsn::This(::vl::__vwsn::Unbox<::vl::Ptr<::gaclib_controls::IUnitTestSnapshotFrame>>(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetSelectedItem()).Obj())->GetElementsAsJsonText(); } catch(...){ return ::vl::WString::Unmanaged(L""); } }(); + auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->WindowTitle(); ::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_)); } - void __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1) + void __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0() { this->__vwsn_bind_activator_(); } @@ -740,8 +723,8 @@ Closures if ((! __vwsn_bind_opened_)) { (__vwsn_bind_opened_ = true); - (__vwsn_bind_cache_0 = [&](){ try{ return __vwsnthis_0->textListFrames; } catch(...){ return static_cast<::vl::presentation::controls::GuiBindableTextList*>(nullptr); } }()); - (__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->SelectionChanged, ::vl::Func(this, &__vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }()); + (__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::UnitTestSnapshotViewerWindow*>(nullptr); } }()); + (__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func(this, &__vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }()); return true; } return false; @@ -764,10 +747,10 @@ Closures (__vwsn_bind_closed_ = true); if (static_cast(__vwsn_bind_handler_0_0)) { - ::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->SelectionChanged, __vwsn_bind_handler_0_0); + ::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0); (__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>()); } - (__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiBindableTextList*>(nullptr)); + (__vwsn_bind_cache_0 = static_cast<::gaclib_controls::UnitTestSnapshotViewerWindow*>(nullptr)); (__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>()); return true; } @@ -776,11 +759,10 @@ Closures //------------------------------------------------------------------- - __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0) - :__vwsn_this_(__vwsnctor___vwsn_this_) - , __vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0)) + __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0) + :__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0)) { - this->__vwsn_bind_cache_0 = static_cast<::gaclib_controls::UnitTestSnapshotViewerWindow*>(nullptr); + this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>(); this->__vwsn_bind_opened_ = false; this->__vwsn_bind_closed_ = false; @@ -788,7 +770,7 @@ Closures void __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_() { - auto __vwsn_bind_activator_result_ = ::vl::__vwsn::This(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetStrings().Obj())->WindowTitle(); + auto __vwsn_bind_activator_result_ = ::gaclib_controls::UnitTestSnapshotViewerStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale()); ::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_)); } @@ -802,8 +784,8 @@ Closures if ((! __vwsn_bind_opened_)) { (__vwsn_bind_opened_ = true); - (__vwsn_bind_cache_0 = [&](){ try{ return __vwsn_this_; } catch(...){ return static_cast<::gaclib_controls::UnitTestSnapshotViewerWindow*>(nullptr); } }()); - (__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, ::vl::Func(this, &__vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }()); + (__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }()); + (__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func(this, &__vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }()); return true; } return false; @@ -820,67 +802,6 @@ Closures } bool __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::Close() - { - if ((! __vwsn_bind_closed_)) - { - (__vwsn_bind_closed_ = true); - if (static_cast(__vwsn_bind_handler_0_0)) - { - ::vl::__vwsn::EventDetach(::vl::__vwsn::This(__vwsn_bind_cache_0)->StringsChanged, __vwsn_bind_handler_0_0); - (__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>()); - } - (__vwsn_bind_cache_0 = static_cast<::gaclib_controls::UnitTestSnapshotViewerWindow*>(nullptr)); - (__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>()); - return true; - } - return false; - } - - //------------------------------------------------------------------- - - __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0) - :__vwsnthis_0(::vl::__vwsn::This(__vwsnctorthis_0)) - { - this->__vwsn_bind_cache_0 = static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); - this->__vwsn_bind_handler_0_0 = ::vl::Ptr<::vl::reflection::description::IEventHandler>(); - this->__vwsn_bind_opened_ = false; - this->__vwsn_bind_closed_ = false; - } - - void __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_activator_() - { - auto __vwsn_bind_activator_result_ = ::gaclib_controls::UnitTestSnapshotViewerStrings::Get(::vl::__vwsn::This(__vwsn_bind_cache_0)->GetLocale()); - ::vl::__vwsn::EventInvoke(this->ValueChanged)(::vl::__vwsn::Box(__vwsn_bind_activator_result_)); - } - - void __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0() - { - this->__vwsn_bind_activator_(); - } - - bool __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::Open() - { - if ((! __vwsn_bind_opened_)) - { - (__vwsn_bind_opened_ = true); - (__vwsn_bind_cache_0 = [&](){ try{ return ::vl::presentation::controls::GetApplication(); } catch(...){ return static_cast<::vl::presentation::controls::GuiApplication*>(nullptr); } }()); - (__vwsn_bind_handler_0_0 = [&](){ try{ return ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_bind_cache_0)->LocaleChanged, ::vl::Func(this, &__vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::__vwsn_bind_callback_0_0)); } catch(...){ return ::vl::Ptr<::vl::reflection::description::IEventHandler>(); } }()); - return true; - } - return false; - } - - bool __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::Update() - { - if ((__vwsn_bind_opened_ && (! __vwsn_bind_closed_))) - { - this->__vwsn_bind_activator_(); - return true; - } - return false; - } - - bool __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription::Close() { if ((! __vwsn_bind_closed_)) { @@ -899,11 +820,11 @@ Closures //------------------------------------------------------------------- - __vwsnc7_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings::__vwsnc7_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings() + __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings::__vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings() { } - ::vl::WString __vwsnc7_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings::WindowTitle() + ::vl::WString __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings::WindowTitle() { return ::vl::WString::Unmanaged(L"Unit Test Snapshot Viewer"); } @@ -934,7 +855,7 @@ Class (::gaclib_controls::UnitTestSnapshotViewerStrings) ::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerStringsStrings> UnitTestSnapshotViewerStrings::__vwsn_ls_en_US_BuildStrings(::vl::Locale __vwsn_ls_locale) { - return ::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerStringsStrings>(new ::vl_workflow_global::__vwsnc7_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings()); + return ::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerStringsStrings>(new ::vl_workflow_global::__vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings()); } void UnitTestSnapshotViewerStrings::Install(::vl::Locale __vwsn_ls_locale, ::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerStringsStrings> __vwsn_ls_impl) @@ -971,15 +892,15 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) ::vl::__vwsn::This(this->self)->SetClientSize([&](){ ::vl::presentation::Size __vwsn_temp__; __vwsn_temp__.x = static_cast<::vl::vint>(1920); __vwsn_temp__.y = static_cast<::vl::vint>(1080); return __vwsn_temp__; }()); } (this->__vwsn_precompile_0 = new ::vl::presentation::compositions::GuiTableComposition()); + { + ::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren); + } { ::vl::__vwsn::This(this->__vwsn_precompile_0)->SetCellPadding(static_cast<::vl::vint>(5)); } { ::vl::__vwsn::This(this->__vwsn_precompile_0)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }()); } - { - ::vl::__vwsn::This(this->__vwsn_precompile_0)->SetMinSizeLimitation(::vl::presentation::compositions::GuiGraphicsComposition::MinSizeLimitation::LimitToElementAndChildren); - } { ::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowsAndColumns(static_cast<::vl::vint>(1), static_cast<::vl::vint>(4)); ::vl::__vwsn::This(this->__vwsn_precompile_0)->SetRowOption(static_cast<::vl::vint>(0), [&](){ ::vl::presentation::compositions::GuiCellOption __vwsn_temp__; __vwsn_temp__.composeType = ::vl::presentation::compositions::GuiCellOption::ComposeType::Percentage; __vwsn_temp__.percentage = static_cast(1.0); return __vwsn_temp__; }()); @@ -1013,12 +934,6 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) { ::vl::__vwsn::This(this->treeViewFileNodes)->SetChildrenProperty(vl::Func(::vl_workflow_global::__vwsnf1_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(this))); } - { - ::vl::__vwsn::This(this->treeViewFileNodes)->SetHorizontalAlwaysVisible(false); - } - { - ::vl::__vwsn::This(this->treeViewFileNodes)->SetVerticalAlwaysVisible(false); - } { ::vl::__vwsn::This(this->treeViewFileNodes)->SetTextProperty(vl::Func(::vl_workflow_global::__vwsnf2_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(this))); } @@ -1026,6 +941,12 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) { ::vl::__vwsn::This(this->__vwsn_precompile_4)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }()); } + { + ::vl::__vwsn::This(this->treeViewFileNodes)->SetHorizontalAlwaysVisible(false); + } + { + ::vl::__vwsn::This(this->treeViewFileNodes)->SetVerticalAlwaysVisible(false); + } { ::vl::__vwsn::This(this->__vwsn_precompile_3)->AddChild(static_cast<::vl::presentation::compositions::GuiGraphicsComposition*>(::vl::__vwsn::This(this->treeViewFileNodes)->GetBoundsComposition())); } @@ -1049,12 +970,6 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) (this->textListFrames = new ::vl::presentation::controls::GuiBindableTextList(::vl::presentation::theme::ThemeName::TextList)); ::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"textListFrames"), ::vl::__vwsn::Box(this->textListFrames)); } - { - ::vl::__vwsn::This(this->textListFrames)->SetHorizontalAlwaysVisible(false); - } - { - ::vl::__vwsn::This(this->textListFrames)->SetVerticalAlwaysVisible(false); - } { ::vl::__vwsn::This(this->textListFrames)->SetTextProperty(vl::Func(::vl_workflow_global::__vwsnf3_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(this))); } @@ -1062,6 +977,12 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) { ::vl::__vwsn::This(this->__vwsn_precompile_9)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }()); } + { + ::vl::__vwsn::This(this->textListFrames)->SetHorizontalAlwaysVisible(false); + } + { + ::vl::__vwsn::This(this->textListFrames)->SetVerticalAlwaysVisible(false); + } { ::vl::__vwsn::This(this->__vwsn_precompile_8)->AddChild(static_cast<::vl::presentation::controls::GuiControl*>(this->textListFrames)); } @@ -1096,16 +1017,16 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) (this->scRendering = new ::vl::presentation::controls::GuiScrollContainer(::vl::presentation::theme::ThemeName::ScrollView)); ::vl::__vwsn::This(__vwsn_this_)->SetNamedObject(::vl::WString::Unmanaged(L"scRendering"), ::vl::__vwsn::Box(this->scRendering)); } + (this->__vwsn_precompile_14 = ::vl::__vwsn::This(this->scRendering)->GetBoundsComposition()); + { + ::vl::__vwsn::This(this->__vwsn_precompile_14)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }()); + } { ::vl::__vwsn::This(this->scRendering)->SetHorizontalAlwaysVisible(false); } { ::vl::__vwsn::This(this->scRendering)->SetVerticalAlwaysVisible(false); } - (this->__vwsn_precompile_14 = ::vl::__vwsn::This(this->scRendering)->GetBoundsComposition()); - { - ::vl::__vwsn::This(this->__vwsn_precompile_14)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }()); - } { ::vl::__vwsn::This(this->__vwsn_precompile_13)->AddChild(static_cast<::vl::presentation::controls::GuiControl*>(this->scRendering)); } @@ -1122,16 +1043,16 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) { (this->__vwsn_precompile_16 = new ::vl::presentation::controls::GuiMultilineTextBox(::vl::presentation::theme::ThemeName::MultilineTextBox)); } + (this->__vwsn_precompile_17 = ::vl::__vwsn::This(this->__vwsn_precompile_16)->GetBoundsComposition()); + { + ::vl::__vwsn::This(this->__vwsn_precompile_17)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }()); + } { ::vl::__vwsn::This(this->__vwsn_precompile_16)->SetHorizontalAlwaysVisible(false); } { ::vl::__vwsn::This(this->__vwsn_precompile_16)->SetVerticalAlwaysVisible(false); } - (this->__vwsn_precompile_17 = ::vl::__vwsn::This(this->__vwsn_precompile_16)->GetBoundsComposition()); - { - ::vl::__vwsn::This(this->__vwsn_precompile_17)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }()); - } { ::vl::__vwsn::This(this->__vwsn_precompile_15)->AddChild(static_cast<::vl::presentation::controls::GuiControl*>(this->__vwsn_precompile_16)); } @@ -1143,21 +1064,21 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) (this->__vwsn_precompile_18 = new ::vl::presentation::controls::GuiTabPage(::vl::presentation::theme::ThemeName::CustomControl)); } { - ::vl::__vwsn::This(this->__vwsn_precompile_18)->SetText(::vl::WString::Unmanaged(L"Commands")); + ::vl::__vwsn::This(this->__vwsn_precompile_18)->SetText(::vl::WString::Unmanaged(L"Elements")); } { (this->__vwsn_precompile_19 = new ::vl::presentation::controls::GuiMultilineTextBox(::vl::presentation::theme::ThemeName::MultilineTextBox)); } + (this->__vwsn_precompile_20 = ::vl::__vwsn::This(this->__vwsn_precompile_19)->GetBoundsComposition()); + { + ::vl::__vwsn::This(this->__vwsn_precompile_20)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }()); + } { ::vl::__vwsn::This(this->__vwsn_precompile_19)->SetHorizontalAlwaysVisible(false); } { ::vl::__vwsn::This(this->__vwsn_precompile_19)->SetVerticalAlwaysVisible(false); } - (this->__vwsn_precompile_20 = ::vl::__vwsn::This(this->__vwsn_precompile_19)->GetBoundsComposition()); - { - ::vl::__vwsn::This(this->__vwsn_precompile_20)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }()); - } { ::vl::__vwsn::This(this->__vwsn_precompile_18)->AddChild(static_cast<::vl::presentation::controls::GuiControl*>(this->__vwsn_precompile_19)); } @@ -1165,32 +1086,6 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) auto __vwsn_collection_ = ::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueObservableList>(::vl::__vwsn::This(this->__vwsn_precompile_11)->GetPages()); ::vl::__vwsn::This(__vwsn_collection_.Obj())->Add(::vl::__vwsn::Box(this->__vwsn_precompile_18)); } - { - (this->__vwsn_precompile_21 = new ::vl::presentation::controls::GuiTabPage(::vl::presentation::theme::ThemeName::CustomControl)); - } - { - ::vl::__vwsn::This(this->__vwsn_precompile_21)->SetText(::vl::WString::Unmanaged(L"Elements")); - } - { - (this->__vwsn_precompile_22 = new ::vl::presentation::controls::GuiMultilineTextBox(::vl::presentation::theme::ThemeName::MultilineTextBox)); - } - { - ::vl::__vwsn::This(this->__vwsn_precompile_22)->SetHorizontalAlwaysVisible(false); - } - { - ::vl::__vwsn::This(this->__vwsn_precompile_22)->SetVerticalAlwaysVisible(false); - } - (this->__vwsn_precompile_23 = ::vl::__vwsn::This(this->__vwsn_precompile_22)->GetBoundsComposition()); - { - ::vl::__vwsn::This(this->__vwsn_precompile_23)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(5); __vwsn_temp__.top = static_cast<::vl::vint>(5); __vwsn_temp__.right = static_cast<::vl::vint>(5); __vwsn_temp__.bottom = static_cast<::vl::vint>(5); return __vwsn_temp__; }()); - } - { - ::vl::__vwsn::This(this->__vwsn_precompile_21)->AddChild(static_cast<::vl::presentation::controls::GuiControl*>(this->__vwsn_precompile_22)); - } - { - auto __vwsn_collection_ = ::vl::__vwsn::UnboxCollection<::vl::reflection::description::IValueObservableList>(::vl::__vwsn::This(this->__vwsn_precompile_11)->GetPages()); - ::vl::__vwsn::This(__vwsn_collection_.Obj())->Add(::vl::__vwsn::Box(this->__vwsn_precompile_21)); - } (this->__vwsn_precompile_12 = ::vl::__vwsn::This(this->__vwsn_precompile_11)->GetBoundsComposition()); { ::vl::__vwsn::This(this->__vwsn_precompile_12)->SetAlignmentToParent([&](){ ::vl::presentation::Margin __vwsn_temp__; __vwsn_temp__.left = static_cast<::vl::vint>(0); __vwsn_temp__.top = static_cast<::vl::vint>(0); __vwsn_temp__.right = static_cast<::vl::vint>(0); __vwsn_temp__.bottom = static_cast<::vl::vint>(0); return __vwsn_temp__; }()); @@ -1226,25 +1121,23 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) ::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_); } { - auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(this)); + auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this)); ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf8_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(this))); ::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_); } { - auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(__vwsn_this_, this)); + auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(this)); ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf9_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(this))); ::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_); } - { - auto __vwsn_created_subscription_ = ::vl::Ptr<::vl::reflection::description::IValueSubscription>(new ::vl_workflow_global::__vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(this)); - ::vl::__vwsn::EventAttach(::vl::__vwsn::This(__vwsn_created_subscription_.Obj())->ValueChanged, vl::Func(::vl_workflow_global::__vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(this))); - ::vl::__vwsn::This(__vwsn_this_)->AddSubscription(__vwsn_created_subscription_); - } } UnitTestSnapshotViewerWindowConstructor::UnitTestSnapshotViewerWindowConstructor() - : self(static_cast<::gaclib_controls::UnitTestSnapshotViewerWindow*>(nullptr)) - , ViewModel(::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerViewModel>()) + : ViewModel(::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerViewModel>()) + , self(static_cast<::gaclib_controls::UnitTestSnapshotViewerWindow*>(nullptr)) + , treeViewFileNodes(static_cast<::vl::presentation::controls::GuiBindableTreeView*>(nullptr)) + , textListFrames(static_cast<::vl::presentation::controls::GuiBindableTextList*>(nullptr)) + , scRendering(static_cast<::vl::presentation::controls::GuiScrollContainer*>(nullptr)) , __vwsn_precompile_0(static_cast<::vl::presentation::compositions::GuiTableComposition*>(nullptr)) , __vwsn_precompile_1(static_cast<::vl::presentation::compositions::GuiColumnSplitterComposition*>(nullptr)) , __vwsn_precompile_2(static_cast<::vl::presentation::compositions::GuiColumnSplitterComposition*>(nullptr)) @@ -1266,12 +1159,6 @@ Class (::gaclib_controls::UnitTestSnapshotViewerWindowConstructor) , __vwsn_precompile_18(static_cast<::vl::presentation::controls::GuiTabPage*>(nullptr)) , __vwsn_precompile_19(static_cast<::vl::presentation::controls::GuiMultilineTextBox*>(nullptr)) , __vwsn_precompile_20(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr)) - , __vwsn_precompile_21(static_cast<::vl::presentation::controls::GuiTabPage*>(nullptr)) - , __vwsn_precompile_22(static_cast<::vl::presentation::controls::GuiMultilineTextBox*>(nullptr)) - , __vwsn_precompile_23(static_cast<::vl::presentation::compositions::GuiBoundsComposition*>(nullptr)) - , treeViewFileNodes(static_cast<::vl::presentation::controls::GuiBindableTreeView*>(nullptr)) - , textListFrames(static_cast<::vl::presentation::controls::GuiBindableTextList*>(nullptr)) - , scRendering(static_cast<::vl::presentation::controls::GuiScrollContainer*>(nullptr)) { } @@ -1445,20 +1332,20 @@ UnitTestSnapshotFrame class UnitTestSnapshotFrame : public Object, public virtual IUnitTestSnapshotFrame { protected: - vint index; - RenderingFrame frame; - WString elements; - WString commands; - WString dom; - JsonFormatting formatting; + vint index; + UnitTest_RenderingFrame frame; + WString elements; + WString commands; + WString dom; + JsonFormatting formatting; - friend const remoteprotocol::RenderingFrame& GetRenderingFrame(Ptr frame) + friend const remoteprotocol::UnitTest_RenderingFrame& GetRenderingFrame(Ptr frame) { return frame.Cast()->frame; } public: - UnitTestSnapshotFrame(vint _index, RenderingFrame _frame) + UnitTestSnapshotFrame(vint _index, UnitTest_RenderingFrame _frame) : index(_index) , frame(_frame) { @@ -1489,15 +1376,6 @@ UnitTestSnapshotFrame return elements; } - WString GetCommandsAsJsonText() override - { - if (commands == L"") - { - commands = JsonToString(ConvertCustomTypeToJson(frame.commands), formatting); - } - return commands; - } - WString GetDomAsJsonText() override { if (dom == L"") @@ -1516,10 +1394,10 @@ UnitTestSnapshotFileNode { protected: File file; - Ptr renderingTrace; + Ptr renderingTrace; List> frames; - friend const remoteprotocol::RenderingTrace& GetRenderingTrace(Ptr node) + friend const remoteprotocol::UnitTest_RenderingTrace& GetRenderingTrace(Ptr node) { return *node.Cast()->renderingTrace.Obj(); } @@ -1534,7 +1412,7 @@ UnitTestSnapshotFileNode glr::json::Parser parser; jsonNode = JsonParse(jsonText, parser); } - renderingTrace = Ptr(new RenderingTrace); + renderingTrace = Ptr(new UnitTest_RenderingTrace); ConvertJsonToCustomType(jsonNode, *renderingTrace.Obj()); frames.Clear(); diff --git a/Import/GacUI.UnitTest.UI.h b/Import/GacUI.UnitTest.UI.h index 6551dcba..b38ed8b6 100644 --- a/Import/GacUI.UnitTest.UI.h +++ b/Import/GacUI.UnitTest.UI.h @@ -38,7 +38,6 @@ https://github.com/vczh-libraries namespace vl_workflow_global { - struct __vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; struct __vwsnf1_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; struct __vwsnf2_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; struct __vwsnf3_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; @@ -53,8 +52,7 @@ namespace vl_workflow_global class __vwsnc3_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; class __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; class __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; - class __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; - class __vwsnc7_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings; + class __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings; } namespace __vwsn_enums @@ -101,7 +99,6 @@ namespace gaclib_controls public: virtual ::vl::WString GetName() = 0; virtual ::vl::WString GetElementsAsJsonText() = 0; - virtual ::vl::WString GetCommandsAsJsonText() = 0; virtual ::vl::WString GetDomAsJsonText() = 0; }; @@ -125,7 +122,7 @@ namespace gaclib_controls class UnitTestSnapshotViewerStrings : public ::vl::Object, public ::vl::reflection::Description { - friend class ::vl_workflow_global::__vwsnc7_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings; + friend class ::vl_workflow_global::__vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings; #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA friend struct ::vl::reflection::description::CustomTypeDescriptorSelector; #endif @@ -143,8 +140,6 @@ namespace gaclib_controls friend class ::vl_workflow_global::__vwsnc3_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; friend class ::vl_workflow_global::__vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; friend class ::vl_workflow_global::__vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; - friend class ::vl_workflow_global::__vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; - friend struct ::vl_workflow_global::__vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; friend struct ::vl_workflow_global::__vwsnf1_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; friend struct ::vl_workflow_global::__vwsnf2_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; friend struct ::vl_workflow_global::__vwsnf3_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; @@ -158,8 +153,11 @@ namespace gaclib_controls friend struct ::vl::reflection::description::CustomTypeDescriptorSelector; #endif protected: - ::gaclib_controls::UnitTestSnapshotViewerWindow* self; ::vl::Ptr<::gaclib_controls::IUnitTestSnapshotViewerViewModel> ViewModel; + ::gaclib_controls::UnitTestSnapshotViewerWindow* self; + ::vl::presentation::controls::GuiBindableTreeView* treeViewFileNodes; + ::vl::presentation::controls::GuiBindableTextList* textListFrames; + ::vl::presentation::controls::GuiScrollContainer* scRendering; ::vl::presentation::compositions::GuiTableComposition* __vwsn_precompile_0; ::vl::presentation::compositions::GuiColumnSplitterComposition* __vwsn_precompile_1; ::vl::presentation::compositions::GuiColumnSplitterComposition* __vwsn_precompile_2; @@ -181,12 +179,6 @@ namespace gaclib_controls ::vl::presentation::controls::GuiTabPage* __vwsn_precompile_18; ::vl::presentation::controls::GuiMultilineTextBox* __vwsn_precompile_19; ::vl::presentation::compositions::GuiBoundsComposition* __vwsn_precompile_20; - ::vl::presentation::controls::GuiTabPage* __vwsn_precompile_21; - ::vl::presentation::controls::GuiMultilineTextBox* __vwsn_precompile_22; - ::vl::presentation::compositions::GuiBoundsComposition* __vwsn_precompile_23; - ::vl::presentation::controls::GuiBindableTreeView* treeViewFileNodes; - ::vl::presentation::controls::GuiBindableTextList* textListFrames; - ::vl::presentation::controls::GuiScrollContainer* scRendering; void __vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize(::gaclib_controls::UnitTestSnapshotViewerWindow* __vwsn_this_); public: UnitTestSnapshotViewerWindowConstructor(); @@ -200,8 +192,6 @@ namespace gaclib_controls friend class ::vl_workflow_global::__vwsnc3_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; friend class ::vl_workflow_global::__vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; friend class ::vl_workflow_global::__vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; - friend class ::vl_workflow_global::__vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription; - friend struct ::vl_workflow_global::__vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; friend struct ::vl_workflow_global::__vwsnf1_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; friend struct ::vl_workflow_global::__vwsnf2_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; friend struct ::vl_workflow_global::__vwsnf3_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_; @@ -251,15 +241,6 @@ namespace vl_workflow_global Closures ***********************************************************************/ - struct __vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_ - { - ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnthis_0; - - __vwsnf10_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0); - - void operator()(const ::vl::reflection::description::Value& __vwsn_value_) const; - }; - struct __vwsnf1_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize_ { ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnthis_0; @@ -397,29 +378,11 @@ Closures class __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription : public ::vl::Object, public virtual ::vl::reflection::description::IValueSubscription { - public: - ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnthis_0; - - __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0); - - ::vl::presentation::controls::GuiBindableTextList* __vwsn_bind_cache_0 = nullptr; - ::vl::Ptr<::vl::reflection::description::IEventHandler> __vwsn_bind_handler_0_0; - bool __vwsn_bind_opened_ = false; - bool __vwsn_bind_closed_ = false; - void __vwsn_bind_activator_(); - void __vwsn_bind_callback_0_0(::vl::presentation::compositions::GuiGraphicsComposition* __vwsn_bind_callback_argument_0, ::vl::presentation::compositions::GuiEventArgs* __vwsn_bind_callback_argument_1); - bool Open() override; - bool Update() override; - bool Close() override; - }; - - class __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription : public ::vl::Object, public virtual ::vl::reflection::description::IValueSubscription - { public: ::gaclib_controls::UnitTestSnapshotViewerWindow* __vwsn_this_; ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnthis_0; - __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0); + __vwsnc4_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindow* __vwsnctor___vwsn_this_, ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0); ::gaclib_controls::UnitTestSnapshotViewerWindow* __vwsn_bind_cache_0 = nullptr; ::vl::Ptr<::vl::reflection::description::IEventHandler> __vwsn_bind_handler_0_0; @@ -432,12 +395,12 @@ Closures bool Close() override; }; - class __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription : public ::vl::Object, public virtual ::vl::reflection::description::IValueSubscription + class __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription : public ::vl::Object, public virtual ::vl::reflection::description::IValueSubscription { public: ::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnthis_0; - __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0); + __vwsnc5_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerWindowConstructor___vwsn_gaclib_controls_UnitTestSnapshotViewerWindow_Initialize__vl_reflection_description_IValueSubscription(::gaclib_controls::UnitTestSnapshotViewerWindowConstructor* __vwsnctorthis_0); ::vl::presentation::controls::GuiApplication* __vwsn_bind_cache_0 = nullptr; ::vl::Ptr<::vl::reflection::description::IEventHandler> __vwsn_bind_handler_0_0; @@ -450,10 +413,10 @@ Closures bool Close() override; }; - class __vwsnc7_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings : public ::vl::Object, public virtual ::gaclib_controls::IUnitTestSnapshotViewerStringsStrings + class __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings : public ::vl::Object, public virtual ::gaclib_controls::IUnitTestSnapshotViewerStringsStrings { public: - __vwsnc7_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings(); + __vwsnc6_GuiUnitTestSnapshotViewer_gaclib_controls_UnitTestSnapshotViewerStrings___vwsn_ls_en_US_BuildStrings__gaclib_controls_IUnitTestSnapshotViewerStringsStrings(); ::vl::WString WindowTitle() override; }; @@ -495,8 +458,8 @@ https://github.com/vczh-libraries namespace vl::presentation::remoteprotocol { - struct RenderingFrame; - struct RenderingTrace; + struct UnitTest_RenderingFrame; + struct UnitTest_RenderingTrace; } namespace vl::presentation::unittest @@ -515,8 +478,8 @@ namespace vl::presentation::unittest Ptr GetRootNode() override; }; - extern const remoteprotocol::RenderingTrace& GetRenderingTrace(Ptr node); - extern const remoteprotocol::RenderingFrame& GetRenderingFrame(Ptr frame); + extern const remoteprotocol::UnitTest_RenderingTrace& GetRenderingTrace(Ptr node); + extern const remoteprotocol::UnitTest_RenderingFrame& GetRenderingFrame(Ptr frame); } /*********************************************************************** diff --git a/Import/GacUI.UnitTest.UIReflection.cpp b/Import/GacUI.UnitTest.UIReflection.cpp index 20c542be..013c5a85 100644 --- a/Import/GacUI.UnitTest.UIReflection.cpp +++ b/Import/GacUI.UnitTest.UIReflection.cpp @@ -64,11 +64,9 @@ namespace vl BEGIN_INTERFACE_MEMBER(::gaclib_controls::IUnitTestSnapshotFrame) CLASS_MEMBER_BASE(::vl::reflection::IDescriptable) - CLASS_MEMBER_METHOD(GetCommandsAsJsonText, NO_PARAMETER) CLASS_MEMBER_METHOD(GetDomAsJsonText, NO_PARAMETER) CLASS_MEMBER_METHOD(GetElementsAsJsonText, NO_PARAMETER) CLASS_MEMBER_METHOD(GetName, NO_PARAMETER) - CLASS_MEMBER_PROPERTY_READONLY(CommandsAsJsonText, GetCommandsAsJsonText) CLASS_MEMBER_PROPERTY_READONLY(DomAsJsonText, GetDomAsJsonText) CLASS_MEMBER_PROPERTY_READONLY(ElementsAsJsonText, GetElementsAsJsonText) CLASS_MEMBER_PROPERTY_READONLY(Name, GetName) @@ -133,9 +131,6 @@ namespace vl CLASS_MEMBER_FIELD(__vwsn_precompile_19) CLASS_MEMBER_FIELD(__vwsn_precompile_2) CLASS_MEMBER_FIELD(__vwsn_precompile_20) - CLASS_MEMBER_FIELD(__vwsn_precompile_21) - CLASS_MEMBER_FIELD(__vwsn_precompile_22) - CLASS_MEMBER_FIELD(__vwsn_precompile_23) CLASS_MEMBER_FIELD(__vwsn_precompile_3) CLASS_MEMBER_FIELD(__vwsn_precompile_4) CLASS_MEMBER_FIELD(__vwsn_precompile_5) diff --git a/Import/GacUI.UnitTest.UIReflection.h b/Import/GacUI.UnitTest.UIReflection.h index d5402d90..65d57e6a 100644 --- a/Import/GacUI.UnitTest.UIReflection.h +++ b/Import/GacUI.UnitTest.UIReflection.h @@ -86,10 +86,6 @@ namespace vl END_INTERFACE_PROXY(::gaclib_controls::IUnitTestSnapshotFileNode) BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(::gaclib_controls::IUnitTestSnapshotFrame) - ::vl::WString GetCommandsAsJsonText() override - { - INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetCommandsAsJsonText); - } ::vl::WString GetDomAsJsonText() override { INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetDomAsJsonText); diff --git a/Import/GacUI.UnitTest.cpp b/Import/GacUI.UnitTest.cpp index 32d427d0..3d3fe2c9 100644 --- a/Import/GacUI.UnitTest.cpp +++ b/Import/GacUI.UnitTest.cpp @@ -146,9 +146,167 @@ File GacUIUnitTest_PrepareSnapshotFile(const WString& appName, const WString& ex #undef ERROR_MESSAGE_PREFIX } +void GacUIUnitTest_WriteSnapshotFileIfChanged(File& snapshotFile, const WString& textLog) +{ +#define ERROR_MESSAGE_PREFIX L"GacUIUnitTest_WriteSnapshotFileIfChanged(File&, const WString&)#" + bool skipWriting = false; + if (snapshotFile.Exists()) + { + auto previousLog = snapshotFile.ReadAllTextByBom(); + if (previousLog == textLog) + { + skipWriting = true; + } + } + if (!skipWriting) + { + bool succeeded = snapshotFile.WriteAllText(textLog, true, stream::BomEncoder::Utf8); + CHECK_ERROR(succeeded, ERROR_MESSAGE_PREFIX L"Failed to write the snapshot file."); + } +#undef ERROR_MESSAGE_PREFIX +} + +void GacUIUnitTest_LogUI(const WString& appName, UnitTestRemoteProtocol& unitTestProtocol) +{ +#define ERROR_MESSAGE_PREFIX L"GacUIUnitTest_LogUI(const WString&, UnitTestRemoteProtocol&)#" + File snapshotFile = GacUIUnitTest_PrepareSnapshotFile(appName, WString::Unmanaged(L".json")); + + JsonFormatting formatting; + formatting.spaceAfterColon = true; + formatting.spaceAfterComma = true; + formatting.crlf = true; + formatting.compact = true; + + auto jsonLog = remoteprotocol::ConvertCustomTypeToJson(unitTestProtocol.GetLoggedTrace()); + auto textLog = JsonToString(jsonLog, formatting); + { + remoteprotocol::UnitTest_RenderingTrace deserialized; + remoteprotocol::ConvertJsonToCustomType(jsonLog, deserialized); + auto jsonLog2 = remoteprotocol::ConvertCustomTypeToJson(deserialized); + auto textLog2 = JsonToString(jsonLog2, formatting); + CHECK_ERROR(textLog == textLog2, ERROR_MESSAGE_PREFIX L"Serialization and deserialization doesn't match."); + } + + GacUIUnitTest_WriteSnapshotFileIfChanged(snapshotFile, textLog); +#undef ERROR_MESSAGE_PREFIX +} + +void GacUIUnitTest_LogCommands(const WString& appName, UnitTestRemoteProtocol& unitTestProtocol) +{ + File snapshotFile = GacUIUnitTest_PrepareSnapshotFile(appName, WString::Unmanaged(L"[commands].txt")); + + JsonFormatting formatting; + formatting.spaceAfterColon = true; + formatting.spaceAfterComma = true; + formatting.crlf = false; + formatting.compact = true; + + auto textLog = stream::GenerateToStream([&unitTestProtocol, &formatting](stream::TextWriter& writer) + { + auto&& loggedFrames = unitTestProtocol.GetLoggedFrames(); + for (auto loggedFrame : loggedFrames) + { + writer.WriteLine(L"========================================"); + writer.WriteLine(itow(loggedFrame->frameId)); + writer.WriteLine(L"========================================"); + for (auto&& commandLog : loggedFrame->renderingCommandsLog) + { + writer.WriteLine(commandLog); + } + }; + }); + + GacUIUnitTest_WriteSnapshotFileIfChanged(snapshotFile, textLog); +} + +void GacUIUnitTest_LogDiffs(const WString& appName, UnitTestRemoteProtocol& unitTestProtocol) +{ + File snapshotFile = GacUIUnitTest_PrepareSnapshotFile(appName, WString::Unmanaged(L"[diffs].txt")); + + JsonFormatting formatting; + formatting.spaceAfterColon = true; + formatting.spaceAfterComma = true; + formatting.crlf = false; + formatting.compact = true; + + auto textLog = stream::GenerateToStream([&unitTestProtocol, &formatting](stream::TextWriter& writer) + { + Ptr dom; + DomIndex domIndex; + auto&& loggedFrames = unitTestProtocol.GetLoggedFrames(); + for (auto loggedFrame : loggedFrames) + { + writer.WriteLine(L"========================================"); + writer.WriteLine(itow(loggedFrame->frameId)); + writer.WriteLine(L"========================================"); + + if (!dom) + { + dom = loggedFrame->renderingDom; + BuildDomIndex(dom, domIndex); + + List>> lines; + lines.Add({ 0,dom }); + for (vint i = 0; i < lines.Count(); i++) + { + for (vint j = 0; j < lines[i].key; j++) + { + writer.WriteString(L" "); + } + + auto line = lines[i].value; + writer.WriteString(itow(line->id)); + writer.WriteString(L": "); + + auto jsonLog = remoteprotocol::ConvertCustomTypeToJson(line->content); + writer.WriteLine(JsonToString(jsonLog, formatting)); + + if (line->children) + { + for (auto child : *line->children.Obj()) + { + lines.Add({ lines[i].key + 1,child }); + } + } + } + } + else + { + DomIndex nextDomIndex; + BuildDomIndex(loggedFrame->renderingDom, nextDomIndex); + + Ptr> diffList; + if (loggedFrame->renderingDiffs) + { + diffList = loggedFrame->renderingDiffs.Value().diffsInOrder; + } + else + { + RenderingDom_DiffsInOrder diffs; + DiffDom(dom, domIndex, loggedFrame->renderingDom, nextDomIndex, diffs); + diffList = diffs.diffsInOrder; + } + + if (diffList) + { + for (auto&& diff : *diffList.Obj()) + { + auto jsonLog = remoteprotocol::ConvertCustomTypeToJson(diff); + writer.WriteLine(JsonToString(jsonLog, formatting)); + } + } + + dom = loggedFrame->renderingDom; + domIndex = std::move(nextDomIndex); + } + }; + }); + + GacUIUnitTest_WriteSnapshotFileIfChanged(snapshotFile, textLog); +} + void GacUIUnitTest_Start(const WString& appName, Nullable config) { -#define ERROR_MESSAGE_PREFIX L"GacUIUnitTest_Start(const WString&, Nullable)#" UnitTestScreenConfig globalConfig; if (config) { @@ -159,50 +317,131 @@ void GacUIUnitTest_Start(const WString& appName, Nullable globalConfig.FastInitialize(1024, 768); } + // Renderer UnitTestRemoteProtocol unitTestProtocol(appName, globalConfig); - repeatfiltering::GuiRemoteProtocolFilterVerifier verifierProtocol(unitTestProtocol.GetProtocol()); + auto jsonParser = Ptr(new glr::json::Parser); + + // Data Processing in Renderer + channeling::GuiRemoteJsonChannelFromProtocol channelReceiver(unitTestProtocol.GetProtocol()); + channeling::GuiRemoteJsonChannelStringDeserializer channelJsonDeserializer(&channelReceiver, jsonParser); + channeling::GuiRemoteUtfStringChannelDeserializer channelUtf8Deserializer(&channelJsonDeserializer); + + // Boundary between Binaries + + // Data Processing in Core + channeling::GuiRemoteUtfStringChannelSerializer channelUtf8Serializer(&channelUtf8Deserializer); + channeling::GuiRemoteJsonChannelStringSerializer channelJsonSerializer(&channelUtf8Serializer, jsonParser); + + // Boundary between threads + + channeling::GuiRemoteProtocolFromJsonChannel channelSender(&channelJsonSerializer); + + // Core + repeatfiltering::GuiRemoteProtocolFilterVerifier verifierProtocol( + globalConfig.useChannel == UnitTestRemoteChannel::None + ? unitTestProtocol.GetProtocol() + : &channelSender + ); repeatfiltering::GuiRemoteProtocolFilter filteredProtocol(&verifierProtocol); + GuiRemoteProtocolDomDiffConverter diffConverterProtocol(&filteredProtocol); UnitTestContextImpl unitTestContext(&unitTestProtocol); guiMainUnitTestContext = &unitTestContext; - SetupRemoteNativeController(&filteredProtocol); + SetupRemoteNativeController( + globalConfig.useDomDiff + ? static_cast(&diffConverterProtocol) + : &filteredProtocol + ); GacUIUnitTest_SetGuiMainProxy({}); + GacUIUnitTest_LogUI(appName, unitTestProtocol); + if (!globalConfig.useDomDiff) { - File snapshotFile = GacUIUnitTest_PrepareSnapshotFile(appName, WString::Unmanaged(L".json")); - - JsonFormatting formatting; - formatting.spaceAfterColon = true; - formatting.spaceAfterComma = true; - formatting.crlf = true; - formatting.compact = true; - - auto jsonLog = remoteprotocol::ConvertCustomTypeToJson(unitTestProtocol.GetLoggedTrace()); - auto textLog = JsonToString(jsonLog, formatting); - { - remoteprotocol::RenderingTrace deserialized; - remoteprotocol::ConvertJsonToCustomType(jsonLog, deserialized); - auto jsonLog2 = remoteprotocol::ConvertCustomTypeToJson(deserialized); - auto textLog2 = JsonToString(jsonLog2, formatting); - CHECK_ERROR(textLog == textLog2, ERROR_MESSAGE_PREFIX L"Serialization and deserialization doesn't match."); - } - - bool skipWriting = false; - if (snapshotFile.Exists()) - { - auto previousLog = snapshotFile.ReadAllTextByBom(); - if (previousLog == textLog) - { - skipWriting = true; - } - } - if (!skipWriting) - { - bool succeeded = snapshotFile.WriteAllText(textLog, true, stream::BomEncoder::Utf8); - CHECK_ERROR(succeeded, ERROR_MESSAGE_PREFIX L"Failed to write the snapshot file."); - } + GacUIUnitTest_LogCommands(appName, unitTestProtocol); } -#undef ERROR_MESSAGE_PREFIX + GacUIUnitTest_LogDiffs(appName, unitTestProtocol); +} + +template +void RunInNewThread(T&& threadProc) +{ + Thread::CreateAndStart([threadProc]() + { + try + { + threadProc(); + } + catch (const Exception& e) + { + (void)e; + throw; + } + catch (const Error& e) + { + (void)e; + throw; + } + }); +} + +void GacUIUnitTest_StartAsync(const WString& appName, Nullable config) +{ + TEST_ASSERT(config && config.Value().useChannel == UnitTestRemoteChannel::Async); + + // Renderer + UnitTestRemoteProtocol unitTestProtocol(appName, config.Value()); + auto jsonParser = Ptr(new glr::json::Parser); + + // Data Processing in Renderer + channeling::GuiRemoteJsonChannelFromProtocol channelReceiver(unitTestProtocol.GetProtocol()); + channeling::GuiRemoteJsonChannelStringDeserializer channelJsonDeserializer(&channelReceiver, jsonParser); + channeling::GuiRemoteUtfStringChannelDeserializer channelUtf8Deserializer(&channelJsonDeserializer); + + // Boundary between Binaries + + // Data Processing in Core + channeling::GuiRemoteUtfStringChannelSerializer channelUtf8Serializer(&channelUtf8Deserializer); + channeling::GuiRemoteJsonChannelStringSerializer channelJsonSerializer(&channelUtf8Serializer, jsonParser); + + // Boundary between threads + + channeling::GuiRemoteProtocolAsyncJsonChannelSerializer asyncChannelSender; + asyncChannelSender.Start( + &channelJsonSerializer, + [&unitTestProtocol, config](channeling::GuiRemoteProtocolAsyncJsonChannelSerializer* channel) + { + channeling::GuiRemoteProtocolFromJsonChannel channelSender(channel); + + // Core + repeatfiltering::GuiRemoteProtocolFilterVerifier verifierProtocol(&channelSender); + repeatfiltering::GuiRemoteProtocolFilter filteredProtocol(&verifierProtocol); + GuiRemoteProtocolDomDiffConverter diffConverterProtocol(&filteredProtocol); + + UnitTestContextImpl unitTestContext(&unitTestProtocol); + guiMainUnitTestContext = &unitTestContext; + SetupRemoteNativeController( + config.Value().useDomDiff + ? static_cast(&diffConverterProtocol) + : &filteredProtocol + ); + GacUIUnitTest_SetGuiMainProxy({}); + }, + []( + channeling::GuiRemoteProtocolAsyncJsonChannelSerializer::TChannelThreadProc channelThreadProc, + channeling::GuiRemoteProtocolAsyncJsonChannelSerializer::TUIThreadProc uiThreadProc + ) + { + RunInNewThread(channelThreadProc); + RunInNewThread(uiThreadProc); + }); + + asyncChannelSender.WaitForStopped(); + GacUIUnitTest_LogUI(appName, unitTestProtocol); + if (!config.Value().useDomDiff) + { + GacUIUnitTest_LogCommands(appName, unitTestProtocol); + } + GacUIUnitTest_LogDiffs(appName, unitTestProtocol); } void GacUIUnitTest_Start_WithResourceAsText(const WString& appName, Nullable config, const WString& resourceText) @@ -240,7 +479,15 @@ void GacUIUnitTest_Start_WithResourceAsText(const WString& appName, Nullable(const WindowStyleConfig&) const = default; }; + enum class UnitTestRemoteChannel + { + None, + Sync, + Async, + }; + struct UnitTestScreenConfig { using FontConfig = vl::presentation::remoteprotocol::FontConfig; @@ -56,6 +63,8 @@ namespace vl::presentation::unittest NativeMargin customFramePadding; FontConfig fontConfig; ScreenConfig screenConfig; + bool useDomDiff = false; + UnitTestRemoteChannel useChannel = UnitTestRemoteChannel::None; void FastInitialize(vint width, vint height, vint taskBarHeight = 0); }; @@ -594,11 +603,18 @@ namespace vl::presentation::unittest UnitTestRemoteProtocol ***********************************************************************/ - using ElementDescVariant = remoteprotocol::ElementDescVariant; - using UnitTestRenderingCommand = remoteprotocol::RenderingCommand; - using UnitTestRenderingCommandList = collections::List; - using UnitTestRenderingCommandListRef = Ptr; + using ElementDescVariant = remoteprotocol::UnitTest_ElementDescVariant; using UnitTestRenderingDom = remoteprotocol::RenderingDom; + + struct UnitTestLoggedFrame + { + vint frameId; + collections::List renderingCommandsLog; + Nullable renderingDiffs; + Ptr renderingDom; + }; + + using UnitTestLoggedFrameList = collections::List>; template class UnitTestRemoteProtocol_Rendering : public TProtocol @@ -607,20 +623,25 @@ UnitTestRemoteProtocol using Base64ToImageMetadataMap = collections::Dictionary; using ElementDescMap = collections::Dictionary; using ImageMetadataMap = collections::Dictionary; - using CommandList = UnitTestRenderingCommandList; - using CommandListRef = UnitTestRenderingCommandListRef; + protected: + remoteprotocol::RenderingDomBuilder renderingDomBuilder; + remoteprotocol::UnitTest_RenderingTrace loggedTrace; + UnitTestLoggedFrameList loggedFrames; + bool lastRenderingCommandsOpening = false; - remoteprotocol::RenderingTrace loggedTrace; - ElementDescMap lastElementDescs; - IdSet removedElementIds; - IdSet removedImageIds; - Ptr cachedImageMetadatas; + Ptr receivedDom; + remoteprotocol::DomIndex receivedDomIndex; + bool receivedDomDiffMessage = false; + bool receivedElementMessage = false; - remoteprotocol::ElementMeasurings measuringForNextRendering; - regex::Regex regexCrLf{ L"/n|/r(/n)?" }; - vint lastFrameId = 0; - CommandListRef lastRenderingCommands; + ElementDescMap lastElementDescs; + IdSet removedElementIds; + IdSet removedImageIds; + Ptr cachedImageMetadatas; + + remoteprotocol::ElementMeasurings measuringForNextRendering; + regex::Regex regexCrLf{ L"/n|/r(/n)?" }; void ResetCreatedObjects() { @@ -636,7 +657,7 @@ UnitTestRemoteProtocol : TProtocol(std::forward(args)...) { ResetCreatedObjects(); - loggedTrace.frames = Ptr(new collections::List); + loggedTrace.frames = Ptr(new collections::List); } protected: @@ -645,49 +666,112 @@ UnitTestRemoteProtocol IGuiRemoteProtocolMessages (Rendering) ***********************************************************************/ + Ptr GetLastRenderingFrame() + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::GetLastRenderingCommands()#" + CHECK_ERROR(lastRenderingCommandsOpening, ERROR_MESSAGE_PREFIX L"The latest frame of commands is not accepting new commands."); + return loggedFrames[loggedFrames.Count() - 1]; +#undef ERROR_MESSAGE_PREFIX + } + + Ptr TryGetLastRenderingFrameAndReset() + { + if (loggedFrames.Count() == 0) return nullptr; + if (!lastRenderingCommandsOpening) return nullptr; + lastRenderingCommandsOpening = false; + return loggedFrames[loggedFrames.Count() - 1]; + } + void RequestRendererBeginRendering(const remoteprotocol::ElementBeginRendering& arguments) override { - lastFrameId = arguments.frameId; - lastRenderingCommands = Ptr(new CommandList); + receivedDomDiffMessage = false; + receivedElementMessage = false; + lastRenderingCommandsOpening = true; + auto frame = Ptr(new UnitTestLoggedFrame); + frame->frameId = arguments.frameId; + loggedFrames.Add(frame); } void RequestRendererEndRendering(vint id) override { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::RequestRendererEndRendering(vint)#" + CHECK_ERROR(receivedElementMessage || receivedDomDiffMessage, ERROR_MESSAGE_PREFIX L"Either dom-diff or element message should be sent before this message."); + + auto lastFrame = GetLastRenderingFrame(); + if (receivedElementMessage) + { + lastFrame->renderingDom = renderingDomBuilder.RequestRendererEndRendering(); + } + if (receivedDomDiffMessage) + { + // receivedDom will be updated in RequestRendererRenderDomDiff + // store a copy to log + lastFrame->renderingDom = CopyDom(receivedDom); + } this->GetEvents()->RespondRendererEndRendering(id, measuringForNextRendering); measuringForNextRendering = {}; +#undef ERROR_MESSAGE_PREFIX } +/*********************************************************************** +IGuiRemoteProtocolMessages (Rendering - Element) +***********************************************************************/ + void RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments) override { - lastRenderingCommands->Add(remoteprotocol::RenderingCommand_BeginBoundary{ arguments }); +#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::RequestRendererBeginBoundary(const ElementBoundary&)#" + CHECK_ERROR(!receivedDomDiffMessage, ERROR_MESSAGE_PREFIX L"This message could not be used with dom-diff messages in the same rendering cycle."); + if (!receivedElementMessage) + { + renderingDomBuilder.RequestRendererBeginRendering(); + receivedElementMessage = true; + } + + renderingDomBuilder.RequestRendererBeginBoundary(arguments); + + glr::json::JsonFormatting formatting; + formatting.spaceAfterColon = true; + formatting.spaceAfterComma = true; + formatting.crlf = false; + formatting.compact = true; + + GetLastRenderingFrame()->renderingCommandsLog.Add(L"RequestRendererBeginBoundary: " + stream::GenerateToStream([&](stream::TextWriter& writer) + { + auto jsonLog = remoteprotocol::ConvertCustomTypeToJson(arguments); + writer.WriteString(glr::json::JsonToString(jsonLog, formatting)); + })); +#undef ERROR_MESSAGE_PREFIX } void RequestRendererEndBoundary() override { - lastRenderingCommands->Add(remoteprotocol::RenderingCommand_EndBoundary{}); +#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::RequestRendererEndBoundary()#" + CHECK_ERROR(!receivedDomDiffMessage, ERROR_MESSAGE_PREFIX L"This message could not be used with dom-diff messages in the same rendering cycle."); + if (!receivedElementMessage) + { + renderingDomBuilder.RequestRendererBeginRendering(); + receivedElementMessage = true; + } + + renderingDomBuilder.RequestRendererEndBoundary(); + GetLastRenderingFrame()->renderingCommandsLog.Add(L"RequestRendererEndBoundary"); +#undef ERROR_MESSAGE_PREFIX } - template - void RequestRendererRenderElement(const remoteprotocol::ElementRendering& rendering, const T& element) + void EnsureRenderedElement(vint id, Rect bounds) { - lastRenderingCommands->Add(remoteprotocol::RenderingCommand_Element{ rendering,element.id }); - } +#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::EnsureRenderedElement(id&)#" - void RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments) override - { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::RequestRendererRenderElement(const ElementRendering&)#" - vint index = loggedTrace.createdElements->Keys().IndexOf(arguments.id); + vint index = loggedTrace.createdElements->Keys().IndexOf(id); CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Renderer with the specified id has not been created."); - auto rendererType = loggedTrace.createdElements->Values()[index]; if (rendererType == remoteprotocol::RendererType::FocusRectangle) { // FocusRectangle does not has a ElementDesc - lastRenderingCommands->Add(remoteprotocol::RenderingCommand_Element{ arguments,arguments.id }); return; } - index = lastElementDescs.Keys().IndexOf(arguments.id); + index = lastElementDescs.Keys().IndexOf(id); CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Renderer with the specified id has not been updated after created."); lastElementDescs.Values()[index].Apply(Overloading( [](remoteprotocol::RendererType) @@ -696,13 +780,90 @@ IGuiRemoteProtocolMessages (Rendering) }, [&](const remoteprotocol::ElementDesc_SolidLabel& solidLabel) { - CalculateSolidLabelSizeIfNecessary(arguments.bounds.Width(), arguments.bounds.Height(), solidLabel); - RequestRendererRenderElement(arguments, solidLabel); + CalculateSolidLabelSizeIfNecessary(bounds.Width(), bounds.Height(), solidLabel); }, [&](const auto& element) { - RequestRendererRenderElement(arguments, element); })); + +#undef ERROR_MESSAGE_PREFIX + } + + void RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments) override + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::RequestRendererRenderElement(const ElementRendering&)#" + CHECK_ERROR(!receivedDomDiffMessage, ERROR_MESSAGE_PREFIX L"This message could not be used with dom-diff messages in the same rendering cycle."); + if (!receivedElementMessage) + { + renderingDomBuilder.RequestRendererBeginRendering(); + receivedElementMessage = true; + } + + { + renderingDomBuilder.RequestRendererRenderElement(arguments); + + glr::json::JsonFormatting formatting; + formatting.spaceAfterColon = true; + formatting.spaceAfterComma = true; + formatting.crlf = false; + formatting.compact = true; + GetLastRenderingFrame()->renderingCommandsLog.Add(L"RequestRendererRenderElement: " + stream::GenerateToStream([&](stream::TextWriter& writer) + { + auto jsonLog = remoteprotocol::ConvertCustomTypeToJson(arguments); + writer.WriteString(glr::json::JsonToString(jsonLog, formatting)); + })); + } + + EnsureRenderedElement(arguments.id, arguments.bounds); +#undef ERROR_MESSAGE_PREFIX + } + +/*********************************************************************** +IGuiRemoteProtocolMessages (Rendering - Dom) +***********************************************************************/ + + void CalculateSolidLabelSizesIfNecessary(Ptr dom) + { + if (dom->content.element) + { + EnsureRenderedElement(dom->content.element.Value(), dom->content.bounds); + } + if (dom->children) + { + for (auto child : *dom->children.Obj()) + { + CalculateSolidLabelSizesIfNecessary(child); + } + } + } + + void RequestRendererRenderDom(const Ptr& arguments) override + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::RequestRendererRenderElement(const RenderingDom&)#" + CHECK_ERROR(!receivedElementMessage, ERROR_MESSAGE_PREFIX L"This message could not be used with element messages in the same rendering cycle."); + if (!receivedDomDiffMessage) + { + receivedDomDiffMessage = true; + } + + receivedDom = arguments; + remoteprotocol::BuildDomIndex(receivedDom, receivedDomIndex); + CalculateSolidLabelSizesIfNecessary(receivedDom); +#undef ERROR_MESSAGE_PREFIX + } + + void RequestRendererRenderDomDiff(const remoteprotocol::RenderingDom_DiffsInOrder& arguments) override + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Rendering::RequestRendererRenderElement(const RenderingDom_DiffsInOrder&)#" + CHECK_ERROR(!receivedElementMessage, ERROR_MESSAGE_PREFIX L"This message could not be used with element messages in the same rendering cycle."); + if (!receivedDomDiffMessage) + { + receivedDomDiffMessage = true; + } + + remoteprotocol::UpdateDomInplace(receivedDom, receivedDomIndex, arguments); + GetLastRenderingFrame()->renderingDiffs = arguments; + CalculateSolidLabelSizesIfNecessary(receivedDom); #undef ERROR_MESSAGE_PREFIX } @@ -1138,205 +1299,31 @@ UnitTestRemoteProtocol template class UnitTestRemoteProtocol_Logging : public TProtocol { - using CommandList = UnitTestRenderingCommandList; - using CommandListRef = UnitTestRenderingCommandListRef; - using RenderingResultRef = Ptr; - using RenderingResultRefList = collections::List; - using LoggedFrameList = collections::List; protected: - bool everRendered = false; - vint candidateFrameId = 0; - CommandListRef candidateRenderingResult; - - RenderingResultRef TransformLastRenderingResult(CommandListRef commandListRef) - { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_Logging::TransformLastRenderingResult(CommandListRef)#" - - RenderingResultRefList domStack; - collections::List domBoundaries; - - auto domRoot = Ptr(new UnitTestRenderingDom); - auto domCurrent = domRoot; - domStack.Add(domRoot); - - auto getCurrentBoundary = [&]() -> vint - { - if (domBoundaries.Count() > 0) - { - return domBoundaries[domBoundaries.Count() - 1]; - } - else - { - return 0; - } - }; - - auto push = [&](RenderingResultRef ref) - { - CHECK_ERROR(ref, ERROR_MESSAGE_PREFIX L"[push] Cannot push a null dom object."); - vint index = domStack.Add(ref); - if (!domCurrent->children) domCurrent->children = Ptr(new RenderingResultRefList); - domCurrent->children->Add(ref); - domCurrent = ref; - return index; - }; - - auto popTo = [&](vint index) - { - if (index == domStack.Count() - 1) return; - CHECK_ERROR(0 <= index && index < domStack.Count(), ERROR_MESSAGE_PREFIX L"[popTo] Cannot pop to an invalid position."); - CHECK_ERROR(index >= getCurrentBoundary(), ERROR_MESSAGE_PREFIX L"[popTo] Cannot pop across a boundary."); - while (domStack.Count() - 1 > index) - { - domStack.RemoveAt(domStack.Count() - 1); - } - domCurrent = domStack[index]; - }; - - auto pop = [&]() - { - popTo(domStack.Count() - 2); - }; - - auto popBoundary = [&]() - { - CHECK_ERROR(domBoundaries.Count() > 0, ERROR_MESSAGE_PREFIX L"[popBoundary] Cannot pop a boundary when none is in the stack."); - auto boundaryIndex = domBoundaries.Count() - 1; - auto boundary = domBoundaries[boundaryIndex]; - domBoundaries.RemoveAt(boundaryIndex); - popTo(boundary - 1); - }; - - auto prepareParentFromCommand = [&]( - Rect commandBounds, - Rect commandValidArea, - auto&& calculateValidAreaFromDom - ) - { - vint min = getCurrentBoundary(); - bool found = false; - if (commandValidArea.Contains(commandBounds)) - { - // if the command is not clipped - for (vint i = domStack.Count() - 1; i >= min; i--) - { - if (domStack[i]->validArea.Contains(commandBounds) || i == 0) - { - // find the deepest node that could contain the command - popTo(i); - found = true; - break; - } - } - } - else - { - // otherwise, a parent node causing such clipping should be found or created - for (vint i = domStack.Count() - 1; i >= min; i--) - { - auto domValidArea = calculateValidAreaFromDom(domStack[i]); - if (domValidArea == commandValidArea) - { - // if there is a node who clips command's bound to its valid area - // that is the parent node of the command - popTo(i); - found = true; - break; - } - else if (domValidArea.Contains(commandValidArea) || i == 0) - { - // otherwise find a deepest node who could visually contain the command - // create a virtual node to satisfy the clipper - popTo(i); - auto parent = Ptr(new UnitTestRenderingDom); - parent->bounds = commandValidArea; - parent->validArea = commandValidArea; - push(parent); - found = true; - break; - } - } - } - - // if the new boundary could not fit in the current boundary - // there must be something wrong - CHECK_ERROR(found, ERROR_MESSAGE_PREFIX L"Incorrect valid area of dom."); - }; - - for (auto&& command : *commandListRef.Obj()) - { - command.Apply(Overloading( - [&](const remoteprotocol::RenderingCommand_BeginBoundary& command) - { - // a new boundary should be a new node covering existing nodes - // the valid area of boundary is clipped by its bounds - // so the valid area to compare from its potential parent dom needs to clipped by its bounds - prepareParentFromCommand( - command.boundary.bounds, - command.boundary.areaClippedBySelf, - [&](auto&& dom) { return dom->validArea.Intersect(command.boundary.bounds); } - ); - - auto dom = Ptr(new UnitTestRenderingDom); - dom->hitTestResult = command.boundary.hitTestResult; - dom->cursor = command.boundary.cursor; - dom->bounds = command.boundary.bounds; - dom->validArea = command.boundary.areaClippedBySelf; - domBoundaries.Add(push(dom)); - }, - [&](const remoteprotocol::RenderingCommand_EndBoundary& command) - { - popBoundary(); - }, - [&](const remoteprotocol::RenderingCommand_Element& command) - { - // a new element should be a new node covering existing nodes - // the valid area of boundary is clipped by its parent - // so the valid area to compare from its potential parent dom is its valid area - prepareParentFromCommand( - command.rendering.bounds, - command.rendering.areaClippedByParent, - [&](auto&& dom) { return dom->validArea; } - ); - - auto dom = Ptr(new UnitTestRenderingDom); - dom->element = command.element; - dom->bounds = command.rendering.bounds; - dom->validArea = command.rendering.bounds.Intersect(command.rendering.areaClippedByParent); - push(dom); - })); - } - - return domRoot; -#undef ERROR_MESSAGE_PREFIX - } + Ptr candidateFrame; bool LogRenderingResult() { - if (this->lastRenderingCommands) + if (auto lastFrame = this->TryGetLastRenderingFrameAndReset()) { - candidateFrameId = this->lastFrameId; - candidateRenderingResult = this->lastRenderingCommands; - this->lastRenderingCommands = {}; + candidateFrame = lastFrame; everRendered = true; } else if (everRendered) { - if (candidateRenderingResult) + if (candidateFrame) { - auto descs = Ptr(new collections::Dictionary); + auto descs = Ptr(new collections::Dictionary); CopyFrom(*descs.Obj(), this->lastElementDescs); - auto transformed = TransformLastRenderingResult(candidateRenderingResult); this->loggedTrace.frames->Add({ - candidateFrameId, + candidateFrame->frameId, {}, this->sizingConfig, descs, - candidateRenderingResult, - transformed + candidateFrame->renderingDom }); - candidateRenderingResult = {}; + candidateFrame = {}; return true; } } @@ -1355,6 +1342,11 @@ UnitTestRemoteProtocol { return this->loggedTrace; } + + const auto& GetLoggedFrames() + { + return this->loggedFrames; + } }; } @@ -1468,8 +1460,9 @@ IGuiRemoteProtocolMessages (Initialization) IGuiRemoteProtocol ***********************************************************************/ - void Submit() override + void Submit(bool& disconnected) override { + // TODO: Failure injection to disconnected } void ProcessRemoteEvents() override @@ -1529,6 +1522,7 @@ extern void GacUIUnitTest_Finalize(); extern void GacUIUnitTest_SetGuiMainProxy(const vl::presentation::unittest::UnitTestMainFunc& proxy); extern void GacUIUnitTest_LinkGuiMainProxy(const vl::presentation::unittest::UnitTestLinkFunc& proxy); extern void GacUIUnitTest_Start(const vl::WString& appName, vl::Nullable config = {}); +extern void GacUIUnitTest_StartAsync(const vl::WString& appName, vl::Nullable config = {}); extern void GacUIUnitTest_Start_WithResourceAsText(const vl::WString& appName, vl::Nullable config, const vl::WString& resourceText); extern vl::Ptr GacUIUnitTest_CompileAndLoad(const vl::WString& xmlResource); diff --git a/Import/GacUI.Windows.cpp b/Import/GacUI.Windows.cpp index e4312949..5cb8fe5f 100644 --- a/Import/GacUI.Windows.cpp +++ b/Import/GacUI.Windows.cpp @@ -999,13 +999,14 @@ WindowsForm return true; } break; + case WM_NCLBUTTONUP: case WM_LBUTTONUP: { - POINTS location = MAKEPOINTS(lParam); + NativeWindowMouseInfo info = ConvertMouse(wParam, lParam, false, nonClient); // TODO: (enumerable) this for-loop needs to be removed, because it is not looping, just leave the body for (vint i = 0; i < listeners.Count(); i++) { - switch (PerformHitTest(From(listeners), { location.x,location.y })) + switch (PerformHitTest(From(listeners), { info.x,info.y })) { case INativeWindowListener::ButtonMinimum: ShowMinimized(); @@ -2867,7 +2868,7 @@ using namespace vl::presentation; using namespace vl::presentation::windows; using namespace vl::presentation::elements_windows_d2d; -int SetupWindowsDirect2DRendererInternal(bool hosted) +int SetupWindowsDirect2DRendererInternal(bool hosted, bool raw) { InitDpiAwareness(true); CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -2897,7 +2898,7 @@ int SetupWindowsDirect2DRendererInternal(bool hosted) nativeController->CallbackService()->InstallListener(&listener); direct2DListener = &listener; // main - RendererMainDirect2D(hostedController); + RendererMainDirect2D(hostedController, raw); // uninstall listener direct2DListener = nullptr; nativeController->CallbackService()->UninstallListener(&listener); @@ -2916,12 +2917,17 @@ int SetupWindowsDirect2DRendererInternal(bool hosted) int SetupWindowsDirect2DRenderer() { - return SetupWindowsDirect2DRendererInternal(false); + return SetupWindowsDirect2DRendererInternal(false, false); } int SetupHostedWindowsDirect2DRenderer() { - return SetupWindowsDirect2DRendererInternal(true); + return SetupWindowsDirect2DRendererInternal(true, false); +} + +int SetupRawWindowsDirect2DRenderer() +{ + return SetupWindowsDirect2DRendererInternal(false, true); } /*********************************************************************** @@ -5127,24 +5133,27 @@ GuiImageFrameElementRenderer void GuiImageFrameElementRenderer::UpdateBitmap(IWindowsDirect2DRenderTarget* renderTarget) { - if(renderTarget && element->GetImage()) + if (element->GetImage() && 0 <= element->GetFrameIndex() && element->GetFrameIndex() < element->GetImage()->GetFrameCount()) { - INativeImageFrame* frame=element->GetImage()->GetFrame(element->GetFrameIndex()); - bitmap=renderTarget->GetBitmap(frame, element->GetEnabled()); + INativeImageFrame* frame = element->GetImage()->GetFrame(element->GetFrameIndex()); + if (renderTarget) + { + bitmap = renderTarget->GetBitmap(frame, element->GetEnabled()); + } if (element->GetStretch()) { - minSize=Size(0,0); + minSize = Size(0, 0); } else { - minSize=frame->GetSize(); + minSize = frame->GetSize(); } } else { - bitmap=nullptr; - minSize=Size(0, 0); + bitmap = nullptr; + minSize = Size(0, 0); } } @@ -6439,9 +6448,11 @@ NativeMain using namespace vl::presentation; using namespace vl::presentation::elements; + +extern void GuiRawMain(); extern void GuiApplicationMain(); -void RendererMainDirect2D(GuiHostedController* hostedController) +void RendererMainDirect2D(GuiHostedController* hostedController, bool raw) { elements_windows_d2d::WindowsDirect2DResourceManager resourceManager; elements_windows_d2d::SetWindowsDirect2DResourceManager(&resourceManager); @@ -6470,7 +6481,14 @@ void RendererMainDirect2D(GuiHostedController* hostedController) elements::GuiDocumentElement::GuiDocumentElementRenderer::Register(); if (hostedController) hostedController->Initialize(); - GuiApplicationMain(); + if (raw) + { + GuiRawMain(); + } + else + { + GuiApplicationMain(); + } if (hostedController) hostedController->Finalize(); } @@ -8627,7 +8645,7 @@ using namespace vl::presentation; using namespace vl::presentation::windows; using namespace vl::presentation::elements_windows_gdi; -int SetupWindowsGDIRendererInternal(bool hosted) +int SetupWindowsGDIRendererInternal(bool hosted, bool raw) { InitDpiAwareness(false); CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -8657,7 +8675,7 @@ int SetupWindowsGDIRendererInternal(bool hosted) nativeController->CallbackService()->InstallListener(&listener); gdiListener = &listener; // main - RendererMainGDI(hostedController); + RendererMainGDI(hostedController, raw); // uninstall listener gdiListener = nullptr; nativeController->CallbackService()->UninstallListener(&listener); @@ -8676,12 +8694,17 @@ int SetupWindowsGDIRendererInternal(bool hosted) int SetupWindowsGDIRenderer() { - return SetupWindowsGDIRendererInternal(false); + return SetupWindowsGDIRendererInternal(false, false); } int SetupHostedWindowsGDIRenderer() { - return SetupWindowsGDIRendererInternal(true); + return SetupWindowsGDIRendererInternal(true, false); +} + +int SetupRawWindowsGDIRenderer() +{ + return SetupWindowsGDIRendererInternal(false, true); } /*********************************************************************** @@ -9658,25 +9681,25 @@ GuiImageFrameElementRenderer void GuiImageFrameElementRenderer::UpdateBitmap() { - if(element->GetImage()) + if (element->GetImage() && 0 <= element->GetFrameIndex() && element->GetFrameIndex() < element->GetImage()->GetFrameCount()) { - auto resourceManager=GetWindowsGDIResourceManager(); - INativeImageFrame* frame=element->GetImage()->GetFrame(element->GetFrameIndex()); - bitmap=resourceManager->GetBitmap(frame, element->GetEnabled()); + auto resourceManager = GetWindowsGDIResourceManager(); + INativeImageFrame* frame = element->GetImage()->GetFrame(element->GetFrameIndex()); + bitmap = resourceManager->GetBitmap(frame, element->GetEnabled()); if (element->GetStretch()) { - minSize=Size(0,0); + minSize = Size(0, 0); } else { - minSize=frame->GetSize(); + minSize = frame->GetSize(); } } else { - bitmap=0; - minSize=Size(0, 0); + bitmap = nullptr; + minSize = Size(0, 0); } } @@ -9740,7 +9763,7 @@ GuiImageFrameElementRenderer } destination=Rect(x, y, x+minSize.x, y+minSize.y); } - if(element->GetImage()->GetFormat()==INativeImage::Gif && element->GetFrameIndex()>0) + if(element->GetImage()->GetFormat()==INativeImage::Gif && element->GetFrameIndex()>0) { auto resourceManager=GetWindowsGDIResourceManager(); vint max=element->GetFrameIndex(); @@ -13041,9 +13064,10 @@ NativeMain using namespace vl::presentation; using namespace vl::presentation::elements; +extern void GuiRawMain(); extern void GuiApplicationMain(); -void RendererMainGDI(GuiHostedController* hostedController) +void RendererMainGDI(GuiHostedController* hostedController, bool raw) { elements_windows_gdi::WindowsGDIResourceManager resourceManager; elements_windows_gdi::SetWindowsGDIResourceManager(&resourceManager); @@ -13072,7 +13096,14 @@ void RendererMainGDI(GuiHostedController* hostedController) elements::GuiDocumentElement::GuiDocumentElementRenderer::Register(); if (hostedController) hostedController->Initialize(); - GuiApplicationMain(); + if (raw) + { + GuiRawMain(); + } + else + { + GuiApplicationMain(); + } if (hostedController) hostedController->Finalize(); } diff --git a/Import/GacUI.Windows.h b/Import/GacUI.Windows.h index f96ee995..74b7706e 100644 --- a/Import/GacUI.Windows.h +++ b/Import/GacUI.Windows.h @@ -229,7 +229,7 @@ OS Supporting } } -extern void RendererMainDirect2D(vl::presentation::GuiHostedController* hostedController); +extern void RendererMainDirect2D(vl::presentation::GuiHostedController* hostedController, bool raw); #endif @@ -1512,7 +1512,7 @@ OS Supporting } } -extern void RendererMainGDI(vl::presentation::GuiHostedController* hostedController); +extern void RendererMainGDI(vl::presentation::GuiHostedController* hostedController, bool raw); #endif diff --git a/Import/GacUI.cpp b/Import/GacUI.cpp index e97aa443..0ebda376 100644 --- a/Import/GacUI.cpp +++ b/Import/GacUI.cpp @@ -657,10 +657,59 @@ GuiApplicationMain ThreadLocalStorage::DisposeStorages(); } } + + void GuiRawInitialize() + { + if (!GACUI_UNITTEST_ONLY_SKIP_TYPE_AND_PLUGIN_LOAD_UNLOAD) + { +#ifndef VCZH_DEBUG_NO_REFLECTION + GetGlobalTypeManager()->Load(); +#endif + GetPluginManager()->Load(true, true); + } + else + { + GetPluginManager()->Load(false, true); + } + + GetCurrentController()->InputService()->StartTimer(); + { + IAsyncScheduler::RegisterSchedulerForCurrentThread(Ptr(new UIThreadAsyncScheduler)); + IAsyncScheduler::RegisterDefaultScheduler(Ptr(new OtherThreadAsyncScheduler)); + GuiMain(); + IAsyncScheduler::UnregisterDefaultScheduler(); + IAsyncScheduler::UnregisterSchedulerForCurrentThread(); + } + GetCurrentController()->InputService()->StopTimer(); + FinalizeGlobalStorage(); + + if (!GACUI_UNITTEST_ONLY_SKIP_TYPE_AND_PLUGIN_LOAD_UNLOAD) + { + GetPluginManager()->Unload(true, true); + DestroyPluginManager(); +#ifndef VCZH_DEBUG_NO_REFLECTION + ResetGlobalTypeManager(); +#endif + } + else + { + GetPluginManager()->Unload(false, true); + } + + if (!GACUI_UNITTEST_ONLY_SKIP_THREAD_LOCAL_STORAGE_DISPOSE_STORAGES) + { + ThreadLocalStorage::DisposeStorages(); + } + } } } } +void GuiRawMain() +{ + vl::presentation::controls::GuiRawInitialize(); +} + void GuiApplicationMain() { vl::presentation::controls::GuiApplicationInitialize(); @@ -2533,9 +2582,9 @@ GuiControlHost void GuiControlHost::Hide() { - if(host->GetNativeWindow()) + if (auto window = host->GetNativeWindow()) { - host->GetNativeWindow()->Hide(false); + window->Hide(false); } } @@ -2543,16 +2592,17 @@ GuiControlHost { if (auto window = host->GetNativeWindow()) { - auto mainWindow = GetCurrentController()->WindowService()->GetMainWindow(); - if (mainWindow == window) - { - SetNativeWindow(nullptr); - GetCurrentController()->WindowService()->DestroyNativeWindow(window); - } - else - { - window->Hide(true); - } + window->Hide(true); + // auto mainWindow = GetCurrentController()->WindowService()->GetMainWindow(); + // if (mainWindow == window) + // { + // SetNativeWindow(nullptr); + // GetCurrentController()->WindowService()->DestroyNativeWindow(window); + // } + // else + // { + // window->Hide(true); + // } } } @@ -33845,11 +33895,11 @@ GuiImageFrameElement ***********************************************************************/ GuiImageFrameElement::GuiImageFrameElement() - :frameIndex(0) - ,hAlignment(Alignment::Left) - ,vAlignment(Alignment::Top) - ,stretch(false) - ,enabled(true) + : frameIndex(0) + , hAlignment(Alignment::Left) + , vAlignment(Alignment::Top) + , stretch(false) + , enabled(true) { } @@ -33875,17 +33925,19 @@ GuiImageFrameElement void GuiImageFrameElement::SetImage(Ptr _image, vint _frameIndex) { - if(image!=_image || frameIndex!=_frameIndex) + if (image != _image || frameIndex != _frameIndex) { - if(!_image) + if (!_image) { - image=0; - frameIndex=0; + image = nullptr; + frameIndex = 0; } - else if(0<=_frameIndex && _frameIndex<_image->GetFrameCount()) + else if (0 <= _frameIndex) { - image=_image; - frameIndex=_frameIndex; + // do not check frame count because + // on remote protocol metadata could have not been loaded yet + image = _image; + frameIndex = _frameIndex; } InvokeOnElementStateChanged(); } @@ -33913,10 +33965,10 @@ GuiImageFrameElement void GuiImageFrameElement::SetAlignments(Alignment horizontal, Alignment vertical) { - if(hAlignment!=horizontal || vAlignment!=vertical) + if (hAlignment != horizontal || vAlignment != vertical) { - hAlignment=horizontal; - vAlignment=vertical; + hAlignment = horizontal; + vAlignment = vertical; InvokeOnElementStateChanged(); } } @@ -33928,9 +33980,9 @@ GuiImageFrameElement void GuiImageFrameElement::SetStretch(bool value) { - if(stretch!=value) + if (stretch != value) { - stretch=value; + stretch = value; InvokeOnElementStateChanged(); } } @@ -33942,9 +33994,9 @@ GuiImageFrameElement void GuiImageFrameElement::SetEnabled(bool value) { - if(enabled!=value) + if (enabled != value) { - enabled=value; + enabled = value; InvokeOnElementStateChanged(); } } @@ -36816,7 +36868,33 @@ GuiHostedController::INativeWindowService SettingHostedWindowsBeforeRunning(); wmManager->needRefresh = true; - nativeController->WindowService()->Run(nativeWindow); + try + { + nativeController->WindowService()->Run(nativeWindow); + } + catch (const Exception& e) + { + (void)e; + DestroyHostedWindowsAfterRunning(); + throw; + } + catch (const Error& e) + { + (void)e; + DestroyHostedWindowsAfterRunning(); + throw; + } + catch (const unittest::UnitTestAssertError& e) + { + (void)e; + DestroyHostedWindowsAfterRunning(); + throw; + } + catch (...) + { + DestroyHostedWindowsAfterRunning(); + throw; + } CHECK_ERROR((nativeWindow == nullptr) == (mainWindow == nullptr), ERROR_MESSAGE_PREFIX L"Hosted windows should have been destroyed if the native windows is destroyed."); DestroyHostedWindowsAfterRunning(); #undef ERROR_MESSAGE_PREFIX @@ -37270,7 +37348,9 @@ GuiHostedWindow if (this != controller->mainWindow) { - // for main window, the underlying INativeWindow will run the process + // when the main window is being closed + // the underlying INativeWindow will run the process + // so we don't need to worry about it here bool cancel = false; for (auto listener : listeners) { @@ -38199,7 +38279,9 @@ GuiRemoteController::INativeInputService bool GuiRemoteController::IsKeyPressing(VKEY code) { vint idIsKeyPressing = remoteMessages.RequestIOIsKeyPressing(code); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + if (disconnected) return false; bool result = remoteMessages.RetrieveIOIsKeyPressing(idIsKeyPressing); return result; } @@ -38207,7 +38289,9 @@ GuiRemoteController::INativeInputService bool GuiRemoteController::IsKeyToggled(VKEY code) { vint idIsKeyToggled = remoteMessages.RequestIOIsKeyToggled(code); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + if (disconnected) return false; bool result = remoteMessages.RetrieveIOIsKeyToggled(idIsKeyToggled); return result; } @@ -38265,7 +38349,9 @@ GuiRemoteController::INativeInputService hotKeyIds.Add(id, entry); UpdateGlobalShortcutKey(); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + // there is no result from this request, assuming succeeded return id; } @@ -38280,7 +38366,9 @@ GuiRemoteController::INativeInputService hotKeySet.Remove(entry); UpdateGlobalShortcutKey(); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + // there is no result from this request, assuming succeeded return true; } @@ -38390,6 +38478,7 @@ GuiRemoteController::INativeWindowService applicationRunning = true; window->Show(); while (RunOneCycle()); + asyncService.ExecuteAsyncTasks(); applicationRunning = false; } @@ -38398,8 +38487,9 @@ GuiRemoteController::INativeWindowService if (!connectionStopped) { remoteProtocol->ProcessRemoteEvents(); - remoteMessages.Submit(); - if (timerEnabled) + bool disconnected = false; + remoteMessages.Submit(disconnected); + if (timerEnabled && !disconnected) { callbackService.InvokeGlobalTimer(); } @@ -38417,7 +38507,9 @@ GuiRemoteController (events) UpdateGlobalShortcutKey(); vint idGetFontConfig = remoteMessages.RequestControllerGetFontConfig(); vint idGetScreenConfig = remoteMessages.RequestControllerGetScreenConfig(); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + if (disconnected) return; remoteFontConfig = remoteMessages.RetrieveControllerGetFontConfig(idGetFontConfig); remoteScreenConfig = remoteMessages.RetrieveControllerGetScreenConfig(idGetScreenConfig); remoteWindow.OnControllerConnect(); @@ -38446,6 +38538,7 @@ GuiRemoteController (events) void GuiRemoteController::OnControllerScreenUpdated(const remoteprotocol::ScreenConfig& arguments) { remoteScreenConfig = arguments; + remoteWindow.OnControllerScreenUpdated(arguments); } /*********************************************************************** @@ -38475,7 +38568,9 @@ GuiRemoteController { imageService.Finalize(); remoteMessages.RequestControllerConnectionStopped(); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + // there is no result from this request, assuming succeeded } /*********************************************************************** @@ -38594,9 +38689,9 @@ GuiRemoteMessages { } - void GuiRemoteMessages::Submit() + void GuiRemoteMessages::Submit(bool& disconnected) { - remote->remoteProtocol->Submit(); + remote->remoteProtocol->Submit(disconnected); } /*********************************************************************** @@ -38696,7 +38791,10 @@ GuiRemoteEvents (events) { remote->remoteMessages.RequestControllerConnectionEstablished(); remote->OnControllerConnect(); - remote->remoteMessages.Submit(); + bool disconnected = false; + remote->remoteMessages.Submit(disconnected); + // there is no result from this request, assuming succeeded + // if disconnected, OnControllerDisconnect will be called } void GuiRemoteEvents::OnControllerDisconnect() @@ -38938,7 +39036,9 @@ GuiRemoteGraphicsRenderTarget { CHECK_ERROR(hitTestResults.Count() == 0, L"vl::presentation::elements::GuiRemoteGraphicsRenderTarget::StartRenderingOnNativeWindow()#Internal error: hit test result stack is not cleared."); vint idRendering = remote->remoteMessages.RequestRendererEndRendering(); - remote->remoteMessages.Submit(); + bool disconnected = false; + remote->remoteMessages.Submit(disconnected); + if (disconnected) return RenderTargetFailure::None; auto measuring = remote->remoteMessages.RetrieveRendererEndRendering(idRendering); bool minSizeChanged = false; @@ -39044,6 +39144,13 @@ GuiRemoteGraphicsRenderTarget if (arguments.hitTestResult || arguments.cursor) { + // GetHitTestResultFromGenerator or GetCursorFromGenerator ensures generator must be a composition + auto composition = dynamic_cast(generator); + if (composition->remoteId == -1) + { + composition->remoteId = ++usedCompositionIds; + } + arguments.id = composition->remoteId; arguments.bounds = clipper; arguments.areaClippedBySelf = validArea; remote->remoteMessages.RequestRendererBeginBoundary(arguments); @@ -39291,6 +39398,8 @@ GuiSolidBorderElementRenderer { id = newRenderTarget->AllocateNewElementId(); newRenderTarget->RegisterRenderer(this); + updated = true; + renderTargetChanged = true; } } @@ -39322,6 +39431,7 @@ GuiSolidBorderElementRenderer void RENDERER_CLASS_TYPE::ResetUpdated() { updated = false; + renderTargetChanged = false; } RENDERER_TEMPLATE_HEADER @@ -39612,12 +39722,12 @@ GuiSolidLabelElementRenderer elementFont = GetCurrentController()->ResourceService()->GetDefaultFont(); } - if (fullContent || lastFont != elementFont) + if (renderTargetChanged || fullContent || lastFont != elementFont) { arguments.font = elementFont; } - if (fullContent || lastText != elementText) + if (renderTargetChanged || fullContent || lastText != elementText) { arguments.text = elementText; } @@ -39630,7 +39740,7 @@ GuiSolidLabelElementRenderer TryFetchMinSizeFromCache(); if (!needFontHeight) { - arguments.measuringRequest = {}; + arguments.measuringRequest.Reset(); } } @@ -39689,9 +39799,9 @@ GuiImageFrameElementRenderer { #define ERROR_MESSAGE_PREFIX L"vl::presentation::elements_remoteprotocol::GuiImageFrameElementRenderer::TryFetchMinSizeFromCache()#" auto image = GetRemoteImage(); - if (image) + if (!image || image->status != GuiRemoteGraphicsImage::MetadataStatus::Retrived) { - CHECK_ERROR(image->status == GuiRemoteGraphicsImage::MetadataStatus::Retrived, ERROR_MESSAGE_PREFIX L"The expected metadata of an image does not exist."); + return; } UpdateMinSizeFromImage(image); needUpdateSize = false; @@ -39704,13 +39814,24 @@ GuiImageFrameElementRenderer if (image) { needUpdateSize = true; - if (fullContent && image->status == GuiRemoteGraphicsImage::MetadataStatus::Retrived) + if (fullContent) { - image->status = GuiRemoteGraphicsImage::MetadataStatus::Uninitialized; + if (fullContent && image->status == GuiRemoteGraphicsImage::MetadataStatus::Retrived) + { + image->status = GuiRemoteGraphicsImage::MetadataStatus::Uninitialized; + } + } + else + { + if (image->status == GuiRemoteGraphicsImage::MetadataStatus::Uninitialized) + { + image->EnsureMetadata(); + } } if (image->status == GuiRemoteGraphicsImage::MetadataStatus::Retrived) { UpdateMinSizeFromImage(image); + renderTargetChanged = false; } } @@ -39745,7 +39866,7 @@ GuiImageFrameElementRenderer arguments.verticalAlignment = ElementVerticalAlignment::Center; } - if (needUpdateSize && image) + if ((renderTargetChanged || needUpdateSize) && image) { arguments.imageCreation = image->GenerateImageCreation(); } @@ -39864,7 +39985,9 @@ GuiRemoteGraphicsImage auto arguments = GenerateImageCreation(); vint idImageCreated = remote->remoteMessages.RequestImageCreated(arguments); - remote->remoteMessages.Submit(); + bool disconnected = false; + remote->remoteMessages.Submit(disconnected); + if (disconnected) return; auto imageMetadata = remote->remoteMessages.RetrieveImageCreated(idImageCreated); UpdateFromImageMetadata(imageMetadata); } @@ -40000,7 +40123,7 @@ GuiRemoteGraphicsImageService { } - void GuiRemoteGraphicsImageService::OnControllerConnect() + void GuiRemoteGraphicsImageService::ResetImageMetadata() { for (auto image : images.Values()) { @@ -40008,6 +40131,11 @@ GuiRemoteGraphicsImageService } } + void GuiRemoteGraphicsImageService::OnControllerConnect() + { + ResetImageMetadata(); + } + void GuiRemoteGraphicsImageService::OnControllerDisconnect() { } @@ -40250,6 +40378,1152 @@ namespace vl::presentation::remoteprotocol } +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_CHANNEL_ASYNC.CPP +***********************************************************************/ + +namespace vl::presentation::remoteprotocol::channeling +{ + using namespace vl::collections; + +/*********************************************************************** +GuiRemoteProtocolAsyncChannelSerializerBase +***********************************************************************/ + + void GuiRemoteProtocolAsyncChannelSerializerBase::QueueTask(SpinLock& lock, collections::List& tasks, TTaskProc task, EventObject* signalAfterQueue) + { + SPIN_LOCK(lock) + { + tasks.Add(task); + } + + if (signalAfterQueue) + { + signalAfterQueue->Signal(); + } + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::QueueTaskAndWait(SpinLock& lock, collections::List& tasks, TTaskProc task, EventObject* signalAfterQueue) + { + auto taskEvent = Ptr(new vl::EventObject); + taskEvent->CreateAutoUnsignal(false); + auto taskWithEvent = [=]() + { + task(); + taskEvent->Signal(); + }; + + QueueTask(lock, tasks, taskWithEvent, signalAfterQueue); + taskEvent->Wait(); + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::FetchTasks(SpinLock& lock, collections::List& tasks, collections::List& results) + { + SPIN_LOCK(lock) + { + results = std::move(tasks); + } + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::FetchAndExecuteTasks(SpinLock& lock, collections::List& tasks) + { + List results; + FetchTasks(lock, tasks, results); + for (auto&& task : results) + { + task(); + } + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::FetchAndExecuteChannelTasks() + { + FetchAndExecuteTasks(channelThreadLock, channelThreadTasks); + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::FetchAndExecuteUITasks() + { + FetchAndExecuteTasks(uiThreadLock, uiThreadTasks); + } + + GuiRemoteProtocolAsyncChannelSerializerBase::GuiRemoteProtocolAsyncChannelSerializerBase() + { + } + + GuiRemoteProtocolAsyncChannelSerializerBase::~GuiRemoteProtocolAsyncChannelSerializerBase() + { + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::QueueToChannelThread(TTaskProc task, EventObject* signalAfterQueue) + { + QueueTask(channelThreadLock, channelThreadTasks, task, signalAfterQueue); + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::QueueToChannelThreadAndWait(TTaskProc task, EventObject* signalAfterQueue) + { + QueueTaskAndWait(channelThreadLock, channelThreadTasks, task, signalAfterQueue); + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::QueueToUIThread(TTaskProc task, EventObject* signalAfterQueue) + { + QueueTask(uiThreadLock, uiThreadTasks, task, signalAfterQueue); + } + + void GuiRemoteProtocolAsyncChannelSerializerBase::QueueToUIThreadAndWait(TTaskProc task, EventObject* signalAfterQueue) + { + QueueTaskAndWait(uiThreadLock, uiThreadTasks, task, signalAfterQueue); + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_CHANNEL_JSON.CPP +***********************************************************************/ + +namespace vl::presentation::remoteprotocol::channeling +{ +/*********************************************************************** +ChannelPackageSemantic +***********************************************************************/ + + void JsonChannelPack(ChannelPackageSemantic semantic, vint id, const WString& name, Ptr arguments, Ptr& package) + { + package = Ptr(new glr::json::JsonObject); + + { + auto value = Ptr(new glr::json::JsonString); + switch (semantic) + { + case ChannelPackageSemantic::Message: + value->content.value = WString::Unmanaged(L"Message"); + break; + case ChannelPackageSemantic::Request: + value->content.value = WString::Unmanaged(L"Request"); + break; + case ChannelPackageSemantic::Response: + value->content.value = WString::Unmanaged(L"Response"); + break; + case ChannelPackageSemantic::Event: + value->content.value = WString::Unmanaged(L"Event"); + break; + default: + value->content.value = WString::Unmanaged(L"Unknown"); + } + + auto field = Ptr(new glr::json::JsonObjectField); + field->name.value = WString::Unmanaged(L"semantic"); + field->value = value; + package->fields.Add(field); + } + + if (id != -1) + { + auto value = Ptr(new glr::json::JsonNumber); + value->content.value = itow(id); + + auto field = Ptr(new glr::json::JsonObjectField); + field->name.value = WString::Unmanaged(L"id"); + field->value = value; + package->fields.Add(field); + } + + { + auto value = Ptr(new glr::json::JsonString); + value->content.value = name; + + auto field = Ptr(new glr::json::JsonObjectField); + field->name.value = WString::Unmanaged(L"name"); + field->value = value; + package->fields.Add(field); + } + + if (arguments) + { + auto field = Ptr(new glr::json::JsonObjectField); + field->name.value = WString::Unmanaged(L"arguments"); + field->value = arguments; + package->fields.Add(field); + } + } + + void JsonChannelUnpack(Ptr package, ChannelPackageSemantic& semantic, vint& id, WString& name, Ptr& arguments) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::JsonChannelPack(Ptr, ProtocolSemantic&, vint&, WString&, Ptr&)#" + + for (auto&& field : package->fields) + { + if (field->name.value == L"semantic") + { + auto value = field->value.Cast(); + CHECK_ERROR(value, ERROR_MESSAGE_PREFIX L"The semantic field should be a string."); + + if (value->content.value == L"Message") + { + semantic = ChannelPackageSemantic::Message; + } + else if (value->content.value == L"Request") + { + semantic = ChannelPackageSemantic::Request; + } + else if (value->content.value == L"Response") + { + semantic = ChannelPackageSemantic::Response; + } + else if (value->content.value == L"Event") + { + semantic = ChannelPackageSemantic::Event; + } + } + else if (field->name.value == L"id") + { + auto value = field->value.Cast(); + CHECK_ERROR(value, ERROR_MESSAGE_PREFIX L"The id field should be a number."); + + id = wtoi(value->content.value); + } + else if (field->name.value == L"name") + { + auto value = field->value.Cast(); + CHECK_ERROR(value, ERROR_MESSAGE_PREFIX L"The name field should be a string."); + + name = value->content.value; + } + else if (field->name.value == L"arguments") + { + arguments = field->value; + } + } +#undef ERROR_MESSAGE_PREFIX + } + + void ChannelPackageSemanticUnpack(Ptr package, ChannelPackageSemantic& semantic, vint& id, WString& name) + { + Ptr arguments; + JsonChannelUnpack(package, semantic, id, name, arguments); + } + +/*********************************************************************** +GuiRemoteProtocolFromJsonChannel +***********************************************************************/ + + void GuiRemoteProtocolFromJsonChannel::OnReceive(const Ptr& package) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolFromJsonChannel::OnReceive(const Ptr&)#" + + auto semantic = ChannelPackageSemantic::Unknown; + vint id = -1; + WString name; + Ptr jsonArguments; + JsonChannelUnpack(package, semantic, id, name, jsonArguments); + +#define EVENT_NOREQ(NAME, REQUEST)\ + if (name == L ## #NAME)\ + {\ + events->On ## NAME();\ + } else\ + +#define EVENT_REQ(NAME, REQUEST)\ + if (name == L ## #NAME)\ + {\ + REQUEST arguments;\ + ConvertJsonToCustomType(jsonArguments, arguments);\ + events->On ## NAME(arguments);\ + } else\ + +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST) + if (semantic == ChannelPackageSemantic::Event) + { + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) + { + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized event name"); + } + } + else +#undef EVENT_HANDLER +#undef EVENT_REQ +#undef EVENT_NOREQ + +#define MESSAGE_NORES(NAME, RESPONSE) +#define MESSAGE_RES(NAME, RESPONSE)\ + if (name == L ## #NAME)\ + {\ + RESPONSE arguments;\ + ConvertJsonToCustomType(jsonArguments, arguments);\ + events->Respond ## NAME(id, arguments);\ + } else\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) + if (semantic == ChannelPackageSemantic::Response) + { + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) + { + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized response name"); + } + } else +#undef MESSAGE_HANDLER +#undef MESSAGE_RES +#undef MESSAGE_NORES + + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized category name"); +#undef ERROR_MESSAGE_PREFIX + } + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)\ + void GuiRemoteProtocolFromJsonChannel::Request ## NAME()\ + {\ + Ptr package;\ + JsonChannelPack(ChannelPackageSemantic::Message, -1, WString::Unmanaged(L ## #NAME), {}, package);\ + channel->Write(package);\ + }\ + +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)\ + void GuiRemoteProtocolFromJsonChannel::Request ## NAME(vint id)\ + {\ + Ptr package;\ + JsonChannelPack(ChannelPackageSemantic::Request, id, WString::Unmanaged(L ## #NAME), {}, package);\ + channel->Write(package);\ + }\ + +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)\ + void GuiRemoteProtocolFromJsonChannel::Request ## NAME(const REQUEST& arguments)\ + {\ + Ptr package;\ + JsonChannelPack(ChannelPackageSemantic::Message, -1, WString::Unmanaged(L ## #NAME), ConvertCustomTypeToJson(arguments), package);\ + channel->Write(package);\ + }\ + +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)\ + void GuiRemoteProtocolFromJsonChannel::Request ## NAME(vint id, const REQUEST& arguments)\ + {\ + Ptr package;\ + JsonChannelPack(ChannelPackageSemantic::Request, id, WString::Unmanaged(L ## #NAME), ConvertCustomTypeToJson(arguments), package);\ + channel->Write(package);\ + }\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_REQ_RES +#undef MESSAGE_REQ_NORES +#undef MESSAGE_NOREQ_RES +#undef MESSAGE_NOREQ_NORES + + GuiRemoteProtocolFromJsonChannel::GuiRemoteProtocolFromJsonChannel(IJsonChannel* _channel) + : channel(_channel) + { + } + + GuiRemoteProtocolFromJsonChannel::~GuiRemoteProtocolFromJsonChannel() + { + } + + void GuiRemoteProtocolFromJsonChannel::Initialize(IGuiRemoteProtocolEvents* _events) + { + events = _events; + channel->Initialize(this); + } + + WString GuiRemoteProtocolFromJsonChannel::GetExecutablePath() + { + return channel->GetExecutablePath(); + } + + void GuiRemoteProtocolFromJsonChannel::Submit(bool& disconnected) + { + channel->Submit(disconnected); + } + + void GuiRemoteProtocolFromJsonChannel::ProcessRemoteEvents() + { + channel->ProcessRemoteEvents(); + } + +/*********************************************************************** +GuiRemoteJsonChannelFromProtocol +***********************************************************************/ + +#define EVENT_NOREQ(NAME, REQUEST)\ + void GuiRemoteJsonChannelFromProtocol::On ## NAME()\ + {\ + Ptr package;\ + JsonChannelPack(ChannelPackageSemantic::Event, -1, WString::Unmanaged(L ## #NAME), {}, package);\ + receiver->OnReceive(package);\ + }\ + +#define EVENT_REQ(NAME, REQUEST)\ + void GuiRemoteJsonChannelFromProtocol::On ## NAME(const REQUEST& arguments)\ + {\ + Ptr package;\ + JsonChannelPack(ChannelPackageSemantic::Event, -1, WString::Unmanaged(L ## #NAME), ConvertCustomTypeToJson(arguments), package);\ + receiver->OnReceive(package);\ + }\ + +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST) + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) +#undef EVENT_HANDLER +#undef EVENT_REQ +#undef EVENT_NOREQ + +#define MESSAGE_NORES(NAME, RESPONSE) +#define MESSAGE_RES(NAME, RESPONSE)\ + void GuiRemoteJsonChannelFromProtocol::Respond ## NAME(vint id, const RESPONSE& arguments)\ + {\ + Ptr package;\ + JsonChannelPack(ChannelPackageSemantic::Response, id, WString::Unmanaged(L ## #NAME), ConvertCustomTypeToJson(arguments), package);\ + receiver->OnReceive(package);\ + }\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_RES +#undef MESSAGE_NORES + + GuiRemoteJsonChannelFromProtocol::GuiRemoteJsonChannelFromProtocol(IGuiRemoteProtocol* _protocol) + : protocol(_protocol) + { + } + + GuiRemoteJsonChannelFromProtocol::~GuiRemoteJsonChannelFromProtocol() + { + } + + void GuiRemoteJsonChannelFromProtocol::Initialize(IJsonChannelReceiver* _receiver) + { + receiver = _receiver; + protocol->Initialize(this); + } + + IJsonChannelReceiver* GuiRemoteJsonChannelFromProtocol::GetReceiver() + { + return receiver; + } + + void GuiRemoteJsonChannelFromProtocol::Write(const Ptr& package) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteJsonChannelFromProtocol::Write(const Ptr&)#" + + auto semantic = ChannelPackageSemantic::Unknown; + vint id = -1; + WString name; + Ptr jsonArguments; + JsonChannelUnpack(package, semantic, id, name, jsonArguments); + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)\ + if (name == L ## #NAME)\ + {\ + protocol->Request ## NAME();\ + } else\ + +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)\ + if (name == L ## #NAME)\ + {\ + protocol->Request ## NAME(id);\ + } else\ + +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)\ + if (name == L ## #NAME)\ + {\ + REQUEST arguments;\ + ConvertJsonToCustomType(jsonArguments, arguments);\ + protocol->Request ## NAME(arguments);\ + } else\ + +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)\ + if (name == L ## #NAME)\ + {\ + REQUEST arguments;\ + ConvertJsonToCustomType(jsonArguments, arguments);\ + protocol->Request ## NAME(id, arguments);\ + } else\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) + { + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized request name"); + } +#undef MESSAGE_HANDLER +#undef MESSAGE_REQ_RES +#undef MESSAGE_REQ_NORES +#undef MESSAGE_NOREQ_RES +#undef MESSAGE_NOREQ_NORES + +#undef ERROR_MESSAGE_PREFIX + } + + WString GuiRemoteJsonChannelFromProtocol::GetExecutablePath() + { + return protocol->GetExecutablePath(); + } + + void GuiRemoteJsonChannelFromProtocol::Submit(bool& disconnected) + { + protocol->Submit(disconnected); + } + + void GuiRemoteJsonChannelFromProtocol::ProcessRemoteEvents() + { + protocol->ProcessRemoteEvents(); + } + +/*********************************************************************** +JsonToStringSerializer +***********************************************************************/ + + void JsonToStringSerializer::Serialize(Ptr parser, const SourceType& source, DestType& dest) + { + glr::json::JsonFormatting formatting; + formatting.spaceAfterColon = false; + formatting.spaceAfterComma = false; + formatting.crlf = false; + formatting.compact = true; + dest = glr::json::JsonToString(source, formatting); + } + + void JsonToStringSerializer::Deserialize(Ptr parser, const DestType& source, SourceType& dest) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteJsonChannelFromProtocol::Write(const Ptr&)#" + auto value = glr::json::JsonParse(source, *parser.Obj()); + dest = value.Cast(); + CHECK_ERROR(dest, ERROR_MESSAGE_PREFIX L"JSON parssing between the channel should be JsonObject."); +#undef ERROR_MESSAGE_PREFIX + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_DOMDIFF.CPP +***********************************************************************/ + +namespace vl::presentation::remoteprotocol +{ + +/*********************************************************************** +GuiRemoteEventDomDiffConverter +***********************************************************************/ + + GuiRemoteEventDomDiffConverter::GuiRemoteEventDomDiffConverter() + { + } + + GuiRemoteEventDomDiffConverter::~GuiRemoteEventDomDiffConverter() + { + } + + void GuiRemoteEventDomDiffConverter::OnControllerConnect() + { + lastDom = {}; + TBase::OnControllerConnect(); + } + +/*********************************************************************** +GuiRemoteProtocolDomDiffConverter +***********************************************************************/ + + GuiRemoteProtocolDomDiffConverter::GuiRemoteProtocolDomDiffConverter(IGuiRemoteProtocol* _protocol) + : TBase(_protocol) + { + } + + GuiRemoteProtocolDomDiffConverter::~GuiRemoteProtocolDomDiffConverter() + { + } + + void GuiRemoteProtocolDomDiffConverter::RequestRendererBeginRendering(const remoteprotocol::ElementBeginRendering& arguments) + { + renderingDomBuilder.RequestRendererBeginRendering(); + TBase::RequestRendererBeginRendering(arguments); + } + + void GuiRemoteProtocolDomDiffConverter::RequestRendererEndRendering(vint id) + { + auto dom = renderingDomBuilder.RequestRendererEndRendering(); + DomIndex domIndex; + BuildDomIndex(dom, domIndex); + + if (eventCombinator.lastDom) + { + RenderingDom_DiffsInOrder diffs; + DiffDom(eventCombinator.lastDom, eventCombinator.lastDomIndex, dom, domIndex, diffs); + targetProtocol->RequestRendererRenderDomDiff(diffs); + } + else + { + targetProtocol->RequestRendererRenderDom(dom); + } + + eventCombinator.lastDom = dom; + eventCombinator.lastDomIndex = std::move(domIndex); + TBase::RequestRendererEndRendering(id); + } + + void GuiRemoteProtocolDomDiffConverter::RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments) + { + renderingDomBuilder.RequestRendererBeginBoundary(arguments); + } + + void GuiRemoteProtocolDomDiffConverter::RequestRendererEndBoundary() + { + renderingDomBuilder.RequestRendererEndBoundary(); + } + + void GuiRemoteProtocolDomDiffConverter::RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments) + { + renderingDomBuilder.RequestRendererRenderElement(arguments); + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_FILTER.CPP +***********************************************************************/ + +namespace vl::presentation::remoteprotocol::repeatfiltering +{ + +/*********************************************************************** +GuiRemoteEventFilter +***********************************************************************/ + + GuiRemoteEventFilter::GuiRemoteEventFilter() + { + } + + GuiRemoteEventFilter::~GuiRemoteEventFilter() + { + } + + void GuiRemoteEventFilter::ProcessResponses() + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::repeatfiltering::GuiRemoteProtocolFilter::ProcessResponses()#" + for (auto&& response : filteredResponses) + { +#define MESSAGE_NORES(NAME, RESPONSE) +#define MESSAGE_RES(NAME, RESPONSE)\ + case FilteredResponseNames::NAME:\ + targetEvents->Respond ## NAME(response.id, response.arguments.Get());\ + break;\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) + switch (response.name) + { + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) + default: + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unrecognized response."); + } +#undef MESSAGE_HANDLER +#undef MESSAGE_RES +#undef MESSAGE_NORES + } + + CHECK_ERROR(responseIds.Count() == 0, ERROR_MESSAGE_PREFIX L"Messages sending to IGuiRemoteProtocol should be all responded."); + filteredResponses.Clear(); +#undef ERROR_MESSAGE_PREFIX + } + + void GuiRemoteEventFilter::ProcessEvents() + { +#define EVENT_NODROP(NAME) +#define EVENT_DROPREP(NAME) lastDropRepeatEvent ## NAME = -1; +#define EVENT_DROPCON(NAME) lastDropConsecutiveEvent ## NAME = -1; +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## DROPTAG(NAME) + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) +#undef EVENT_HANDLER +#undef EVENT_DROPCON +#undef EVENT_DROPREP +#undef EVENT_NODROP + + collections::List events(std::move(filteredEvents)); + + for (auto&& event : events) + { + if (event.dropped) + { + continue; + } + +#define EVENT_NOREQ(NAME, REQUEST)\ + case FilteredEventNames::NAME:\ + targetEvents->On ## NAME();\ + break;\ + +#define EVENT_REQ(NAME, REQUEST)\ + case FilteredEventNames::NAME:\ + targetEvents->On ## NAME(event.arguments.Get());\ + break;\ + +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST) + switch (event.name) + { + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) + default: + CHECK_FAIL(L"vl::presentation::remoteprotocol::GuiRemoteEventFilter::ProcessEvents()#Unrecognized event."); + } +#undef EVENT_HANDLER +#undef EVENT_REQ +#undef EVENT_NOREQ + } + } + + // responses + +#define MESSAGE_NORES(NAME, RESPONSE) +#define MESSAGE_RES(NAME, RESPONSE)\ + void GuiRemoteEventFilter::Respond ## NAME(vint id, const RESPONSE& arguments)\ + {\ + CHECK_ERROR(\ + responseIds[id] == FilteredResponseNames::NAME,\ + L"vl::presentation::remoteprotocol::GuiRemoteEventFilter::"\ + L"Respond" L ## #NAME L"()#"\ + L"Messages sending to IGuiRemoteProtocol should be responded by calling the correct function.");\ + responseIds.Remove(id);\ + FilteredResponse response;\ + response.id = id;\ + response.name = FilteredResponseNames::NAME;\ + response.arguments = arguments;\ + filteredResponses.Add(response);\ + }\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_RES +#undef MESSAGE_NORES + + // events + +#define EVENT_NODROP(NAME) + +#define EVENT_DROPREP(NAME)\ + if (lastDropRepeatEvent ## NAME != -1)\ + {\ + filteredEvents[lastDropRepeatEvent ## NAME].dropped = true;\ + }\ + lastDropRepeatEvent ## NAME = filteredEvents.Count() - 1\ + +#define EVENT_DROPCON(NAME)\ + if (lastDropConsecutiveEvent ## NAME != -1 && lastDropConsecutiveEvent ## NAME == filteredEvents.Count() - 1)\ + {\ + filteredEvents[lastDropConsecutiveEvent ## NAME].dropped = true;\ + }\ + lastDropConsecutiveEvent ## NAME = filteredEvents.Count() - 1\ + +#define EVENT_NOREQ(NAME, REQUEST, DROPTAG)\ + void GuiRemoteEventFilter::On ## NAME()\ + {\ + if (submitting)\ + {\ + EVENT_ ## DROPTAG(NAME);\ + FilteredEvent event;\ + event.name = FilteredEventNames::NAME;\ + filteredEvents.Add(event);\ + }\ + else\ + {\ + targetEvents->On ## NAME();\ + }\ + }\ + +#define EVENT_REQ(NAME, REQUEST, DROPTAG)\ + void GuiRemoteEventFilter::On ## NAME(const REQUEST& arguments)\ + {\ + if (submitting)\ + {\ + EVENT_ ## DROPTAG(NAME);\ + FilteredEvent event;\ + event.name = FilteredEventNames::NAME;\ + event.arguments = arguments;\ + filteredEvents.Add(event);\ + }\ + else\ + {\ + targetEvents->On ## NAME(arguments);\ + }\ + }\ + +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST, DROPTAG) + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) +#undef EVENT_HANDLER +#undef EVENT_REQ +#undef EVENT_NOREQ +#undef EVENT_DROPCON +#undef EVENT_DROPREP +#undef EVENT_NOREP + +/*********************************************************************** +GuiRemoteProtocolFilter +***********************************************************************/ + + void GuiRemoteProtocolFilter::ProcessRequests() + { +#define MESSAGE_NODROP(NAME) +#define MESSAGE_DROPREP(NAME) lastDropRepeatRequest ## NAME = -1; +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG) MESSAGE_ ## DROPTAG(NAME) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_DROPREP +#undef MESSAGE_NODROP + + for (auto&& request : filteredRequests) + { + CHECK_ERROR(\ + !request.dropped || request.id == -1,\ + L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::ProcessRequests()#"\ + L"Messages with id cannot be dropped.");\ + if (request.dropped) + { + continue; + } + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)\ + case FilteredRequestNames::NAME:\ + targetProtocol->Request ## NAME();\ + break;\ + +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)\ + case FilteredRequestNames::NAME:\ + targetProtocol->Request ## NAME(request.id);\ + break;\ + +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)\ + case FilteredRequestNames::NAME:\ + targetProtocol->Request ## NAME(request.arguments.Get());\ + break;\ + +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)\ + case FilteredRequestNames::NAME:\ + targetProtocol->Request ## NAME(request.id, request.arguments.Get());\ + break;\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE) + switch (request.name) + { + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) + default: + CHECK_FAIL(L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::ProcessRequests()#Unrecognized request."); + } +#undef MESSAGE_HANDLER +#undef MESSAGE_REQ_RES +#undef MESSAGE_REQ_NORES +#undef MESSAGE_NOREQ_RES +#undef MESSAGE_NOREQ_NORES + } + + filteredRequests.Clear(); + } + + GuiRemoteProtocolFilter::GuiRemoteProtocolFilter(IGuiRemoteProtocol* _protocol) + : GuiRemoteProtocolCombinator(_protocol) + { + } + + GuiRemoteProtocolFilter::~GuiRemoteProtocolFilter() + { + } + + // messages + +#define MESSAGE_NODROP(NAME) + +#define MESSAGE_DROPREP(NAME)\ + if (lastDropRepeatRequest ## NAME != -1)\ + {\ + filteredRequests[lastDropRepeatRequest ## NAME].dropped = true;\ + }\ + lastDropRepeatRequest ## NAME = filteredRequests.Count()\ + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\ + void GuiRemoteProtocolFilter::Request ## NAME()\ + {\ + MESSAGE_ ## DROPTAG(NAME);\ + FilteredRequest request;\ + request.name = FilteredRequestNames::NAME;\ + filteredRequests.Add(request);\ + }\ + +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\ + void GuiRemoteProtocolFilter::Request ## NAME(vint id)\ + {\ + MESSAGE_ ## DROPTAG(NAME);\ + CHECK_ERROR(\ + lastRequestId < id,\ + L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::"\ + L"Request" L ## #NAME L"()#"\ + L"Id of a message sending to IGuiRemoteProtocol should be increasing.");\ + lastRequestId = id;\ + FilteredRequest request;\ + request.id = id;\ + request.name = FilteredRequestNames::NAME;\ + filteredRequests.Add(request);\ + eventCombinator.responseIds.Add(id, FilteredResponseNames::NAME);\ + }\ + +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\ + void GuiRemoteProtocolFilter::Request ## NAME(const REQUEST& arguments)\ + {\ + MESSAGE_ ## DROPTAG(NAME);\ + FilteredRequest request;\ + request.name = FilteredRequestNames::NAME;\ + request.arguments = arguments;\ + filteredRequests.Add(request);\ + }\ + +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\ + void GuiRemoteProtocolFilter::Request ## NAME(vint id, const REQUEST& arguments)\ + {\ + MESSAGE_ ## DROPTAG(NAME);\ + CHECK_ERROR(\ + lastRequestId < id,\ + L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::"\ + L"Request" L ## #NAME L"()#"\ + L"Id of a message sending to IGuiRemoteProtocol should be increasing.");\ + lastRequestId = id;\ + FilteredRequest request;\ + request.id = id;\ + request.name = FilteredRequestNames::NAME;\ + request.arguments = arguments;\ + filteredRequests.Add(request);\ + eventCombinator.responseIds.Add(id, FilteredResponseNames::NAME);\ + }\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE, DROPTAG) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_REQ_RES +#undef MESSAGE_REQ_NORES +#undef MESSAGE_NOREQ_RES +#undef MESSAGE_NOREQ_NORES +#undef MESSAGE_DROPREP +#undef MESSAGE_NODROP + + // protocol + + void GuiRemoteProtocolFilter::Initialize(IGuiRemoteProtocolEvents* _events) + { + if (auto verifierProtocol = dynamic_cast(targetProtocol)) + { + verifierProtocol->targetProtocol->Initialize(&eventCombinator); + eventCombinator.targetEvents = &verifierProtocol->eventCombinator; + verifierProtocol->eventCombinator.targetEvents = _events; + } + else + { + GuiRemoteProtocolCombinator::Initialize(_events); + } + } + + void GuiRemoteProtocolFilter::Submit(bool& disconnected) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::repeatfiltering::GuiRemoteProtocolFilter::Submit()#" + CHECK_ERROR(!eventCombinator.submitting, ERROR_MESSAGE_PREFIX L"This function is not allowed to be called recursively."); + eventCombinator.submitting = true; + ProcessRequests(); + GuiRemoteProtocolCombinator::Submit(disconnected); + if (disconnected) + { + eventCombinator.responseIds.Clear(); + } + else + { + eventCombinator.ProcessResponses(); + } + eventCombinator.submitting = false; + eventCombinator.ProcessEvents(); +#undef ERROR_MESSAGE_PREFIX + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_FILTERVERIFIER.CPP +***********************************************************************/ + +namespace vl::presentation::remoteprotocol::repeatfiltering +{ +/*********************************************************************** +GuiRemoteEventFilterVerifier +***********************************************************************/ + + GuiRemoteEventFilterVerifier::GuiRemoteEventFilterVerifier() + { + } + + GuiRemoteEventFilterVerifier::~GuiRemoteEventFilterVerifier() + { + } + + void GuiRemoteEventFilterVerifier::ClearDropRepeatMasks() + { +#define EVENT_NODROP(NAME) +#define EVENT_DROPREP(NAME) lastDropRepeatEvent ## NAME = false; +#define EVENT_DROPCON(NAME) +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## DROPTAG(NAME) + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) +#undef EVENT_HANDLER +#undef EVENT_DROPCON +#undef EVENT_DROPREP +#undef EVENT_NODROP + } + + void GuiRemoteEventFilterVerifier::ClearDropConsecutiveMasks() + { +#define EVENT_NODROP(NAME) +#define EVENT_DROPREP(NAME) +#define EVENT_DROPCON(NAME) lastDropConsecutiveEvent ## NAME = false; +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## DROPTAG(NAME) + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) +#undef EVENT_HANDLER +#undef EVENT_DROPCON +#undef EVENT_DROPREP +#undef EVENT_NODROP + } + + // responses + +#define MESSAGE_NORES(NAME, RESPONSE) +#define MESSAGE_RES(NAME, RESPONSE)\ + void GuiRemoteEventFilterVerifier::Respond ## NAME(vint id, const RESPONSE& arguments)\ + {\ + targetEvents->Respond ## NAME(id, arguments);\ + }\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_RES +#undef MESSAGE_NORES + + // events + +#define EVENT_NODROP(NAME) + +#define EVENT_DROPREP(NAME)\ + CHECK_ERROR(!lastDropRepeatEvent ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteEventFilterVerifier::On" L ## #NAME L"(...)#[@DropRepeat] event repeated.");\ + lastDropRepeatEvent ## NAME = true;\ + +#define EVENT_DROPCON(NAME)\ + CHECK_ERROR(!lastDropConsecutiveEvent ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteEventFilterVerifier::On" L ## #NAME L"(...)#[@DropConsecutive] event repeated.");\ + ClearDropConsecutiveMasks();\ + lastDropConsecutiveEvent ## NAME = true;\ + +#define EVENT_NOREQ(NAME, REQUEST, DROPTAG)\ + void GuiRemoteEventFilterVerifier::On ## NAME()\ + {\ + if (submitting)\ + {\ + EVENT_ ## DROPTAG(NAME);\ + targetEvents->On ## NAME();\ + }\ + else\ + {\ + targetEvents->On ## NAME();\ + }\ + }\ + +#define EVENT_REQ(NAME, REQUEST, DROPTAG)\ + void GuiRemoteEventFilterVerifier::On ## NAME(const REQUEST& arguments)\ + {\ + if (submitting)\ + {\ + EVENT_ ## DROPTAG(NAME);\ + targetEvents->On ## NAME(arguments);\ + }\ + else\ + {\ + targetEvents->On ## NAME(arguments);\ + }\ + }\ + +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST, DROPTAG) + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) +#undef EVENT_HANDLER +#undef EVENT_REQ +#undef EVENT_NOREQ +#undef EVENT_DROPCON +#undef EVENT_DROPREP +#undef EVENT_NOREP + +/*********************************************************************** +GuiRemoteProtocolFilterVerifier +***********************************************************************/ + + void GuiRemoteProtocolFilterVerifier::ClearDropRepeatMasks() + { +#define MESSAGE_NODROP(NAME) +#define MESSAGE_DROPREP(NAME) lastDropRepeatRequest ## NAME = false; +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG) MESSAGE_ ## DROPTAG(NAME) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_DROPREP +#undef MESSAGE_NODROP + } + + GuiRemoteProtocolFilterVerifier::GuiRemoteProtocolFilterVerifier(IGuiRemoteProtocol* _protocol) + : GuiRemoteProtocolCombinator(_protocol) + { + } + + GuiRemoteProtocolFilterVerifier::~GuiRemoteProtocolFilterVerifier() + { + } + + // messages + +#define MESSAGE_NODROP(NAME) + +#define MESSAGE_DROPREP(NAME)\ + CHECK_ERROR(!lastDropRepeatRequest ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilterVerifier::Request" L ## #NAME L"(...)#[@DropRepeat] message repeated.");\ + lastDropRepeatRequest ## NAME = true;\ + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\ + void GuiRemoteProtocolFilterVerifier::Request ## NAME()\ + {\ + MESSAGE_ ## DROPTAG(NAME);\ + targetProtocol->Request ## NAME();\ + }\ + +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\ + void GuiRemoteProtocolFilterVerifier::Request ## NAME(vint id)\ + {\ + MESSAGE_ ## DROPTAG(NAME);\ + targetProtocol->Request ## NAME(id);\ + }\ + +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\ + void GuiRemoteProtocolFilterVerifier::Request ## NAME(const REQUEST& arguments)\ + {\ + MESSAGE_ ## DROPTAG(NAME);\ + targetProtocol->Request ## NAME(arguments);\ + }\ + +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\ + void GuiRemoteProtocolFilterVerifier::Request ## NAME(vint id, const REQUEST& arguments)\ + {\ + MESSAGE_ ## DROPTAG(NAME);\ + targetProtocol->Request ## NAME(id, arguments);\ + }\ + +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE, DROPTAG) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_REQ_RES +#undef MESSAGE_REQ_NORES +#undef MESSAGE_NOREQ_RES +#undef MESSAGE_NOREQ_NORES +#undef MESSAGE_DROPREP +#undef MESSAGE_NODROP + + // protocol + + void GuiRemoteProtocolFilterVerifier::Submit(bool& disconnected) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::repeatfiltering::GuiRemoteProtocolFilterVerifier::Submit()#" + CHECK_ERROR(!eventCombinator.submitting, ERROR_MESSAGE_PREFIX L"This function is not allowed to be called recursively."); + eventCombinator.submitting = true; + GuiRemoteProtocolCombinator::Submit(disconnected); + ClearDropRepeatMasks(); + eventCombinator.ClearDropRepeatMasks(); + eventCombinator.ClearDropConsecutiveMasks(); + eventCombinator.submitting = false; +#undef ERROR_MESSAGE_PREFIX + } +} + /*********************************************************************** .\PLATFORMPROVIDERS\REMOTE\GUIREMOTEWINDOW.CPP ***********************************************************************/ @@ -40277,9 +41551,11 @@ GuiRemoteWindow void GuiRemoteWindow::RequestGetBounds() { - sizingConfigInvalidated = false; vint idGetBounds = remoteMessages.RequestWindowGetBounds(); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + if (disconnected) return; + sizingConfigInvalidated = false; OnWindowBoundsUpdated(remoteMessages.RetrieveWindowGetBounds(idGetBounds)); } @@ -40318,7 +41594,9 @@ GuiRemoteWindow windowShowing.activate = activate; windowShowing.sizeState = sizeState; remoteMessages.RequestWindowNotifyShow(windowShowing); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + // there is no result from this request, assuming succeeded remoteWindowSizingConfig.sizeState = sizeState; Opened(); @@ -40342,8 +41620,15 @@ GuiRemoteWindow (events) } sizingConfigInvalidated = true; + remoteMessages.RequestWindowNotifySetBounds(remoteWindowSizingConfig.bounds); RequestGetBounds(); + // TODO: + // This is a workaround to call GuiWindow::UpdateCustomFramePadding + // Refactor to make it more elegant. + for (auto l : listeners) l->DpiChanged(true); + for (auto l : listeners) l->DpiChanged(false); + if (remote->applicationRunning) { remoteMessages.RequestWindowNotifySetTitle(styleTitle); @@ -40365,7 +41650,9 @@ GuiRemoteWindow (events) { remoteMessages.RequestIOReleaseCapture(); } - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + // there is no result from this request, assuming succeeded } } @@ -40486,6 +41773,17 @@ GuiRemoteWindow (INativeWindow) { if (remoteWindowSizingConfig.bounds != bounds) { + auto x1 = remoteWindowSizingConfig.clientBounds.x1 - remoteWindowSizingConfig.bounds.x1; + auto y1 = remoteWindowSizingConfig.clientBounds.y1 - remoteWindowSizingConfig.bounds.y1; + auto x2 = remoteWindowSizingConfig.clientBounds.x2 - remoteWindowSizingConfig.bounds.x2; + auto y2 = remoteWindowSizingConfig.clientBounds.y2 - remoteWindowSizingConfig.bounds.y2; + remoteWindowSizingConfig.bounds = bounds; + remoteWindowSizingConfig.clientBounds = { + x1 + remoteWindowSizingConfig.bounds.x1, + y1 + remoteWindowSizingConfig.bounds.y1, + x2 + remoteWindowSizingConfig.bounds.x2, + y2 + remoteWindowSizingConfig.bounds.y2 + }; remoteMessages.RequestWindowNotifySetBounds(bounds); sizingConfigInvalidated = true; } @@ -40501,6 +41799,17 @@ GuiRemoteWindow (INativeWindow) { if (remoteWindowSizingConfig.clientBounds.GetSize() != size) { + auto x1 = remoteWindowSizingConfig.bounds.x1 - remoteWindowSizingConfig.clientBounds.x1; + auto y1 = remoteWindowSizingConfig.bounds.y1 - remoteWindowSizingConfig.clientBounds.y1; + auto x2 = remoteWindowSizingConfig.bounds.x2 - remoteWindowSizingConfig.clientBounds.x2; + auto y2 = remoteWindowSizingConfig.bounds.y2 - remoteWindowSizingConfig.clientBounds.y2; + remoteWindowSizingConfig.clientBounds = { remoteWindowSizingConfig.clientBounds.LeftTop(),size }; + remoteWindowSizingConfig.bounds = { + x1 + remoteWindowSizingConfig.clientBounds.x1, + y1 + remoteWindowSizingConfig.clientBounds.y1, + x2 + remoteWindowSizingConfig.clientBounds.x2, + y2 + remoteWindowSizingConfig.clientBounds.y2 + }; remoteMessages.RequestWindowNotifySetClientSize(size); sizingConfigInvalidated = true; } @@ -40725,7 +42034,9 @@ GuiRemoteWindow (INativeWindow) { statusCapturing = true; remoteMessages.RequestIORequireCapture(); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + // there is no result from this request, assuming succeeded } return true; } @@ -40736,7 +42047,9 @@ GuiRemoteWindow (INativeWindow) { statusCapturing = false; remoteMessages.RequestIOReleaseCapture(); - remoteMessages.Submit(); + bool disconnected = false; + remoteMessages.Submit(disconnected); + // there is no result from this request, assuming succeeded } return true; } @@ -40854,6 +42167,605 @@ GuiRemoteWindow (INativeWindow) #undef SET_REMOTE_WINDOW_STYLE } +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\PROTOCOL\FRAMEOPERATIONS\GUIREMOTEPROTOCOLSCHEMA_BUILDFRAME.CPP +***********************************************************************/ + +namespace vl::presentation::remoteprotocol +{ + vint RenderingDomBuilder::GetCurrentBoundary() + { + if (domBoundaries.Count() > 0) + { + return domBoundaries[domBoundaries.Count() - 1]; + } + else + { + return 0; + } + } + + vint RenderingDomBuilder::Push(RenderingResultRef ref) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::RenderingDomBuilder::Push(RenderingResultRef)#" + CHECK_ERROR(ref, ERROR_MESSAGE_PREFIX L"Cannot push a null dom object."); + vint index = domStack.Add(ref); + if (!domCurrent->children) domCurrent->children = Ptr(new RenderingResultRefList); + domCurrent->children->Add(ref); + domCurrent = ref; + return index; +#undef ERROR_MESSAGE_PREFIX + } + + void RenderingDomBuilder::PopTo(vint index) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::RenderingDomBuilder::PopTo(vint)#" + if (index == domStack.Count() - 1) return; + CHECK_ERROR(0 <= index && index < domStack.Count(), ERROR_MESSAGE_PREFIX L"Cannot pop to an invalid position."); + CHECK_ERROR(index >= GetCurrentBoundary(), ERROR_MESSAGE_PREFIX L"Cannot pop across a boundary."); + while (domStack.Count() - 1 > index) + { + domStack.RemoveAt(domStack.Count() - 1); + } + domCurrent = domStack[index]; +#undef ERROR_MESSAGE_PREFIX + } + + void RenderingDomBuilder::Pop() + { + PopTo(domStack.Count() - 2); + } + + void RenderingDomBuilder::PopBoundary() + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::RenderingDomBuilder::PopBoundary()#" + CHECK_ERROR(domBoundaries.Count() > 0, ERROR_MESSAGE_PREFIX L"Cannot pop a boundary when none is in the stack."); + auto boundaryIndex = domBoundaries.Count() - 1; + auto boundary = domBoundaries[boundaryIndex]; + domBoundaries.RemoveAt(boundaryIndex); + PopTo(boundary - 1); +#undef ERROR_MESSAGE_PREFIX + } + + + template + void RenderingDomBuilder::PrepareParentFromCommand(Rect commandBounds, Rect commandValidArea, vint newDomId, TCallback&& calculateValidAreaFromDom) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::RenderingDomBuilder::PrepareParentFromCommand(Rect, Rect, vint, auto&&)#" + vint min = GetCurrentBoundary(); + bool found = false; + if (commandValidArea.Contains(commandBounds)) + { + // if the command is not clipped + for (vint i = domStack.Count() - 1; i >= min; i--) + { + if (domStack[i]->content.validArea.Contains(commandBounds) || i == 0) + { + // find the deepest node that could contain the command + PopTo(i); + found = true; + break; + } + } + } + else + { + // otherwise, a parent node causing such clipping should be found or created + for (vint i = domStack.Count() - 1; i >= min; i--) + { + auto domValidArea = calculateValidAreaFromDom(domStack[i]); + if (domValidArea == commandValidArea) + { + // if there is a node who clips command's bound to its valid area + // that is the parent node of the command + PopTo(i); + found = true; + break; + } + else if (domValidArea.Contains(commandValidArea) || i == 0) + { + // otherwise find a deepest node who could visually contain the command + // create a virtual node to satisfy the clipper + PopTo(i); + auto parent = Ptr(new RenderingDom); + parent->id = newDomId; + parent->content.bounds = commandValidArea; + parent->content.validArea = commandValidArea; + Push(parent); + found = true; + break; + } + } + } + + // if the new boundary could not fit in the current boundary + // there must be something wrong + CHECK_ERROR(found, ERROR_MESSAGE_PREFIX L"Incorrect valid area of dom."); +#undef ERROR_MESSAGE_PREFIX + } + + void RenderingDomBuilder::RequestRendererBeginRendering() + { + domStack.Clear(); + domBoundaries.Clear(); + domRoot = Ptr(new RenderingDom); + domRoot->id = -1; + domCurrent = domRoot; + domStack.Add(domRoot); + } + + void RenderingDomBuilder::RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments) + { + // a new boundary should be a new node covering existing nodes + // the valid area of boundary is clipped by its bounds + // so the valid area to compare from its potential parent dom needs to clipped by its bounds + PrepareParentFromCommand( + arguments.bounds, + arguments.areaClippedBySelf, + (arguments.id << 2) + 3, + [&](auto&& dom) { return dom->content.validArea.Intersect(arguments.bounds); } + ); + + auto dom = Ptr(new RenderingDom); + dom->id = (arguments.id << 2) + 2; + dom->content.hitTestResult = arguments.hitTestResult; + dom->content.cursor = arguments.cursor; + dom->content.bounds = arguments.bounds; + dom->content.validArea = arguments.areaClippedBySelf; + domBoundaries.Add(Push(dom)); + } + + void RenderingDomBuilder::RequestRendererEndBoundary() + { + PopBoundary(); + } + + void RenderingDomBuilder::RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments) + { + // a new element should be a new node covering existing nodes + // the valid area of boundary is clipped by its parent + // so the valid area to compare from its potential parent dom is its valid area + PrepareParentFromCommand( + arguments.bounds, + arguments.areaClippedByParent, + (arguments.id << 2) + 1, + [&](auto&& dom) { return dom->content.validArea; } + ); + + auto dom = Ptr(new RenderingDom); + dom->id = (arguments.id << 2) + 0; + dom->content.element = arguments.id; + dom->content.bounds = arguments.bounds; + dom->content.validArea = arguments.bounds.Intersect(arguments.areaClippedByParent); + Push(dom); + } + + Ptr RenderingDomBuilder::RequestRendererEndRendering() + { + return domRoot; + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\PROTOCOL\FRAMEOPERATIONS\GUIREMOTEPROTOCOLSCHEMA_COPYDOM.CPP +***********************************************************************/ + +namespace vl::presentation::remoteprotocol +{ + using namespace collections; + + Ptr CopyDom(Ptr root) + { + auto newRoot = Ptr(new RenderingDom); + newRoot->id = root->id; + newRoot->content = root->content; + if (root->children) + { + newRoot->children = Ptr(new List>); + for (auto child : *root->children.Obj()) + { + newRoot->children->Add(CopyDom(child)); + } + } + return newRoot; + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\PROTOCOL\FRAMEOPERATIONS\GUIREMOTEPROTOCOLSCHEMA_DIFFFRAME.CPP +***********************************************************************/ + +namespace vl::presentation::remoteprotocol +{ + using namespace collections; + + vint CountDomIndex(Ptr root) + { + vint counter = 1; + if (root->children) + { + for (auto child : *root->children.Obj()) + { + counter += CountDomIndex(child); + } + } + return counter; + } + + void BuildDomIndexInternal(Ptr dom, vint parentId, DomIndex& index, vint& writing) + { + index[writing++] = { dom->id,parentId,dom }; + if (dom->children) + { + for (auto child : *dom->children.Obj()) + { + BuildDomIndexInternal(child, dom->id, index, writing); + } + } + } + + void SortDomIndex(DomIndex& index) + { + if (index.Count() > 0) + { + SortLambda(&index[0], index.Count(), [](const DomIndexItem& a, const DomIndexItem& b) + { + return a.id <=> b.id; + }); + } + } + + void BuildDomIndex(Ptr root, DomIndex& index) + { + vint count = CountDomIndex(root); + vint writing = 0; + index.Resize(count); + if (count > 0) + { + BuildDomIndexInternal(root, -1, index, writing); + SortDomIndex(index); + } + } + + void UpdateDomInplace(Ptr root, DomIndex& index, const RenderingDom_DiffsInOrder& diffs) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::UpdateDomInplace(Ptr, DomIndex&, const RenderingDom_DiffsInOrder&)#" + CHECK_ERROR(root && root->id == -1, ERROR_MESSAGE_PREFIX L"Roots of a DOM must have ID -1."); + + vint createdCount = 0; + + // creating + { + vint readingFrom = 0; + vint readingTo = 0; + + auto markCreated = [&]() + { + auto&& to = diffs.diffsInOrder->Get(readingTo++); + CHECK_ERROR(to.diffType == RenderingDom_DiffType::Created, ERROR_MESSAGE_PREFIX L"Diff of unexisting node must have diffType == Created."); + createdCount++; + }; + + while (diffs.diffsInOrder && readingTo < diffs.diffsInOrder->Count()) + { + if (readingFrom < index.Count()) + { + auto&& from = index[readingFrom]; + auto&& to = diffs.diffsInOrder->Get(readingTo); + if (from.id < to.id) + { + // Nothing happened to this DOM node + readingFrom++; + } + else if (from.id > to.id) + { + markCreated(); + } + else + { + // Modified will be delayed and processed together with Created + readingFrom++; + readingTo++; + CHECK_ERROR(to.diffType != RenderingDom_DiffType::Created, ERROR_MESSAGE_PREFIX L"Diff of existing node must have diffType != Created."); + } + } + else + { + markCreated(); + } + } + } + + { + vint writing = index.Count(); + index.Resize(index.Count() + createdCount); + if (diffs.diffsInOrder) + { + + for (auto&& to : *diffs.diffsInOrder.Obj()) + { + if (to.diffType == RenderingDom_DiffType::Created) + { + // parentId will be filled later + auto dom = Ptr(new RenderingDom); + dom->id = to.id; + index[writing++] = { to.id,-1,dom }; + } + } + } + SortDomIndex(index); + } + + // modifying + { + vint readingFrom = 0; + vint readingTo = 0; + + while (readingFrom < index.Count() && (diffs.diffsInOrder && readingTo < diffs.diffsInOrder->Count())) + { + bool hasFrom = readingFrom < index.Count(); + bool hasTo = diffs.diffsInOrder && readingTo < diffs.diffsInOrder->Count(); + + auto&& from = index[readingFrom]; + auto&& to = diffs.diffsInOrder->Get(readingTo); + if (from.id < to.id) + { + readingFrom++; + } + else if (from.id > to.id) + { + readingTo++; + } + else + { + readingFrom++; + readingTo++; + + if (to.diffType != RenderingDom_DiffType::Deleted) + { + if (to.content) + { + from.dom->content = to.content.Value(); + } + + if (to.children) + { + if (to.children->Count() == 0) + { + from.dom->children = nullptr; + } + else + { + from.dom->children = Ptr(new List>); + for (vint childId : *to.children.Obj()) + { + // Binary search in index for childId + vint start = 0; + vint end = index.Count() - 1; + bool found = false; + while (start <= end) + { + vint mid = (start + end) / 2; + vint midId = index[mid].id; + if (childId < midId) + { + end = mid - 1; + } + else if (childId > midId) + { + start = mid + 1; + } + else + { + // Fill parentId of the new DOM node + index[mid].parentId = from.id; + from.dom->children->Add(index[mid].dom); + found = true; + break; + } + } + CHECK_ERROR(found, ERROR_MESSAGE_PREFIX L"Unknown DOM id in diff."); + } + } + } + } + } + } + } + + // deleting + { + vint readingFrom = 0; + vint readingTo = 0; + List deleteIndices; + + while (diffs.diffsInOrder && readingTo < diffs.diffsInOrder->Count()) + { + if (readingFrom < index.Count()) + { + auto&& from = index[readingFrom]; + auto&& to = diffs.diffsInOrder->Get(readingTo); + if (from.id < to.id) + { + readingFrom++; + } + else if (from.id > to.id) + { + readingTo++; + } + else + { + if (to.diffType == RenderingDom_DiffType::Deleted) + { + deleteIndices.Add(readingFrom); + } + readingFrom++; + readingTo++; + } + } + else + { + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Nodes to be deleted must should appear in the index before modification"); + } + } + + vint reading = 0; + vint writing = 0; + vint testing = 0; + + while (reading < index.Count()) + { + if (testing < deleteIndices.Count() && deleteIndices[testing] == reading) + { + // A node to delete is found, mark and skip + testing++; + reading++; + } + else + { + if (reading != writing) + { + // Compact index by removing deleted entries + index[writing] = index[reading]; + } + reading++; + writing++; + } + } + index.Resize(index.Count() - deleteIndices.Count()); + } +#undef ERROR_MESSAGE_PREFIX + } + + void DiffDom(Ptr domFrom, DomIndex& indexFrom, Ptr domTo, DomIndex& indexTo, RenderingDom_DiffsInOrder& diffs) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::DiffDom(Ptr, DomIndex&, Ptr, DomIndex&, RenderingDom_DiffsInOrder&)#" + CHECK_ERROR(domFrom && domTo && domFrom->id == domTo->id, ERROR_MESSAGE_PREFIX L"Roots of two DOMs tree must have the same ID."); + diffs.diffsInOrder = Ptr(new List); + + vint readingFrom = 0; + vint readingTo = 0; + + auto pushDeleted = [&]() + { + auto&& dom = indexFrom[readingFrom++].dom; + RenderingDom_Diff diff; + + diff.id = dom->id; + diff.diffType = RenderingDom_DiffType::Deleted; + diffs.diffsInOrder->Add(diff); + }; + + auto pushCreated = [&]() + { + auto&& dom = indexTo[readingTo++].dom; + RenderingDom_Diff diff; + diff.id = dom->id; + diff.diffType = RenderingDom_DiffType::Created; + + diff.content = dom->content; + if (dom->children && dom->children->Count() > 0) + { + diff.children = Ptr(new List); + CopyFrom( + *diff.children.Obj(), + From(*dom->children.Obj()) + .Select([](Ptr child) { return child->id; }) + ); + } + diffs.diffsInOrder->Add(diff); + }; + + auto pushModified = [&]() + { + auto&& domFrom = indexFrom[readingFrom++].dom; + auto&& domTo = indexTo[readingTo++].dom; + RenderingDom_Diff diff; + diff.id = domFrom->id; + diff.diffType = RenderingDom_DiffType::Modified; + + if ( + domFrom->content.hitTestResult != domTo->content.hitTestResult || + domFrom->content.cursor != domTo->content.cursor || + domFrom->content.element != domTo->content.element || + domFrom->content.bounds != domTo->content.bounds || + domFrom->content.validArea != domTo->content.validArea + ) + { + diff.content = domTo->content; + } + + bool fromHasChild = domFrom->children && domFrom->children->Count() > 0; + bool toHasChild = domTo->children && domTo->children->Count() > 0; + bool childDifferent = false; + + if (fromHasChild != toHasChild) + { + childDifferent = true; + } + else if (fromHasChild && toHasChild) + { + auto fromIds = From(*domFrom->children.Obj()) + .Select([](Ptr child) { return child->id; }); + auto toIds = From(*domTo->children.Obj()) + .Select([](Ptr child) { return child->id; }); + childDifferent = CompareEnumerable(fromIds, toIds) != 0; + } + + if (childDifferent) + { + diff.children = Ptr(new List); + if (toHasChild) + { + CopyFrom( + *diff.children.Obj(), + From(*domTo->children.Obj()) + .Select([](Ptr child) { return child->id; }) + ); + } + } + + if (diff.content || diff.children) + { + diffs.diffsInOrder->Add(diff); + } + }; + + while (true) + { + if (readingFrom < indexFrom.Count() && readingTo < indexTo.Count()) + { + if (indexFrom[readingFrom].id < indexTo[readingTo].id) + { + pushDeleted(); + } + else if (indexFrom[readingFrom].id > indexTo[readingTo].id) + { + pushCreated(); + } + else + { + pushModified(); + } + } + else if (readingFrom < indexFrom.Count()) + { + pushDeleted(); + } + else if (readingTo < indexTo.Count()) + { + pushCreated(); + } + else + { + break; + } + } + +#undef ERROR_MESSAGE_PREFIX + } +} + /*********************************************************************** .\PLATFORMPROVIDERS\REMOTE\PROTOCOL\GENERATED\GUIREMOTEPROTOCOLSCHEMA.CPP ***********************************************************************/ @@ -41080,6 +42992,21 @@ namespace vl::presentation::remoteprotocol #undef ERROR_MESSAGE_PREFIX } + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(const ::vl::presentation::remoteprotocol::RenderingDom_DiffType & value) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(const ::vl::presentation::remoteprotocol::RenderingDom_DiffType&)#" + auto node = Ptr(new glr::json::JsonString); + switch (value) + { + case ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Deleted: node->content.value = WString::Unmanaged(L"Deleted"); break; + case ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Created: node->content.value = WString::Unmanaged(L"Created"); break; + case ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Modified: node->content.value = WString::Unmanaged(L"Modified"); break; + default: CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value."); + } + return node; +#undef ERROR_MESSAGE_PREFIX + } + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::NativeCoordinate>(const ::vl::presentation::NativeCoordinate & value) { auto node = Ptr(new glr::json::JsonObject); @@ -41416,6 +43343,7 @@ namespace vl::presentation::remoteprotocol template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementBoundary>(const ::vl::presentation::remoteprotocol::ElementBoundary & value) { auto node = Ptr(new glr::json::JsonObject); + ConvertCustomTypeToJsonField(node, L"id", value.id); ConvertCustomTypeToJsonField(node, L"hitTestResult", value.hitTestResult); ConvertCustomTypeToJsonField(node, L"cursor", value.cursor); ConvertCustomTypeToJsonField(node, L"bounds", value.bounds); @@ -41449,7 +43377,7 @@ namespace vl::presentation::remoteprotocol return node; } - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom>(const ::vl::presentation::remoteprotocol::RenderingDom & value) + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDomContent>(const ::vl::presentation::remoteprotocol::RenderingDomContent & value) { auto node = Ptr(new glr::json::JsonObject); ConvertCustomTypeToJsonField(node, L"hitTestResult", value.hitTestResult); @@ -41457,44 +43385,47 @@ namespace vl::presentation::remoteprotocol ConvertCustomTypeToJsonField(node, L"element", value.element); ConvertCustomTypeToJsonField(node, L"bounds", value.bounds); ConvertCustomTypeToJsonField(node, L"validArea", value.validArea); + return node; + } + + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom>(const ::vl::presentation::remoteprotocol::RenderingDom & value) + { + auto node = Ptr(new glr::json::JsonObject); + ConvertCustomTypeToJsonField(node, L"id", value.id); + ConvertCustomTypeToJsonField(node, L"content", value.content); ConvertCustomTypeToJsonField(node, L"children", value.children); return node; } - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary>(const ::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary & value) + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_Diff>(const ::vl::presentation::remoteprotocol::RenderingDom_Diff & value) { auto node = Ptr(new glr::json::JsonObject); - ConvertCustomTypeToJsonField(node, L"boundary", value.boundary); + ConvertCustomTypeToJsonField(node, L"id", value.id); + ConvertCustomTypeToJsonField(node, L"diffType", value.diffType); + ConvertCustomTypeToJsonField(node, L"content", value.content); + ConvertCustomTypeToJsonField(node, L"children", value.children); return node; } - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary>(const ::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary & value) + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder>(const ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder & value) { auto node = Ptr(new glr::json::JsonObject); + ConvertCustomTypeToJsonField(node, L"diffsInOrder", value.diffsInOrder); return node; } - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingCommand_Element>(const ::vl::presentation::remoteprotocol::RenderingCommand_Element & value) - { - auto node = Ptr(new glr::json::JsonObject); - ConvertCustomTypeToJsonField(node, L"rendering", value.rendering); - ConvertCustomTypeToJsonField(node, L"element", value.element); - return node; - } - - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingFrame>(const ::vl::presentation::remoteprotocol::RenderingFrame & value) + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>(const ::vl::presentation::remoteprotocol::UnitTest_RenderingFrame & value) { auto node = Ptr(new glr::json::JsonObject); ConvertCustomTypeToJsonField(node, L"frameId", value.frameId); ConvertCustomTypeToJsonField(node, L"frameName", value.frameName); ConvertCustomTypeToJsonField(node, L"windowSize", value.windowSize); ConvertCustomTypeToJsonField(node, L"elements", value.elements); - ConvertCustomTypeToJsonField(node, L"commands", value.commands); ConvertCustomTypeToJsonField(node, L"root", value.root); return node; } - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingTrace>(const ::vl::presentation::remoteprotocol::RenderingTrace & value) + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace>(const ::vl::presentation::remoteprotocol::UnitTest_RenderingTrace & value) { auto node = Ptr(new glr::json::JsonObject); ConvertCustomTypeToJsonField(node, L"createdElements", value.createdElements); @@ -41683,6 +43614,18 @@ namespace vl::presentation::remoteprotocol #undef ERROR_MESSAGE_PREFIX } + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom_DiffType& value) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(Ptr, ::vl::presentation::remoteprotocol::RenderingDom_DiffType&)#" + auto jsonNode = node.Cast(); + CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); + if (jsonNode->content.value == L"Deleted") value = ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Deleted; else + if (jsonNode->content.value == L"Created") value = ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Created; else + if (jsonNode->content.value == L"Modified") value = ::vl::presentation::remoteprotocol::RenderingDom_DiffType::Modified; else + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported enum value."); +#undef ERROR_MESSAGE_PREFIX + } + template<> void ConvertJsonToCustomType<::vl::presentation::NativeCoordinate>(vl::Ptr node, ::vl::presentation::NativeCoordinate& value) { #define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::NativeCoordinate>(Ptr, ::vl::presentation::NativeCoordinate&)#" @@ -42227,6 +44170,7 @@ namespace vl::presentation::remoteprotocol CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); for (auto field : jsonNode->fields) { + if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else if (field->name.value == L"hitTestResult") ConvertJsonToCustomType(field->value, value.hitTestResult); else if (field->name.value == L"cursor") ConvertJsonToCustomType(field->value, value.cursor); else if (field->name.value == L"bounds") ConvertJsonToCustomType(field->value, value.bounds); else @@ -42280,9 +44224,9 @@ namespace vl::presentation::remoteprotocol #undef ERROR_MESSAGE_PREFIX } - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom& value) + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDomContent>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDomContent& value) { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom>(Ptr, ::vl::presentation::remoteprotocol::RenderingDom&)#" +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDomContent>(Ptr, ::vl::presentation::remoteprotocol::RenderingDomContent&)#" auto jsonNode = node.Cast(); CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); for (auto field : jsonNode->fields) @@ -42292,54 +44236,58 @@ namespace vl::presentation::remoteprotocol if (field->name.value == L"element") ConvertJsonToCustomType(field->value, value.element); else if (field->name.value == L"bounds") ConvertJsonToCustomType(field->value, value.bounds); else if (field->name.value == L"validArea") ConvertJsonToCustomType(field->value, value.validArea); else + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member."); + } +#undef ERROR_MESSAGE_PREFIX + } + + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom& value) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom>(Ptr, ::vl::presentation::remoteprotocol::RenderingDom&)#" + auto jsonNode = node.Cast(); + CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); + for (auto field : jsonNode->fields) + { + if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else + if (field->name.value == L"content") ConvertJsonToCustomType(field->value, value.content); else if (field->name.value == L"children") ConvertJsonToCustomType(field->value, value.children); else CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member."); } #undef ERROR_MESSAGE_PREFIX } - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary& value) + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_Diff>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom_Diff& value) { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary>(Ptr, ::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary&)#" +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_Diff>(Ptr, ::vl::presentation::remoteprotocol::RenderingDom_Diff&)#" auto jsonNode = node.Cast(); CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); for (auto field : jsonNode->fields) { - if (field->name.value == L"boundary") ConvertJsonToCustomType(field->value, value.boundary); else + if (field->name.value == L"id") ConvertJsonToCustomType(field->value, value.id); else + if (field->name.value == L"diffType") ConvertJsonToCustomType(field->value, value.diffType); else + if (field->name.value == L"content") ConvertJsonToCustomType(field->value, value.content); else + if (field->name.value == L"children") ConvertJsonToCustomType(field->value, value.children); else CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member."); } #undef ERROR_MESSAGE_PREFIX } - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary& value) + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder& value) { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary>(Ptr, ::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary&)#" +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder>(Ptr, ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder&)#" auto jsonNode = node.Cast(); CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); for (auto field : jsonNode->fields) { + if (field->name.value == L"diffsInOrder") ConvertJsonToCustomType(field->value, value.diffsInOrder); else CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member."); } #undef ERROR_MESSAGE_PREFIX } - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_Element>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingCommand_Element& value) + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>(vl::Ptr node, ::vl::presentation::remoteprotocol::UnitTest_RenderingFrame& value) { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_Element>(Ptr, ::vl::presentation::remoteprotocol::RenderingCommand_Element&)#" - auto jsonNode = node.Cast(); - CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); - for (auto field : jsonNode->fields) - { - if (field->name.value == L"rendering") ConvertJsonToCustomType(field->value, value.rendering); else - if (field->name.value == L"element") ConvertJsonToCustomType(field->value, value.element); else - CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member."); - } -#undef ERROR_MESSAGE_PREFIX - } - - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingFrame>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingFrame& value) - { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingFrame>(Ptr, ::vl::presentation::remoteprotocol::RenderingFrame&)#" +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>(Ptr, ::vl::presentation::remoteprotocol::UnitTest_RenderingFrame&)#" auto jsonNode = node.Cast(); CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); for (auto field : jsonNode->fields) @@ -42348,16 +44296,15 @@ namespace vl::presentation::remoteprotocol if (field->name.value == L"frameName") ConvertJsonToCustomType(field->value, value.frameName); else if (field->name.value == L"windowSize") ConvertJsonToCustomType(field->value, value.windowSize); else if (field->name.value == L"elements") ConvertJsonToCustomType(field->value, value.elements); else - if (field->name.value == L"commands") ConvertJsonToCustomType(field->value, value.commands); else if (field->name.value == L"root") ConvertJsonToCustomType(field->value, value.root); else CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unsupported struct member."); } #undef ERROR_MESSAGE_PREFIX } - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingTrace>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingTrace& value) + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace>(vl::Ptr node, ::vl::presentation::remoteprotocol::UnitTest_RenderingTrace& value) { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingTrace>(Ptr, ::vl::presentation::remoteprotocol::RenderingTrace&)#" +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace>(Ptr, ::vl::presentation::remoteprotocol::UnitTest_RenderingTrace&)#" auto jsonNode = node.Cast(); CHECK_ERROR(jsonNode, ERROR_MESSAGE_PREFIX L"Json node does not match the expected type."); for (auto field : jsonNode->fields) @@ -42374,6 +44321,1139 @@ namespace vl::presentation::remoteprotocol } +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE.CPP +***********************************************************************/ + +namespace vl::presentation::remote_renderer +{ + using namespace elements; + using namespace remoteprotocol; + + remoteprotocol::ScreenConfig GuiRemoteRendererSingle::GetScreenConfig(INativeScreen* screen) + { + ScreenConfig response; + response.bounds = screen->GetBounds(); + response.clientBounds = screen->GetClientBounds(); + response.scalingX = screen->GetScalingX(); + response.scalingY = screen->GetScalingY(); + return response; + } + + remoteprotocol::WindowSizingConfig GuiRemoteRendererSingle::GetWindowSizingConfig() + { + WindowSizingConfig response; + response.bounds = window->GetBounds(); + response.clientBounds = window->GetClientBoundsInScreen(); + response.sizeState = window->GetSizeState(); + response.customFramePadding = window->GetCustomFramePadding(); + return response; + } + + void GuiRemoteRendererSingle::UpdateConfigsIfNecessary() + { + if (screen) + { + auto currentScreen = GetCurrentController()->ScreenService()->GetScreen(window); + if (screen != currentScreen) + { + screen = currentScreen; + events->OnControllerScreenUpdated(GetScreenConfig(screen)); + } + + auto newWindowSizingConfig = GetWindowSizingConfig(); + if ( + newWindowSizingConfig.bounds != windowSizingConfig.bounds || + newWindowSizingConfig.clientBounds != windowSizingConfig.clientBounds) + { + windowSizingConfig = newWindowSizingConfig; + if (!updatingBounds) + { + events->OnWindowBoundsUpdated(windowSizingConfig); + } + } + else if ( + newWindowSizingConfig.sizeState != windowSizingConfig.sizeState || + newWindowSizingConfig.customFramePadding != windowSizingConfig.customFramePadding) + { + windowSizingConfig = newWindowSizingConfig; + events->OnWindowBoundsUpdated(windowSizingConfig); + } + } + } + + void GuiRemoteRendererSingle::NativeWindowDestroying(INativeWindow* _window) + { + if (window == _window) + { + window->UninstallListener(this); + window = nullptr; + } + } + + void GuiRemoteRendererSingle::Opened() + { + events->OnControllerConnect(); + } + + void GuiRemoteRendererSingle::BeforeClosing(bool& cancel) + { + if (!disconnectingFromCore) + { + cancel = true; + events->OnControllerRequestExit(); + } + } + + void GuiRemoteRendererSingle::AfterClosing() + { + renderingDom = nullptr; + availableElements.Clear(); + availableImages.Clear(); + } + + void GuiRemoteRendererSingle::Closed() + { + } + + void GuiRemoteRendererSingle::Moved() + { + UpdateConfigsIfNecessary(); + } + + void GuiRemoteRendererSingle::DpiChanged(bool preparing) + { + if (preparing) + { + UpdateRenderTarget(nullptr); + } + else + { + GetGuiGraphicsResourceManager()->RecreateRenderTarget(window); + UpdateRenderTarget(GetGuiGraphicsResourceManager()->GetRenderTarget(window)); + UpdateConfigsIfNecessary(); + } + } + + void GuiRemoteRendererSingle::RenderingAsActivated() + { + if (disconnectingFromCore) return; + events->OnWindowActivatedUpdated(true); + } + + void GuiRemoteRendererSingle::RenderingAsDeactivated() + { + if (disconnectingFromCore) return; + events->OnWindowActivatedUpdated(false); + } + + GuiRemoteRendererSingle::GuiRemoteRendererSingle() + { + } + + GuiRemoteRendererSingle::~GuiRemoteRendererSingle() + { + } + + void GuiRemoteRendererSingle::RegisterMainWindow(INativeWindow* _window) + { + window = _window; + window->InstallListener(this); + GetCurrentController()->CallbackService()->InstallListener(this); + } + + void GuiRemoteRendererSingle::UnregisterMainWindow() + { + GetCurrentController()->CallbackService()->UninstallListener(this); + } + + void GuiRemoteRendererSingle::ForceExitByFatelError() + { + if (window) + { + disconnectingFromCore = true; + window->Hide(true); + } + } + + WString GuiRemoteRendererSingle::GetExecutablePath() + { + CHECK_FAIL(L"This function should not be called!"); + } + + void GuiRemoteRendererSingle::Initialize(IGuiRemoteProtocolEvents* _events) + { + events = _events; + } + + void GuiRemoteRendererSingle::Submit(bool& disconnected) + { + CHECK_FAIL(L"This function should not be called!"); + } + + void GuiRemoteRendererSingle::ProcessRemoteEvents() + { + CHECK_FAIL(L"This function should not be called!"); + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_CONTROLLER.CPP +***********************************************************************/ + +namespace vl::presentation::remote_renderer +{ + using namespace collections; + using namespace remoteprotocol; + + void GuiRemoteRendererSingle::RequestControllerGetFontConfig(vint id) + { + FontConfig response; + auto rs = GetCurrentController()->ResourceService(); + response.defaultFont = rs->GetDefaultFont(); + response.supportedFonts = Ptr(new List); + rs->EnumerateFonts(*response.supportedFonts.Obj()); + events->RespondControllerGetFontConfig(id, response); + } + + void GuiRemoteRendererSingle::RequestControllerGetScreenConfig(vint id) + { + auto primary = screen ? screen : GetCurrentController()->ScreenService()->GetScreen((vint)0); + events->RespondControllerGetScreenConfig(id, GetScreenConfig(primary)); + } + + void GuiRemoteRendererSingle::RequestControllerConnectionEstablished() + { + } + + void GuiRemoteRendererSingle::RequestControllerConnectionStopped() + { + if (window) + { + disconnectingFromCore = true; + window->ReleaseCapture(); + window->Hide(true); + } + } +} + + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_IO.CPP +***********************************************************************/ + +namespace vl::presentation::remote_renderer +{ + using namespace remoteprotocol; + +/*********************************************************************** +* Rendering (Commands) +***********************************************************************/ + + void GuiRemoteRendererSingle::RequestIOUpdateGlobalShortcutKey(const Ptr>& arguments) + { + CHECK_ERROR(arguments->Count() == 0, L"Not Implemented"); + } + + void GuiRemoteRendererSingle::RequestIORequireCapture() + { + window->RequireCapture(); + } + + void GuiRemoteRendererSingle::RequestIOReleaseCapture() + { + window->ReleaseCapture(); + } + + void GuiRemoteRendererSingle::RequestIOIsKeyPressing(vint id, const VKEY& arguments) + { + CHECK_FAIL(L"Not Implemented"); + } + + void GuiRemoteRendererSingle::RequestIOIsKeyToggled(vint id, const VKEY& arguments) + { + CHECK_FAIL(L"Not Implemented"); + } + +/*********************************************************************** +* Rendering (INativeWindow) +***********************************************************************/ + + void GuiRemoteRendererSingle::LeftButtonDown(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Left; + arguments.info = info; + events->OnIOButtonDown(arguments); + } + + void GuiRemoteRendererSingle::LeftButtonUp(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Left; + arguments.info = info; + events->OnIOButtonUp(arguments); + } + + void GuiRemoteRendererSingle::LeftButtonDoubleClick(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Left; + arguments.info = info; + events->OnIOButtonDoubleClick(arguments); + } + + void GuiRemoteRendererSingle::RightButtonDown(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Right; + arguments.info = info; + events->OnIOButtonDown(arguments); + } + + void GuiRemoteRendererSingle::RightButtonUp(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Right; + arguments.info = info; + events->OnIOButtonUp(arguments); + } + + void GuiRemoteRendererSingle::RightButtonDoubleClick(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Right; + arguments.info = info; + events->OnIOButtonDoubleClick(arguments); + } + + void GuiRemoteRendererSingle::MiddleButtonDown(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Middle; + arguments.info = info; + events->OnIOButtonDown(arguments); + } + + void GuiRemoteRendererSingle::MiddleButtonUp(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Middle; + arguments.info = info; + events->OnIOButtonUp(arguments); + } + + void GuiRemoteRendererSingle::MiddleButtonDoubleClick(const NativeWindowMouseInfo& info) + { + IOMouseInfoWithButton arguments; + arguments.button = IOMouseButton::Middle; + arguments.info = info; + events->OnIOButtonDoubleClick(arguments); + } + + void GuiRemoteRendererSingle::HorizontalWheel(const NativeWindowMouseInfo& info) + { + } + + void GuiRemoteRendererSingle::VerticalWheel(const NativeWindowMouseInfo& info) + { + } + + void GuiRemoteRendererSingle::MouseMoving(const NativeWindowMouseInfo& info) + { + if (renderingDom) + { + INativeWindowListener::HitTestResult hitTestResult = INativeWindowListener::NoDecision; + INativeCursor* cursor = nullptr; + HitTest(renderingDom, window->Convert(NativePoint{ info.x,info.y }), hitTestResult, cursor); + window->SetWindowCursor(cursor); + } + events->OnIOMouseMoving(info); + } + + void GuiRemoteRendererSingle::MouseEntered() + { + events->OnIOMouseEntered(); + } + + void GuiRemoteRendererSingle::MouseLeaved() + { + events->OnIOMouseLeaved(); + } + + void GuiRemoteRendererSingle::KeyDown(const NativeWindowKeyInfo& info) + { + events->OnIOKeyDown(info); + } + + void GuiRemoteRendererSingle::KeyUp(const NativeWindowKeyInfo& info) + { + if (!info.ctrl && !info.shift && info.code == VKEY::KEY_MENU) + { + window->SupressAlt(); + } + events->OnIOKeyUp(info); + } + + void GuiRemoteRendererSingle::Char(const NativeWindowCharInfo& info) + { + events->OnIOChar(info); + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_MAINWINDOW.CPP +***********************************************************************/ + +namespace vl::presentation::remote_renderer +{ + using namespace remoteprotocol; + + void GuiRemoteRendererSingle::RequestWindowGetBounds(vint id) + { + events->RespondWindowGetBounds(id, GetWindowSizingConfig()); + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetBounds(const NativeRect& arguments) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestWindowNotifySetBounds(const NativeRect&)#" + CHECK_ERROR(!updatingBounds, ERROR_MESSAGE_PREFIX L"This function cannot be called recursively."); + + updatingBounds = true; + if (!screen) + { + auto primary = GetCurrentController()->ScreenService()->GetScreen((vint)0); + NativeRect screenBounds = primary->GetBounds(); + NativeRect windowBounds = arguments; + windowBounds.x1 = (screenBounds.Width() - windowBounds.Width()) / 2; + windowBounds.y1 = (screenBounds.Height() - windowBounds.Height()) / 2; + window->SetBounds(windowBounds); + + screen = primary; + windowSizingConfig = GetWindowSizingConfig(); + } + else + { + window->SetBounds(arguments); + } + updatingBounds = false; +#undef ERROR_MESSAGE_PREFIX + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetTitle(const WString& arguments) + { + window->SetTitle(arguments); + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetEnabled(const bool& arguments) + { + if (arguments) + { + window->Enable(); + } + else + { + window->Disable(); + } + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetTopMost(const bool& arguments) + { + window->SetTopMost(arguments); + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetShowInTaskBar(const bool& arguments) + { + if (arguments) + { + window->ShowInTaskBar(); + } + else + { + window->HideInTaskBar(); + } + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetClientSize(const NativeSize& arguments) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestWindowNotifySetClientSize(const NativeSize&)#" + CHECK_ERROR(screen, ERROR_MESSAGE_PREFIX L"This function cannot be called before RequestWindowNotifySetBounds."); + + window->SetClientSize(arguments); +#undef ERROR_MESSAGE_PREFIX + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetCustomFrameMode(const bool& arguments) + { + if (window->IsCustomFrameModeEnabled() != arguments) + { + if (arguments) + { + window->EnableCustomFrameMode(); + } + else + { + window->DisableCustomFrameMode(); + } + UpdateConfigsIfNecessary(); + } + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetMaximizedBox(const bool& arguments) + { + window->SetMaximizedBox(arguments); + UpdateConfigsIfNecessary(); + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetMinimizedBox(const bool& arguments) + { + window->SetMinimizedBox(arguments); + UpdateConfigsIfNecessary(); + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetBorder(const bool& arguments) + { + window->SetBorder(arguments); + UpdateConfigsIfNecessary(); + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetSizeBox(const bool& arguments) + { + window->SetSizeBox(arguments); + UpdateConfigsIfNecessary(); + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetIconVisible(const bool& arguments) + { + window->SetIconVisible(arguments); + UpdateConfigsIfNecessary(); + } + + void GuiRemoteRendererSingle::RequestWindowNotifySetTitleBar(const bool& arguments) + { + window->SetTitleBar(arguments); + UpdateConfigsIfNecessary(); + } + + void GuiRemoteRendererSingle::RequestWindowNotifyActivate() + { + window->SetActivate(); + } + + void GuiRemoteRendererSingle::RequestWindowNotifyShow(const remoteprotocol::WindowShowing& arguments) + { + if (arguments.sizeState != window->GetSizeState()) + { + if (arguments.activate) + { + window->SetActivate(); + } + switch (arguments.sizeState) + { + case INativeWindow::Minimized: + window->ShowMinimized(); + break; + case INativeWindow::Restored: + window->ShowRestored(); + break; + case INativeWindow::Maximized: + window->ShowMaximized(); + break; + } + } + } +} + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE_RENDERING.CPP +***********************************************************************/ + +namespace vl::presentation::remote_renderer +{ + using namespace collections; + using namespace elements; + using namespace remoteprotocol; + + Alignment GuiRemoteRendererSingle::GetAlignment(remoteprotocol::ElementHorizontalAlignment alignment) + { + switch (alignment) + { + case remoteprotocol::ElementHorizontalAlignment::Left: return Alignment::Left; + case remoteprotocol::ElementHorizontalAlignment::Right: return Alignment::Right; + default: return Alignment::Center; + } + } + + Alignment GuiRemoteRendererSingle::GetAlignment(remoteprotocol::ElementVerticalAlignment alignment) + { + switch (alignment) + { + case remoteprotocol::ElementVerticalAlignment::Top: return Alignment::Top; + case remoteprotocol::ElementVerticalAlignment::Bottom: return Alignment::Bottom; + default: return Alignment::Center; + } + } + +/*********************************************************************** +* Rendering +***********************************************************************/ + + void GuiRemoteRendererSingle::RequestRendererCreated(const Ptr>& arguments) + { + if (arguments) + { + for (auto&& rc : *arguments.Obj()) + { + Ptr element; + switch (rc.type) + { + case RendererType::FocusRectangle: + element = Ptr(GuiFocusRectangleElement::Create()); + break; + case RendererType::SolidBorder: + element = Ptr(GuiSolidBorderElement::Create()); + break; + case RendererType::SinkBorder: + element = Ptr(Gui3DBorderElement::Create()); + break; + case RendererType::SinkSplitter: + element = Ptr(Gui3DSplitterElement::Create()); + break; + case RendererType::SolidBackground: + element = Ptr(GuiSolidBackgroundElement::Create()); + break; + case RendererType::GradientBackground: + element = Ptr(GuiGradientBackgroundElement::Create()); + break; + case RendererType::InnerShadow: + element = Ptr(GuiInnerShadowElement::Create()); + break; + case RendererType::SolidLabel: + element = Ptr(GuiSolidLabelElement::Create()); + break; + case RendererType::Polygon: + element = Ptr(GuiPolygonElement::Create()); + break; + case RendererType::ImageFrame: + element = Ptr(GuiImageFrameElement::Create()); + break; + default:; + } + + element->GetRenderer()->SetRenderTarget(GetGuiGraphicsResourceManager()->GetRenderTarget(window)); + + if (availableElements.Keys().Contains(rc.id)) + { + availableElements.Set(rc.id, element); + } + else + { + availableElements.Add(rc.id, element); + } + } + } + } + + void GuiRemoteRendererSingle::RequestRendererDestroyed(const Ptr>& arguments) + { + if (arguments) + { + for (auto id : *arguments.Obj()) + { + availableElements.Remove(id); + solidLabelMeasurings.Remove(id); + } + } + } + + void GuiRemoteRendererSingle::RequestRendererBeginRendering(const remoteprotocol::ElementBeginRendering& arguments) + { + } + + void GuiRemoteRendererSingle::RequestRendererEndRendering(vint id) + { + events->RespondRendererEndRendering(id, elementMeasurings); + elementMeasurings = {}; + fontHeightMeasurings.Clear(); + } + +/*********************************************************************** +* Rendering (Elemnents) +***********************************************************************/ + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_SolidBorder(const remoteprotocol::ElementDesc_SolidBorder& arguments) + { + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetColor(arguments.borderColor); + element->SetShape(arguments.shape); + } + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_SinkBorder(const remoteprotocol::ElementDesc_SinkBorder& arguments) + { + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetColors(arguments.leftTopColor, arguments.rightBottomColor); + } + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_SinkSplitter(const remoteprotocol::ElementDesc_SinkSplitter& arguments) + { + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetColors(arguments.leftTopColor, arguments.rightBottomColor); + element->SetDirection(arguments.direction); + } + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_SolidBackground(const remoteprotocol::ElementDesc_SolidBackground& arguments) + { + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetColor(arguments.backgroundColor); + element->SetShape(arguments.shape); + } + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_GradientBackground(const remoteprotocol::ElementDesc_GradientBackground& arguments) + { + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetColors(arguments.leftTopColor, arguments.rightBottomColor); + element->SetDirection(arguments.direction); + element->SetShape(arguments.shape); + } + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_InnerShadow(const remoteprotocol::ElementDesc_InnerShadow& arguments) + { + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetColor(arguments.shadowColor); + element->SetThickness(arguments.thickness); + } + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_Polygon(const remoteprotocol::ElementDesc_Polygon& arguments) + { + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetSize(arguments.size); + element->SetBorderColor(arguments.borderColor); + element->SetBackgroundColor(arguments.backgroundColor); + + if (arguments.points && arguments.points->Count() > 0) + { + element->SetPoints(&arguments.points->Get(0), arguments.points->Count()); + } + } + +/*********************************************************************** +* Rendering (Elemnents -- Label) +***********************************************************************/ + + void GuiRemoteRendererSingle::StoreLabelMeasuring(vint id, remoteprotocol::ElementSolidLabelMeasuringRequest request, Ptr solidLabel, Size minSize) + { + switch (request) + { + case ElementSolidLabelMeasuringRequest::FontHeight: + { + Pair key = { solidLabel->GetFont().fontFamily,solidLabel->GetFont().size }; + if (fontHeightMeasurings.Contains(key)) return; + fontHeightMeasurings.Add(key); + + ElementMeasuring_FontHeight response; + response.fontFamily = key.key; + response.fontSize = key.value; + response.height = minSize.y; + + if (!elementMeasurings.fontHeights) + { + elementMeasurings.fontHeights = Ptr(new List); + } + elementMeasurings.fontHeights->Add(response); + } + break; + case ElementSolidLabelMeasuringRequest::TotalSize: + { + ElementMeasuring_ElementMinSize response; + response.id = id; + response.minSize = minSize; + + if (!elementMeasurings.minSizes) + { + elementMeasurings.minSizes = Ptr(new List); + } + elementMeasurings.minSizes->Add(response); + } + break; + } + } + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_SolidLabel(const remoteprotocol::ElementDesc_SolidLabel& arguments) + { + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetColor(arguments.textColor); + element->SetAlignments(GetAlignment(arguments.horizontalAlignment), GetAlignment(arguments.verticalAlignment)); + element->SetWrapLine(arguments.wrapLine); + element->SetWrapLineHeightCalculation(arguments.wrapLineHeightCalculation); + element->SetEllipse(arguments.ellipse); + element->SetMultiline(arguments.multiline); + + if (arguments.font) + { + element->SetFont(arguments.font.Value()); + } + if (arguments.text) + { + element->SetText(arguments.text.Value()); + } + + if (arguments.measuringRequest) + { + SolidLabelMeasuring measuring; + measuring.request = arguments.measuringRequest.Value(); + index = solidLabelMeasurings.Keys().IndexOf(arguments.id); + if (solidLabelMeasurings.Keys().Contains(arguments.id)) + { + solidLabelMeasurings.Set(arguments.id, measuring); + } + else + { + solidLabelMeasurings.Add(arguments.id, measuring); + } + + StoreLabelMeasuring(arguments.id, measuring.request, element, element->GetRenderer()->GetMinSize()); + } + } + +/*********************************************************************** +* Rendering (Elements -- Image) +***********************************************************************/ + + remoteprotocol::ImageMetadata GuiRemoteRendererSingle::CreateImageMetadata(vint id, INativeImage* image) + { + ImageMetadata response; + response.id = id; + response.format = image->GetFormat(); + response.frames = Ptr(new List); + for (vint i = 0; i < image->GetFrameCount(); i++) + { + auto frame = image->GetFrame(i); + response.frames->Add({ frame->GetSize() }); + } + + return response; + } + + remoteprotocol::ImageMetadata GuiRemoteRendererSingle::CreateImage(const remoteprotocol::ImageCreation& arguments) + { + arguments.imageData->SeekFromBegin(0); + auto image = GetCurrentController()->ImageService()->CreateImageFromStream(*arguments.imageData.Obj()); + if (availableImages.Keys().Contains(arguments.id)) + { + availableImages.Set(arguments.id, image); + } + else + { + availableImages.Add(arguments.id, image); + } + return CreateImageMetadata(arguments.id, image.Obj()); + } + + void GuiRemoteRendererSingle::RequestImageCreated(vint id, const remoteprotocol::ImageCreation& arguments) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestImageCreated(const ImageCreation&)#" + CHECK_ERROR(!arguments.imageDataOmitted && arguments.imageData, ERROR_MESSAGE_PREFIX L"Binary content of the image is missing."); + + events->RespondImageCreated(id, CreateImage(arguments)); +#undef ERROR_MESSAGE_PREFIX + } + + void GuiRemoteRendererSingle::RequestImageDestroyed(const vint& arguments) + { + availableImages.Remove(arguments); + } + + void GuiRemoteRendererSingle::RequestRendererUpdateElement_ImageFrame(const remoteprotocol::ElementDesc_ImageFrame& arguments) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererUpdateElement_ImageFrame(const arguments&)#" + + vint index = availableElements.Keys().IndexOf(arguments.id); + if (index == -1) return; + auto element = availableElements.Values()[index].Cast(); + if (!element) return; + + element->SetAlignments(GetAlignment(arguments.horizontalAlignment), GetAlignment(arguments.verticalAlignment)); + element->SetStretch(arguments.stretch); + element->SetEnabled(arguments.enabled); + + if (arguments.imageId && arguments.imageCreation) + { + CHECK_ERROR(arguments.imageId.Value() == arguments.imageCreation.Value().id, ERROR_MESSAGE_PREFIX L"imageId and imageCreation.id must be identical."); + } + + if (arguments.imageId) + { + if (arguments.imageCreation && !elementMeasurings.createdImages) + { + elementMeasurings.createdImages = Ptr(new List); + } + + vint index = availableImages.Keys().IndexOf(arguments.imageId.Value()); + if (index == -1) + { + CHECK_ERROR(arguments.imageCreation && !arguments.imageCreation.Value().imageDataOmitted && arguments.imageCreation.Value().imageData, ERROR_MESSAGE_PREFIX L"Binary content of the image is missing."); + + auto response = CreateImage(arguments.imageCreation.Value()); + element->SetImage(availableImages[response.id], arguments.imageFrame); + elementMeasurings.createdImages->Add(response); + } + else + { + auto image = availableImages.Values()[index]; + element->SetImage(image, arguments.imageFrame); + if (arguments.imageCreation) + { + elementMeasurings.createdImages->Add(CreateImageMetadata(arguments.imageId.Value(), image.Obj())); + } + } + } +#undef ERROR_MESSAGE_PREFIX + } + +/*********************************************************************** +* Rendering (Dom) +***********************************************************************/ + + void GuiRemoteRendererSingle::CheckDom() + { + needRefresh = true; + } + + void GuiRemoteRendererSingle::RequestRendererRenderDom(const Ptr& arguments) + { + renderingDom = arguments; + if (renderingDom) + { + BuildDomIndex(renderingDom, renderingDomIndex); + } + CheckDom(); + } + + void GuiRemoteRendererSingle::RequestRendererRenderDomDiff(const remoteprotocol::RenderingDom_DiffsInOrder& arguments) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererRenderDomDiff(const RenderingDom_DiffsInOrder&)#" + CHECK_ERROR(renderingDom, ERROR_MESSAGE_PREFIX L"This function must be called after RequestRendererRenderDom."); + + UpdateDomInplace(renderingDom, renderingDomIndex, arguments); + CheckDom(); +#undef ERROR_MESSAGE_PREFIX + } + +/*********************************************************************** +* Rendering (Commands) +***********************************************************************/ + + void GuiRemoteRendererSingle::RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererBeginBoundary(const ElementBoundary&)#" + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"The current implementation require dom-diff enabled in core side."); +#undef ERROR_MESSAGE_PREFIX + } + + void GuiRemoteRendererSingle::RequestRendererEndBoundary() + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererEndBoundary()#" + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"The current implementation require dom-diff enabled in core side."); +#undef ERROR_MESSAGE_PREFIX + } + + void GuiRemoteRendererSingle::RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remote_renderer::GuiRemoteRendererSingle::RequestRendererRenderElement(const ElementRendering&)#" + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"The current implementation require dom-diff enabled in core side."); +#undef ERROR_MESSAGE_PREFIX + } + +/*********************************************************************** +* Rendering (INativeWindow) +***********************************************************************/ + + void GuiRemoteRendererSingle::UpdateRenderTarget(elements::IGuiGraphicsRenderTarget* rt) + { + for (auto element : availableElements.Values()) + { + element->GetRenderer()->SetRenderTarget(rt); + } + } + + void GuiRemoteRendererSingle::Render(Ptr dom, elements::IGuiGraphicsRenderTarget* rt) + { + if (dom->content.element) + { + vint index = availableElements.Keys().IndexOf(dom->content.element.Value()); + if (index != -1) + { + auto element = availableElements.Values()[index]; + rt->PushClipper(dom->content.validArea, nullptr); + element->GetRenderer()->Render(dom->content.bounds); + rt->PopClipper(nullptr); + + if (auto solidLabel = element.Cast()) + { + index = solidLabelMeasurings.Keys().IndexOf(dom->content.element.Value()); + if (index != -1) + { + auto& measuring = const_cast(solidLabelMeasurings.Values()[index]); + auto minSize = element->GetRenderer()->GetMinSize(); + + bool measuringChanged = false; + if (!measuring.minSize) + { + measuringChanged = true; + } + else switch (measuring.request) + { + case ElementSolidLabelMeasuringRequest::FontHeight: + if (measuring.minSize.Value().y != minSize.y) + { + measuringChanged = true; + } + break; + case ElementSolidLabelMeasuringRequest::TotalSize: + if (measuring.minSize.Value() != minSize) + { + measuringChanged = true; + } + break; + } + + measuring.minSize = minSize; + if (measuringChanged) + { + StoreLabelMeasuring(dom->content.element.Value(), measuring.request, solidLabel, minSize); + } + } + } + } + } + + if (dom->children) + { + for (auto child : *dom->children.Obj()) + { + if (child->content.validArea.Width() > 0 && child->content.validArea.Height()> 0) + { + Render(child, rt); + } + } + } + } + + void GuiRemoteRendererSingle::HitTestInternal(Ptr dom, Point location, Nullable& hitTestResult, Nullable& cursorType) + { + if (dom->children) + { + for (auto child : *dom->children.Obj()) + { + if (child->content.validArea.Contains(location)) + { + HitTestInternal(child, location, hitTestResult, cursorType); + + if (!hitTestResult && child->content.hitTestResult) + { + hitTestResult = child->content.hitTestResult; + } + if (!cursorType && child->content.cursor) + { + cursorType = child->content.cursor; + } + } + } + } + } + + void GuiRemoteRendererSingle::HitTest(Ptr dom, Point location, INativeWindowListener::HitTestResult& hitTestResult, INativeCursor*& cursor) + { + Nullable hitTestResultNullable; + Nullable cursorTypeNullable; + HitTestInternal(dom, location, hitTestResultNullable, cursorTypeNullable); + hitTestResult = hitTestResultNullable ? hitTestResultNullable.Value() : INativeWindowListener::NoDecision; + cursor = cursorTypeNullable ? GetCurrentController()->ResourceService()->GetSystemCursor(cursorTypeNullable.Value()) : GetCurrentController()->ResourceService()->GetDefaultSystemCursor(); + } + + void GuiRemoteRendererSingle::GlobalTimer() + { + if (!needRefresh) return; + needRefresh = false; + if (!window) return; + if (!renderingDom) return; + + supressPaint = true; + auto rt = GetGuiGraphicsResourceManager()->GetRenderTarget(window); + rt->StartRendering(); + Render(renderingDom, rt); + auto result = rt->StopRendering(); + window->RedrawContent(); + supressPaint = false; + + switch (result) + { + case RenderTargetFailure::ResizeWhileRendering: + GetGuiGraphicsResourceManager()->ResizeRenderTarget(window); + needRefresh = true; + break; + case RenderTargetFailure::LostDevice: + UpdateRenderTarget(nullptr); + GetGuiGraphicsResourceManager()->RecreateRenderTarget(window); + UpdateRenderTarget(GetGuiGraphicsResourceManager()->GetRenderTarget(window)); + needRefresh = true; + break; + default:; + } + } + + void GuiRemoteRendererSingle::Paint() + { + if (!supressPaint) + { + needRefresh = true; + } + } + + INativeWindowListener::HitTestResult GuiRemoteRendererSingle::HitTest(NativePoint location) + { + INativeWindowListener::HitTestResult hitTestResult = INativeWindowListener::NoDecision; + INativeCursor* cursor = nullptr; + if (renderingDom) + { + HitTest(renderingDom, window->Convert(location), hitTestResult, cursor); + } + return hitTestResult; + } +} + /*********************************************************************** .\RESOURCES\GUIDOCUMENT.CPP ***********************************************************************/ diff --git a/Import/GacUI.h b/Import/GacUI.h index e0484cbd..e76231be 100644 --- a/Import/GacUI.h +++ b/Import/GacUI.h @@ -4633,6 +4633,11 @@ namespace vl class GuiControlHost; } + namespace elements + { + class GuiRemoteGraphicsRenderTarget; + } + namespace compositions { class GuiGraphicsComposition_Trivial; @@ -4661,6 +4666,7 @@ Basic Construction friend class GuiWindowComposition; friend class controls::GuiControl; friend class GuiGraphicsHost; + friend class elements::GuiRemoteGraphicsRenderTarget; friend void InvokeOnCompositionStateChanged(compositions::GuiGraphicsComposition* composition); public: @@ -4695,6 +4701,7 @@ Basic Construction bool visible = true; bool transparentToMouse = false; MinSizeLimitation minSizeLimitation = MinSizeLimitation::NoLimit; + vint remoteId = -1; Ptr eventReceiver; GraphicsHostRecord* relatedHostRecord = nullptr; @@ -22145,12 +22152,12 @@ namespace vl::presentation::remoteprotocol struct ElementMeasuring_FontHeight; struct ElementMeasuring_ElementMinSize; struct ElementMeasurings; + struct RenderingDomContent; struct RenderingDom; - struct RenderingCommand_BeginBoundary; - struct RenderingCommand_EndBoundary; - struct RenderingCommand_Element; - struct RenderingFrame; - struct RenderingTrace; + struct RenderingDom_Diff; + struct RenderingDom_DiffsInOrder; + struct UnitTest_RenderingFrame; + struct UnitTest_RenderingTrace; } namespace vl::presentation::remoteprotocol { @@ -22192,12 +22199,12 @@ namespace vl::presentation::remoteprotocol template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight> { static constexpr const wchar_t* Name = L"ElementMeasuring_FontHeight"; }; template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize> { static constexpr const wchar_t* Name = L"ElementMeasuring_ElementMinSize"; }; template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::ElementMeasurings> { static constexpr const wchar_t* Name = L"ElementMeasurings"; }; + template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::RenderingDomContent> { static constexpr const wchar_t* Name = L"RenderingDomContent"; }; template<> struct JsonNameHelper<::vl::Ptr<::vl::presentation::remoteprotocol::RenderingDom>> { static constexpr const wchar_t* Name = L"RenderingDom"; }; - template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary> { static constexpr const wchar_t* Name = L"RenderingCommand_BeginBoundary"; }; - template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary> { static constexpr const wchar_t* Name = L"RenderingCommand_EndBoundary"; }; - template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::RenderingCommand_Element> { static constexpr const wchar_t* Name = L"RenderingCommand_Element"; }; - template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::RenderingFrame> { static constexpr const wchar_t* Name = L"RenderingFrame"; }; - template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::RenderingTrace> { static constexpr const wchar_t* Name = L"RenderingTrace"; }; + template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::RenderingDom_Diff> { static constexpr const wchar_t* Name = L"RenderingDom_Diff"; }; + template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder> { static constexpr const wchar_t* Name = L"RenderingDom_DiffsInOrder"; }; + template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame> { static constexpr const wchar_t* Name = L"UnitTest_RenderingFrame"; }; + template<> struct JsonNameHelper<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace> { static constexpr const wchar_t* Name = L"UnitTest_RenderingTrace"; }; } namespace vl::presentation::remoteprotocol { @@ -22244,7 +22251,14 @@ namespace vl::presentation::remoteprotocol UnsupportedDocument, }; - using ElementDescVariant = ::vl::Variant< + enum class RenderingDom_DiffType + { + Deleted, + Created, + Modified, + }; + + using UnitTest_ElementDescVariant = ::vl::Variant< ::vl::presentation::remoteprotocol::ElementDesc_SolidBorder, ::vl::presentation::remoteprotocol::ElementDesc_SinkBorder, ::vl::presentation::remoteprotocol::ElementDesc_SinkSplitter, @@ -22256,12 +22270,6 @@ namespace vl::presentation::remoteprotocol ::vl::presentation::remoteprotocol::ElementDesc_ImageFrame >; - using RenderingCommand = ::vl::Variant< - ::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary, - ::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary, - ::vl::presentation::remoteprotocol::RenderingCommand_Element - >; - struct FontConfig { ::vl::presentation::FontProperties defaultFont; @@ -22425,6 +22433,7 @@ namespace vl::presentation::remoteprotocol struct ElementBoundary { + ::vl::vint id; ::vl::Nullable<::vl::presentation::INativeWindowListener::HitTestResult> hitTestResult; ::vl::Nullable<::vl::presentation::INativeCursor::SystemCursorType> cursor; ::vl::presentation::Rect bounds; @@ -22451,47 +22460,50 @@ namespace vl::presentation::remoteprotocol ::vl::Ptr<::vl::collections::List<::vl::presentation::remoteprotocol::ImageMetadata>> createdImages; }; - struct RenderingDom + struct RenderingDomContent { ::vl::Nullable<::vl::presentation::INativeWindowListener::HitTestResult> hitTestResult; ::vl::Nullable<::vl::presentation::INativeCursor::SystemCursorType> cursor; ::vl::Nullable<::vl::vint> element; ::vl::presentation::Rect bounds; ::vl::presentation::Rect validArea; + }; + + struct RenderingDom + { + ::vl::vint id; + ::vl::presentation::remoteprotocol::RenderingDomContent content; ::vl::Ptr<::vl::collections::List<::vl::Ptr<::vl::presentation::remoteprotocol::RenderingDom>>> children; }; - struct RenderingCommand_BeginBoundary + struct RenderingDom_Diff { - ::vl::presentation::remoteprotocol::ElementBoundary boundary; + ::vl::vint id; + ::vl::presentation::remoteprotocol::RenderingDom_DiffType diffType; + ::vl::Nullable<::vl::presentation::remoteprotocol::RenderingDomContent> content; + ::vl::Ptr<::vl::collections::List<::vl::vint>> children; }; - struct RenderingCommand_EndBoundary + struct RenderingDom_DiffsInOrder { + ::vl::Ptr<::vl::collections::List<::vl::presentation::remoteprotocol::RenderingDom_Diff>> diffsInOrder; }; - struct RenderingCommand_Element - { - ::vl::presentation::remoteprotocol::ElementRendering rendering; - ::vl::Nullable<::vl::vint> element; - }; - - struct RenderingFrame + struct UnitTest_RenderingFrame { ::vl::vint frameId; ::vl::Nullable<::vl::WString> frameName; ::vl::presentation::remoteprotocol::WindowSizingConfig windowSize; - ::vl::Ptr<::vl::collections::Dictionary<::vl::vint, ::vl::presentation::remoteprotocol::ElementDescVariant>> elements; - ::vl::Ptr<::vl::collections::List<::vl::presentation::remoteprotocol::RenderingCommand>> commands; + ::vl::Ptr<::vl::collections::Dictionary<::vl::vint, ::vl::presentation::remoteprotocol::UnitTest_ElementDescVariant>> elements; ::vl::Ptr<::vl::presentation::remoteprotocol::RenderingDom> root; }; - struct RenderingTrace + struct UnitTest_RenderingTrace { ::vl::Ptr<::vl::collections::Dictionary<::vl::vint, ::vl::presentation::remoteprotocol::RendererType>> createdElements; ::vl::Ptr<::vl::presentation::remoteprotocol::ArrayMap<::vl::vint, ::vl::presentation::remoteprotocol::ImageCreation, &::vl::presentation::remoteprotocol::ImageCreation::id>> imageCreations; ::vl::Ptr<::vl::presentation::remoteprotocol::ArrayMap<::vl::vint, ::vl::presentation::remoteprotocol::ImageMetadata, &::vl::presentation::remoteprotocol::ImageMetadata::id>> imageMetadatas; - ::vl::Ptr<::vl::collections::List<::vl::presentation::remoteprotocol::RenderingFrame>> frames; + ::vl::Ptr<::vl::collections::List<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>> frames; }; template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::INativeWindowListener::HitTestResult>(const ::vl::presentation::INativeWindowListener::HitTestResult & value); @@ -22506,6 +22518,7 @@ namespace vl::presentation::remoteprotocol template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest>(const ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest & value); template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::INativeImage::FormatType>(const ::vl::presentation::INativeImage::FormatType & value); template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RendererType>(const ::vl::presentation::remoteprotocol::RendererType & value); + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(const ::vl::presentation::remoteprotocol::RenderingDom_DiffType & value); template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::NativeCoordinate>(const ::vl::presentation::NativeCoordinate & value); template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::NativePoint>(const ::vl::presentation::NativePoint & value); template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::NativeSize>(const ::vl::presentation::NativeSize & value); @@ -22544,12 +22557,12 @@ namespace vl::presentation::remoteprotocol template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight>(const ::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight & value); template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize>(const ::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize & value); template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::ElementMeasurings>(const ::vl::presentation::remoteprotocol::ElementMeasurings & value); + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDomContent>(const ::vl::presentation::remoteprotocol::RenderingDomContent & value); template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom>(const ::vl::presentation::remoteprotocol::RenderingDom & value); - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary>(const ::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary & value); - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary>(const ::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary & value); - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingCommand_Element>(const ::vl::presentation::remoteprotocol::RenderingCommand_Element & value); - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingFrame>(const ::vl::presentation::remoteprotocol::RenderingFrame & value); - template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingTrace>(const ::vl::presentation::remoteprotocol::RenderingTrace & value); + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_Diff>(const ::vl::presentation::remoteprotocol::RenderingDom_Diff & value); + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder>(const ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder & value); + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>(const ::vl::presentation::remoteprotocol::UnitTest_RenderingFrame & value); + template<> vl::Ptr ConvertCustomTypeToJson<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace>(const ::vl::presentation::remoteprotocol::UnitTest_RenderingTrace & value); template<> void ConvertJsonToCustomType<::vl::presentation::INativeWindowListener::HitTestResult>(vl::Ptr node, ::vl::presentation::INativeWindowListener::HitTestResult& value); template<> void ConvertJsonToCustomType<::vl::presentation::INativeCursor::SystemCursorType>(vl::Ptr node, ::vl::presentation::INativeCursor::SystemCursorType& value); @@ -22563,6 +22576,7 @@ namespace vl::presentation::remoteprotocol template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest>(vl::Ptr node, ::vl::presentation::remoteprotocol::ElementSolidLabelMeasuringRequest& value); template<> void ConvertJsonToCustomType<::vl::presentation::INativeImage::FormatType>(vl::Ptr node, ::vl::presentation::INativeImage::FormatType& value); template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RendererType>(vl::Ptr node, ::vl::presentation::remoteprotocol::RendererType& value); + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffType>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom_DiffType& value); template<> void ConvertJsonToCustomType<::vl::presentation::NativeCoordinate>(vl::Ptr node, ::vl::presentation::NativeCoordinate& value); template<> void ConvertJsonToCustomType<::vl::presentation::NativePoint>(vl::Ptr node, ::vl::presentation::NativePoint& value); template<> void ConvertJsonToCustomType<::vl::presentation::NativeSize>(vl::Ptr node, ::vl::presentation::NativeSize& value); @@ -22601,12 +22615,12 @@ namespace vl::presentation::remoteprotocol template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight>(vl::Ptr node, ::vl::presentation::remoteprotocol::ElementMeasuring_FontHeight& value); template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize>(vl::Ptr node, ::vl::presentation::remoteprotocol::ElementMeasuring_ElementMinSize& value); template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::ElementMeasurings>(vl::Ptr node, ::vl::presentation::remoteprotocol::ElementMeasurings& value); + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDomContent>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDomContent& value); template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom& value); - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingCommand_BeginBoundary& value); - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingCommand_EndBoundary& value); - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingCommand_Element>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingCommand_Element& value); - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingFrame>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingFrame& value); - template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingTrace>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingTrace& value); + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_Diff>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom_Diff& value); + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder>(vl::Ptr node, ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder& value); + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingFrame>(vl::Ptr node, ::vl::presentation::remoteprotocol::UnitTest_RenderingFrame& value); + template<> void ConvertJsonToCustomType<::vl::presentation::remoteprotocol::UnitTest_RenderingTrace>(vl::Ptr node, ::vl::presentation::remoteprotocol::UnitTest_RenderingTrace& value); #define GACUI_REMOTEPROTOCOL_MESSAGES(HANDLER)\ HANDLER(ControllerGetFontConfig, void, ::vl::presentation::remoteprotocol::FontConfig, NOREQ, RES, NODROP)\ @@ -22652,6 +22666,8 @@ namespace vl::presentation::remoteprotocol HANDLER(RendererRenderElement, ::vl::presentation::remoteprotocol::ElementRendering, void, REQ, NORES, NODROP)\ HANDLER(RendererEndBoundary, void, void, NOREQ, NORES, NODROP)\ HANDLER(RendererEndRendering, void, ::vl::presentation::remoteprotocol::ElementMeasurings, NOREQ, RES, NODROP)\ + HANDLER(RendererRenderDom, ::vl::Ptr<::vl::presentation::remoteprotocol::RenderingDom>, void, REQ, NORES, NODROP)\ + HANDLER(RendererRenderDomDiff, ::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder, void, REQ, NORES, NODROP)\ #define GACUI_REMOTEPROTOCOL_EVENTS(HANDLER)\ HANDLER(ControllerConnect, void, NOREQ, NODROP)\ @@ -22678,6 +22694,7 @@ namespace vl::presentation::remoteprotocol HANDLER(::vl::Ptr<::vl::collections::List<::vl::presentation::remoteprotocol::GlobalShortcutKey>>)\ HANDLER(::vl::Ptr<::vl::collections::List<::vl::presentation::remoteprotocol::RendererCreation>>)\ HANDLER(::vl::Ptr<::vl::collections::List<::vl::vint>>)\ + HANDLER(::vl::Ptr<::vl::presentation::remoteprotocol::RenderingDom>)\ HANDLER(::vl::WString)\ HANDLER(::vl::presentation::NativeRect)\ HANDLER(::vl::presentation::NativeSize)\ @@ -22695,6 +22712,7 @@ namespace vl::presentation::remoteprotocol HANDLER(::vl::presentation::remoteprotocol::ElementDesc_SolidLabel)\ HANDLER(::vl::presentation::remoteprotocol::ElementRendering)\ HANDLER(::vl::presentation::remoteprotocol::ImageCreation)\ + HANDLER(::vl::presentation::remoteprotocol::RenderingDom_DiffsInOrder)\ HANDLER(::vl::presentation::remoteprotocol::WindowShowing)\ HANDLER(::vl::vint)\ HANDLER(bool)\ @@ -22830,6 +22848,7 @@ GuiRemoteGraphicsImageService GuiRemoteGraphicsImageService(GuiRemoteController* _remote); ~GuiRemoteGraphicsImageService(); + void ResetImageMetadata(); void OnControllerConnect(); void OnControllerDisconnect(); void Initialize(); @@ -22891,6 +22910,7 @@ GuiRemoteGraphicsRenderTarget NativeSize canvasSize; vint usedFrameIds = 0; vint usedElementIds = 0; + vint usedCompositionIds = 0; RendererMap renderers; collections::SortedList createdRenderers; collections::SortedList destroyedRenderers; @@ -23008,6 +23028,7 @@ namespace vl::presentation::elements_remoteprotocol vint id = -1; vuint64_t renderingBatchId = 0; bool updated = true; + bool renderTargetChanged = false; void InitializeInternal(); void FinalizeInternal(); @@ -23246,7 +23267,7 @@ IGuiRemoteProtocol { public: virtual void Initialize(IGuiRemoteProtocolEvents* events) = 0; - virtual void Submit() = 0; + virtual void Submit(bool& disconnected) = 0; virtual void ProcessRemoteEvents() = 0; }; @@ -23256,9 +23277,12 @@ IGuiRemoteProtocol IGuiRemoteProtocolEvents* targetEvents = nullptr; }; + template + class GuiRemoteProtocolCombinator; + template requires(std::is_base_of_v) - class GuiRemoteProtocolCombinator : public Object, public virtual IGuiRemoteProtocol + class GuiRemoteProtocolCombinator : public Object, public virtual IGuiRemoteProtocol { protected: IGuiRemoteProtocol* targetProtocol = nullptr; @@ -23283,9 +23307,9 @@ IGuiRemoteProtocol targetProtocol->Initialize(&eventCombinator); } - void Submit() override + void Submit(bool& disconnected) override { - targetProtocol->Submit(); + targetProtocol->Submit(disconnected); } void ProcessRemoteEvents() override @@ -23293,6 +23317,900 @@ IGuiRemoteProtocol targetProtocol->ProcessRemoteEvents(); } }; + + template<> + class GuiRemoteProtocolCombinator : public Object, public virtual IGuiRemoteProtocol + { + protected: + IGuiRemoteProtocol* targetProtocol = nullptr; + IGuiRemoteProtocolEvents* events = nullptr; + + public: + GuiRemoteProtocolCombinator(IGuiRemoteProtocol* _protocol) + : targetProtocol(_protocol) + { + } + + // protocol + + WString GetExecutablePath() override + { + return targetProtocol->GetExecutablePath(); + } + + void Initialize(IGuiRemoteProtocolEvents* _events) override + { + events = _events; + targetProtocol->Initialize(_events); + } + + void Submit(bool& disconnected) override + { + targetProtocol->Submit(disconnected); + } + + void ProcessRemoteEvents() override + { + targetProtocol->ProcessRemoteEvents(); + } + }; + +/*********************************************************************** +Passing through +***********************************************************************/ + + class GuiRemoteEventCombinator_PassingThrough : public GuiRemoteEventCombinator + { + public: +#define EVENT_NOREQ(NAME, REQUEST) void On ## NAME() override { this->targetEvents->On ## NAME(); } +#define EVENT_REQ(NAME, REQUEST) void On ## NAME(const REQUEST& arguments) override { this->targetEvents->On ## NAME(arguments); } +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST) + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) +#undef EVENT_HANDLER +#undef EVENT_REQ +#undef EVENT_NOREQ + +#define MESSAGE_NORES(NAME, RESPONSE) +#define MESSAGE_RES(NAME, RESPONSE) void Respond ## NAME(vint id, const RESPONSE& arguments) override { this->targetEvents->Respond ## NAME(id, arguments); } +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_RES +#undef MESSAGE_NORES + }; + + template + class GuiRemoteProtocolCombinator_PassingThrough : public GuiRemoteProtocolCombinator + { + public: + GuiRemoteProtocolCombinator_PassingThrough(IGuiRemoteProtocol* _protocol) + : GuiRemoteProtocolCombinator(_protocol) + { + } + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME() override { this->targetProtocol->Request ## NAME(); } +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE) void Request ## NAME(vint id) override { this->targetProtocol->Request ## NAME(id); } +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME(const REQUEST& arguments) override { this->targetProtocol->Request ## NAME(arguments); } +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE) void Request ## NAME(vint id, const REQUEST& arguments) override { this->targetProtocol->Request ## NAME(id, arguments); } +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_REQ_RES +#undef MESSAGE_REQ_NORES +#undef MESSAGE_NOREQ_RES +#undef MESSAGE_NOREQ_NORES + }; +} + +#endif + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_CHANNEL_SHARED.H +***********************************************************************/ +/*********************************************************************** +Vczh Library++ 3.0 +Developer: Zihan Chen(vczh) +GacUI::Remote Window + +Interfaces: + IGuiRemoteProtocolChannel + +***********************************************************************/ + +#ifndef VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL_CHANNEL +#define VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL_CHANNEL + + +namespace vl::presentation::remoteprotocol::channeling +{ + +/*********************************************************************** +IGuiRemoteProtocolChannel +***********************************************************************/ + + template + class IGuiRemoteProtocolChannelReceiver : public virtual Interface + { + public: + virtual void OnReceive(const TPackage& package) = 0; + }; + + template + class IGuiRemoteProtocolChannel : public virtual Interface + { + public: + virtual void Initialize(IGuiRemoteProtocolChannelReceiver* receiver) = 0; + virtual IGuiRemoteProtocolChannelReceiver* GetReceiver() = 0; + virtual void Write(const TPackage& package) = 0; + virtual WString GetExecutablePath() = 0; + virtual void Submit(bool& disconnected) = 0; + virtual void ProcessRemoteEvents() = 0; + }; + +/*********************************************************************** +Serialization +***********************************************************************/ + + template + class GuiRemoteProtocolChannelTransformerBase + : public Object + , public virtual IGuiRemoteProtocolChannel + , protected virtual IGuiRemoteProtocolChannelReceiver + { + protected: + IGuiRemoteProtocolChannel* channel = nullptr; + IGuiRemoteProtocolChannelReceiver* receiver = nullptr; + + public: + GuiRemoteProtocolChannelTransformerBase(IGuiRemoteProtocolChannel* _channel) + : channel(_channel) + { + } + + void Initialize(IGuiRemoteProtocolChannelReceiver* _receiver) override + { + receiver = _receiver; + channel->Initialize(this); + } + + IGuiRemoteProtocolChannelReceiver* GetReceiver() override + { + return receiver; + } + + WString GetExecutablePath() override + { + return channel->GetExecutablePath(); + } + + void Submit(bool& disconnected) override + { + channel->Submit(disconnected); + } + + void ProcessRemoteEvents() override + { + channel->ProcessRemoteEvents(); + } + }; + + template + class GuiRemoteProtocolChannelSerializer + : public GuiRemoteProtocolChannelTransformerBase + { + protected: + typename TSerialization::ContextType context; + + void OnReceive(const typename TSerialization::DestType& package) override + { + typename TSerialization::SourceType deserialized; + TSerialization::Deserialize(context, package, deserialized); + this->receiver->OnReceive(deserialized); + } + + public: + GuiRemoteProtocolChannelSerializer(IGuiRemoteProtocolChannel* _channel, const typename TSerialization::ContextType& _context = {}) + : GuiRemoteProtocolChannelTransformerBase(_channel) + , context(_context) + { + } + + void Write(const typename TSerialization::SourceType& package) override + { + typename TSerialization::DestType serialized; + TSerialization::Serialize(context, package, serialized); + this->channel->Write(serialized); + } + }; + + template + class GuiRemoteProtocolChannelDeserializer + : public GuiRemoteProtocolChannelTransformerBase + { + protected: + typename TSerialization::ContextType context; + + void OnReceive(const typename TSerialization::SourceType& package) override + { + typename TSerialization::DestType serialized; + TSerialization::Serialize(context, package, serialized); + this->receiver->OnReceive(serialized); + } + + public: + GuiRemoteProtocolChannelDeserializer(IGuiRemoteProtocolChannel* _channel, const typename TSerialization::ContextType& _context = {}) + : GuiRemoteProtocolChannelTransformerBase(_channel) + , context(_context) + { + } + + void Write(const typename TSerialization::DestType& package) override + { + typename TSerialization::SourceType deserialized; + TSerialization::Deserialize(context, package, deserialized); + this->channel->Write(deserialized); + } + }; + +/*********************************************************************** +String Transformation +***********************************************************************/ + + template + static void ConvertUtfString(const ObjectString& source, ObjectString& dest) + { + vint len = _utftoutf(source.Buffer(), nullptr, 0); + if (len < 1) dest = {}; + TTo* buffer = new TTo[len]; + memset(buffer, 0, len * sizeof(TTo)); + _utftoutf(source.Buffer(), buffer, len); + dest = ObjectString::TakeOver(buffer, len - 1); + } + + template + struct UtfStringSerializer + { + using SourceType = ObjectString; + using DestType = ObjectString; + using ContextType = std::nullptr_t; + + static void Serialize(const ContextType&, const SourceType& source, DestType& dest) + { + ConvertUtfString(source, dest); + } + + static void Deserialize(const ContextType&, const DestType& source, SourceType& dest) + { + ConvertUtfString(source, dest); + } + }; + + template + using GuiRemoteUtfStringChannelSerializer = GuiRemoteProtocolChannelSerializer>; + + template + using GuiRemoteUtfStringChannelDeserializer = GuiRemoteProtocolChannelDeserializer>; +} + +#endif + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_CHANNEL_ASYNC.H +***********************************************************************/ +/*********************************************************************** +Vczh Library++ 3.0 +Developer: Zihan Chen(vczh) +GacUI::Remote Window + +Interfaces: + IGuiRemoteProtocolChannel + +***********************************************************************/ + +#ifndef VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL_CHANNEL_ASYNC +#define VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL_CHANNEL_ASYNC + + +namespace vl::presentation::remoteprotocol::channeling +{ + +/*********************************************************************** +Metadata +***********************************************************************/ + + enum class ChannelPackageSemantic + { + Message, + Request, + Response, + Event, + Unknown, + }; + + enum class ChannelAsyncState + { + Ready, + Running, + Stopped, + }; + +/*********************************************************************** +Async + A certain package type could run in async mode + if the following function is defined + and accessible via argument-dependent lookup + +void ChannelPackageSemanticUnpack( + const T& package, + ChannelPackageSemantic& semantic, + vint& id, + WString& name + ); +***********************************************************************/ + + class GuiRemoteProtocolAsyncChannelSerializerBase : public Object + { + public: + using TTaskProc = Func; + + private: + collections::List channelThreadTasks; + SpinLock channelThreadLock; + collections::List uiThreadTasks; + SpinLock uiThreadLock; + + protected: + void QueueTask(SpinLock& lock, collections::List& tasks, TTaskProc task, EventObject* signalAfterQueue); + void QueueTaskAndWait(SpinLock& lock, collections::List& tasks, TTaskProc task, EventObject* signalAfterQueue); + void FetchTasks(SpinLock& lock, collections::List& tasks, collections::List& results); + void FetchAndExecuteTasks(SpinLock& lock, collections::List& tasks); + + void FetchAndExecuteChannelTasks(); + void FetchAndExecuteUITasks(); + + void QueueToChannelThread(TTaskProc task, EventObject* signalAfterQueue); + void QueueToChannelThreadAndWait(TTaskProc task, EventObject* signalAfterQueue); + void QueueToUIThread(TTaskProc task, EventObject* signalAfterQueue); + void QueueToUIThreadAndWait(TTaskProc task, EventObject* signalAfterQueue); + + public: + GuiRemoteProtocolAsyncChannelSerializerBase(); + ~GuiRemoteProtocolAsyncChannelSerializerBase(); + }; + + template + class GuiRemoteProtocolAsyncChannelSerializer + : public GuiRemoteProtocolAsyncChannelSerializerBase + , public virtual IGuiRemoteProtocolChannel + , protected virtual IGuiRemoteProtocolChannelReceiver + { + static_assert( + std::is_same_v(), + std::declval(), + std::declval(), + std::declval() + ))>, + "ChannelPackageSemanticUnpack must be defined for this TPackage" + ); + + public: + using TChannelThreadProc = Func; + using TUIThreadProc = Func; + using TStartingProc = Func; + using TStoppingProc = Func; + using TUIMainProc = Func*)>; + + protected: + struct PendingRequestGroup + { + vint connectionCounter = -1; + collections::List requestIds; + }; + + IGuiRemoteProtocolChannel* channel = nullptr; + IGuiRemoteProtocolChannelReceiver* receiver = nullptr; + TUIMainProc uiMainProc; + collections::List uiPendingPackages; + + SpinLock lockEvents; + collections::List queuedEvents; + + SpinLock lockResponses; + EventObject eventAutoResponses; + collections::Dictionary queuedResponses; + Ptr pendingRequest; + + SpinLock lockConnection; + volatile vint connectionCounter = 0; + volatile bool connectionAvailable = false; + + volatile bool started = false; + volatile bool stopping = false; + volatile bool stopped = false; + Nullable executablePath; + + EventObject eventAutoChannelTaskQueued; + EventObject eventManualChannelThreadStopped; + EventObject eventManualUIThreadStopped; + + void UIThreadProc() + { + uiMainProc(this); + uiMainProc = {}; + + // Signal and wait for ChannelThreadProc to finish + stopping = true; + eventAutoChannelTaskQueued.Signal(); + eventManualChannelThreadStopped.Wait(); + + // All remaining queued callbacks should be executed + FetchAndExecuteUITasks(); + eventManualUIThreadStopped.Signal(); + } + + void ChannelThreadProc() + { + // TODO: + // The current version always start a channel thread + // So that it does not matter whether the underlying IO is sync or async + // But async IO does not need a channel thread + // Refactor and optimize the channel thread to be optional in the future + + // All members of "_channel" argument to Start is called in this thread + // So that the implementation does not need to care about thread safety + + // The thread stopped after receiving a signal from UIThreadProc + while (!stopping) + { + eventAutoChannelTaskQueued.Wait(); + FetchAndExecuteChannelTasks(); + } + + // All remaining queued callbacks should be executed + FetchAndExecuteChannelTasks(); + eventManualChannelThreadStopped.Signal(); + } + + protected: + + bool AreCurrentPendingRequestGroupSatisfied(bool disconnected) + { + if (!pendingRequest) return false; + if (disconnected) return true; + for (vint requestId : pendingRequest->requestIds) + { + if (!queuedResponses.Keys().Contains(requestId)) + { + return false; + } + } + return true; + } + + void OnReceive(const TPackage& package) override + { + // Called from any thread, very likely the channel thread +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncChannelSerializer::OnReceive(...)#" + // If it is a response, unblock Submit() + // If it is an event, send to ProcessRemoteEvents() + + auto semantic = ChannelPackageSemantic::Unknown; + vint id = -1; + WString name; + ChannelPackageSemanticUnpack(package, semantic, id, name); + + switch (semantic) + { + case ChannelPackageSemantic::Event: + { + SPIN_LOCK(lockEvents) + { + queuedEvents.Add(package); + } + } + break; + case ChannelPackageSemantic::Response: + { + SPIN_LOCK(lockResponses) + { + queuedResponses.Add(id, package); + if (AreCurrentPendingRequestGroupSatisfied(false)) + { + eventAutoResponses.Signal(); + } + } + } + break; + default: + CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Only responses and events are expected."); + } + +#undef ERROR_MESSAGE_PREFIX + } + + public: + + void Write(const TPackage& package) override + { + // Called from UI thread + uiPendingPackages.Add(package); + } + + void Submit(bool& disconnected) override + { + // Called from UI thread +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncChannelSerializer::Submit(...)#" + + SPIN_LOCK(lockConnection) + { + if (!connectionAvailable) + { + disconnected = true; + uiPendingPackages.Clear(); + return; + } + } + + // Group all pending requests into a group + auto requestGroup = Ptr(new PendingRequestGroup); + requestGroup->connectionCounter = connectionCounter; + for (auto&& package : uiPendingPackages) + { + auto semantic = ChannelPackageSemantic::Unknown; + vint id = -1; + WString name; + ChannelPackageSemanticUnpack(package, semantic, id, name); + + if (semantic == ChannelPackageSemantic::Request) + { + requestGroup->requestIds.Add(id); + } + } + SPIN_LOCK(lockResponses) + { + CHECK_ERROR(!pendingRequest, ERROR_MESSAGE_PREFIX L"Internal error."); + pendingRequest = requestGroup; + } + + QueueToChannelThread([this, requestGroup, packages = std::move(uiPendingPackages)]() + { + for (auto&& package : packages) + { + channel->Write(package); + } + bool disconnected = false; + channel->Submit(disconnected); + if (disconnected) + { + SPIN_LOCK(lockConnection) + { + if (requestGroup->connectionCounter == connectionCounter) + { + connectionAvailable = false; + } + } + } + + if (disconnected || requestGroup->requestIds.Count() == 0) + { + eventAutoResponses.Signal(); + } + }, &eventAutoChannelTaskQueued); + + // Block until the all responses of the top request group are received + // Re-entrance recursively is possible + eventAutoResponses.Wait(); + SPIN_LOCK(lockConnection) + { + if (requestGroup->connectionCounter != connectionCounter || !connectionAvailable) + { + disconnected = true; + } + } + + collections::List responses; + SPIN_LOCK(lockResponses) + { + if (!disconnected) + { + for (vint id : requestGroup->requestIds) + { + responses.Add(queuedResponses[id]); + queuedResponses.Remove(id); + } + } + pendingRequest = nullptr; + queuedResponses.Clear(); + } + + for (auto&& response : responses) + { + receiver->OnReceive(response); + } + +#undef ERROR_MESSAGE_PREFIX + } + + void ProcessRemoteEvents() override + { + // Called from UI thread + QueueToChannelThread([this]() + { + channel->ProcessRemoteEvents(); + }, &eventAutoChannelTaskQueued); + + FetchAndExecuteUITasks(); + + // Process of queued events from channel + collections::List events; + SPIN_LOCK(lockEvents) + { + events = std::move(queuedEvents); + } + + for (auto&& event : events) + { + { + auto semantic = ChannelPackageSemantic::Unknown; + vint id = -1; + WString name; + ChannelPackageSemanticUnpack(event, semantic, id, name); + + if (name == L"ControllerConnect") + { + SPIN_LOCK(lockConnection) + { + connectionCounter++; + connectionAvailable = true; + } + } + } + receiver->OnReceive(event); + } + } + + public: + + /// + /// Start the async channel. + /// + /// + /// A channel object that runs in the argument offered to startingProc. + /// + /// + /// A callback that runs in the argument offered to startingProc, which is supposed to call . + /// An example of argument to would be + /// over + /// over + /// over + /// + /// A callback executed in the current thread, that responsible to start two threads for arguments and . + /// + void Start( + IGuiRemoteProtocolChannel* _channel, + TUIMainProc _uiMainProc, + TStartingProc startingProc + ) + { +#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncChannelSerializer::Start(...)#" + CHECK_ERROR(!started, ERROR_MESSAGE_PREFIX L"This function can only be called once."); + + channel = _channel; + uiMainProc = _uiMainProc; + + TChannelThreadProc thread_channel = [this]() + { + ChannelThreadProc(); + }; + + TUIThreadProc thread_ui = [this]() + { + UIThreadProc(); + }; + + eventAutoResponses.CreateAutoUnsignal(false); + eventAutoChannelTaskQueued.CreateAutoUnsignal(false); + eventManualChannelThreadStopped.CreateManualUnsignal(false); + eventManualUIThreadStopped.CreateManualUnsignal(false); + startingProc(thread_channel, thread_ui); + started = true; + +#undef ERROR_MESSAGE_PREFIX + } + + ChannelAsyncState GetAsyncStateUnsafe() + { + if (started) + { + if (stopped) + { + return ChannelAsyncState::Stopped; + } + else + { + return ChannelAsyncState::Running; + } + } + else + { + return ChannelAsyncState::Ready; + } + } + + void WaitForStopped() + { + eventManualUIThreadStopped.Wait(); + } + + public: + + GuiRemoteProtocolAsyncChannelSerializer() = default; + ~GuiRemoteProtocolAsyncChannelSerializer() = default; + + void ExecuteInChannelThread(TTaskProc task) + { + QueueToChannelThread(task, &eventAutoChannelTaskQueued); + } + + void Initialize(IGuiRemoteProtocolChannelReceiver* _receiver) override + { + // Called from UI thread + receiver = _receiver; + QueueToChannelThreadAndWait([this]() + { + channel->Initialize(this); + }, &eventAutoChannelTaskQueued); + } + + IGuiRemoteProtocolChannelReceiver* GetReceiver() override + { + // Called from UI thread + return receiver; + } + + WString GetExecutablePath() override + { + // Called from UI thread + if (!executablePath) + { + QueueToChannelThreadAndWait([this]() + { + executablePath = channel->GetExecutablePath(); + }, &eventAutoChannelTaskQueued); + } + return executablePath.Value(); + } + }; +} + +#endif + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_CHANNEL_JSON.H +***********************************************************************/ +/*********************************************************************** +Vczh Library++ 3.0 +Developer: Zihan Chen(vczh) +GacUI::Remote Window + +Interfaces: + IGuiRemoteProtocolChannel + +***********************************************************************/ + +#ifndef VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL_CHANNEL_JSON +#define VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL_CHANNEL_JSON + + +namespace vl::presentation::remoteprotocol::channeling +{ + using IJsonChannelReceiver = IGuiRemoteProtocolChannelReceiver>; + using IJsonChannel = IGuiRemoteProtocolChannel>; + +/*********************************************************************** +ChannelPackageSemantic +***********************************************************************/ + + extern void ChannelPackageSemanticUnpack(Ptr package, ChannelPackageSemantic& semantic, vint& id, WString& name); + +/*********************************************************************** +GuiRemoteProtocolFromJsonChannel +***********************************************************************/ + + class GuiRemoteProtocolFromJsonChannel + : public Object + , public virtual IGuiRemoteProtocol + , protected IJsonChannelReceiver + { + protected: + IJsonChannel* channel = nullptr; + IGuiRemoteProtocolEvents* events = nullptr; + + void OnReceive(const Ptr& package) override; + + public: + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME() override; +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE) void Request ## NAME(vint id) override; +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME(const REQUEST& arguments) override; +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE) void Request ## NAME(vint id, const REQUEST& arguments) override; +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_REQ_RES +#undef MESSAGE_REQ_NORES +#undef MESSAGE_NOREQ_RES +#undef MESSAGE_NOREQ_NORES + + GuiRemoteProtocolFromJsonChannel(IJsonChannel* _channel); + ~GuiRemoteProtocolFromJsonChannel(); + + void Initialize(IGuiRemoteProtocolEvents* _events) override; + WString GetExecutablePath() override; + void Submit(bool& disconnected) override; + void ProcessRemoteEvents() override; + }; + +/*********************************************************************** +GuiRemoteJsonChannelFromProtocol +***********************************************************************/ + + class GuiRemoteJsonChannelFromProtocol + : public Object + , public virtual IJsonChannel + , protected virtual IGuiRemoteProtocolEvents + { + protected: + IJsonChannelReceiver* receiver = nullptr; + IGuiRemoteProtocol* protocol = nullptr; + +#define EVENT_NOREQ(NAME, REQUEST) void On ## NAME() override; +#define EVENT_REQ(NAME, REQUEST) void On ## NAME(const REQUEST& arguments) override; +#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST) + GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) +#undef EVENT_HANDLER +#undef EVENT_REQ +#undef EVENT_NOREQ + +#define MESSAGE_NORES(NAME, RESPONSE) +#define MESSAGE_RES(NAME, RESPONSE) void Respond ## NAME(vint id, const RESPONSE& arguments) override; +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_RES +#undef MESSAGE_NORES + public: + + GuiRemoteJsonChannelFromProtocol(IGuiRemoteProtocol* _protocol); + ~GuiRemoteJsonChannelFromProtocol(); + + void Initialize(IJsonChannelReceiver* _receiver) override; + IJsonChannelReceiver* GetReceiver() override; + void Write(const Ptr& package) override; + WString GetExecutablePath() override; + void Submit(bool& disconnected) override; + void ProcessRemoteEvents() override; + }; + +/*********************************************************************** +JsonToStringSerializer +***********************************************************************/ + + struct JsonToStringSerializer + { + using SourceType = Ptr; + using DestType = WString; + using ContextType = Ptr; + + static void Serialize(Ptr parser, const SourceType& source, DestType& dest); + static void Deserialize(Ptr parser, const DestType& source, SourceType& dest); + }; + + using GuiRemoteJsonChannelStringSerializer = GuiRemoteProtocolChannelSerializer; + using GuiRemoteJsonChannelStringDeserializer = GuiRemoteProtocolChannelDeserializer; } #endif @@ -23336,41 +24254,16 @@ GuiRemoteEventFilterVerifier public: bool submitting = false; - void ClearDropRepeatMasks() - { -#define EVENT_NODROP(NAME) -#define EVENT_DROPREP(NAME) lastDropRepeatEvent ## NAME = false; -#define EVENT_DROPCON(NAME) -#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## DROPTAG(NAME) - GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) -#undef EVENT_HANDLER -#undef EVENT_DROPCON -#undef EVENT_DROPREP -#undef EVENT_NODROP - } + GuiRemoteEventFilterVerifier(); + ~GuiRemoteEventFilterVerifier(); - void ClearDropConsecutiveMasks() - { -#define EVENT_NODROP(NAME) -#define EVENT_DROPREP(NAME) -#define EVENT_DROPCON(NAME) lastDropConsecutiveEvent ## NAME = false; -#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## DROPTAG(NAME) - GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) -#undef EVENT_HANDLER -#undef EVENT_DROPCON -#undef EVENT_DROPREP -#undef EVENT_NODROP - } + void ClearDropRepeatMasks(); + void ClearDropConsecutiveMasks(); // responses #define MESSAGE_NORES(NAME, RESPONSE) -#define MESSAGE_RES(NAME, RESPONSE)\ - void Respond ## NAME(vint id, const RESPONSE& arguments) override\ - {\ - targetEvents->Respond ## NAME(id, arguments);\ - }\ - +#define MESSAGE_RES(NAME, RESPONSE) void Respond ## NAME(vint id, const RESPONSE& arguments) override; #define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) #undef MESSAGE_HANDLER @@ -23378,54 +24271,13 @@ GuiRemoteEventFilterVerifier #undef MESSAGE_NORES // events - -#define EVENT_NODROP(NAME) - -#define EVENT_DROPREP(NAME)\ - CHECK_ERROR(!lastDropRepeatEvent ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteEventFilterVerifier::On" L ## #NAME L"(...)#[@DropRepeat] event repeated.");\ - lastDropRepeatEvent ## NAME = true;\ - -#define EVENT_DROPCON(NAME)\ - CHECK_ERROR(!lastDropConsecutiveEvent ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteEventFilterVerifier::On" L ## #NAME L"(...)#[@DropConsecutive] event repeated.");\ - ClearDropConsecutiveMasks();\ - lastDropConsecutiveEvent ## NAME = true;\ - -#define EVENT_NOREQ(NAME, REQUEST, DROPTAG)\ - void On ## NAME() override\ - {\ - if (submitting)\ - {\ - EVENT_ ## DROPTAG(NAME);\ - targetEvents->On ## NAME();\ - }\ - else\ - {\ - targetEvents->On ## NAME();\ - }\ - }\ - -#define EVENT_REQ(NAME, REQUEST, DROPTAG)\ - void On ## NAME(const REQUEST& arguments) override\ - {\ - if (submitting)\ - {\ - EVENT_ ## DROPTAG(NAME);\ - targetEvents->On ## NAME(arguments);\ - }\ - else\ - {\ - targetEvents->On ## NAME(arguments);\ - }\ - }\ - +#define EVENT_NOREQ(NAME, REQUEST, DROPTAG) void On ## NAME() override; +#define EVENT_REQ(NAME, REQUEST, DROPTAG) void On ## NAME(const REQUEST& arguments) override; #define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST, DROPTAG) GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) #undef EVENT_HANDLER #undef EVENT_REQ #undef EVENT_NOREQ -#undef EVENT_DROPCON -#undef EVENT_DROPREP -#undef EVENT_NOREP }; /*********************************************************************** @@ -23438,7 +24290,7 @@ GuiRemoteProtocolFilterVerifier { friend class GuiRemoteProtocolFilter; protected: - vint lastRequestId = -1; + vint lastRequestId = -1; #define MESSAGE_NODROP(NAME) #define MESSAGE_DROPREP(NAME) bool lastDropRepeatRequest ## NAME = false; @@ -23448,62 +24300,20 @@ GuiRemoteProtocolFilterVerifier #undef MESSAGE_DROPREP #undef MESSAGE_NODROP - void ClearDropRepeatMasks() - { -#define MESSAGE_NODROP(NAME) -#define MESSAGE_DROPREP(NAME) lastDropRepeatRequest ## NAME = false; -#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG) MESSAGE_ ## DROPTAG(NAME) - GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) -#undef MESSAGE_HANDLER -#undef MESSAGE_DROPREP -#undef MESSAGE_NODROP - } + void ClearDropRepeatMasks(); + public: - GuiRemoteProtocolFilterVerifier(IGuiRemoteProtocol* _protocol) - : GuiRemoteProtocolCombinator(_protocol) - { - } - - protected: + GuiRemoteProtocolFilterVerifier(IGuiRemoteProtocol* _protocol); + ~GuiRemoteProtocolFilterVerifier(); public: // messages -#define MESSAGE_NODROP(NAME) - -#define MESSAGE_DROPREP(NAME)\ - CHECK_ERROR(!lastDropRepeatRequest ## NAME, L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilterVerifier::Request" L ## #NAME L"(...)#[@DropRepeat] message repeated.");\ - lastDropRepeatRequest ## NAME = true;\ - -#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\ - void Request ## NAME() override\ - {\ - MESSAGE_ ## DROPTAG(NAME);\ - targetProtocol->Request ## NAME();\ - }\ - -#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\ - void Request ## NAME(vint id) override\ - {\ - MESSAGE_ ## DROPTAG(NAME);\ - targetProtocol->Request ## NAME(id);\ - }\ - -#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\ - void Request ## NAME(const REQUEST& arguments) override\ - {\ - MESSAGE_ ## DROPTAG(NAME);\ - targetProtocol->Request ## NAME(arguments);\ - }\ - -#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\ - void Request ## NAME(vint id, const REQUEST& arguments) override\ - {\ - MESSAGE_ ## DROPTAG(NAME);\ - targetProtocol->Request ## NAME(id, arguments);\ - }\ - +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG) void Request ## NAME() override; +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE, DROPTAG) void Request ## NAME(vint id) override; +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG) void Request ## NAME(const REQUEST& arguments) override; +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE, DROPTAG) void Request ## NAME(vint id, const REQUEST& arguments) override; #define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE, DROPTAG) GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) #undef MESSAGE_HANDLER @@ -23511,23 +24321,10 @@ GuiRemoteProtocolFilterVerifier #undef MESSAGE_REQ_NORES #undef MESSAGE_NOREQ_RES #undef MESSAGE_NOREQ_NORES -#undef MESSAGE_DROPREP -#undef MESSAGE_NODROP // protocol - void Submit() override - { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::repeatfiltering::GuiRemoteProtocolFilterVerifier::Submit()#" - CHECK_ERROR(!eventCombinator.submitting, ERROR_MESSAGE_PREFIX L"This function is not allowed to be called recursively."); - eventCombinator.submitting = true; - GuiRemoteProtocolCombinator::Submit(); - ClearDropRepeatMasks(); - eventCombinator.ClearDropRepeatMasks(); - eventCombinator.ClearDropConsecutiveMasks(); - eventCombinator.submitting = false; -#undef ERROR_MESSAGE_PREFIX - } + void Submit(bool& disconnected) override; }; } @@ -23644,95 +24441,17 @@ GuiRemoteEventFilter public: bool submitting = false; collections::Dictionary responseIds; + + GuiRemoteEventFilter(); + ~GuiRemoteEventFilter(); - void ProcessResponses() - { - for (auto&& response : filteredResponses) - { -#define MESSAGE_NORES(NAME, RESPONSE) -#define MESSAGE_RES(NAME, RESPONSE)\ - case FilteredResponseNames::NAME:\ - targetEvents->Respond ## NAME(response.id, response.arguments.Get());\ - break;\ - -#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) - switch (response.name) - { - GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) - default: - CHECK_FAIL(L"vl::presentation::remoteprotocol::GuiRemoteEventFilter::ProcessResponses()#Unrecognized response."); - } -#undef MESSAGE_HANDLER -#undef MESSAGE_RES -#undef MESSAGE_NORES - } - - filteredResponses.Clear(); - } - - void ProcessEvents() - { -#define EVENT_NODROP(NAME) -#define EVENT_DROPREP(NAME) lastDropRepeatEvent ## NAME = -1; -#define EVENT_DROPCON(NAME) lastDropConsecutiveEvent ## NAME = -1; -#define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## DROPTAG(NAME) - GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) -#undef EVENT_HANDLER -#undef EVENT_DROPCON -#undef EVENT_DROPREP -#undef EVENT_NODROP - - collections::List events(std::move(filteredEvents)); - - for (auto&& event : events) - { - if (event.dropped) - { - continue; - } - -#define EVENT_NOREQ(NAME, REQUEST)\ - case FilteredEventNames::NAME:\ - targetEvents->On ## NAME();\ - break;\ - -#define EVENT_REQ(NAME, REQUEST)\ - case FilteredEventNames::NAME:\ - targetEvents->On ## NAME(event.arguments.Get());\ - break;\ - -#define EVENT_HANDLER(NAME, REQUEST, REQTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST) - switch (event.name) - { - GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) - default: - CHECK_FAIL(L"vl::presentation::remoteprotocol::GuiRemoteEventFilter::ProcessEvents()#Unrecognized event."); - } -#undef EVENT_HANDLER -#undef EVENT_REQ -#undef EVENT_NOREQ - } - } + void ProcessResponses(); + void ProcessEvents(); // responses #define MESSAGE_NORES(NAME, RESPONSE) -#define MESSAGE_RES(NAME, RESPONSE)\ - void Respond ## NAME(vint id, const RESPONSE& arguments) override\ - {\ - CHECK_ERROR(\ - responseIds[id] == FilteredResponseNames::NAME,\ - L"vl::presentation::remoteprotocol::GuiRemoteEventFilter::"\ - L"Respond" L ## #NAME L"()#"\ - L"Messages sending to IGuiRemoteProtocol should be responded by calling the correct function.");\ - responseIds.Remove(id);\ - FilteredResponse response;\ - response.id = id;\ - response.name = FilteredResponseNames::NAME;\ - response.arguments = arguments;\ - filteredResponses.Add(response);\ - }\ - +#define MESSAGE_RES(NAME, RESPONSE) void Respond ## NAME(vint id, const RESPONSE& arguments) override; #define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## RESTAG(NAME, RESPONSE) GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) #undef MESSAGE_HANDLER @@ -23740,64 +24459,14 @@ GuiRemoteEventFilter #undef MESSAGE_NORES // events - -#define EVENT_NODROP(NAME) - -#define EVENT_DROPREP(NAME)\ - if (lastDropRepeatEvent ## NAME != -1)\ - {\ - filteredEvents[lastDropRepeatEvent ## NAME].dropped = true;\ - }\ - lastDropRepeatEvent ## NAME = filteredEvents.Count() - 1\ - -#define EVENT_DROPCON(NAME)\ - if (lastDropConsecutiveEvent ## NAME != -1 && lastDropConsecutiveEvent ## NAME == filteredEvents.Count() - 1)\ - {\ - filteredEvents[lastDropConsecutiveEvent ## NAME].dropped = true;\ - }\ - lastDropConsecutiveEvent ## NAME = filteredEvents.Count() - 1\ - -#define EVENT_NOREQ(NAME, REQUEST, DROPTAG)\ - void On ## NAME() override\ - {\ - if (submitting)\ - {\ - EVENT_ ## DROPTAG(NAME);\ - FilteredEvent event;\ - event.name = FilteredEventNames::NAME;\ - filteredEvents.Add(event);\ - }\ - else\ - {\ - targetEvents->On ## NAME();\ - }\ - }\ - -#define EVENT_REQ(NAME, REQUEST, DROPTAG)\ - void On ## NAME(const REQUEST& arguments) override\ - {\ - if (submitting)\ - {\ - EVENT_ ## DROPTAG(NAME);\ - FilteredEvent event;\ - event.name = FilteredEventNames::NAME;\ - event.arguments = arguments;\ - filteredEvents.Add(event);\ - }\ - else\ - {\ - targetEvents->On ## NAME(arguments);\ - }\ - }\ - + +#define EVENT_NOREQ(NAME, REQUEST, DROPTAG) void On ## NAME() override; +#define EVENT_REQ(NAME, REQUEST, DROPTAG) void On ## NAME(const REQUEST& arguments) override; #define EVENT_HANDLER(NAME, REQUEST, REQTAG, DROPTAG, ...) EVENT_ ## REQTAG(NAME, REQUEST, DROPTAG) GACUI_REMOTEPROTOCOL_EVENTS(EVENT_HANDLER) #undef EVENT_HANDLER #undef EVENT_REQ #undef EVENT_NOREQ -#undef EVENT_DROPCON -#undef EVENT_DROPREP -#undef EVENT_NOREP }; /*********************************************************************** @@ -23807,8 +24476,8 @@ GuiRemoteProtocolFilter class GuiRemoteProtocolFilter : public GuiRemoteProtocolCombinator { protected: - vint lastRequestId = -1; - collections::List filteredRequests; + vint lastRequestId = -1; + collections::List filteredRequests; #define MESSAGE_NODROP(NAME) #define MESSAGE_DROPREP(NAME) vint lastDropRepeatRequest ## NAME = -1; @@ -23817,140 +24486,23 @@ GuiRemoteProtocolFilter #undef MESSAGE_HANDLER #undef MESSAGE_DROPREP #undef MESSAGE_NODROP - - void ProcessRequests() - { -#define MESSAGE_NODROP(NAME) -#define MESSAGE_DROPREP(NAME) lastDropRepeatRequest ## NAME = -1; -#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG) MESSAGE_ ## DROPTAG(NAME) - GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) -#undef MESSAGE_HANDLER -#undef MESSAGE_DROPREP -#undef MESSAGE_NODROP - - for (auto&& request : filteredRequests) - { - CHECK_ERROR(\ - !request.dropped || request.id == -1,\ - L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::ProcessRequests()#"\ - L"Messages with id cannot be dropped.");\ - if (request.dropped) - { - continue; - } - -#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE)\ - case FilteredRequestNames::NAME:\ - targetProtocol->Request ## NAME();\ - break;\ - -#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE)\ - case FilteredRequestNames::NAME:\ - targetProtocol->Request ## NAME(request.id);\ - break;\ - -#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE)\ - case FilteredRequestNames::NAME:\ - targetProtocol->Request ## NAME(request.arguments.Get());\ - break;\ - -#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE)\ - case FilteredRequestNames::NAME:\ - targetProtocol->Request ## NAME(request.id, request.arguments.Get());\ - break;\ - -#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE) - switch (request.name) - { - GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) - default: - CHECK_FAIL(L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::ProcessRequests()#Unrecognized request."); - } -#undef MESSAGE_HANDLER -#undef MESSAGE_REQ_RES -#undef MESSAGE_REQ_NORES -#undef MESSAGE_NOREQ_RES -#undef MESSAGE_NOREQ_NORES - } - - CHECK_ERROR(eventCombinator.responseIds.Count() == 0, L"Messages sending to IGuiRemoteProtocol should be all responded."); - filteredRequests.Clear(); - } + + void ProcessRequests(); public: - GuiRemoteProtocolFilter(IGuiRemoteProtocol* _protocol) - : GuiRemoteProtocolCombinator(_protocol) - { - } + GuiRemoteProtocolFilter(IGuiRemoteProtocol* _protocol); + ~GuiRemoteProtocolFilter(); protected: public: // messages - -#define MESSAGE_NODROP(NAME) - -#define MESSAGE_DROPREP(NAME)\ - if (lastDropRepeatRequest ## NAME != -1)\ - {\ - filteredRequests[lastDropRepeatRequest ## NAME].dropped = true;\ - }\ - lastDropRepeatRequest ## NAME = filteredRequests.Count()\ - -#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\ - void Request ## NAME() override\ - {\ - MESSAGE_ ## DROPTAG(NAME);\ - FilteredRequest request;\ - request.name = FilteredRequestNames::NAME;\ - filteredRequests.Add(request);\ - }\ - -#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\ - void Request ## NAME(vint id) override\ - {\ - MESSAGE_ ## DROPTAG(NAME);\ - CHECK_ERROR(\ - lastRequestId < id,\ - L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::"\ - L"Request" L ## #NAME L"()#"\ - L"Id of a message sending to IGuiRemoteProtocol should be increasing.");\ - lastRequestId = id;\ - FilteredRequest request;\ - request.id = id;\ - request.name = FilteredRequestNames::NAME;\ - filteredRequests.Add(request);\ - eventCombinator.responseIds.Add(id, FilteredResponseNames::NAME);\ - }\ - -#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG)\ - void Request ## NAME(const REQUEST& arguments) override\ - {\ - MESSAGE_ ## DROPTAG(NAME);\ - FilteredRequest request;\ - request.name = FilteredRequestNames::NAME;\ - request.arguments = arguments;\ - filteredRequests.Add(request);\ - }\ - -#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE, DROPTAG)\ - void Request ## NAME(vint id, const REQUEST& arguments) override\ - {\ - MESSAGE_ ## DROPTAG(NAME);\ - CHECK_ERROR(\ - lastRequestId < id,\ - L"vl::presentation::remoteprotocol::GuiRemoteProtocolFilter::"\ - L"Request" L ## #NAME L"()#"\ - L"Id of a message sending to IGuiRemoteProtocol should be increasing.");\ - lastRequestId = id;\ - FilteredRequest request;\ - request.id = id;\ - request.name = FilteredRequestNames::NAME;\ - request.arguments = arguments;\ - filteredRequests.Add(request);\ - eventCombinator.responseIds.Add(id, FilteredResponseNames::NAME);\ - }\ - + + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG) void Request ## NAME() override; +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE, DROPTAG) void Request ## NAME(vint id) override; +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE, DROPTAG) void Request ## NAME(const REQUEST& arguments) override; +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE, DROPTAG) void Request ## NAME(vint id, const REQUEST& arguments) override; #define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, DROPTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE, DROPTAG) GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) #undef MESSAGE_HANDLER @@ -23958,37 +24510,291 @@ GuiRemoteProtocolFilter #undef MESSAGE_REQ_NORES #undef MESSAGE_NOREQ_RES #undef MESSAGE_NOREQ_NORES -#undef MESSAGE_DROPREP -#undef MESSAGE_NODROP - + // protocol - - void Initialize(IGuiRemoteProtocolEvents* _events) override + + void Initialize(IGuiRemoteProtocolEvents* _events) override; + void Submit(bool& disconnected) override; + }; +} + +#endif + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\PROTOCOL\FRAMEOPERATIONS\GUIREMOTEPROTOCOLSCHEMA_FRAMEOPERATIONS.H +***********************************************************************/ +/*********************************************************************** +Vczh Library++ 3.0 +Developer: Zihan Chen(vczh) +GacUI::Remote Window + +***********************************************************************/ + +#ifndef VCZH_PRESENTATION_GUIREMOTECONTROLLER_REMOTEPROTOCOLSCHEMA_FRAMEOPERATIONS +#define VCZH_PRESENTATION_GUIREMOTECONTROLLER_REMOTEPROTOCOLSCHEMA_FRAMEOPERATIONS + + +namespace vl::presentation::remoteprotocol +{ + /* + * dom id: + * + * root: -1 + * element: (elementId << 2) + 0 + * parent of element: (elementId << 2) + 1 + * hittest: (compositionId << 2) + 2 + * parent of hittest: (compositionId << 2) + 3 + */ + + class RenderingDomBuilder + { + using RenderingResultRef = Ptr; + using RenderingResultRefList = collections::List; + protected: + RenderingResultRefList domStack; + collections::List domBoundaries; + Ptr domRoot; + Ptr domCurrent; + + vint GetCurrentBoundary(); + vint Push(RenderingResultRef ref); + void PopTo(vint index); + void Pop(); + void PopBoundary(); + + template + void PrepareParentFromCommand(Rect commandBounds, Rect commandValidArea, vint newDomId, TCallback&& calculateValidAreaFromDom); + public: + RenderingDomBuilder() = default; + ~RenderingDomBuilder() = default; + + void RequestRendererBeginRendering(); + void RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments); + void RequestRendererEndBoundary(); + void RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments); + Ptr RequestRendererEndRendering(); + }; + + extern Ptr CopyDom(Ptr root); + + struct DomIndexItem + { + vint id; + vint parentId; + Ptr dom; + + auto operator<=>(const DomIndexItem&) const = default; + }; + using DomIndex = collections::Array; + + extern void BuildDomIndex(Ptr root, DomIndex& index); + extern void UpdateDomInplace(Ptr root, DomIndex& index, const RenderingDom_DiffsInOrder& diffs); + extern void DiffDom(Ptr domFrom, DomIndex& indexFrom, Ptr domTo, DomIndex& indexTo, RenderingDom_DiffsInOrder& diffs); +} + +#endif + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTERENDERER\GUIREMOTERENDERERSINGLE.H +***********************************************************************/ +/*********************************************************************** +Vczh Library++ 3.0 +Developer: Zihan Chen(vczh) +GacUI::Remote Window + +Interfaces: + GuiRemoteRendererSingle + +***********************************************************************/ + +#ifndef VCZH_PRESENTATION_GUIREMOTECONTROLLER_REMOTERENDERER_GUIREMOTERENDERERSINGLE +#define VCZH_PRESENTATION_GUIREMOTECONTROLLER_REMOTERENDERER_GUIREMOTERENDERERSINGLE + + +namespace vl::presentation::remote_renderer +{ + class GuiRemoteRendererSingle + : public Object + , public virtual IGuiRemoteProtocol + , protected virtual INativeWindowListener + , protected virtual INativeControllerListener + { + protected: + INativeWindow* window = nullptr; + INativeScreen* screen = nullptr; + IGuiRemoteProtocolEvents* events = nullptr; + bool disconnectingFromCore = false; + + bool updatingBounds = false; + remoteprotocol::WindowSizingConfig windowSizingConfig; + + remoteprotocol::ScreenConfig GetScreenConfig(INativeScreen* screen); + remoteprotocol::WindowSizingConfig GetWindowSizingConfig(); + void UpdateConfigsIfNecessary(); + + void NativeWindowDestroying(INativeWindow* _window) override; + + void Opened() override; + void BeforeClosing(bool& cancel) override; + void AfterClosing() override; + void Closed() override; + + void Moved() override; + void DpiChanged(bool preparing) override; + void RenderingAsActivated() override; + void RenderingAsDeactivated() override; + + protected: + struct SolidLabelMeasuring { - if (auto verifierProtocol = dynamic_cast(targetProtocol)) - { - verifierProtocol->targetProtocol->Initialize(&eventCombinator); - eventCombinator.targetEvents = &verifierProtocol->eventCombinator; - verifierProtocol->eventCombinator.targetEvents = _events; - } - else - { - GuiRemoteProtocolCombinator::Initialize(_events); - } - } + remoteprotocol::ElementSolidLabelMeasuringRequest request; + Nullable minSize; + }; + + using ElementMap = collections::Dictionary>; + using ImageMap = collections::Dictionary>; + using SolidLabelMeasuringMap = collections::Dictionary; + using FontHeightMeasuringSet = collections::SortedList>; + + remoteprotocol::ElementMeasurings elementMeasurings; + FontHeightMeasuringSet fontHeightMeasurings; + SolidLabelMeasuringMap solidLabelMeasurings; + + ElementMap availableElements; + ImageMap availableImages; + Ptr renderingDom; + remoteprotocol::DomIndex renderingDomIndex; + + Alignment GetAlignment(remoteprotocol::ElementHorizontalAlignment alignment); + Alignment GetAlignment(remoteprotocol::ElementVerticalAlignment alignment); + void StoreLabelMeasuring(vint id, remoteprotocol::ElementSolidLabelMeasuringRequest request, Ptr solidLabel, Size minSize); + remoteprotocol::ImageMetadata CreateImageMetadata(vint id, INativeImage* image); + remoteprotocol::ImageMetadata CreateImage(const remoteprotocol::ImageCreation& arguments); + void CheckDom(); + + protected: + bool supressPaint = false; + bool needRefresh = false; + + void UpdateRenderTarget(elements::IGuiGraphicsRenderTarget* rt); + void Render(Ptr dom, elements::IGuiGraphicsRenderTarget* rt); + void HitTestInternal(Ptr dom, Point location, Nullable& hitTestResult, Nullable& cursorType); + void HitTest(Ptr dom, Point location, INativeWindowListener::HitTestResult& hitTestResult, INativeCursor*& cursor); + + void GlobalTimer() override; + void Paint() override; + INativeWindowListener::HitTestResult HitTest(NativePoint location) override; + + protected: + + void LeftButtonDown(const NativeWindowMouseInfo& info) override; + void LeftButtonUp(const NativeWindowMouseInfo& info) override; + void LeftButtonDoubleClick(const NativeWindowMouseInfo& info) override; + void RightButtonDown(const NativeWindowMouseInfo& info) override; + void RightButtonUp(const NativeWindowMouseInfo& info) override; + void RightButtonDoubleClick(const NativeWindowMouseInfo& info) override; + void MiddleButtonDown(const NativeWindowMouseInfo& info) override; + void MiddleButtonUp(const NativeWindowMouseInfo& info) override; + void MiddleButtonDoubleClick(const NativeWindowMouseInfo& info) override; + void HorizontalWheel(const NativeWindowMouseInfo& info) override; + void VerticalWheel(const NativeWindowMouseInfo& info) override; + void MouseMoving(const NativeWindowMouseInfo& info) override; + void MouseEntered() override; + void MouseLeaved() override; + void KeyDown(const NativeWindowKeyInfo& info) override; + void KeyUp(const NativeWindowKeyInfo& info) override; + void Char(const NativeWindowCharInfo& info) override; + + public: + GuiRemoteRendererSingle(); + ~GuiRemoteRendererSingle(); + + void RegisterMainWindow(INativeWindow* _window); + void UnregisterMainWindow(); + void ForceExitByFatelError(); + + WString GetExecutablePath() override; + void Initialize(IGuiRemoteProtocolEvents* _events) override; + void Submit(bool& disconnected) override; + void ProcessRemoteEvents() override; + + +#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME() override; +#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE) void Request ## NAME(vint id) override; +#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME(const REQUEST& arguments) override; +#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE) void Request ## NAME(vint id, const REQUEST& arguments) override; +#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE) + GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER) +#undef MESSAGE_HANDLER +#undef MESSAGE_REQ_RES +#undef MESSAGE_REQ_NORES +#undef MESSAGE_NOREQ_RES +#undef MESSAGE_NOREQ_NORES + }; +} + +#endif + +/*********************************************************************** +.\PLATFORMPROVIDERS\REMOTE\GUIREMOTEPROTOCOL_DOMDIFF.H +***********************************************************************/ +/*********************************************************************** +Vczh Library++ 3.0 +Developer: Zihan Chen(vczh) +GacUI::Remote Window + +Interfaces: + IGuiRemoteProtocol + +***********************************************************************/ + +#ifndef VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL_DOMDIFF +#define VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL_DOMDIFF + + +namespace vl::presentation::remoteprotocol +{ + +/*********************************************************************** +GuiRemoteEventDomDiffConverter +***********************************************************************/ + + class GuiRemoteProtocolDomDiffConverter; + + class GuiRemoteEventDomDiffConverter : public GuiRemoteEventCombinator_PassingThrough + { + friend class GuiRemoteProtocolDomDiffConverter; + using TBase = GuiRemoteEventCombinator_PassingThrough; + protected: + Ptr lastDom; + DomIndex lastDomIndex; + + public: + GuiRemoteEventDomDiffConverter(); + ~GuiRemoteEventDomDiffConverter(); + + void OnControllerConnect() override; + }; + +/*********************************************************************** +GuiRemoteProtocolDomDiffConverter +***********************************************************************/ - void Submit() override - { -#define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::repeatfiltering::GuiRemoteProtocolFilter::Submit()#" - CHECK_ERROR(!eventCombinator.submitting, ERROR_MESSAGE_PREFIX L"This function is not allowed to be called recursively."); - eventCombinator.submitting = true; - ProcessRequests(); - eventCombinator.ProcessResponses(); - GuiRemoteProtocolCombinator::Submit(); - eventCombinator.submitting = false; - eventCombinator.ProcessEvents(); -#undef ERROR_MESSAGE_PREFIX - } + class GuiRemoteProtocolDomDiffConverter : public GuiRemoteProtocolCombinator_PassingThrough + { + using TBase = GuiRemoteProtocolCombinator_PassingThrough; + protected: + RenderingDomBuilder renderingDomBuilder; + + public: + GuiRemoteProtocolDomDiffConverter(IGuiRemoteProtocol* _protocol); + ~GuiRemoteProtocolDomDiffConverter(); + + void RequestRendererBeginRendering(const remoteprotocol::ElementBeginRendering& arguments) override; + void RequestRendererEndRendering(vint id) override; + void RequestRendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments) override; + void RequestRendererEndBoundary() override; + void RequestRendererRenderElement(const remoteprotocol::ElementRendering& arguments) override; }; } @@ -24011,6 +24817,11 @@ Interfaces: #define VCZH_PRESENTATION_GUIREMOTECONTROLLER_GUIREMOTEPROTOCOL +namespace vl::presentation::remoteprotocol::channeling +{ + using GuiRemoteProtocolAsyncJsonChannelSerializer = GuiRemoteProtocolAsyncChannelSerializer>; +} + #endif /*********************************************************************** @@ -25042,6 +25853,8 @@ extern int SetupWindowsGDIRenderer(); extern int SetupWindowsDirect2DRenderer(); extern int SetupHostedWindowsGDIRenderer(); extern int SetupHostedWindowsDirect2DRenderer(); +extern int SetupRawWindowsGDIRenderer(); +extern int SetupRawWindowsDirect2DRenderer(); // Gtk extern int SetupGtkRenderer(); @@ -28627,7 +29440,7 @@ GuiRemoteMessages GuiRemoteMessages(GuiRemoteController* _remote); ~GuiRemoteMessages(); - void Submit(); + void Submit(bool& disconnected); // messages diff --git a/Import/Metadata/RemoteProtocol.json b/Import/Metadata/RemoteProtocol.json index f912c5fc..7d789a26 100644 --- a/Import/Metadata/RemoteProtocol.json +++ b/Import/Metadata/RemoteProtocol.json @@ -2211,6 +2211,13 @@ "attributes": [], "name": "ElementBoundary", "members": [{ + "$ast": "StructMember", + "name": "id", + "type": { + "$ast": "PrimitiveType", + "type": "Integer" + } + }, { "$ast": "StructMember", "name": "hitTestResult", "type": { @@ -2383,42 +2390,10 @@ "name": "ElementMeasurings" } } - }, { - "$ast": "UnionDecl", - "attributes": [], - "name": "ElementDescVariant", - "members": [{ - "$ast": "UnionMember", - "name": "ElementDesc_SolidBorder" - }, { - "$ast": "UnionMember", - "name": "ElementDesc_SinkBorder" - }, { - "$ast": "UnionMember", - "name": "ElementDesc_SinkSplitter" - }, { - "$ast": "UnionMember", - "name": "ElementDesc_SolidBackground" - }, { - "$ast": "UnionMember", - "name": "ElementDesc_GradientBackground" - }, { - "$ast": "UnionMember", - "name": "ElementDesc_InnerShadow" - }, { - "$ast": "UnionMember", - "name": "ElementDesc_Polygon" - }, { - "$ast": "UnionMember", - "name": "ElementDesc_SolidLabel" - }, { - "$ast": "UnionMember", - "name": "ElementDesc_ImageFrame" - }] }, { "$ast": "StructDecl", "attributes": [], - "name": "RenderingDom", + "name": "RenderingDomContent", "members": [{ "$ast": "StructMember", "name": "hitTestResult", @@ -2463,6 +2438,26 @@ "$ast": "ReferenceType", "name": "Rect" } + }], + "type": "Struct" + }, { + "$ast": "StructDecl", + "attributes": [], + "name": "RenderingDom", + "members": [{ + "$ast": "StructMember", + "name": "id", + "type": { + "$ast": "PrimitiveType", + "type": "Integer" + } + }, { + "$ast": "StructMember", + "name": "content", + "type": { + "$ast": "ReferenceType", + "name": "RenderingDomContent" + } }, { "$ast": "StructMember", "name": "children", @@ -2476,40 +2471,52 @@ }], "type": "Class" }, { - "$ast": "StructDecl", + "$ast": "EnumDecl", "attributes": [], - "name": "RenderingCommand_BeginBoundary", + "name": "RenderingDom_DiffType", "members": [{ - "$ast": "StructMember", - "name": "boundary", - "type": { - "$ast": "ReferenceType", - "name": "ElementBoundary" - } - }], - "type": "Struct" + "$ast": "EnumMember", + "name": "Deleted" + }, { + "$ast": "EnumMember", + "name": "Created" + }, { + "$ast": "EnumMember", + "name": "Modified" + }] }, { "$ast": "StructDecl", "attributes": [], - "name": "RenderingCommand_EndBoundary", - "members": [], - "type": "Struct" - }, { - "$ast": "StructDecl", - "attributes": [], - "name": "RenderingCommand_Element", + "name": "RenderingDom_Diff", "members": [{ "$ast": "StructMember", - "name": "rendering", + "name": "id", "type": { - "$ast": "ReferenceType", - "name": "ElementRendering" + "$ast": "PrimitiveType", + "type": "Integer" } }, { "$ast": "StructMember", - "name": "element", + "name": "diffType", + "type": { + "$ast": "ReferenceType", + "name": "RenderingDom_DiffType" + } + }, { + "$ast": "StructMember", + "name": "content", "type": { "$ast": "OptionalType", + "element": { + "$ast": "ReferenceType", + "name": "RenderingDomContent" + } + } + }, { + "$ast": "StructMember", + "name": "children", + "type": { + "$ast": "ArrayType", "element": { "$ast": "PrimitiveType", "type": "Integer" @@ -2517,24 +2524,82 @@ } }], "type": "Struct" + }, { + "$ast": "StructDecl", + "attributes": [], + "name": "RenderingDom_DiffsInOrder", + "members": [{ + "$ast": "StructMember", + "name": "diffsInOrder", + "type": { + "$ast": "ArrayType", + "element": { + "$ast": "ReferenceType", + "name": "RenderingDom_Diff" + } + } + }], + "type": "Struct" + }, { + "$ast": "MessageDecl", + "attributes": [], + "name": "RendererRenderDom", + "request": { + "$ast": "MessageRequest", + "type": { + "$ast": "ReferenceType", + "name": "RenderingDom" + } + }, + "response": null + }, { + "$ast": "MessageDecl", + "attributes": [], + "name": "RendererRenderDomDiff", + "request": { + "$ast": "MessageRequest", + "type": { + "$ast": "ReferenceType", + "name": "RenderingDom_DiffsInOrder" + } + }, + "response": null }, { "$ast": "UnionDecl", "attributes": [], - "name": "RenderingCommand", + "name": "UnitTest_ElementDescVariant", "members": [{ "$ast": "UnionMember", - "name": "RenderingCommand_BeginBoundary" + "name": "ElementDesc_SolidBorder" }, { "$ast": "UnionMember", - "name": "RenderingCommand_EndBoundary" + "name": "ElementDesc_SinkBorder" }, { "$ast": "UnionMember", - "name": "RenderingCommand_Element" + "name": "ElementDesc_SinkSplitter" + }, { + "$ast": "UnionMember", + "name": "ElementDesc_SolidBackground" + }, { + "$ast": "UnionMember", + "name": "ElementDesc_GradientBackground" + }, { + "$ast": "UnionMember", + "name": "ElementDesc_InnerShadow" + }, { + "$ast": "UnionMember", + "name": "ElementDesc_Polygon" + }, { + "$ast": "UnionMember", + "name": "ElementDesc_SolidLabel" + }, { + "$ast": "UnionMember", + "name": "ElementDesc_ImageFrame" }] }, { "$ast": "StructDecl", "attributes": [], - "name": "RenderingFrame", + "name": "UnitTest_RenderingFrame", "members": [{ "$ast": "StructMember", "name": "frameId", @@ -2566,23 +2631,13 @@ "$ast": "MapType", "element": { "$ast": "ReferenceType", - "name": "ElementDescVariant" + "name": "UnitTest_ElementDescVariant" }, "keyType": { "$ast": "PrimitiveType", "type": "Integer" } } - }, { - "$ast": "StructMember", - "name": "commands", - "type": { - "$ast": "ArrayType", - "element": { - "$ast": "ReferenceType", - "name": "RenderingCommand" - } - } }, { "$ast": "StructMember", "name": "root", @@ -2595,7 +2650,7 @@ }, { "$ast": "StructDecl", "attributes": [], - "name": "RenderingTrace", + "name": "UnitTest_RenderingTrace", "members": [{ "$ast": "StructMember", "name": "createdElements", @@ -2633,7 +2688,7 @@ "$ast": "ArrayType", "element": { "$ast": "ReferenceType", - "name": "RenderingFrame" + "name": "UnitTest_RenderingFrame" } } }], diff --git a/Import/Metadata/RemoteProtocol/Protocol_Renderer.txt b/Import/Metadata/RemoteProtocol/Protocol_Renderer.txt index 299c3430..9fccfd5e 100644 --- a/Import/Metadata/RemoteProtocol/Protocol_Renderer.txt +++ b/Import/Metadata/RemoteProtocol/Protocol_Renderer.txt @@ -37,6 +37,7 @@ struct ElementRendering struct ElementBoundary { + var id : int; var hitTestResult : WindowHitTestResult?; var cursor: WindowSystemCursorType?; var bounds : Rect; diff --git a/Import/Metadata/RemoteProtocol/Protocol_SyncDom.txt b/Import/Metadata/RemoteProtocol/Protocol_SyncDom.txt index b1854ccd..6e551b61 100644 --- a/Import/Metadata/RemoteProtocol/Protocol_SyncDom.txt +++ b/Import/Metadata/RemoteProtocol/Protocol_SyncDom.txt @@ -1,62 +1,39 @@ -union ElementDescVariant -{ - ElementDesc_SolidBorder, - ElementDesc_SinkBorder, - ElementDesc_SinkSplitter, - ElementDesc_SolidBackground, - ElementDesc_GradientBackground, - ElementDesc_InnerShadow, - ElementDesc_Polygon, - ElementDesc_SolidLabel, - ElementDesc_ImageFrame, -} - -class RenderingDom +struct RenderingDomContent { var hitTestResult: WindowHitTestResult?; var cursor: WindowSystemCursorType?; var element: int?; var bounds: Rect; var validArea: Rect; +} + +class RenderingDom +{ + var id: int; + var content: RenderingDomContent; var children: RenderingDom[]; } -struct RenderingCommand_BeginBoundary +enum RenderingDom_DiffType { - var boundary: ElementBoundary; + Deleted, + Created, + Modified, } -struct RenderingCommand_EndBoundary +struct RenderingDom_Diff { + var id: int; + var diffType: RenderingDom_DiffType; + var content: RenderingDomContent?; + var children: int[]; } -struct RenderingCommand_Element +struct RenderingDom_DiffsInOrder { - var rendering: ElementRendering; - var element: int?; + var diffsInOrder: RenderingDom_Diff[]; } -union RenderingCommand -{ - RenderingCommand_BeginBoundary, - RenderingCommand_EndBoundary, - RenderingCommand_Element, -} -struct RenderingFrame -{ - var frameId : int; - var frameName : string?; - var windowSize: WindowSizingConfig; - var elements: ElementDescVariant[int]; - var commands: RenderingCommand[]; - var root: RenderingDom; -} - -struct RenderingTrace -{ - var createdElements: RendererType[int]; - var imageCreations: ImageCreation[.id]; - var imageMetadatas: ImageMetadata[.id]; - var frames: RenderingFrame[]; -} \ No newline at end of file +message RendererRenderDom { request: RenderingDom; } +message RendererRenderDomDiff { request: RenderingDom_DiffsInOrder; } \ No newline at end of file diff --git a/Import/Metadata/RemoteProtocol/Protocol_UnitTest.txt b/Import/Metadata/RemoteProtocol/Protocol_UnitTest.txt new file mode 100644 index 00000000..73dddf84 --- /dev/null +++ b/Import/Metadata/RemoteProtocol/Protocol_UnitTest.txt @@ -0,0 +1,29 @@ +union UnitTest_ElementDescVariant +{ + ElementDesc_SolidBorder, + ElementDesc_SinkBorder, + ElementDesc_SinkSplitter, + ElementDesc_SolidBackground, + ElementDesc_GradientBackground, + ElementDesc_InnerShadow, + ElementDesc_Polygon, + ElementDesc_SolidLabel, + ElementDesc_ImageFrame, +} + +struct UnitTest_RenderingFrame +{ + var frameId : int; + var frameName : string?; + var windowSize: WindowSizingConfig; + var elements: UnitTest_ElementDescVariant[int]; + var root: RenderingDom; +} + +struct UnitTest_RenderingTrace +{ + var createdElements: RendererType[int]; + var imageCreations: ImageCreation[.id]; + var imageMetadatas: ImageMetadata[.id]; + var frames: UnitTest_RenderingFrame[]; +} \ No newline at end of file diff --git a/Import/Metadata/RemoteProtocol/Protocols.txt b/Import/Metadata/RemoteProtocol/Protocols.txt index 6ce9a255..b846776c 100644 --- a/Import/Metadata/RemoteProtocol/Protocols.txt +++ b/Import/Metadata/RemoteProtocol/Protocols.txt @@ -4,4 +4,5 @@ Protocol_IO Protocol_Renderer_BasicElements Protocol_Renderer_ImageFrame Protocol_Renderer -Protocol_SyncDom \ No newline at end of file +Protocol_SyncDom +Protocol_UnitTest \ No newline at end of file diff --git a/Import/VlppOS.cpp b/Import/VlppOS.cpp index 34feae2d..bbd88082 100644 --- a/Import/VlppOS.cpp +++ b/Import/VlppOS.cpp @@ -466,6 +466,7 @@ Licensed under https://github.com/vczh-libraries/License #if defined VCZH_ARM +#include #elif defined VCZH_MSVC || defined VCZH_GCC #include #endif diff --git a/Tools/Reflection32.bin b/Tools/Reflection32.bin index fdf89757..644fb3ac 100644 Binary files a/Tools/Reflection32.bin and b/Tools/Reflection32.bin differ diff --git a/Tools/Reflection64.bin b/Tools/Reflection64.bin index 57838c7a..5042b06a 100644 Binary files a/Tools/Reflection64.bin and b/Tools/Reflection64.bin differ diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 index eec1ef08..538da0d8 100644 Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 differ diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 index 76bc896d..ee9a2a9f 100644 Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 differ