View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0002492 | NoesisGUI | C++ SDK | public | 2023-01-13 19:38 | 2023-01-19 10:10 |
Reporter | jack.barkov | Assigned To | sfernandez | ||
Priority | normal | Severity | crash | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Product Version | 3.1.6 | ||||
Target Version | 3.1.7 | Fixed in Version | 3.1.7 | ||
Summary | 0002492: Noesis::TextBox::GetRangeBounds() - Crash | ||||
Description | I have a hard to reproduce problem happening in my application. My test app is a chat, where you press enter, a TextBox is displayed, the user types a text and presses enter to send. Sometimes when the user does this, the crash happens on: Noesis.dll!Noesis::TextBox::GetRangeBounds() Then I tried to reproduce in the noesis examples until I managed to reproduce in the c++ sample.login example. To reproduce basically apply the patch below and run the program that you will simulate what happens in my program. Here the crash happens in a few seconds after opening. Stacktrace: Noesis.dll!Noesis::TextBox::GetRangeBounds() + 6 bytes Unknown [Frames below may be incorrect and/or missing, no symbols loaded for Noesis.dll] > NoesisApp.dll!TsfTextStore::GetTextExt(unsigned long vcView=0, long acpStart=0, long acpEnd=0, tagRECT * prc=0x012fee14, int * pfClipped=0x012fedcc) Line 654 C++ TextInputFramework.dll!CACPWrap::GetTextExt(unsigned long,struct IAnchor *,struct IAnchor *,struct tagRECT *,int *) Unknown TextInputFramework.dll!CContextView::GetTextExt(unsigned long,struct ITfRange *,struct tagRECT *,int *) Unknown TextInputFramework.dll!CInputContextAdapter::GetLayoutBounds(unsigned int,struct EditControlRange const &,struct TextRect *,struct TextRect *) Unknown TextInputFramework.dll!CTSF3LayoutQuery::Execute(struct IInputContextAdapter *) Unknown TextInputFramework.dll!CInputContextAdapter::_ExecuteOperation(class CTSF3Operation *,bool) Unknown TextInputFramework.dll!CInputContextAdapter::GetLayoutBounds(struct EditControlRange,struct TextRect *,struct TextRect *) Unknown TextInputFramework.dll!CTextInputClientOwnerAsync::GetLayoutBoundsAsync(struct EditControlRange) Unknown TextInputFramework.dll!TextInputClient::UpdateLayoutInfo(unsigned int,bool) Unknown TextInputFramework.dll!TextInputClient::EditControlLayoutChanged(unsigned int) Unknown TextInputFramework.dll!<lambda>(void)() Unknown TextInputFramework.dll!CTextInputClientFreeThread::RunOrDispatch(unsigned int,class std::function<long >,bool) Unknown TextInputFramework.dll!CTextInputClientFreeThread::EditControlLayoutChanged(unsigned int) Unknown TextInputFramework.dll!CInputContextAdapter::OnEditSessionEnded(unsigned long,struct ITfEditRecord *,bool) Unknown TextInputFramework.dll!CInputContext::_NotifyEndEdit(void) Unknown TextInputFramework.dll!CInputContext::_SynchAppChanges(unsigned long) Unknown TextInputFramework.dll!CInputContext::OnLockGranted(unsigned long) Unknown TextInputFramework.dll!CACPWrap::OnLockGranted(unsigned long) Unknown NoesisApp.dll!TsfTextStore::RequestLock(unsigned long dwLockFlags=2, HRESULT * phrSession=0x012ff1a4) Line 318 C++ TextInputFramework.dll!CACPWrap::RequestLock(unsigned long,long *) Unknown TextInputFramework.dll!SafeRequestLock(struct ITextStoreAnchor *,unsigned long,long *) Unknown TextInputFramework.dll!CInputContext::OnLayoutChange(enum __MIDL___MIDL_itf_textstor_0000_0000_0002,unsigned long) Unknown TextInputFramework.dll!CACPWrap::OnLayoutChange(enum __MIDL___MIDL_itf_textstor_0000_0000_0002,unsigned long) Unknown NoesisApp.dll!TsfTextStore::OnLayoutChanged() Line 198 C++ NoesisApp.dll!TsfTextStore::OnScrollChanged(Noesis::BaseComponent * __formal=0x1a77ab28, const Noesis::RoutedEventArgs & __formal={...}) Line 1035 C++ NoesisApp.dll!Noesis::Delegate<void __cdecl(Noesis::BaseComponent *,Noesis::RoutedEventArgs const &)>::MemberFuncStub<TsfTextStore,void (__thiscall TsfTextStore::*)(Noesis::BaseComponent *,Noesis::RoutedEventArgs const &)>::Invoke(Noesis::BaseComponent * <args_0>=0x1a77ab28, const Noesis::RoutedEventArgs & <args_1>={...}, const void * __formal=0x012ff458, bool(*)(const void *) __formal=0x79599b20) Line 473 C++ Noesis.dll!Noesis::UIElement::NotifyHandlers() + 140 bytes Unknown Noesis.dll!Noesis::UIElement::BubblingEvent() + 90 bytes Unknown Noesis.dll!Noesis::ScrollViewer::OnLayoutUpdated() + 956 bytes Unknown Noesis.dll!Noesis::UIElement::RaiseEvent() + 100 bytes Unknown Noesis.dll!Noesis::Viewbox::StaticGetClassType() + 1867 bytes Unknown Noesis.dll!Noesis::Viewbox::StaticGetClassType() + 3086 bytes Unknown Noesis.dll!Noesis::Viewbox::StaticGetClassType() + 2669 bytes Unknown Noesis.dll!Noesis::Visual::GetContentBoundsCore() + 5163 bytes Unknown NoesisApp.dll!NoesisApp::Window::Render(double time=0.94558699999999996) Line 213 C++ NoesisApp.dll!NoesisApp::Application::Tick(double time=0.94558699999999996) Line 217 C++ NoesisApp.dll!NoesisApp::ApplicationLauncher::OnTick(double time=0.94558699999999996) Line 116 C++ NoesisApp.dll!NoesisApp::DisplayLauncher::Run::__l2::<lambda_1>::operator()(NoesisApp::Display * __formal=0x015d6c00) Line 42 C++ NoesisApp.dll!Noesis::Delegate<void __cdecl(NoesisApp::Display *)>::FunctorStub<`NoesisApp::DisplayLauncher::Run'::`2'::<lambda_1>>::Invoke(NoesisApp::Display * <args_0>=0x015d6c00) Line 432 C++ Samples.Login.exe!Noesis::Delegate<void __cdecl(NoesisApp::Display *)>::operator()(NoesisApp::Display * <args_0>=0x015d6c00) Line 172 C++ Samples.Login.exe!Noesis::Delegate<void __cdecl(NoesisApp::Display *)>::MultiDelegate::Invoke(NoesisApp::Display * <args_0>=0x015d6c00) Line 576 C++ NoesisApp.dll!Noesis::Delegate<void __cdecl(NoesisApp::Display *)>::operator()(NoesisApp::Display * <args_0>=0x015d6c00) Line 172 C++ NoesisApp.dll!NoesisApp::Win32Display::EnterMessageLoop(bool runInBackground=false) Line 482 C++ NoesisApp.dll!NoesisApp::DisplayLauncher::Run() Line 47 C++ Samples.Login.exe!NsMain(int argc=1, char * * argv=0x015204c8) Line 71 C++ Samples.Login.exe!WinMain(HINSTANCE__ * __formal=0x00ed0000, HINSTANCE__ * __formal=0x00000000, char * __formal=0x0151a01e, int __formal=10) Line 36 C++ Samples.Login.exe!invoke_main() Line 107 C++ Samples.Login.exe!__scrt_common_main_seh() Line 288 C++ Samples.Login.exe!__scrt_common_main() Line 331 C++ Samples.Login.exe!WinMainCRTStartup(void * __formal=0x010a1000) Line 17 C++ [email protected]@12() Unknown [email protected]() Unknown [email protected]() Unknown | ||||
Tags | C++ | ||||
Platform | Windows | ||||
Could you try the following patch in TSF.cpp located in Src/Packages/App/Win32Display:Index: TSF.cpp =================================================================== --- TSF.cpp (revision 11921) +++ TSF.cpp (working copy) @@ -650,6 +650,12 @@ NS_ASSERT(mTextBox != 0); mTextBox->UpdateLayout(); + // UpdateLayout can release the focus from the TextBox, in that case we just return + if (mTextBox == 0) + { + return E_INVALIDARG; + } + // Get bounding box of the selected text Rect bounds = mTextBox->GetRangeBounds(acpStart, acpEnd); |
|
I can't explain exactly what happened, however, in Sample.Login.exe the error stopped happening. But in my application even with the patch you sent me, the crash continues. My application uses several views, and this view that the crash happens is precisely the view that has the TextBox. Sometimes the crash doesn't happen, but the process goes into an infinite loop inside noesis when pause is always in the same stacktrace. Noesis.dll!Noesis::GUI::SetSoftwareKeyboardCallback() + 1883 bytes Unknown [Frames below may be incorrect and/or missing, no symbols loaded for Noesis.dll] Noesis.dll!Noesis::UIElement::RaiseEvent() + 30 bytes Unknown Noesis.dll!Noesis::Viewbox::StaticGetClassType() + 1867 bytes Unknown Noesis.dll!Noesis::Viewbox::StaticGetClassType() + 3086 bytes Unknown Noesis.dll!Noesis::Viewbox::StaticGetClassType() + 2669 bytes Unknown Noesis.dll!Noesis::Visual::GetContentBoundsCore() + 5163 bytes Unknown I couldn't quite understand how this patch you sent me would work. How could `mTextBox->UpdateLayout();` invalidate the `mTextBox` pointer by setting nullptr right after it was called? Doesn't seem to make much sense... I'm trying to figure out how to best reproduce the problem, but I'm having trouble. Would it be possible to make available a Noesis.dll in debug or the pdb of Noesis.dll release build 3.1.6.11756 x86 as jsantos sent me once so we can see the stacktrace in more detail? Thanks |
|
Trying to reproduce the problem, a situation happened that the crash happens again on the same line. I know this crash is due to the TextBox being without any style, however, the crash happens again on the same line. This is not the case with my application, as I am using the default Noesis theme. To reproduce, in the examples use Sample.HelloWorld.exe, replace the MainWindow.xaml content with: <Window x:Class="HelloWorld.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:HelloWorld" mc:Ignorable="d" FontFamily="./#Aero Matics" FontSize="36" Background="#FF124C7A" Title="NoesisGUI - Hello, World!"> <Grid> <Viewbox> <Grid Width="325.8" Margin="24"> <TextBox x:Name="ChatInput" Visibility="Visible" /> </Grid> </Viewbox> </Grid> </Window> When opening the application click on the pink field and the crash will happen exactly on the same line again. Could it be that the fact that the field has Visibility="Collapsed" when I press VK_RETURN in my application could be causing the TSF to have a problem with regard to style? Thanks |
|
I tried to reproduce the problem using a very simple implementation with Sample.IntegrationGLUT.exe. After many attempts, I managed to have the exact same crash that I have in my application. The crash sometimes happens quickly, sometimes it takes time to happen. I really have no idea what's going on... Below is a file on google drive with everything compiled and prepared in debug. I moved the TSF implementation into the integration glut, I made the TSF calls manually with the patch you sent me. Inside the file below, you will find a dump that I took in debug in my VS along with the exe, and pdb of the moment of execution. I hope I can help with something. https://drive.google.com/file/d/1pVraAG-BTwhO6DKPVh5kw9vwDPCxgBhf/view?usp=sharing I also attached a print of the stacktrace at the time of the error (which is the same as the attached dump /bin/Samples.IntegrationGLUT.dmp) Thanks, |
|
From what I could understand, in the example above it happens when you start giving dozens of clicks on the text fields until suddenly the crash happens. I only left a test block in the video as you can see, but anyway I will send here the cpp I used in this video. I made a video showing the crash happening (sorry for the fact that it's on a cell phone, but my resolution is very high, and this was the best way I imagined for the video to be readable) Link: https://youtu.be/hDG296REfV0 Thanks, Main.cpp (21,572 bytes)
//////////////////////////////////////////////////////////////////////////////////////////////////// // NoesisGUI - http://www.noesisengine.com // Copyright (c) 2013 Noesis Technologies S.L. All Rights Reserved. //////////////////////////////////////////////////////////////////////////////////////////////////// // This is a minimal integration example. For simplification purposes only basic input events are // handled, no resource providers are used and the shutdown procedure is omitted. A more complete // multiplatform integration sample with step by step comments can be found at 'Samples/Integration' #ifdef _WIN32 #include "glut.h" #pragma comment(linker,"/SUBSYSTEM:CONSOLE") #endif #ifdef __APPLE__ #include <GLUT/glut.h> #endif #ifdef __EMSCRIPTEN__ #include <GL/glut.h> #include <GLES3/gl32.h> #include <emscripten/html5.h> #endif #ifdef __linux__ #define GL_GLEXT_PROTOTYPES #include <GL/gl.h> #include <GL/glut.h> #endif #ifdef _MSC_VER #define UNUSED_ARGS(...) (void)(true ? (void)0 : ((void)(__VA_ARGS__))) #else #define UNUSED_ARGS(...) #endif #include <NsApp/ThemeProviders.h> #include <NsRender/GLFactory.h> #include <NsGui/FontProperties.h> #include <NsGui/IntegrationAPI.h> #include <NsGui/IRenderer.h> #include <NsGui/IView.h> #include <NsGui/Grid.h> #include <NsCore/HighResTimer.h> #include <NSGui/TextBox.h> #include <NoesisPCH.h> #include "TSF.h" #include <string> #include <list> Noesis::Key ConvertCharKeyToNoesisKey(unsigned char key) { if (key == 127) //GLUT treats delete key as char key, this is fixed keycode { return Noesis::Key::Key_Delete; } short scanKey = VkKeyScanA(key); Noesis::Key noesisKey = Noesis::Key_None; switch (scanKey) { case VK_BACK: noesisKey = Noesis::Key::Key_Back; break; case VK_TAB: noesisKey = Noesis::Key::Key_Tab; break; case VK_CLEAR: noesisKey = Noesis::Key::Key_Clear; break; case VK_RETURN: noesisKey = Noesis::Key::Key_Return; break; case VK_PAUSE: noesisKey = Noesis::Key::Key_Pause; break; case VK_SHIFT: noesisKey = Noesis::Key::Key_LeftShift; break; case VK_LSHIFT: noesisKey = Noesis::Key::Key_LeftShift; break; case VK_RSHIFT: noesisKey = Noesis::Key::Key_RightShift; break; case VK_CONTROL: noesisKey = Noesis::Key::Key_LeftCtrl; break; case VK_LCONTROL: noesisKey = Noesis::Key::Key_LeftCtrl; break; case VK_RCONTROL: noesisKey = Noesis::Key::Key_RightCtrl; break; case VK_MENU: noesisKey = Noesis::Key::Key_LeftAlt; break; case VK_LMENU: noesisKey = Noesis::Key::Key_LeftAlt; break; case VK_RMENU: noesisKey = Noesis::Key::Key_RightAlt; break; case VK_LWIN: noesisKey = Noesis::Key::Key_LWin; break; case VK_RWIN: noesisKey = Noesis::Key::Key_RWin; break; case VK_ESCAPE: noesisKey = Noesis::Key::Key_Escape; break; case VK_SPACE: noesisKey = Noesis::Key::Key_Space; break; case VK_PRIOR: noesisKey = Noesis::Key::Key_Prior; break; case VK_NEXT: noesisKey = Noesis::Key::Key_Next; break; case VK_END: noesisKey = Noesis::Key::Key_End; break; case VK_HOME: noesisKey = Noesis::Key::Key_Home; break; case VK_LEFT: noesisKey = Noesis::Key::Key_Left; break; case VK_UP: noesisKey = Noesis::Key::Key_Up; break; case VK_RIGHT: noesisKey = Noesis::Key::Key_Right; break; case VK_DOWN: noesisKey = Noesis::Key::Key_Down; break; case VK_SELECT: noesisKey = Noesis::Key::Key_Select; break; case VK_PRINT: noesisKey = Noesis::Key::Key_Print; break; case VK_EXECUTE: noesisKey = Noesis::Key::Key_Execute; break; case VK_SNAPSHOT: noesisKey = Noesis::Key::Key_Snapshot; break; case VK_INSERT: noesisKey = Noesis::Key::Key_Insert; break; case VK_DELETE: noesisKey = Noesis::Key::Key_Delete; break; case VK_HELP: noesisKey = Noesis::Key::Key_Help; break; case '0': noesisKey = Noesis::Key::Key_D0; break; case '1': noesisKey = Noesis::Key::Key_D1; break; case '2': noesisKey = Noesis::Key::Key_D2; break; case '3': noesisKey = Noesis::Key::Key_D3; break; case '4': noesisKey = Noesis::Key::Key_D4; break; case '5': noesisKey = Noesis::Key::Key_D5; break; case '6': noesisKey = Noesis::Key::Key_D6; break; case '7': noesisKey = Noesis::Key::Key_D7; break; case '8': noesisKey = Noesis::Key::Key_D8; break; case '9': noesisKey = Noesis::Key::Key_D9; break; case VK_NUMPAD0: noesisKey = Noesis::Key::Key_NumPad0; break; case VK_NUMPAD1: noesisKey = Noesis::Key::Key_NumPad1; break; case VK_NUMPAD2: noesisKey = Noesis::Key::Key_NumPad2; break; case VK_NUMPAD3: noesisKey = Noesis::Key::Key_NumPad3; break; case VK_NUMPAD4: noesisKey = Noesis::Key::Key_NumPad4; break; case VK_NUMPAD5: noesisKey = Noesis::Key::Key_NumPad5; break; case VK_NUMPAD6: noesisKey = Noesis::Key::Key_NumPad6; break; case VK_NUMPAD7: noesisKey = Noesis::Key::Key_NumPad7; break; case VK_NUMPAD8: noesisKey = Noesis::Key::Key_NumPad8; break; case VK_NUMPAD9: noesisKey = Noesis::Key::Key_NumPad9; break; case VK_MULTIPLY: noesisKey = Noesis::Key::Key_Multiply; break; case VK_ADD: noesisKey = Noesis::Key::Key_Add; break; case VK_SEPARATOR: noesisKey = Noesis::Key::Key_Separator; break; case VK_SUBTRACT: noesisKey = Noesis::Key::Key_Subtract; break; case VK_DECIMAL: noesisKey = Noesis::Key::Key_Decimal; break; case VK_DIVIDE: noesisKey = Noesis::Key::Key_Divide; break; case 'A': noesisKey = Noesis::Key::Key_A; break; case 'B': noesisKey = Noesis::Key::Key_B; break; case 'C': noesisKey = Noesis::Key::Key_C; break; case 'D': noesisKey = Noesis::Key::Key_D; break; case 'E': noesisKey = Noesis::Key::Key_E; break; case 'F': noesisKey = Noesis::Key::Key_F; break; case 'G': noesisKey = Noesis::Key::Key_G; break; case 'H': noesisKey = Noesis::Key::Key_H; break; case 'I': noesisKey = Noesis::Key::Key_I; break; case 'J': noesisKey = Noesis::Key::Key_J; break; case 'K': noesisKey = Noesis::Key::Key_K; break; case 'L': noesisKey = Noesis::Key::Key_L; break; case 'M': noesisKey = Noesis::Key::Key_M; break; case 'N': noesisKey = Noesis::Key::Key_N; break; case 'O': noesisKey = Noesis::Key::Key_O; break; case 'P': noesisKey = Noesis::Key::Key_P; break; case 'Q': noesisKey = Noesis::Key::Key_Q; break; case 'R': noesisKey = Noesis::Key::Key_R; break; case 'S': noesisKey = Noesis::Key::Key_S; break; case 'T': noesisKey = Noesis::Key::Key_T; break; case 'U': noesisKey = Noesis::Key::Key_U; break; case 'V': noesisKey = Noesis::Key::Key_V; break; case 'W': noesisKey = Noesis::Key::Key_W; break; case 'X': noesisKey = Noesis::Key::Key_X; break; case 'Y': noesisKey = Noesis::Key::Key_Y; break; case 'Z': noesisKey = Noesis::Key::Key_Z; break; case VK_F1: noesisKey = Noesis::Key::Key_F1; break; case VK_F2: noesisKey = Noesis::Key::Key_F2; break; case VK_F3: noesisKey = Noesis::Key::Key_F3; break; case VK_F4: noesisKey = Noesis::Key::Key_F4; break; case VK_F5: noesisKey = Noesis::Key::Key_F5; break; case VK_F6: noesisKey = Noesis::Key::Key_F6; break; case VK_F7: noesisKey = Noesis::Key::Key_F7; break; case VK_F8: noesisKey = Noesis::Key::Key_F8; break; case VK_F9: noesisKey = Noesis::Key::Key_F9; break; case VK_F10: noesisKey = Noesis::Key::Key_F10; break; case VK_F11: noesisKey = Noesis::Key::Key_F11; break; case VK_F12: noesisKey = Noesis::Key::Key_F12; break; case VK_F13: noesisKey = Noesis::Key::Key_F13; break; case VK_F14: noesisKey = Noesis::Key::Key_F14; break; case VK_F15: noesisKey = Noesis::Key::Key_F15; break; case VK_F16: noesisKey = Noesis::Key::Key_F16; break; case VK_F17: noesisKey = Noesis::Key::Key_F17; break; case VK_F18: noesisKey = Noesis::Key::Key_F18; break; case VK_F19: noesisKey = Noesis::Key::Key_F19; break; case VK_F20: noesisKey = Noesis::Key::Key_F20; break; case VK_F21: noesisKey = Noesis::Key::Key_F21; break; case VK_F22: noesisKey = Noesis::Key::Key_F22; break; case VK_F23: noesisKey = Noesis::Key::Key_F23; break; case VK_F24: noesisKey = Noesis::Key::Key_F24; break; case VK_NUMLOCK: noesisKey = Noesis::Key::Key_NumLock; break; case VK_SCROLL: noesisKey = Noesis::Key::Key_Scroll; } return noesisKey; } static Noesis::Ptr<Noesis::RenderDevice> _device; static std::list<Noesis::IView*> _views; /////////////////////////////////////////////////////////////////////////////////////////////////// void NoesisInit() { // A logging handler is installed here. You can also install a custom error handler and memory // allocator. By default errors are redirected to the logging handler Noesis::GUI::SetLogHandler([](const char*, uint32_t, uint32_t level, const char*, const char* msg) { // [TRACE] [DEBUG] [INFO] [WARNING] [ERROR] const char* prefixes[] = { "T", "D", "I", "W", "E" }; printf("[NOESIS/%s] %s\n", prefixes[level], msg); }); // https://www.noesisengine.com/docs/Gui.Core.Licensing.html Noesis::GUI::SetLicense("test", "WOLw8pOp8PLHfabI2XuOBX26rFYjT94cw/+zrr0PBMP7Ve45"); // Noesis initialization. This must be the first step before using any NoesisGUI functionality Noesis::GUI::Init(); _device = NoesisApp::GLFactory::CreateDevice(false); // Setup theme NoesisApp::SetThemeProviders(); Noesis::GUI::LoadApplicationResources("Theme/NoesisTheme.DarkBlue.xaml"); } static void CreateBackground() { // For simplicity purposes we are not using resource providers in this sample. ParseXaml() is // enough if there is no extra XAML dependencies Noesis::Ptr<Noesis::Grid> xaml(Noesis::GUI::ParseXaml<Noesis::Grid>(R"(<?xml version="1.0" encoding="UTF-8"?> <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"> <Grid Grid.Column="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="30"/> <ColumnDefinition Width="54"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="30"/> <RowDefinition Height="11"/> <RowDefinition Height="50"/> </Grid.RowDefinitions> <Button Grid.Column="1" Grid.Row="1" Content="Test" /> </Grid> </Grid> )")); // View creation to render and interact with the user interface // We transfer the ownership to a global pointer instead of a Ptr<> because there is no way // in GLUT to do shutdown and we don't want the Ptr<> to be released at global time Noesis::IView* view = Noesis::GUI::CreateView(xaml).GiveOwnership(); view->SetFlags(Noesis::RenderFlags_PPAA | Noesis::RenderFlags_LCD); view->SetSize(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); // Renderer initialization with an OpenGL device view->GetRenderer()->Init(_device); _views.push_back(view); } static void CreateChatFrame() { // For simplicity purposes we are not using resource providers in this sample. ParseXaml() is // enough if there is no extra XAML dependencies Noesis::Ptr<Noesis::Grid> xaml(Noesis::GUI::ParseXaml<Noesis::Grid>(R"(<?xml version="1.0" encoding="UTF-8"?> <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:b="http://schemas.microsoft.com/xaml/behaviors" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"> <Grid Grid.Column="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="*"/> <RowDefinition Height="*"/> <RowDefinition Height="50"/> </Grid.RowDefinitions> <TextBox Grid.Row="1" x:Name="ChatInput" Text="WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW" /> <TextBox Grid.Row="2" x:Name="ChatSecond" Text="123123" /> </Grid> </Grid> )")); // View creation to render and interact with the user interface // We transfer the ownership to a global pointer instead of a Ptr<> because there is no way // in GLUT to do shutdown and we don't want the Ptr<> to be released at global time Noesis::IView* view = Noesis::GUI::CreateView(xaml).GiveOwnership(); view->SetFlags(Noesis::RenderFlags_PPAA | Noesis::RenderFlags_LCD); view->SetSize(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); // Renderer initialization with an OpenGL device view->GetRenderer()->Init(_device); _views.push_back(view); } static void CreateOtherView() { // For simplicity purposes we are not using resource providers in this sample. ParseXaml() is // enough if there is no extra XAML dependencies Noesis::Ptr<Noesis::Grid> xaml(Noesis::GUI::ParseXaml<Noesis::Grid>(R"(<?xml version="1.0" encoding="UTF-8"?> <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:b="http://schemas.microsoft.com/xaml/behaviors" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"> <Grid Grid.Column="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="*"/> <RowDefinition Height="*"/> <RowDefinition Height="50"/> </Grid.RowDefinitions> <TextBox Grid.Row="3" x:Name="OtherText" Text="8888888" /> </Grid> </Grid> )")); // View creation to render and interact with the user interface // We transfer the ownership to a global pointer instead of a Ptr<> because there is no way // in GLUT to do shutdown and we don't want the Ptr<> to be released at global time Noesis::IView* view = Noesis::GUI::CreateView(xaml).GiveOwnership(); view->SetFlags(Noesis::RenderFlags_PPAA | Noesis::RenderFlags_LCD); view->SetSize(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); // Renderer initialization with an OpenGL device view->GetRenderer()->Init(_device); _views.push_back(view); } /////////////////////////////////////////////////////////////////////////////////////////////////// static void DisplayFunc(void) { glViewport(0, 0, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); glDisable(GL_SCISSOR_TEST); glClearColor(0.0f, 0.0f, 0.25f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); static unsigned long long loop{ 0 }; loop++; for (auto& view : _views) { // Update view (layout, animations, ...) view->Update(glutGet(GLUT_ELAPSED_TIME) / 1000.0); // Offscreen rendering phase populates textures needed by the on-screen rendering view->GetRenderer()->UpdateRenderTree(); view->GetRenderer()->RenderOffscreen(); } for (auto& view : _views) { const std::string test_str = "test string"; for (auto c : test_str) { view->Char(c); } view->Char(VK_RETURN); if (loop % 20 == 0) { Noesis::TextBox* tb = view->GetContent()->FindName<Noesis::TextBox>("ChatInput"); if (tb != nullptr) { if (tb->GetIsVisible()) { tb->SetText(""); tb->SetVisibility(Noesis::Visibility_Collapsed); } else { tb->SetVisibility(Noesis::Visibility_Visible); tb->SetText("test-username-value"); tb->Focus(); } } } /*if (loop % 30 == 0) { Noesis::TextBox* tb = view->GetContent()->FindName<Noesis::TextBox>("ChatSecond"); if (tb != nullptr) { if (tb->GetIsVisible()) { tb->SetText(""); tb->SetVisibility(Noesis::Visibility_Collapsed); } else { tb->SetVisibility(Noesis::Visibility_Visible); tb->SetText("test-username-value"); tb->Focus(); } } } if (loop % 40 == 0) { Noesis::TextBox* tb = view->GetContent()->FindName<Noesis::TextBox>("OtherText"); if (tb != nullptr) { if (tb->GetIsVisible()) { tb->SetText(""); tb->SetVisibility(Noesis::Visibility_Collapsed); } else { tb->SetVisibility(Noesis::Visibility_Visible); tb->SetText("test-username-value"); tb->Focus(); } } }*/ } // My custom render, goes here... // My custom render, goes here... // My custom render, goes here... // My custom render, goes here... for (auto& view : _views) { // If you are going to render here with your own engine you need to restore the GPU state // because noesis changes it. In this case only framebuffer and viewport need to be restored glBindFramebuffer(GL_FRAMEBUFFER, 0); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearStencil(0); // Rendering is done in the active framebuffer view->GetRenderer()->Render(); } glutSwapBuffers(); glutPostRedisplay(); } //////////////////////////////////////////////////////////////////////////////////////////////////// static void ReshapeFunc(int width, int height) { for (auto& view : _views) { view->SetSize(width, height); } } //////////////////////////////////////////////////////////////////////////////////////////////////// static void MouseMoveFunc(int x, int y) { for (auto& view : _views) { view->MouseMove(x, y); } } //////////////////////////////////////////////////////////////////////////////////////////////////// static void MouseFunc(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON) { if (state == GLUT_DOWN) { for (auto& view : _views) { view->MouseButtonDown(x, y, Noesis::MouseButton_Left); } } else { for (auto& view : _views) { view->MouseButtonUp(x, y, Noesis::MouseButton_Left); } } } } //////////////////////////////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_STENCIL); glutInitWindowSize(1000, 600); #ifdef __EMSCRIPTEN__ double width, height; emscripten_get_element_css_size("#canvas", &width, &height); emscripten_set_canvas_element_size("#canvas", (uint32_t)width, (uint32_t)height); glutInitWindowSize((uint32_t)width, (uint32_t)height); #endif glutCreateWindow("NoesisGUI - GLUT integration"); NoesisInit(); NoesisApp::TSF::Init(); NoesisApp::TSF::ActivateWindow(GLUT::hWnd); Noesis::GUI::SetSoftwareKeyboardCallback(nullptr, [](void* _user, Noesis::UIElement* _focused, bool _open) { if (_open) { NoesisApp::TSF::ShowKeyboard(_focused); } else { NoesisApp::TSF::HideKeyboard(); } }); CreateBackground(); CreateChatFrame(); CreateOtherView(); glutDisplayFunc(&DisplayFunc); glutReshapeFunc(&ReshapeFunc); glutPassiveMotionFunc(&MouseMoveFunc); glutMouseFunc(&MouseFunc); glutMainLoop(); return 0; } |
|
Thanks a lot for your examples and feedback. I was able to find a bug in the processing of the LayoutUpdated event. Please try the following patched library and let me know if your problems are solved: https://drive.google.com/file/d/1qouAu1fUyqM--el4kdFA6MTHjB0to5S2/view?usp=share_link |
|
I did the test with the example I prepared yesterday and it really seems to have solved it. My application is x86 only, could you provide me with an x86 build to test better? Thanks, |
|
Of course, here you are: https://drive.google.com/file/d/1MF5r5eCZfFZ2R6qOX4yt2EMbKtd2SgZq/view?usp=share_link | |
I did some tests here and it seems to have really solved it! No bugs happened again. Is it safe to use this dll until the next version 3.1.7 comes out? Thanks! |
|
Yes, you can use this patched library in the meantime. | |
Date Modified | Username | Field | Change |
---|---|---|---|
2023-01-13 19:38 | jack.barkov | New Issue | |
2023-01-13 19:38 | jack.barkov | Tag Attached: C++ | |
2023-01-13 19:38 | jack.barkov | File Added: MainWindow.patch.zip | |
2023-01-16 15:48 | jsantos | Assigned To | => sfernandez |
2023-01-16 15:48 | jsantos | Status | new => assigned |
2023-01-16 15:48 | jsantos | Target Version | => 3.1.7 |
2023-01-16 19:11 | sfernandez | Status | assigned => feedback |
2023-01-16 19:11 | sfernandez | Note Added: 0008212 | |
2023-01-16 19:12 | sfernandez | Note Edited: 0008212 | |
2023-01-16 22:31 | jack.barkov | Note Added: 0008214 | |
2023-01-16 22:31 | jack.barkov | Status | feedback => assigned |
2023-01-16 22:38 | jack.barkov | Note Edited: 0008214 | |
2023-01-16 22:47 | jack.barkov | Note Added: 0008215 | |
2023-01-16 22:47 | jack.barkov | File Added: helloworld-1.png | |
2023-01-17 00:10 | jack.barkov | Note Added: 0008216 | |
2023-01-17 00:10 | jack.barkov | File Added: glut-1.png | |
2023-01-17 00:33 | jack.barkov | Note Added: 0008217 | |
2023-01-17 00:33 | jack.barkov | File Added: Main.cpp | |
2023-01-17 17:36 | sfernandez | Status | assigned => feedback |
2023-01-17 17:36 | sfernandez | Note Added: 0008218 | |
2023-01-17 21:45 | jack.barkov | Note Added: 0008220 | |
2023-01-17 21:45 | jack.barkov | Status | feedback => assigned |
2023-01-18 19:49 | sfernandez | Status | assigned => feedback |
2023-01-18 19:49 | sfernandez | Note Added: 0008223 | |
2023-01-18 22:21 | jack.barkov | Note Added: 0008224 | |
2023-01-18 22:21 | jack.barkov | Status | feedback => assigned |
2023-01-19 10:09 | sfernandez | Note Added: 0008225 | |
2023-01-19 10:10 | sfernandez | Status | assigned => resolved |
2023-01-19 10:10 | sfernandez | Resolution | open => fixed |
2023-01-19 10:10 | sfernandez | Fixed in Version | => 3.1.7 |