mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
fix: WinDbg plugin dynamic dbgeng loading, editor two-tone bg, UI polish
WinDbg plugin: load dbgeng.dll dynamically from Debugging Tools directory instead of static linking (system dbgeng.dll lacks remote DebugConnect). Copy tools dbghelp.dll next to exe so it loads before System32 version. Add COM init on DbgEng thread, browse for tools dir, styled dialog. Editor: derive darker background via theme.background.darker(115) for visual depth between chrome and editor surfaces. UI: global scrollbar styling, workspace accent bar 1px, pane tab font from editor settings, workspace dock default width 128px.
This commit is contained in:
@@ -151,6 +151,26 @@ target_link_libraries(Reclass PRIVATE
|
||||
)
|
||||
if(WIN32)
|
||||
target_link_libraries(Reclass PRIVATE dbghelp dwmapi psapi raw_pdb)
|
||||
|
||||
# Copy Debugging Tools dbghelp.dll next to Reclass.exe so the Windows
|
||||
# loader picks it up (app dir > System32). The system dbghelp.dll
|
||||
# lacks StackWalk2 which the tools dbgeng.dll needs for remote debug.
|
||||
set(_DBG_TOOLS_DIRS
|
||||
"C:/Program Files (x86)/Windows Kits/10/Debuggers/x64"
|
||||
"C:/Program Files/Windows Kits/10/Debuggers/x64")
|
||||
foreach(_dir ${_DBG_TOOLS_DIRS})
|
||||
if(EXISTS "${_dir}/dbghelp.dll")
|
||||
foreach(_dll dbghelp.dll dbgcore.dll symsrv.dll)
|
||||
if(EXISTS "${_dir}/${_dll}")
|
||||
add_custom_command(TARGET Reclass POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${_dir}/${_dll}" $<TARGET_FILE_DIR:Reclass>
|
||||
COMMENT "Copying ${_dll} from Debugging Tools")
|
||||
endif()
|
||||
endforeach()
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
add_executable(ReclassMcpBridge tools/rcx-mcp-stdio.cpp)
|
||||
|
||||
@@ -20,7 +20,7 @@ set(PLUGIN_SOURCES
|
||||
add_library(WinDbgMemoryPlugin SHARED ${PLUGIN_SOURCES})
|
||||
|
||||
# Link Qt + DbgEng
|
||||
target_link_libraries(WinDbgMemoryPlugin PRIVATE ${QT}::Widgets dbgeng ole32)
|
||||
target_link_libraries(WinDbgMemoryPlugin PRIVATE ${QT}::Widgets ole32)
|
||||
|
||||
# Include directories
|
||||
target_include_directories(WinDbgMemoryPlugin PRIVATE
|
||||
|
||||
@@ -12,12 +12,99 @@
|
||||
#include <QDebug>
|
||||
#include <QClipboard>
|
||||
#include <QGuiApplication>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <initguid.h>
|
||||
#include <dbgeng.h>
|
||||
#pragma comment(lib, "dbgeng.lib")
|
||||
// dbgeng.dll is loaded dynamically — see loadDbgEngTools()
|
||||
|
||||
// The system dbgeng.dll (C:\Windows\System32) does not support remote
|
||||
// connections (DebugConnect returns 0x8007053d). The full version lives
|
||||
// in the Debugging Tools for Windows directory. We load it dynamically
|
||||
// so the plugin works without requiring the debugger tools on PATH.
|
||||
static const char* const kDbgToolsDirs[] = {
|
||||
"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64",
|
||||
"C:\\Program Files\\Windows Kits\\10\\Debuggers\\x64",
|
||||
};
|
||||
static const char* const kSettingsKey = "WinDbgPlugin/DbgToolsDir";
|
||||
|
||||
typedef HRESULT (STDAPICALLTYPE *PFN_DebugConnect)(PCSTR, REFIID, PVOID*);
|
||||
typedef HRESULT (STDAPICALLTYPE *PFN_DebugCreate)(REFIID, PVOID*);
|
||||
|
||||
static QString s_loadedDir;
|
||||
static HMODULE s_hDbgEng = nullptr;
|
||||
|
||||
static HMODULE tryLoadFrom(const char* dir) {
|
||||
SetDllDirectoryA(dir);
|
||||
// Pre-load dependencies so the tools versions are used instead of
|
||||
// the older System32 copies (e.g. dbghelp.dll without StackWalk2).
|
||||
char path[MAX_PATH];
|
||||
for (auto dep : {"dbghelp.dll", "dbgcore.dll", "symsrv.dll"}) {
|
||||
snprintf(path, sizeof(path), "%s\\%s", dir, dep);
|
||||
LoadLibraryA(path); // OK if missing
|
||||
}
|
||||
snprintf(path, sizeof(path), "%s\\dbgeng.dll", dir);
|
||||
HMODULE h = LoadLibraryA(path);
|
||||
if (h) {
|
||||
s_loadedDir = QString::fromLocal8Bit(dir);
|
||||
qDebug() << "[WinDbg] Loaded dbgeng.dll from" << dir;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static HMODULE loadDbgEngTools() {
|
||||
if (s_hDbgEng) return s_hDbgEng;
|
||||
|
||||
// 1. Try user-configured path from settings
|
||||
QSettings settings;
|
||||
QString userDir = settings.value(kSettingsKey).toString();
|
||||
if (!userDir.isEmpty()) {
|
||||
s_hDbgEng = tryLoadFrom(userDir.toLocal8Bit().constData());
|
||||
if (s_hDbgEng) return s_hDbgEng;
|
||||
}
|
||||
|
||||
// 2. Try well-known install paths
|
||||
for (auto dir : kDbgToolsDirs) {
|
||||
s_hDbgEng = tryLoadFrom(dir);
|
||||
if (s_hDbgEng) return s_hDbgEng;
|
||||
}
|
||||
|
||||
SetDllDirectoryA(nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool dbgToolsFound() {
|
||||
loadDbgEngTools();
|
||||
return s_hDbgEng != nullptr;
|
||||
}
|
||||
|
||||
static PFN_DebugConnect getDebugConnect() {
|
||||
static PFN_DebugConnect pfn = nullptr;
|
||||
static bool tried = false;
|
||||
if (!tried) {
|
||||
tried = true;
|
||||
HMODULE h = loadDbgEngTools();
|
||||
if (h) pfn = (PFN_DebugConnect)GetProcAddress(h, "DebugConnect");
|
||||
if (!pfn) qWarning() << "[WinDbg] DebugConnect not available — Debugging Tools not found";
|
||||
}
|
||||
return pfn;
|
||||
}
|
||||
|
||||
static PFN_DebugCreate getDebugCreate() {
|
||||
static PFN_DebugCreate pfn = nullptr;
|
||||
static bool tried = false;
|
||||
if (!tried) {
|
||||
tried = true;
|
||||
HMODULE h = loadDbgEngTools();
|
||||
if (h) pfn = (PFN_DebugCreate)GetProcAddress(h, "DebugCreate");
|
||||
if (!pfn) qWarning() << "[WinDbg] DebugCreate not available — Debugging Tools not found";
|
||||
}
|
||||
return pfn;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────
|
||||
@@ -65,6 +152,9 @@ WinDbgMemoryProvider::WinDbgMemoryProvider(const QString& target)
|
||||
dispatchToOwner([this, &target]() {
|
||||
HRESULT hr;
|
||||
|
||||
// COM must be initialized on this thread for DbgEng
|
||||
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
|
||||
qDebug() << "[WinDbg] Opening target:" << target
|
||||
<< "on DbgEng thread" << QThread::currentThread();
|
||||
|
||||
@@ -72,9 +162,11 @@ WinDbgMemoryProvider::WinDbgMemoryProvider(const QString& target)
|
||||
|| target.startsWith("npipe:", Qt::CaseInsensitive))
|
||||
{
|
||||
// ── Remote: connect to existing WinDbg debug server ──
|
||||
auto pfnConnect = getDebugConnect();
|
||||
if (!pfnConnect) { qWarning() << "[WinDbg] Debugging Tools required for remote connections"; return; }
|
||||
QByteArray connUtf8 = target.toUtf8();
|
||||
qDebug() << "[WinDbg] DebugConnect:" << target;
|
||||
hr = DebugConnect(connUtf8.constData(), IID_IDebugClient, (void**)&m_client);
|
||||
hr = pfnConnect(connUtf8.constData(), IID_IDebugClient, (void**)&m_client);
|
||||
qDebug() << "[WinDbg] DebugConnect hr=" << Qt::hex << (unsigned long)hr
|
||||
<< "client=" << (void*)m_client;
|
||||
if (FAILED(hr) || !m_client) {
|
||||
@@ -86,7 +178,9 @@ WinDbgMemoryProvider::WinDbgMemoryProvider(const QString& target)
|
||||
else
|
||||
{
|
||||
// ── Local: create debug client for pid/dump ──
|
||||
hr = DebugCreate(IID_IDebugClient, (void**)&m_client);
|
||||
auto pfnCreate = getDebugCreate();
|
||||
if (!pfnCreate) { qWarning() << "[WinDbg] Debugging Tools required"; return; }
|
||||
hr = pfnCreate(IID_IDebugClient, (void**)&m_client);
|
||||
qDebug() << "[WinDbg] DebugCreate hr=" << Qt::hex << (unsigned long)hr
|
||||
<< "client=" << (void*)m_client;
|
||||
if (FAILED(hr) || !m_client) {
|
||||
@@ -239,6 +333,7 @@ WinDbgMemoryProvider::~WinDbgMemoryProvider()
|
||||
m_client->DetachProcesses();
|
||||
}
|
||||
cleanup();
|
||||
CoUninitialize();
|
||||
});
|
||||
} else {
|
||||
// Thread not running — clean up directly (best-effort)
|
||||
@@ -503,7 +598,7 @@ std::unique_ptr<rcx::Provider> WinDbgMemoryPlugin::createProvider(const QString&
|
||||
*errorMsg = QString("Failed to connect to debug server.\n\n"
|
||||
"Target: %1\n\n"
|
||||
"Make sure WinDbg is running with a matching .server command\n"
|
||||
"(e.g. .server tcp:port=5055) and the port/pipe is reachable.")
|
||||
"(e.g. .server tcp:port=5056) and the port/pipe is reachable.")
|
||||
.arg(target);
|
||||
else if (target.startsWith("pid:", Qt::CaseInsensitive))
|
||||
*errorMsg = QString("Failed to attach to process.\n\n"
|
||||
@@ -532,7 +627,7 @@ bool WinDbgMemoryPlugin::selectTarget(QWidget* parent, QString* target)
|
||||
{
|
||||
QDialog dlg(parent);
|
||||
dlg.setWindowTitle("WinDbg Settings");
|
||||
dlg.resize(460, 300);
|
||||
dlg.resize(480, 360);
|
||||
|
||||
QPalette dlgPal = qApp->palette();
|
||||
dlg.setPalette(dlgPal);
|
||||
@@ -540,17 +635,27 @@ bool WinDbgMemoryPlugin::selectTarget(QWidget* parent, QString* target)
|
||||
|
||||
auto* layout = new QVBoxLayout(&dlg);
|
||||
|
||||
QColor editBg = dlgPal.window().color().darker(115);
|
||||
QString editSS = QStringLiteral(
|
||||
"QLineEdit { background: %1; color: %2; border: 1px solid %3;"
|
||||
" border-radius: 3px; padding: 4px 6px; }")
|
||||
.arg(editBg.name(),
|
||||
dlgPal.color(QPalette::Text).name(),
|
||||
dlgPal.color(QPalette::Mid).name());
|
||||
|
||||
layout->addWidget(new QLabel(
|
||||
"Connect to a running WinDbg debug server.\n"
|
||||
"In WinDbg, run: .server tcp:port=5055\n\n"
|
||||
"In WinDbg, run: .server tcp:port=5056\n\n"
|
||||
"Non-invasive debug and dump files only.\n"
|
||||
"Execution control (bp, g, t, p) is not supported."));
|
||||
"Execution control (bp, g, t, p) is not supported.\n"
|
||||
"WinDbg Classic is recommended."));
|
||||
|
||||
layout->addSpacing(8);
|
||||
layout->addWidget(new QLabel("Connection string:"));
|
||||
auto* connEdit = new QLineEdit;
|
||||
connEdit->setPlaceholderText("tcp:Port=5055,Server=localhost");
|
||||
connEdit->setText("tcp:Port=5055,Server=localhost");
|
||||
connEdit->setPlaceholderText("tcp:Port=5056,Server=127.0.0.1");
|
||||
connEdit->setText("tcp:Port=5056,Server=127.0.0.1");
|
||||
connEdit->setStyleSheet(editSS);
|
||||
layout->addWidget(connEdit);
|
||||
|
||||
layout->addSpacing(4);
|
||||
@@ -574,8 +679,72 @@ bool WinDbgMemoryPlugin::selectTarget(QWidget* parent, QString* target)
|
||||
layout->addLayout(row);
|
||||
};
|
||||
|
||||
addExample(".server tcp:port=5055");
|
||||
addExample(".server tcp:port=5056");
|
||||
addExample(".server npipe:pipe=reclass");
|
||||
|
||||
// ── Debugger Tools status ──
|
||||
layout->addSpacing(8);
|
||||
#ifdef _WIN32
|
||||
bool found = dbgToolsFound();
|
||||
auto* toolsRow = new QHBoxLayout;
|
||||
auto* toolsLabel = new QLabel;
|
||||
if (found) {
|
||||
toolsLabel->setText(QStringLiteral("Debugging Tools: %1").arg(s_loadedDir));
|
||||
QPalette tp = dlgPal;
|
||||
tp.setColor(QPalette::WindowText, dlgPal.color(QPalette::Disabled, QPalette::WindowText));
|
||||
toolsLabel->setPalette(tp);
|
||||
} else {
|
||||
toolsLabel->setText("Debugging Tools: not found");
|
||||
QPalette tp = dlgPal;
|
||||
tp.setColor(QPalette::WindowText, QColor(220, 120, 80));
|
||||
toolsLabel->setPalette(tp);
|
||||
}
|
||||
toolsLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
toolsRow->addWidget(toolsLabel, 1);
|
||||
|
||||
auto* browseBtn = new QPushButton("Browse...");
|
||||
browseBtn->setFixedWidth(70);
|
||||
browseBtn->setToolTip("Locate Debugging Tools for Windows directory (contains dbgeng.dll)");
|
||||
QObject::connect(browseBtn, &QPushButton::clicked, [&dlg, toolsLabel, &dlgPal]() {
|
||||
QString dir = QFileDialog::getExistingDirectory(&dlg,
|
||||
"Locate Debugging Tools for Windows",
|
||||
"C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers");
|
||||
if (dir.isEmpty()) return;
|
||||
QString dllPath = dir + "/dbgeng.dll";
|
||||
if (!QFileInfo::exists(dllPath)) {
|
||||
QMessageBox::warning(&dlg, "Not Found",
|
||||
"dbgeng.dll was not found in that directory.\n"
|
||||
"Select the folder containing dbgeng.dll\n"
|
||||
"(e.g. Debuggers\\x64).");
|
||||
return;
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue(kSettingsKey, dir);
|
||||
// Force reload on next use
|
||||
s_hDbgEng = nullptr;
|
||||
s_loadedDir.clear();
|
||||
if (dbgToolsFound()) {
|
||||
toolsLabel->setText(QStringLiteral("Debugging Tools: %1").arg(s_loadedDir));
|
||||
QPalette tp = dlgPal;
|
||||
tp.setColor(QPalette::WindowText, dlgPal.color(QPalette::Disabled, QPalette::WindowText));
|
||||
toolsLabel->setPalette(tp);
|
||||
}
|
||||
});
|
||||
toolsRow->addWidget(browseBtn);
|
||||
layout->addLayout(toolsRow);
|
||||
|
||||
if (!found) {
|
||||
auto* note = new QLabel(
|
||||
"The system dbgeng.dll does not support remote connections.\n"
|
||||
"Install Debugging Tools for Windows or use Browse to locate them.");
|
||||
QPalette np = dlgPal;
|
||||
np.setColor(QPalette::WindowText, dlgPal.color(QPalette::Disabled, QPalette::WindowText));
|
||||
note->setPalette(np);
|
||||
note->setWordWrap(true);
|
||||
layout->addWidget(note);
|
||||
}
|
||||
#endif
|
||||
|
||||
layout->addStretch();
|
||||
|
||||
auto* btnLayout = new QHBoxLayout;
|
||||
|
||||
@@ -837,8 +837,11 @@ void RcxEditor::allocateMarginStyles() {
|
||||
}
|
||||
|
||||
void RcxEditor::applyTheme(const Theme& theme) {
|
||||
// Editor uses a slightly darker background than chrome for visual depth
|
||||
const QColor editorBg = theme.background.darker(115);
|
||||
|
||||
// Paper and text
|
||||
m_sci->setPaper(theme.background);
|
||||
m_sci->setPaper(editorBg);
|
||||
m_sci->setColor(theme.text);
|
||||
m_sci->setCaretForegroundColor(theme.text);
|
||||
|
||||
@@ -882,25 +885,25 @@ void RcxEditor::applyTheme(const Theme& theme) {
|
||||
m_lexer->setColor(theme.text, QsciLexerCPP::Operator);
|
||||
m_lexer->setColor(theme.syntaxType, QsciLexerCPP::GlobalClass);
|
||||
for (int i = 0; i <= 127; i++)
|
||||
m_lexer->setPaper(theme.background, i);
|
||||
m_lexer->setPaper(editorBg, i);
|
||||
|
||||
// Margins
|
||||
m_sci->setMarginsBackgroundColor(theme.background);
|
||||
m_sci->setMarginsBackgroundColor(editorBg);
|
||||
m_sci->setMarginsForegroundColor(theme.textFaint);
|
||||
m_sci->setFoldMarginColors(theme.background, theme.background);
|
||||
m_sci->setFoldMarginColors(editorBg, editorBg);
|
||||
|
||||
// Markers
|
||||
m_sci->setMarkerBackgroundColor(theme.markerPtr, M_PTR0);
|
||||
m_sci->setMarkerForegroundColor(theme.markerPtr, M_PTR0);
|
||||
m_sci->setMarkerBackgroundColor(theme.background, M_CYCLE);
|
||||
m_sci->setMarkerForegroundColor(theme.background, M_CYCLE);
|
||||
m_sci->setMarkerBackgroundColor(editorBg, M_CYCLE);
|
||||
m_sci->setMarkerForegroundColor(editorBg, M_CYCLE);
|
||||
m_sci->setMarkerBackgroundColor(theme.markerError, M_ERR);
|
||||
m_sci->setMarkerForegroundColor(theme.text, M_ERR);
|
||||
m_sci->setMarkerBackgroundColor(theme.background, M_STRUCT_BG);
|
||||
m_sci->setMarkerBackgroundColor(editorBg, M_STRUCT_BG);
|
||||
m_sci->setMarkerForegroundColor(theme.text, M_STRUCT_BG);
|
||||
m_sci->setMarkerBackgroundColor(theme.hover, M_HOVER);
|
||||
m_sci->setMarkerBackgroundColor(theme.selected, M_SELECTED);
|
||||
m_sci->setMarkerBackgroundColor(theme.background, M_CMD_ROW);
|
||||
m_sci->setMarkerBackgroundColor(editorBg, M_CMD_ROW);
|
||||
m_sci->setMarkerBackgroundColor(theme.indHoverSpan, M_ACCENT);
|
||||
|
||||
// Margin extended styles
|
||||
@@ -911,7 +914,7 @@ void RcxEditor::applyTheme(const Theme& theme) {
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_STYLESETFORE,
|
||||
abs, theme.textFaint);
|
||||
m_sci->SendScintilla(QsciScintillaBase::SCI_STYLESETBACK,
|
||||
abs, theme.background);
|
||||
abs, editorBg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
46
src/main.cpp
46
src/main.cpp
@@ -509,7 +509,19 @@ static void applyGlobalTheme(const rcx::Theme& theme) {
|
||||
|
||||
qApp->setPalette(pal);
|
||||
|
||||
qApp->setStyleSheet(QString());
|
||||
// Global scrollbar styling — track matches control bg, handle is solid
|
||||
qApp->setStyleSheet(QStringLiteral(
|
||||
"QScrollBar:vertical { background: palette(window); width: 12px; margin: 0; border: none; }"
|
||||
"QScrollBar::handle:vertical { background: %1; min-height: 20px; border: none; }"
|
||||
"QScrollBar::handle:vertical:hover { background: %2; }"
|
||||
"QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; }"
|
||||
"QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; }"
|
||||
"QScrollBar:horizontal { background: palette(window); height: 12px; margin: 0; border: none; }"
|
||||
"QScrollBar::handle:horizontal { background: %1; min-width: 20px; border: none; }"
|
||||
"QScrollBar::handle:horizontal:hover { background: %2; }"
|
||||
"QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0; }"
|
||||
"QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; }")
|
||||
.arg(theme.textFaint.name(), theme.textDim.name()));
|
||||
}
|
||||
|
||||
class BorderOverlay : public QWidget {
|
||||
@@ -1218,16 +1230,20 @@ MainWindow::SplitPane MainWindow::createSplitPane(TabState& tab) {
|
||||
// Style to match the top dock tab bar, with accent line on selected tab
|
||||
{
|
||||
const auto& t = ThemeManager::instance().current();
|
||||
QSettings s("Reclass", "Reclass");
|
||||
QString editorFont = s.value("font", "JetBrains Mono").toString();
|
||||
pane.tabWidget->setStyleSheet(QStringLiteral(
|
||||
"QTabBar { border: none; }"
|
||||
"QTabBar::tab {"
|
||||
" background: %1; color: %2; padding: 0px 16px; border: none; border-radius: 0px; height: 24px;"
|
||||
" font-family: '%7'; font-size: 10pt;"
|
||||
"}"
|
||||
"QTabBar::tab:selected { color: %3; background: %4;"
|
||||
" border-top: 3px solid %6; padding-top: -3px; }"
|
||||
"QTabBar::tab:hover { color: %3; background: %5; }")
|
||||
.arg(t.background.name(), t.textMuted.name(), t.text.name(),
|
||||
t.backgroundAlt.name(), t.hover.name(), t.indHoverSpan.name()));
|
||||
t.backgroundAlt.name(), t.hover.name(), t.indHoverSpan.name(),
|
||||
editorFont));
|
||||
}
|
||||
|
||||
// Create editor via controller (parent = tabWidget for ownership)
|
||||
@@ -2352,16 +2368,19 @@ void MainWindow::applyTheme(const Theme& theme) {
|
||||
|
||||
// Restyle per-pane view tab bars (Reclass / C++)
|
||||
{
|
||||
QString editorFont = QSettings("Reclass", "Reclass").value("font", "JetBrains Mono").toString();
|
||||
QString paneTabStyle = QStringLiteral(
|
||||
"QTabBar { border: none; }"
|
||||
"QTabBar::tab {"
|
||||
" background: %1; color: %2; padding: 0px 16px; border: none; border-radius: 0px; height: 24px;"
|
||||
" font-family: '%7'; font-size: 10pt;"
|
||||
"}"
|
||||
"QTabBar::tab:selected { color: %3; background: %4;"
|
||||
" border-top: 3px solid %6; padding-top: -3px; }"
|
||||
"QTabBar::tab:hover { color: %3; background: %5; }")
|
||||
.arg(theme.background.name(), theme.textMuted.name(), theme.text.name(),
|
||||
theme.backgroundAlt.name(), theme.hover.name(), theme.indHoverSpan.name());
|
||||
theme.backgroundAlt.name(), theme.hover.name(), theme.indHoverSpan.name(),
|
||||
editorFont);
|
||||
for (auto it = m_tabs.begin(); it != m_tabs.end(); ++it) {
|
||||
for (auto& pane : it->panes) {
|
||||
if (pane.tabWidget)
|
||||
@@ -2498,10 +2517,11 @@ void MainWindow::applyTheme(const Theme& theme) {
|
||||
lexer->setColor(theme.text, QsciLexerCPP::Identifier);
|
||||
lexer->setColor(theme.syntaxPreproc, QsciLexerCPP::PreProcessor);
|
||||
lexer->setColor(theme.text, QsciLexerCPP::Operator);
|
||||
const QColor editorBg = theme.background.darker(115);
|
||||
for (int i = 0; i <= 127; i++)
|
||||
lexer->setPaper(theme.background, i);
|
||||
lexer->setPaper(editorBg, i);
|
||||
}
|
||||
sci->setPaper(theme.background);
|
||||
sci->setPaper(theme.background.darker(115));
|
||||
sci->setColor(theme.text);
|
||||
sci->setCaretForegroundColor(theme.text);
|
||||
sci->setCaretLineBackgroundColor(theme.hover);
|
||||
@@ -2631,6 +2651,9 @@ void MainWindow::setEditorFont(const QString& fontName) {
|
||||
tabBar->update();
|
||||
}
|
||||
}
|
||||
// Pane tab bars (Reclass / C++) — re-apply stylesheet with new font
|
||||
// (stylesheet overrides setFont, so font must be in the CSS)
|
||||
applyTheme(ThemeManager::instance().current());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2716,15 +2739,16 @@ void MainWindow::setupRenderedSci(QsciScintilla* sci) {
|
||||
lexer->setColor(theme.text, QsciLexerCPP::Identifier);
|
||||
lexer->setColor(theme.syntaxPreproc, QsciLexerCPP::PreProcessor);
|
||||
lexer->setColor(theme.text, QsciLexerCPP::Operator);
|
||||
const QColor editorBg = theme.background.darker(115);
|
||||
for (int i = 0; i <= 127; i++) {
|
||||
lexer->setPaper(theme.background, i);
|
||||
lexer->setPaper(editorBg, i);
|
||||
lexer->setFont(f, i);
|
||||
}
|
||||
sci->setLexer(lexer);
|
||||
sci->setBraceMatching(QsciScintilla::NoBraceMatch);
|
||||
|
||||
// Colors applied AFTER setLexer() — the lexer resets these on attach
|
||||
sci->setPaper(theme.background);
|
||||
sci->setPaper(editorBg);
|
||||
sci->setColor(theme.text);
|
||||
sci->setCaretForegroundColor(theme.text);
|
||||
sci->setCaretLineVisible(true);
|
||||
@@ -2980,7 +3004,7 @@ void MainWindow::importFromSource() {
|
||||
rebuildWorkspaceModel();
|
||||
if (!m_docDocks.isEmpty()) {
|
||||
splitDockWidget(m_workspaceDock, m_docDocks.first(), Qt::Horizontal);
|
||||
resizeDocks({m_workspaceDock}, {220}, Qt::Horizontal);
|
||||
resizeDocks({m_workspaceDock}, {128}, Qt::Horizontal);
|
||||
}
|
||||
m_workspaceDock->show();
|
||||
setAppStatus(QStringLiteral("Imported %1 classes from source").arg(classCount));
|
||||
@@ -3034,7 +3058,7 @@ void MainWindow::importPdb() {
|
||||
rebuildWorkspaceModel();
|
||||
if (!m_docDocks.isEmpty()) {
|
||||
splitDockWidget(m_workspaceDock, m_docDocks.first(), Qt::Horizontal);
|
||||
resizeDocks({m_workspaceDock}, {220}, Qt::Horizontal);
|
||||
resizeDocks({m_workspaceDock}, {128}, Qt::Horizontal);
|
||||
}
|
||||
m_workspaceDock->show();
|
||||
setAppStatus(QStringLiteral("Imported %1 classes from %2")
|
||||
@@ -3225,7 +3249,7 @@ QDockWidget* MainWindow::project_open(const QString& path) {
|
||||
rebuildWorkspaceModel();
|
||||
if (!m_docDocks.isEmpty()) {
|
||||
splitDockWidget(m_workspaceDock, m_docDocks.first(), Qt::Horizontal);
|
||||
resizeDocks({m_workspaceDock}, {220}, Qt::Horizontal);
|
||||
resizeDocks({m_workspaceDock}, {128}, Qt::Horizontal);
|
||||
}
|
||||
m_workspaceDock->show();
|
||||
int classCount = 0;
|
||||
@@ -3251,7 +3275,7 @@ QDockWidget* MainWindow::project_open(const QString& path) {
|
||||
rebuildWorkspaceModel();
|
||||
if (!m_docDocks.isEmpty()) {
|
||||
splitDockWidget(m_workspaceDock, m_docDocks.first(), Qt::Horizontal);
|
||||
resizeDocks({m_workspaceDock}, {220}, Qt::Horizontal);
|
||||
resizeDocks({m_workspaceDock}, {128}, Qt::Horizontal);
|
||||
}
|
||||
m_workspaceDock->show();
|
||||
addRecentFile(filePath);
|
||||
|
||||
@@ -219,7 +219,7 @@ public:
|
||||
if (opt.state & QStyle::State_Selected) {
|
||||
painter->fillRect(opt.rect, m_selected);
|
||||
// Left accent bar
|
||||
painter->fillRect(QRect(opt.rect.x(), opt.rect.y(), 2, opt.rect.height()), m_accent);
|
||||
painter->fillRect(QRect(opt.rect.x(), opt.rect.y(), 1, opt.rect.height()), m_accent);
|
||||
} else if (opt.state & QStyle::State_MouseOver) {
|
||||
painter->fillRect(opt.rect, m_hover);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
using namespace rcx;
|
||||
|
||||
static const char* CDB_PATH = "C:\\Program Files (x86)\\Windows Kits\\10\\Debuggers\\x64\\cdb.exe";
|
||||
static const int DBG_PORT = 5055;
|
||||
static const int DBG_PORT = 5056;
|
||||
|
||||
class TestWinDbgProvider : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -132,7 +132,7 @@ private slots:
|
||||
|
||||
void initTestCase()
|
||||
{
|
||||
m_connString = QString("tcp:Port=%1,Server=localhost").arg(DBG_PORT);
|
||||
m_connString = QString("tcp:Port=%1,Server=127.0.0.1").arg(DBG_PORT);
|
||||
|
||||
// If a debug server is already listening (e.g. WinDbg with .server),
|
||||
// skip launching our own cdb.exe.
|
||||
@@ -207,7 +207,7 @@ private slots:
|
||||
void plugin_canHandle_tcp()
|
||||
{
|
||||
WinDbgMemoryPlugin plugin;
|
||||
QVERIFY(plugin.canHandle("tcp:Port=5055,Server=localhost"));
|
||||
QVERIFY(plugin.canHandle("tcp:Port=5056,Server=localhost"));
|
||||
QVERIFY(plugin.canHandle("TCP:Port=1234,Server=10.0.0.1"));
|
||||
}
|
||||
|
||||
@@ -608,7 +608,7 @@ private slots:
|
||||
// ── Kernel/dump session tests ──
|
||||
// Set WINDBG_KERNEL_CONN to a target string:
|
||||
// "dump:F:/path/to/file.dmp" — open dump directly
|
||||
// "tcp:Port=5055,Server=localhost" — connect to debug server
|
||||
// "tcp:Port=5056,Server=localhost" — connect to debug server
|
||||
// Set WINDBG_KERNEL_ADDR to a readable hex address (e.g. kernel base).
|
||||
|
||||
static QString kernelTarget()
|
||||
|
||||
Reference in New Issue
Block a user