Fixed crash bug in new decl editor.

This commit is contained in:
Justin Marshall
2026-05-18 14:15:34 -07:00
parent 119058a96e
commit eb7ffe2cdc
+59 -55
View File
@@ -32,6 +32,7 @@ If you have questions concerning this license or the applicable additional terms
#include "../radiant/qe3.h"
#include "DialogDeclBrowser.h"
#include "../radiant/InspectorDialog.h"
#include <commctrl.h>
#ifdef ID_DEBUG_MEMORY
#undef new
@@ -76,6 +77,10 @@ static const UINT IDC_DECLBROWSER_CHILD_EDITOR = 0x5C0B;
static const char *DECL_BROWSER_DARK_FIELD_OLDPROC = "IceTech.DeclBrowser.DarkFieldOldProc";
#ifndef TVS_NOTOOLTIPS
#define TVS_NOTOOLTIPS 0x0080
#endif
toolTip_t DialogDeclBrowser::toolTips[] = {
{ IDC_DECLBROWSER_CHILD_TREE, "declaration browser" },
{ IDC_DECLBROWSER_CHILD_FIND_NAME, "search for declarations with matching name, supports *, ? and [abc...]" },
@@ -268,7 +273,6 @@ int DialogDeclBrowser::OnCreate( LPCREATESTRUCT lpCreateStruct ) {
}
CreateChildControls();
EnableToolTips( TRUE );
ApplyDarkTheme();
PopulateTypeCombo();
InitBaseDeclTree();
@@ -291,8 +295,8 @@ void DialogDeclBrowser::CreateChildControls( void ) {
DWORD editStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL;
DWORD buttonStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON;
declTree.Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS, r, this, IDC_DECLBROWSER_CHILD_TREE );
baseDeclTree.Create( WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, r, this, IDC_DECLBROWSER_CHILD_BASE_TREE );
declTree.Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS, r, this, IDC_DECLBROWSER_CHILD_TREE );
baseDeclTree.Create( WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_NOTOOLTIPS, r, this, IDC_DECLBROWSER_CHILD_BASE_TREE );
findNameStatic.Create( "Name", staticStyle, r, this );
findTextStatic.Create( "Text", staticStyle, r, this );
@@ -380,9 +384,11 @@ void DialogDeclBrowser::ApplyDarkTheme( void ) {
for( HWND child = ::GetWindow( GetSafeHwnd(), GW_CHILD ); child != NULL; child = ::GetWindow( child, GW_HWNDNEXT ) ) {
DeclBrowserApplyNativeDarkTheme( child );
if ( DeclBrowserIsClass( child, "Edit" ) || DeclBrowserIsClass( child, "SysTreeView32" ) || DeclBrowserIsClass( child, "ComboBox" ) ) {
if ( DeclBrowserIsClass( child, "Edit" ) ) {
DeclBrowserRemoveClientEdge( child );
} else if ( DeclBrowserIsClass( child, "SysTreeView32" ) || DeclBrowserIsClass( child, "ComboBox" ) ) {
// Keep tree/combo controls native-subclass free; the tree owns its tooltip path.
DeclBrowserRemoveClientEdge( child );
DeclBrowserSubclassField( child );
}
}
@@ -394,42 +400,16 @@ void DialogDeclBrowser::ApplyDarkTheme( void ) {
}
BOOL DialogDeclBrowser::OnToolTipNotify( UINT id, NMHDR *pNMHDR, LRESULT *pResult ) {
if ( pNMHDR->hwndFrom == declTree.GetSafeHwnd() ) {
CString toolTip;
const idDecl *decl = GetDeclFromTreeItem( (HTREEITEM)pNMHDR->idFrom );
if ( !decl ) {
return FALSE;
}
toolTip = va( "%s, line: %d", decl->GetFileName(), decl->GetLineNum() );
if ( pResult ) {
*pResult = 0;
}
TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
#ifndef _UNICODE
if( pNMHDR->code == TTN_NEEDTEXTA ) {
delete m_pchTip;
m_pchTip = new char[toolTip.GetLength() + 2];
lstrcpyn( m_pchTip, toolTip, toolTip.GetLength() + 1 );
pTTTA->lpszText = (LPSTR)m_pchTip;
} else {
delete m_pwchTip;
m_pwchTip = new WCHAR[toolTip.GetLength() + 2];
_mbstowcsz( m_pwchTip, toolTip, toolTip.GetLength() + 1 );
pTTTW->lpszText = (WCHAR*)m_pwchTip;
}
#else
if( pNMHDR->code == TTN_NEEDTEXTA ) {
delete m_pchTip;
m_pchTip = new char[toolTip.GetLength() + 2];
_wcstombsz( m_pchTip, toolTip, toolTip.GetLength() + 1 );
pTTTA->lpszText = (LPSTR)m_pchTip;
} else {
delete m_pwchTip;
m_pwchTip = new WCHAR[toolTip.GetLength() + 2];
lstrcpyn( m_pwchTip, toolTip, toolTip.GetLength() + 1 );
pTTTW->lpszText = (WCHAR*)m_pwchTip;
}
#endif
return TRUE;
// CPathTreeCtrl already owns its per-item tooltip forwarding. Calling
// TreeView APIs from inside the forwarded TTN_NEEDTEXT path can re-enter
// comctl32 and hang the docked inspector, so the docked browser only uses
// static control tooltips here.
if ( pNMHDR && pNMHDR->hwndFrom == declTree.GetSafeHwnd() ) {
return FALSE;
}
return DefaultOnToolTipNotify( toolTips, id, pNMHDR, pResult );
@@ -650,22 +630,37 @@ void DialogDeclBrowser::GetDeclName( HTREEITEM item, idStr &typeName, idStr &dec
}
const idDecl *DialogDeclBrowser::GetDeclFromTreeItem( HTREEITEM item ) const {
int id, index;
declType_t type;
if ( !item || declTree.GetChildItem( item ) ) {
if ( !item || !declTree.GetSafeHwnd() ) {
return NULL;
}
id = declTree.GetItemData( item );
type = GetTypeFromId( id );
index = GetIndexFromId( id );
TVITEM tvItem;
memset( &tvItem, 0, sizeof( tvItem ) );
tvItem.mask = TVIF_PARAM | TVIF_CHILDREN;
tvItem.hItem = item;
if ( type < 0 || type >= declManager->GetNumDeclTypes() ) {
if ( !::SendMessage( declTree.GetSafeHwnd(), TVM_GETITEM, 0, (LPARAM)&tvItem ) ) {
return NULL;
}
return declManager->DeclByIndex( type, index, false );
if ( tvItem.cChildren != 0 ) {
return NULL;
}
const int id = (int)tvItem.lParam;
declType_t type = GetTypeFromId( id );
const int index = GetIndexFromId( id );
if ( type < 0 || type >= declManager->GetNumDeclTypes() || index < 0 || index >= declManager->GetNumDecls( type ) ) {
return NULL;
}
const idDecl *decl = declManager->DeclByIndex( type, index, false );
if ( !decl || decl->GetType() != type || decl->Index() != index ) {
return NULL;
}
return decl;
}
const idDecl *DialogDeclBrowser::GetSelectedDecl( void ) const {
@@ -680,14 +675,23 @@ bool DialogDeclBrowser::CompareDecl( HTREEITEM item, const char *name ) const {
}
if ( findTextString.Length() ) {
int id, index;
declType_t type;
TVITEM tvItem;
memset( &tvItem, 0, sizeof( tvItem ) );
tvItem.mask = TVIF_PARAM | TVIF_CHILDREN;
tvItem.hItem = item;
id = declTree.GetItemData( item );
type = GetTypeFromId( id );
index = GetIndexFromId( id );
if ( !baseDeclTree.GetSafeHwnd() || !::SendMessage( baseDeclTree.GetSafeHwnd(), TVM_GETITEM, 0, (LPARAM)&tvItem ) ) {
return false;
}
if ( tvItem.cChildren != 0 ) {
return false;
}
if ( type < 0 || type >= declManager->GetNumDeclTypes() ) {
const int id = (int)tvItem.lParam;
declType_t type = GetTypeFromId( id );
const int index = GetIndexFromId( id );
if ( type < 0 || type >= declManager->GetNumDeclTypes() || index < 0 || index >= declManager->GetNumDecls( type ) ) {
return false;
}