diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e1e62309..4f056badf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,10 +64,10 @@ elseif(UNIX AND NOT APPLE) ) endif() if(DEFINED GIT_HASH) - message("Olive: git hash = " "${GIT_HASH}") + message("Olive: Git hash = " "${GIT_HASH}") list(APPEND OLIVE_DEFINITIONS -DGITHASH="${GIT_HASH}") else() - message("Olive: No git hash defined!") + message("Olive: No Git hash defined!") endif() find_package(Doxygen) @@ -87,6 +87,8 @@ set(OLIVE_SOURCES dialogs/autocutsilencedialog.h dialogs/clippropertiesdialog.cpp dialogs/clippropertiesdialog.h + dialogs/crashdialog.cpp + dialogs/crashdialog.h dialogs/debugdialog.cpp dialogs/debugdialog.h dialogs/demonotice.cpp @@ -497,7 +499,8 @@ add_executable(${OLIVE_TARGET} target_compile_definitions(${OLIVE_TARGET} PRIVATE ${OLIVE_DEFINITIONS}) -target_compile_options(${OLIVE_TARGET} PRIVATE $<$:-Wno-reorder>) +target_compile_options(${OLIVE_TARGET} PRIVATE $<$:-Wno-reorder -rdynamic>) +target_link_options(${OLIVE_TARGET} PRIVATE $<$:-rdynamic>) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/dialogs/crashdialog.cpp b/dialogs/crashdialog.cpp new file mode 100644 index 000000000..78b971790 --- /dev/null +++ b/dialogs/crashdialog.cpp @@ -0,0 +1,47 @@ +#include "crashdialog.h" + +#include +#include +#include +#include + +CrashDialog* olive::crash_dialog; + +CrashDialog::CrashDialog() +{ + resize(480, 640); + + QVBoxLayout* layout = new QVBoxLayout(this); + + layout->addWidget(new QLabel(tr("We're very sorry, Olive has crashed. " + "Please send the following data to developers:"))); + + text_edit = new QTextEdit(); + //text_edit->setWordWrapMode(QTextOption::NoWrap); + text_edit->setReadOnly(true); + layout->addWidget(text_edit); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok); + buttons->setCenterButtons(true); + connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); + layout->addWidget(buttons); + + // Set some default data for the crash report so we do as little as possible when we actually crash +#ifdef GITHASH + text_edit->append(QString("Version: %1").arg(GITHASH)); +#else + text_edit->append(QString("Version: (unknown)")); +#endif + text_edit->append(QString("Operating System: %1 %2").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture())); + text_edit->append(QString("Build ABI: %1").arg(QSysInfo::buildAbi())); + text_edit->append(QString()); +} + +void CrashDialog::SetData(int signal, char **t, int size) +{ + text_edit->append(QString("Signal: %1").arg(signal)); + text_edit->append(QString()); + for (int i=0;iappend(t[i]); + } +} diff --git a/dialogs/crashdialog.h b/dialogs/crashdialog.h new file mode 100644 index 000000000..c4e601d3a --- /dev/null +++ b/dialogs/crashdialog.h @@ -0,0 +1,22 @@ +#ifndef CRASHDIALOG_H +#define CRASHDIALOG_H + +#include +#include + +class CrashDialog : public QDialog +{ +public: + CrashDialog(); + + void SetData(int signal, char** t, int size); + +private: + QTextEdit* text_edit; +}; + +namespace olive { + extern CrashDialog* crash_dialog; +} + +#endif // CRASHDIALOG_H diff --git a/main.cpp b/main.cpp index 294c34b2c..a87c88532 100644 --- a/main.cpp +++ b/main.cpp @@ -19,7 +19,15 @@ ***/ #include +#include +#ifdef __GNUC__ +#include +#include +#include +#endif + +#include "dialogs/crashdialog.h" #include "global/debug.h" #include "global/config.h" #include "global/global.h" @@ -33,7 +41,33 @@ extern "C" { #include } +#ifdef __GNUC__ +void handler(int sig) { + void *array[10]; + size_t size; + + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + // print out all the frames to stderr + fprintf(stderr, "Signal: %d\n\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); + + // try to show a GUI crash report + char** bt_syms = backtrace_symbols(array, size); + olive::crash_dialog->SetData(sig, bt_syms, size); + olive::crash_dialog->exec(); + free(bt_syms); + + abort(); +} +#endif + int main(int argc, char *argv[]) { +#ifdef __GNUC__ + signal(SIGSEGV, handler); +#endif + olive::Global = std::unique_ptr(new OliveGlobal); bool launch_fullscreen = false; @@ -130,6 +164,8 @@ int main(int argc, char *argv[]) { QGuiApplication::setDesktopFileName("org.olivevideoeditor.Olive"); #endif + olive::crash_dialog = new CrashDialog(); + MainWindow w(nullptr); // multiply track height constants by the current DPI scale @@ -150,5 +186,5 @@ int main(int argc, char *argv[]) { w.showMaximized(); } - return a.exec(); + return a.exec(); } diff --git a/ui/timelineview.cpp b/ui/timelineview.cpp index 4b2d12bfd..54525e621 100644 --- a/ui/timelineview.cpp +++ b/ui/timelineview.cpp @@ -130,7 +130,8 @@ void TimelineView::show_context_menu(const QPoint& pos) { ParentTimeline()->cursor_track = getTrackFromScreenPoint(pos.y()); // check if the space the cursor is currently at is empty - if (ParentTimeline()->cursor_track->GetClipFromPoint(ParentTimeline()->cursor_frame) == nullptr) { + if (ParentTimeline()->cursor_track != nullptr + && ParentTimeline()->cursor_track->GetClipFromPoint(ParentTimeline()->cursor_frame) == nullptr) { QAction* ripple_delete_action = menu.addAction(tr("R&ipple Delete Empty Space")); connect(ripple_delete_action, SIGNAL(triggered(bool)), ParentTimeline(), SLOT(ripple_delete_empty_space())); } @@ -3294,7 +3295,6 @@ Track *TimelineView::getTrackFromScreenPoint(int y) { } int TimelineView::getScreenPointFromTrack(Track *track) { - qDebug() << "Getting screen point from" << track << track->Index(); return getScreenPointFromTrackIndex(track->Index()); }