diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 8b1b240cf17127e34d6f00572b1c546542200057..e7594707feb5df1bb43c8df5bb63bc9071e3ce31 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -62,9 +62,10 @@ int qtGhVersion = QT_VERSION; #endif #if USE_QT_GUI -# include <QtGui/QWidget> -# include <QtGui/QPixmap> +# include <QtGui/QApplication> # include <QtGui/QImage> +# include <QtGui/QPixmap> +# include <QtGui/QWidget> #endif #ifdef Q_OS_WIN @@ -1457,7 +1458,9 @@ static void qDumpQHashNode(QDumper &d) static void qDumpQImage(QDumper &d) { const QImage &im = *reinterpret_cast<const QImage *>(d.data); - d.putItem("value", "(").put(im.width()).put("x").put(im.height()).put(")"); + d.beginItem("value"); + d.put("(").put(im.width()).put("x").put(im.height()).put(")"); + d.endItem(); d.putItem("type", NS"QImage"); d.putItem("numchild", "1"); if (d.dumpChildren) { @@ -2234,7 +2237,9 @@ static void qDumpQObjectSlotList(QDumper &d) static void qDumpQPixmap(QDumper &d) { const QPixmap &im = *reinterpret_cast<const QPixmap *>(d.data); - d.putItem("value", "(").put(im.width()).put("x").put(im.height()).put(")"); + d.beginItem("value"); + d.put("(").put(im.width()).put("x").put(im.height()).put(")"); + d.endItem(); d.putItem("type", NS"QPixmap"); d.putItem("numchild", "0"); d.disarm(); @@ -3023,6 +3028,14 @@ static void handleProtocolVersion2and3(QDumper & d) } // anonymous namespace +#if USE_QT_GUI +extern "C" Q_DECL_EXPORT +void *watchPoint(int x, int y) +{ + return QApplication::widgetAt(x, y); +} +#endif + extern "C" Q_DECL_EXPORT void *qDumpObjectData440( int protocolVersion, @@ -3115,7 +3128,7 @@ void *qDumpObjectData440( .put(""NS"QStringList=\"").put(sizeof(QStringList)).put("\",") .put(""NS"QObject=\"").put(sizeof(QObject)).put("\",") #if USE_QT_GUI - .put(""NS"QWidget=\"").put(sizeof(QWidget)<< "\",") + .put(""NS"QWidget=\"").put(sizeof(QWidget)).put("\",") #endif #ifdef Q_OS_WIN .put("string=\"").put(sizeof(std::string)).put("\",") diff --git a/share/qtcreator/gdbmacros/gdbmacros.pro b/share/qtcreator/gdbmacros/gdbmacros.pro index 67133e732e88e30dd557d051c5270f24641f39a5..d876af9387fa8f22dcd80f629cc0a2cf7d894025 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.pro +++ b/share/qtcreator/gdbmacros/gdbmacros.pro @@ -1,13 +1,12 @@ TEMPLATE = lib CONFIG += shared -QT = core linux-* { CONFIG -= release CONFIG += debug } SOURCES=gdbmacros.cpp -true { +false { DEFINES += USE_QT_GUI=0 QT = core } else { diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index f32b815e4f00f80d21b093e8eb224dbb41df184f..693dcf4e6617ddf524d1acb4ffea165478b9a89c 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -165,6 +165,9 @@ DebuggerSettings *DebuggerSettings::instance() item = new SavedAction(instance); instance->insertItem(AssignType, item); + item = new SavedAction(instance); + instance->insertItem(WatchPoint, item); + // // DebuggingHelper // diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index d466a78df3dd40b3adacc6a7090dbe40911be710..5f953b6d10e53dfdd5f6d251d33f27c119439b66 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -94,7 +94,7 @@ enum DebuggerActionCode WatchExpression, WatchExpressionInWindow, RemoveWatchExpression, - WatchModelUpdate, + WatchPoint, UseToolTips, AssignValue, AssignType, diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index e9226a7c42277767ba5aca980ea46e46f40e0c25..15c586b5bba226397c49f1cf81c3a15ef912e571 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -434,7 +434,8 @@ void DebuggerManager::init() connect(theDebuggerAction(ExecuteCommand), SIGNAL(triggered()), this, SLOT(executeDebuggerCommand())); - + connect(theDebuggerAction(WatchPoint), SIGNAL(triggered()), + this, SLOT(watchPoint())); m_breakDock = createDockForWidget(m_breakWindow); @@ -1089,6 +1090,13 @@ void DebuggerManager::nextIExec() m_engine->nextIExec(); } +void DebuggerManager::watchPoint() +{ + if (QAction *action = qobject_cast<QAction *>(sender())) + if (m_engine) + m_engine->watchPoint(action->data().toPoint()); +} + void DebuggerManager::executeDebuggerCommand() { if (QAction *action = qobject_cast<QAction *>(sender())) diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 23624c7d601ee2af1ebca6dfdab0ce955fa58f69..bfbfc10e93c1db79bbd7ca815595dc0318273016 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -318,6 +318,8 @@ public slots: void executeDebuggerCommand(); void executeDebuggerCommand(const QString &command); + void watchPoint(); + void showStatusMessage(const QString &msg, int timeout = -1); // -1 forever private slots: diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index ed6e4b7a57eb5f9f8e18f773cd08de0ee23e6118..b564a5468a7c4149079bcb3e0304c3639a3e3e7d 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -103,6 +103,42 @@ static int ¤tToken() return token; } +// reads a MI-encoded item frome the consolestream +static bool parseConsoleStream(const GdbResultRecord &record, GdbMi *contents) +{ + GdbMi output = record.data.findChild("consolestreamoutput"); + QByteArray out = output.data(); + + int markerPos = out.indexOf('"') + 1; // position of 'success marker' + if (markerPos == 0 || out.at(markerPos) == 'f') { // 't' or 'f' + // custom dumper produced no output + return false; + } + + out = out.mid(markerPos + 1); + out = out.left(out.lastIndexOf('"')); + // optimization: dumper output never needs real C unquoting + out.replace('\\', ""); + out = "dummy={" + out + "}"; + + contents->fromString(out); + //qDebug() << "CONTENTS" << contents->toString(true); + return contents->isValid(); +} + +static QByteArray parsePlainConsoleStream(const GdbResultRecord &record) +{ + GdbMi output = record.data.findChild("consolestreamoutput"); + QByteArray out = output.data(); + // FIXME: proper decoding needed + if (out.endsWith("\\n")) + out.chop(2); + while (out.endsWith('\n') || out.endsWith(' ')) + out.chop(1); + int pos = out.indexOf(" = "); + return out.mid(pos + 3); +} + /////////////////////////////////////////////////////////////////////// // // GdbEngine @@ -2823,6 +2859,7 @@ void GdbEngine::setUseDebuggingHelpers(const QVariant &on) //qDebug() << "SWITCHING ON/OFF DUMPER DEBUGGING:" << on; // FIXME: a bit too harsh, but otherwise the treeview sometimes look funny //m_expandedINames.clear(); + Q_UNUSED(on); setTokenBarrier(); updateLocals(); } @@ -3111,16 +3148,9 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record, const { m_dumperHelper.clear(); //qDebug() << "DATA DUMPER TRIAL:" << record.toString(); - GdbMi output = record.data.findChild("consolestreamoutput"); - QByteArray out = output.data(); - out = out.mid(out.indexOf('"') + 2); // + 1 is success marker - out = out.left(out.lastIndexOf('"')); - out.replace('\\', ""); // optimization: dumper output never needs real C unquoting - out = "dummy={" + out + "}"; - //qDebug() << "OUTPUT:" << out; GdbMi contents; - contents.fromString(out); + QTC_ASSERT(parseConsoleStream(record, &contents), /**/); GdbMi simple = contents.findChild("dumpers"); m_dumperHelper.setQtNamespace(_(contents.findChild("namespace").data())); @@ -3281,11 +3311,7 @@ void GdbEngine::handleDebuggingHelperValue1(const GdbResultRecord &record, if (record.resultClass == GdbResultDone) { // ignore this case, data will follow } else if (record.resultClass == GdbResultError) { - // Record an extra result, as the socket result will be lost - // in transmission - //--m_pendingRequests; QString msg = QString::fromLocal8Bit(record.data.findChild("msg").data()); - //qDebug() << "CUSTOM DUMPER ERROR MESSAGE:" << msg; #ifdef QT_DEBUG // Make debugging of dumpers easier if (theDebuggerBoolSetting(DebugDebuggingHelpers) @@ -3296,12 +3322,6 @@ void GdbEngine::handleDebuggingHelperValue1(const GdbResultRecord &record, return; } #endif - //if (msg.startsWith("The program being debugged was sig")) - // msg = strNotInScope; - //if (msg.startsWith("The program being debugged stopped while")) - // msg = strNotInScope; - //data.setError(msg); - //insertData(data); } } @@ -3310,6 +3330,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record, { WatchData data = cookie.value<WatchData>(); QTC_ASSERT(data.isValid(), return); + //qDebug() << "CUSTOM VALUE RESULT:" << record.toString(); //qDebug() << "FOR DATA:" << data.toString() << record.resultClass; if (record.resultClass != GdbResultDone) { @@ -3317,26 +3338,8 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record, return; } - GdbMi output = record.data.findChild("consolestreamoutput"); - QByteArray out = output.data(); - - int markerPos = out.indexOf('"') + 1; // position of 'success marker' - if (markerPos == 0 || out.at(markerPos) == 'f') { // 't' or 'f' - // custom dumper produced no output - data.setError(strNotInScope); - insertData(data); - return; - } - - out = out.mid(markerPos + 1); - out = out.left(out.lastIndexOf('"')); - out.replace('\\', ""); // optimization: dumper output never needs real C unquoting - out = "dummy={" + out + "}"; - GdbMi contents; - contents.fromString(out); - //qDebug() << "CONTENTS" << contents.toString(true); - if (!contents.isValid()) { + if (!parseConsoleStream(record, &contents)) { data.setError(strNotInScope); insertData(data); return; @@ -3759,60 +3762,6 @@ void GdbEngine::handleVarListChildren(const GdbResultRecord &record, } } -/* -void GdbEngine::handleToolTip(const GdbResultRecord &record, - const QVariant &cookie) -{ - const QByteArray &what = cookie.toByteArray(); - //qDebug() << "HANDLE TOOLTIP:" << what << m_toolTip.toString(); - // << "record: " << record.toString(); - if (record.resultClass == GdbResultError) { - if (what == "create") { - postCommand(_("ptype ") + m_toolTip.exp, - Discardable, CB(handleToolTip), QByteArray("ptype")); - return; - } - if (what == "evaluate") { - QByteArray msg = record.data.findChild("msg").data(); - if (msg.startsWith("Cannot look up value of a typedef")) { - m_toolTip.value = tr("%1 is a typedef.").arg(m_toolTip.exp); - //return; - } - } - } else if (record.resultClass == GdbResultDone) { - if (what == "create") { - setWatchDataType(m_toolTip, record.data.findChild("type")); - setWatchDataChildCount(m_toolTip, record.data.findChild("numchild")); - if (hasDebuggingHelperForType(m_toolTip.type)) - runDebuggingHelper(m_toolTip, false); - else - q->showStatusMessage(tr("Retrieving data for tooltip..."), 10000); - postCommand(_("-data-evaluate-expression ") + m_toolTip.exp, - Discardable, CB(handleToolTip), QByteArray("evaluate")); - return; - } - if (what == "evaluate") { - m_toolTip.value = m_toolTip.type + _c(' ') + m_toolTip.exp - + _(" = " + record.data.findChild("value").data()); - //return; - } - if (what == "ptype") { - GdbMi mi = record.data.findChild("consolestreamoutput"); - m_toolTip.value = extractTypeFromPTypeOutput(_(mi.data())); - //return; - } - } - - m_toolTip.iname = tooltipIName; - m_toolTip.setChildrenUnneeded(); - m_toolTip.setHasChildrenUnneeded(); - insertData(m_toolTip); - qDebug() << "DATA INSERTED"; - QTimer::singleShot(0, this, SLOT(updateWatchModel2())); - qDebug() << "HANDLE TOOLTIP END"; -} -*/ - #if 0 void GdbEngine::handleChangedItem(QStandardItem *item) { @@ -3933,6 +3882,29 @@ bool GdbEngine::startModeAllowsDumpers() const || q->startMode() == AttachExternal; } +void GdbEngine::watchPoint(const QPoint &pnt) +{ + //qDebug() << "WATCH " << pnt; + postCommand(_("call (void*)watchPoint(%1,%2)").arg(pnt.x()).arg(pnt.y()), + NeedsStop, CB(handleWatchPoint)); +} + +void GdbEngine::handleWatchPoint(const GdbResultRecord &record, const QVariant &) +{ + //qDebug() << "HANDLE WATCH POINT:" << record.toString(); + if (record.resultClass == GdbResultDone) { + GdbMi contents = record.data.findChild("consolestreamoutput"); + // "$5 = (void *) 0xbfa7ebfc\n" + QString str = _(parsePlainConsoleStream(record)); + // "(void *) 0xbfa7ebfc" + QString addr = str.mid(9); + QString ns = m_dumperHelper.qtNamespace(); + QString type = ns.isEmpty() ? _("QWidget*") : _("'%1QWidget'*").arg(ns); + QString exp = _("(*(%1)%2)").arg(type).arg(addr); + theDebuggerAction(WatchExpression)->trigger(exp); + } +} + IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *opts) { opts->push_back(new GdbOptionsPage); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 47dbd655cfd8676a66c618be15c4a760bb3e36b9..84f8ab32f82a1af820a8f01c93291583686a7440 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -115,6 +115,7 @@ private: void assignValueInDebugger(const QString &expr, const QString &value); void executeDebuggerCommand(const QString & command); + void watchPoint(const QPoint &); void loadSymbols(const QString &moduleName); void loadAllSymbols(); @@ -220,6 +221,7 @@ private: void handleExit(const GdbResultRecord &, const QVariant &); void handleSetTargetAsync(const GdbResultRecord &, const QVariant &); void handleTargetRemote(const GdbResultRecord &, const QVariant &); + void handleWatchPoint(const GdbResultRecord &, const QVariant &); void debugMessage(const QString &msg); bool showToolTip(); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 8a7187b77f281181092fb48d11c535e41f791bbf..dbbdb14314385c5baa7da767c8423468aec055ee 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -93,6 +93,8 @@ public: virtual void reloadSourceFiles() = 0; virtual void reloadFullStack() = 0; + + virtual void watchPoint(const QPoint &) {} }; } // namespace Internal diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 7fedf1520bfe0e27ec8c3a24df76020595e4c18e..feab5a2989cb9350b886587d8836978f5116cc01 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -114,6 +114,8 @@ public: WatchWindow::WatchWindow(Type type, QWidget *parent) : QTreeView(parent), m_alwaysResizeColumnsToContents(true), m_type(type) { + m_grabbing = false; + QAction *act = theDebuggerAction(UseAlternatingRowColors); setWindowTitle(tr("Locals and Watchers")); setAlternatingRowColors(act->isChecked()); @@ -219,6 +221,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) QAction *act3 = new QAction(tr("Insert new watch item"), &menu); menu.addAction(act3); + QAction *act4 = new QAction(tr("Select widget to watch"), &menu); + menu.addAction(act4); menu.addSeparator(); menu.addAction(theDebuggerAction(RecheckDebuggingHelpers)); @@ -233,7 +237,12 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) else if (act == act2) setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents); else if (act == act3) - theDebuggerAction(WatchExpression)->trigger(WatchHandler::watcherEditPlaceHolder()); + theDebuggerAction(WatchExpression) + ->trigger(WatchHandler::watcherEditPlaceHolder()); + else if (act == act4) { + grabMouse(Qt::CrossCursor); + m_grabbing = true; + } } void WatchWindow::resizeColumnsToContents() @@ -253,6 +262,17 @@ void WatchWindow::setAlwaysResizeColumnsToContents(bool on) header()->setResizeMode(1, mode); } +bool WatchWindow::event(QEvent *ev) +{ + if (m_grabbing && ev->type() == QEvent::MouseButtonPress) { + QMouseEvent *mev = static_cast<QMouseEvent *>(ev); + m_grabbing = false; + releaseMouse(); + theDebuggerAction(WatchPoint)->trigger(mapToGlobal(mev->pos())); + } + return QTreeView::event(ev); +} + void WatchWindow::editItem(const QModelIndex &idx) { Q_UNUSED(idx); // FIXME diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h index af8cf163f6a15fc6c8fbd94dda447f3c7edfa240..b32319b64539e7e3cf27a5a0ae175cf2e9961308 100644 --- a/src/plugins/debugger/watchwindow.h +++ b/src/plugins/debugger/watchwindow.h @@ -69,13 +69,14 @@ private: void dragEnterEvent(QDragEnterEvent *ev); void dropEvent(QDropEvent *ev); void dragMoveEvent(QDragMoveEvent *ev); + bool event(QEvent *ev); void editItem(const QModelIndex &idx); - void resetHelper(const QModelIndex &idx); bool m_alwaysResizeColumnsToContents; Type m_type; + bool m_grabbing; };