diff --git a/0001-View-Honor-ENABLE_DECODE-compiler-switch.patch b/0001-View-Honor-ENABLE_DECODE-compiler-switch.patch new file mode 100644 index 0000000..dbe972f --- /dev/null +++ b/0001-View-Honor-ENABLE_DECODE-compiler-switch.patch @@ -0,0 +1,47 @@ +From dcfe0a01f72021aab961245d0ebcc9f8d4504b40 Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Sun, 31 Jan 2016 14:12:44 +0100 +Subject: [PATCH 01/13] View: Honor ENABLE_DECODE compiler switch + +--- + pv/view/view.cpp | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/pv/view/view.cpp b/pv/view/view.cpp +index c9b08bf..6ad7dea 100644 +--- a/pv/view/view.cpp ++++ b/pv/view/view.cpp +@@ -43,7 +43,6 @@ + #include + + #include "analogsignal.hpp" +-#include "decodetrace.hpp" + #include "header.hpp" + #include "logicsignal.hpp" + #include "ruler.hpp" +@@ -59,6 +58,10 @@ + #include "pv/data/logicsegment.hpp" + #include "pv/util.hpp" + ++#ifdef ENABLE_DECODE ++#include "decodetrace.hpp" ++#endif ++ + using boost::shared_lock; + using boost::shared_mutex; + +@@ -455,9 +458,11 @@ void View::enable_coloured_bg(bool state) + if (l) + l->set_coloured_bg(state); + ++#ifdef ENABLE_DECODE + shared_ptr d = dynamic_pointer_cast(i); + if (d) + d->set_coloured_bg(state); ++#endif + } + + viewport_->update(); +-- +2.4.3 + diff --git a/0002-Fix-733-Open-import-files-using-binary-mode.patch b/0002-Fix-733-Open-import-files-using-binary-mode.patch new file mode 100644 index 0000000..05b4174 --- /dev/null +++ b/0002-Fix-733-Open-import-files-using-binary-mode.patch @@ -0,0 +1,25 @@ +From c8e50b6efe18ff5ede06f0321d27d572dc3a6bc5 Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Sun, 31 Jan 2016 15:10:10 +0100 +Subject: [PATCH 02/13] Fix #733: Open import files using binary mode + +--- + pv/devices/inputfile.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pv/devices/inputfile.cpp b/pv/devices/inputfile.cpp +index 3ddc8ae..22c9b1c 100644 +--- a/pv/devices/inputfile.cpp ++++ b/pv/devices/inputfile.cpp +@@ -70,7 +70,7 @@ void InputFile::run() + assert(input_); + + interrupt_ = false; +- std::ifstream f(file_name_); ++ std::ifstream f(file_name_, std::ios::binary); + while (!interrupt_ && f) { + f.read(buffer, BufferSize); + const std::streamsize size = f.gcount(); +-- +2.4.3 + diff --git a/0003-Fix-unit-tests-and-prevent-warnings.patch b/0003-Fix-unit-tests-and-prevent-warnings.patch new file mode 100644 index 0000000..b84e380 --- /dev/null +++ b/0003-Fix-unit-tests-and-prevent-warnings.patch @@ -0,0 +1,63 @@ +From 5d6ae8a26c8d86531d0d85d2fefc67d617c73f56 Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Sun, 31 Jan 2016 18:06:07 +0100 +Subject: [PATCH 03/13] Fix unit tests and prevent warnings + +--- + pv/view/ruler.hpp | 12 ++++++------ + test/util.cpp | 4 ++-- + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/pv/view/ruler.hpp b/pv/view/ruler.hpp +index cf63eaf..90556a0 100644 +--- a/pv/view/ruler.hpp ++++ b/pv/view/ruler.hpp +@@ -30,9 +30,9 @@ + #include + + namespace RulerTest { +-class tick_position_test_0; +-class tick_position_test_1; +-class tick_position_test_2; ++struct tick_position_test_0; ++struct tick_position_test_1; ++struct tick_position_test_2; + } + + namespace pv { +@@ -45,9 +45,9 @@ class Ruler : public MarginWidget + { + Q_OBJECT + +- friend class RulerTest::tick_position_test_0; +- friend class RulerTest::tick_position_test_1; +- friend class RulerTest::tick_position_test_2; ++ friend struct RulerTest::tick_position_test_0; ++ friend struct RulerTest::tick_position_test_1; ++ friend struct RulerTest::tick_position_test_2; + + private: + +diff --git a/test/util.cpp b/test/util.cpp +index 21a32c5..9e4a99c 100644 +--- a/test/util.cpp ++++ b/test/util.cpp +@@ -32,13 +32,13 @@ namespace { + pv::util::SIPrefix unspecified = pv::util::SIPrefix::unspecified; + pv::util::SIPrefix yocto = pv::util::SIPrefix::yocto; + pv::util::SIPrefix nano = pv::util::SIPrefix::nano; +- pv::util::SIPrefix micro = pv::util::SIPrefix::micro; ++/* pv::util::SIPrefix micro = pv::util::SIPrefix::micro; // Not currently used */ + pv::util::SIPrefix milli = pv::util::SIPrefix::milli; + pv::util::SIPrefix none = pv::util::SIPrefix::none; + pv::util::SIPrefix kilo = pv::util::SIPrefix::kilo; + pv::util::SIPrefix yotta = pv::util::SIPrefix::yotta; + +- pv::util::TimeUnit Time = pv::util::TimeUnit::Time; ++/* pv::util::TimeUnit Time = pv::util::TimeUnit::Time; // Not currently used */ + } + + BOOST_AUTO_TEST_SUITE(UtilTest) +-- +2.4.3 + diff --git a/0004-Fix-737-by-adding-the-override-specifier-where-neede.patch b/0004-Fix-737-by-adding-the-override-specifier-where-neede.patch new file mode 100644 index 0000000..cd9c524 --- /dev/null +++ b/0004-Fix-737-by-adding-the-override-specifier-where-neede.patch @@ -0,0 +1,164 @@ +From b2650e6978b19c44a6fc375931bc412ad4eefa5b Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Sun, 31 Jan 2016 18:18:47 +0100 +Subject: [PATCH 04/13] Fix #737 by adding the override specifier where needed + +--- + pv/view/cursorpair.hpp | 14 +++++++------- + pv/view/ruler.hpp | 12 ++++++------ + pv/view/timemarker.hpp | 14 +++++++------- + 3 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/pv/view/cursorpair.hpp b/pv/view/cursorpair.hpp +index 345700f..7cbd4f0 100644 +--- a/pv/view/cursorpair.hpp ++++ b/pv/view/cursorpair.hpp +@@ -49,7 +49,7 @@ public: + /** + * Returns true if the item is visible and enabled. + */ +- bool enabled() const; ++ bool enabled() const override; + + /** + * Returns a pointer to the first cursor. +@@ -66,14 +66,14 @@ public: + */ + void set_time(const pv::util::Timestamp& time) override; + +- float get_x() const; ++ float get_x() const override; + +- QPoint point(const QRect &rect) const; ++ QPoint point(const QRect &rect) const override; + +- pv::widgets::Popup* create_popup(QWidget *parent); ++ pv::widgets::Popup* create_popup(QWidget *parent) override; + + public: +- QRectF label_rect(const QRectF &rect) const; ++ QRectF label_rect(const QRectF &rect) const override; + + /** + * Paints the marker's label to the ruler. +@@ -81,14 +81,14 @@ public: + * @param rect The rectangle of the ruler client area. + * @param hover true if the label is being hovered over by the mouse. + */ +- void paint_label(QPainter &p, const QRect &rect, bool hover); ++ void paint_label(QPainter &p, const QRect &rect, bool hover) override; + + /** + * Paints the background layer of the item with a QPainter + * @param p the QPainter to paint into. + * @param pp the painting parameters object to paint with. + */ +- void paint_back(QPainter &p, const ViewItemPaintParams &pp); ++ void paint_back(QPainter &p, const ViewItemPaintParams &pp) override; + + /** + * Constructs the string to display. +diff --git a/pv/view/ruler.hpp b/pv/view/ruler.hpp +index 90556a0..aabbe48 100644 +--- a/pv/view/ruler.hpp ++++ b/pv/view/ruler.hpp +@@ -63,14 +63,14 @@ public: + Ruler(View &parent); + + public: +- QSize sizeHint() const; ++ QSize sizeHint() const override; + + /** + * The extended area that the header widget would like to be sized to. + * @remarks This area is the area specified by sizeHint, extended by + * the area to overlap the viewport. + */ +- QSize extended_size_hint() const; ++ QSize extended_size_hint() const override; + + /** + * Formats a timestamp depending on its distance to another timestamp. +@@ -109,7 +109,7 @@ private: + /** + * Gets the time items. + */ +- std::vector< std::shared_ptr > items(); ++ std::vector< std::shared_ptr > items() override; + + /** + * Gets the first view item which has a label that contains @c pt . +@@ -118,11 +118,11 @@ private: + * @c shared_ptr if no item was found. + */ + std::shared_ptr get_mouse_over_item( +- const QPoint &pt); ++ const QPoint &pt) override; + +- void paintEvent(QPaintEvent *event); ++ void paintEvent(QPaintEvent *event) override; + +- void mouseDoubleClickEvent(QMouseEvent *e); ++ void mouseDoubleClickEvent(QMouseEvent *e) override; + + /** + * Draw a hover arrow under the cursor position. +diff --git a/pv/view/timemarker.hpp b/pv/view/timemarker.hpp +index f16fea0..c65dab7 100644 +--- a/pv/view/timemarker.hpp ++++ b/pv/view/timemarker.hpp +@@ -68,27 +68,27 @@ public: + */ + void set_time(const pv::util::Timestamp& time) override; + +- float get_x() const; ++ float get_x() const override; + + /** + * Gets the arrow-tip point of the time marker. + * @param rect the rectangle of the ruler area. + */ +- QPoint point(const QRect &rect) const; ++ QPoint point(const QRect &rect) const override; + + /** + * Computes the outline rectangle of a label. + * @param rect the rectangle of the header area. + * @return Returns the rectangle of the signal label. + */ +- QRectF label_rect(const QRectF &rect) const; ++ QRectF label_rect(const QRectF &rect) const override; + + /** + * Computes the outline rectangle of the viewport hit-box. + * @param rect the rectangle of the viewport area. + * @return Returns the rectangle of the hit-box. + */ +- QRectF hit_box_rect(const ViewItemPaintParams &pp) const; ++ QRectF hit_box_rect(const ViewItemPaintParams &pp) const override; + + /** + * Gets the text to show in the marker. +@@ -101,16 +101,16 @@ public: + * @param rect The rectangle of the ruler client area. + * @param hover true if the label is being hovered over by the mouse. + */ +- void paint_label(QPainter &p, const QRect &rect, bool hover); ++ void paint_label(QPainter &p, const QRect &rect, bool hover) override; + + /** + * Paints the foreground layer of the item with a QPainter + * @param p the QPainter to paint into. + * @param pp the painting parameters object to paint with. + */ +- void paint_fore(QPainter &p, const ViewItemPaintParams &pp); ++ void paint_fore(QPainter &p, const ViewItemPaintParams &pp) override; + +- virtual pv::widgets::Popup* create_popup(QWidget *parent); ++ virtual pv::widgets::Popup* create_popup(QWidget *parent) override; + + private Q_SLOTS: + void on_value_changed(const pv::util::Timestamp& value); +-- +2.4.3 + diff --git a/0005-Fix-clang-warning-shifting-a-negative-signed-value-i.patch b/0005-Fix-clang-warning-shifting-a-negative-signed-value-i.patch new file mode 100644 index 0000000..398a1c7 --- /dev/null +++ b/0005-Fix-clang-warning-shifting-a-negative-signed-value-i.patch @@ -0,0 +1,35 @@ +From c28fa62bc89656ba3b1b01011a45e941d6c7d42a Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Sun, 31 Jan 2016 18:22:17 +0100 +Subject: [PATCH 05/13] Fix clang warning: shifting a negative signed value is + undefined + +--- + pv/data/logicsegment.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/pv/data/logicsegment.cpp b/pv/data/logicsegment.cpp +index 3e18b85..a5634b3 100644 +--- a/pv/data/logicsegment.cpp ++++ b/pv/data/logicsegment.cpp +@@ -308,7 +308,7 @@ void LogicSegment::get_subsampled_edges( + pow2_ceil(index, MipMapScalePower)); + + for (; index < final_index && +- (index & ~(~0 << MipMapScalePower)) != 0; ++ (index & ~((uint64_t)(~0) << MipMapScalePower)) != 0; + index++) { + const bool sample = + (get_sample(index) & sig_mask) != 0; +@@ -358,7 +358,7 @@ void LogicSegment::get_subsampled_edges( + sig_mask)) + break; + +- if ((offset & ~(~0 << MipMapScalePower)) == 0) { ++ if ((offset & ~((uint64_t)(~0) << MipMapScalePower)) == 0) { + // If we are now at the beginning of a + // higher level mip-map block ascend one + // level +-- +2.4.3 + diff --git a/0006-Fix-745-by-improving-the-draw_annotations-block-draw.patch b/0006-Fix-745-by-improving-the-draw_annotations-block-draw.patch new file mode 100644 index 0000000..dc8b0a1 --- /dev/null +++ b/0006-Fix-745-by-improving-the-draw_annotations-block-draw.patch @@ -0,0 +1,103 @@ +From bdc2a99bcaa5aba7c6de2543bab6534299b8a5ee Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Thu, 4 Feb 2016 22:37:54 +0100 +Subject: [PATCH 06/13] Fix 745 by improving the draw_annotations() block + drawing algo + +--- + pv/view/decodetrace.cpp | 57 ++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 45 insertions(+), 12 deletions(-) + +diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp +index e0f3a0f..e7ffbbb 100644 +--- a/pv/view/decodetrace.cpp ++++ b/pv/view/decodetrace.cpp +@@ -337,33 +337,63 @@ void DecodeTrace::draw_annotations(vector annotati + using namespace pv::data::decode; + + vector a_block; +- int prev_ann_pos = INT_MIN; ++ int p_end = INT_MIN; + + double samples_per_pixel, pixels_offset; + tie(pixels_offset, samples_per_pixel) = + get_pixels_offset_samples_per_pixel(); + ++ // Sort the annotations by start sample so that decoders ++ // can't confuse us by creating annotations out of order ++ stable_sort(annotations.begin(), annotations.end(), ++ [](const Annotation &a, const Annotation &b) { ++ return a.start_sample() < b.start_sample(); }); ++ + // Gather all annotations that form a visual "block" and draw them as such + for (const Annotation &a : annotations) { + +- const int end = a.end_sample() / samples_per_pixel - pixels_offset; +- const int delta = end - prev_ann_pos; ++ const int a_start = a.start_sample() / samples_per_pixel - pixels_offset; ++ const int a_end = a.end_sample() / samples_per_pixel - pixels_offset; ++ const int a_width = a_end - a_start; ++ ++ const int delta = a_end - p_end; ++ ++ bool a_is_separate = false; ++ ++ // Annotation wider than the threshold for a useful label width? ++ if (a_width > 20) { ++ for (const QString &ann_text : a.annotations()) { ++ const int w = p.boundingRect(QRectF(), 0, ann_text).width(); ++ // Annotation wide enough to fit a label? Don't put it in a block then ++ if (w <= a_width) { ++ a_is_separate = true; ++ break; ++ } ++ } ++ } + +- // Some annotations are in reverse order, so we cannot +- // simply check for delta > 1 +- if (abs(delta) > 1) { +- // Block was broken, draw it +- if (a_block.size() == 1) ++ // Were the previous and this annotation more than a pixel apart? ++ if ((abs(delta) > 1) || a_is_separate) { ++ // Block was broken, draw annotations that form the current block ++ if (a_block.size() == 1) { + draw_annotation(a_block.front(), p, h, pp, y, base_colour); ++ } + else +- if (a_block.size() > 0) +- draw_annotation_block(a_block, p, h, y, base_colour); ++ draw_annotation_block(a_block, p, h, y, base_colour); + + a_block.clear(); + } + +- a_block.push_back(a); +- prev_ann_pos = end; ++ if (a_is_separate) { ++ draw_annotation(a, p, h, pp, y, base_colour); ++ // Next annotation must start a new block. delta will be > 1 ++ // because we set p_end to INT_MIN but that's okay since ++ // a_block will be empty, so nothing will be drawn ++ p_end = INT_MIN; ++ } else { ++ a_block.push_back(a); ++ p_end = a_end; ++ } + } + + if (a_block.size() == 1) +@@ -404,6 +434,9 @@ void DecodeTrace::draw_annotation_block( + { + using namespace pv::data::decode; + ++ if (annotations.empty()) ++ return; ++ + double samples_per_pixel, pixels_offset; + tie(pixels_offset, samples_per_pixel) = + get_pixels_offset_samples_per_pixel(); +-- +2.4.3 + diff --git a/0007-DecodeTrace-Try-to-keep-annotation-labels-within-the.patch b/0007-DecodeTrace-Try-to-keep-annotation-labels-within-the.patch new file mode 100644 index 0000000..d972e43 --- /dev/null +++ b/0007-DecodeTrace-Try-to-keep-annotation-labels-within-the.patch @@ -0,0 +1,72 @@ +From 7352be721b90b630efd742b53e1a0ea16bb834b8 Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Thu, 4 Feb 2016 22:38:34 +0100 +Subject: [PATCH 07/13] DecodeTrace: Try to keep annotation labels within the + view + +Up until now, annotation labels were always drawn centered, +even if the annotation was very wide and mostly off-screen. +This resulted in annotation labels being out of view, even +if there would be enough space to draw it within the view. +This patch fixes this. +--- + pv/view/decodetrace.cpp | 15 +++++++++++---- + pv/view/decodetrace.hpp | 2 +- + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp +index e7ffbbb..eb1f7f8 100644 +--- a/pv/view/decodetrace.cpp ++++ b/pv/view/decodetrace.cpp +@@ -425,7 +425,7 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, + if (a.start_sample() == a.end_sample()) + draw_instant(a, p, fill, outline, h, start, y); + else +- draw_range(a, p, fill, outline, h, start, end, y); ++ draw_range(a, p, fill, outline, h, start, end, y, pp); + } + + void DecodeTrace::draw_annotation_block( +@@ -485,7 +485,7 @@ void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter & + + void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, int h, double start, +- double end, int y) const ++ double end, int y, const ViewItemPaintParams &pp) const + { + const double top = y + .5 - h / 2; + const double bottom = y + .5 + h / 2; +@@ -516,8 +516,15 @@ void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, + if (annotations.empty()) + return; + +- QRectF rect(start + cap_width, y - h / 2, +- end - start - cap_width * 2, h); ++ const int ann_start = start + cap_width; ++ const int ann_end = end - cap_width; ++ ++ const int real_start = std::max(ann_start, pp.left()); ++ const int real_end = std::min(ann_end, pp.right()); ++ ++ const int real_width = real_end - real_start; ++ ++ QRectF rect(real_start, y - h / 2, real_width, h); + if (rect.width() <= 4) + return; + +diff --git a/pv/view/decodetrace.hpp b/pv/view/decodetrace.hpp +index 4964a95..af91518 100644 +--- a/pv/view/decodetrace.hpp ++++ b/pv/view/decodetrace.hpp +@@ -141,7 +141,7 @@ private: + + void draw_range(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, int h, double start, +- double end, int y) const; ++ double end, int y, const ViewItemPaintParams &pp) const; + + void draw_error(QPainter &p, const QString &message, + const ViewItemPaintParams &pp); +-- +2.4.3 + diff --git a/0008-DecodeTrace-Let-annotation-labels-be-pushed-aside-by.patch b/0008-DecodeTrace-Let-annotation-labels-be-pushed-aside-by.patch new file mode 100644 index 0000000..712fa19 --- /dev/null +++ b/0008-DecodeTrace-Let-annotation-labels-be-pushed-aside-by.patch @@ -0,0 +1,174 @@ +From aee9dcf34d3bb5bf53803d3e132ae69475e434b7 Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Thu, 4 Feb 2016 22:39:07 +0100 +Subject: [PATCH 08/13] DecodeTrace: Let annotation labels be pushed aside by + the row title + +--- + pv/view/decodetrace.cpp | 35 +++++++++++++++++++++++++---------- + pv/view/decodetrace.hpp | 9 ++++++--- + 2 files changed, 31 insertions(+), 13 deletions(-) + +diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp +index eb1f7f8..6f00a45 100644 +--- a/pv/view/decodetrace.cpp ++++ b/pv/view/decodetrace.cpp +@@ -86,6 +86,7 @@ const QColor DecodeTrace::NoDecodeColour = QColor(0x88, 0x8A, 0x85); + + const int DecodeTrace::ArrowSize = 4; + const double DecodeTrace::EndCapWidth = 5; ++const int DecodeTrace::RowTitleMargin = 10; + const int DecodeTrace::DrawPadding = 100; + + const QColor DecodeTrace::Colours[16] = { +@@ -201,6 +202,18 @@ void DecodeTrace::paint_mid(QPainter &p, const ViewItemPaintParams &pp) + for (size_t i = 0; i < rows.size(); i++) { + const Row &row = rows[i]; + ++ // Cache the row title widths ++ int row_title_width; ++ try { ++ row_title_width = row_title_widths_.at(row); ++ } catch (std::out_of_range) { ++ const int w = p.boundingRect(QRectF(), 0, row.title()).width() + ++ RowTitleMargin; ++ row_title_widths_[row] = w; ++ row_title_width = w; ++ } ++ ++ // Determine the row's color + size_t base_colour = 0x13579BDF; + boost::hash_combine(base_colour, this); + boost::hash_combine(base_colour, row.decoder()); +@@ -212,7 +225,7 @@ void DecodeTrace::paint_mid(QPainter &p, const ViewItemPaintParams &pp) + sample_range.first, sample_range.second); + if (!annotations.empty()) { + draw_annotations(annotations, p, annotation_height, pp, y, +- base_colour); ++ base_colour, row_title_width); + + y += row_height_; + +@@ -332,7 +345,7 @@ QMenu* DecodeTrace::create_context_menu(QWidget *parent) + + void DecodeTrace::draw_annotations(vector annotations, + QPainter &p, int h, const ViewItemPaintParams &pp, int y, +- size_t base_colour) ++ size_t base_colour, int row_title_width) + { + using namespace pv::data::decode; + +@@ -376,7 +389,8 @@ void DecodeTrace::draw_annotations(vector annotati + if ((abs(delta) > 1) || a_is_separate) { + // Block was broken, draw annotations that form the current block + if (a_block.size() == 1) { +- draw_annotation(a_block.front(), p, h, pp, y, base_colour); ++ draw_annotation(a_block.front(), p, h, pp, y, base_colour, ++ row_title_width); + } + else + draw_annotation_block(a_block, p, h, y, base_colour); +@@ -385,7 +399,7 @@ void DecodeTrace::draw_annotations(vector annotati + } + + if (a_is_separate) { +- draw_annotation(a, p, h, pp, y, base_colour); ++ draw_annotation(a, p, h, pp, y, base_colour, row_title_width); + // Next annotation must start a new block. delta will be > 1 + // because we set p_end to INT_MIN but that's okay since + // a_block will be empty, so nothing will be drawn +@@ -397,14 +411,15 @@ void DecodeTrace::draw_annotations(vector annotati + } + + if (a_block.size() == 1) +- draw_annotation(a_block.front(), p, h, pp, y, base_colour); ++ draw_annotation(a_block.front(), p, h, pp, y, base_colour, ++ row_title_width); + else + draw_annotation_block(a_block, p, h, y, base_colour); + } + + void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, + QPainter &p, int h, const ViewItemPaintParams &pp, int y, +- size_t base_colour) const ++ size_t base_colour, int row_title_width) const + { + double samples_per_pixel, pixels_offset; + tie(pixels_offset, samples_per_pixel) = +@@ -425,7 +440,8 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, + if (a.start_sample() == a.end_sample()) + draw_instant(a, p, fill, outline, h, start, y); + else +- draw_range(a, p, fill, outline, h, start, end, y, pp); ++ draw_range(a, p, fill, outline, h, start, end, y, pp, ++ row_title_width); + } + + void DecodeTrace::draw_annotation_block( +@@ -485,7 +501,7 @@ void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter & + + void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, int h, double start, +- double end, int y, const ViewItemPaintParams &pp) const ++ double end, int y, const ViewItemPaintParams &pp, int row_title_width) const + { + const double top = y + .5 - h / 2; + const double bottom = y + .5 + h / 2; +@@ -519,9 +535,8 @@ void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, + const int ann_start = start + cap_width; + const int ann_end = end - cap_width; + +- const int real_start = std::max(ann_start, pp.left()); ++ const int real_start = std::max(ann_start, pp.left() + row_title_width); + const int real_end = std::min(ann_end, pp.right()); +- + const int real_width = real_end - real_start; + + QRectF rect(real_start, y - h / 2, real_width, h); +diff --git a/pv/view/decodetrace.hpp b/pv/view/decodetrace.hpp +index af91518..fb14ae0 100644 +--- a/pv/view/decodetrace.hpp ++++ b/pv/view/decodetrace.hpp +@@ -77,6 +77,7 @@ private: + + static const int ArrowSize; + static const double EndCapWidth; ++ static const int RowTitleMargin; + static const int DrawPadding; + + static const QColor Colours[16]; +@@ -127,11 +128,11 @@ public: + private: + void draw_annotations(std::vector annotations, + QPainter &p, int h, const ViewItemPaintParams &pp, int y, +- size_t base_colour); ++ size_t base_colour, int row_title_width); + + void draw_annotation(const pv::data::decode::Annotation &a, QPainter &p, + int text_height, const ViewItemPaintParams &pp, int y, +- size_t base_colour) const; ++ size_t base_colour, int row_title_width) const; + + void draw_annotation_block(std::vector a, + QPainter &p, int h, int y, size_t base_colour) const; +@@ -141,7 +142,8 @@ private: + + void draw_range(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, int h, double start, +- double end, int y, const ViewItemPaintParams &pp) const; ++ double end, int y, const ViewItemPaintParams &pp, ++ int row_title_width) const; + + void draw_error(QPainter &p, const QString &message, + const ViewItemPaintParams &pp); +@@ -206,6 +208,7 @@ private: + std::vector decoder_forms_; + + std::vector visible_rows_; ++ std::map row_title_widths_; + int row_height_, max_visible_rows_; + + QSignalMapper delete_mapper_, show_hide_mapper_; +-- +2.4.3 + diff --git a/0009-DecodeTrace-Remove-unnecessary-parameters.patch b/0009-DecodeTrace-Remove-unnecessary-parameters.patch new file mode 100644 index 0000000..a802698 --- /dev/null +++ b/0009-DecodeTrace-Remove-unnecessary-parameters.patch @@ -0,0 +1,93 @@ +From f765c3db91d60e9b038ee05f2fa6acc8587d8470 Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Thu, 4 Feb 2016 22:39:35 +0100 +Subject: [PATCH 09/13] DecodeTrace: Remove unnecessary parameters + +--- + pv/view/decodetrace.cpp | 19 +++++++------------ + pv/view/decodetrace.hpp | 5 ++--- + 2 files changed, 9 insertions(+), 15 deletions(-) + +diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp +index 6f00a45..95e0e5e 100644 +--- a/pv/view/decodetrace.cpp ++++ b/pv/view/decodetrace.cpp +@@ -431,16 +431,16 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, + pixels_offset; + + const size_t colour = (base_colour + a.format()) % countof(Colours); +- const QColor &fill = Colours[colour]; +- const QColor &outline = OutlineColours[colour]; ++ p.setPen(OutlineColours[colour]); ++ p.setBrush(Colours[colour]); + + if (start > pp.right() + DrawPadding || end < pp.left() - DrawPadding) + return; + + if (a.start_sample() == a.end_sample()) +- draw_instant(a, p, fill, outline, h, start, y); ++ draw_instant(a, p, h, start, y); + else +- draw_range(a, p, fill, outline, h, start, end, y, pp, ++ draw_range(a, p, h, start, end, y, pp, + row_title_width); + } + +@@ -483,7 +483,7 @@ void DecodeTrace::draw_annotation_block( + } + + void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter &p, +- QColor fill, QColor outline, int h, double x, int y) const ++ int h, double x, int y) const + { + const QString text = a.annotations().empty() ? + QString() : a.annotations().back(); +@@ -491,8 +491,6 @@ void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter & + 0.0) + h; + const QRectF rect(x - w / 2, y - h / 2, w, h); + +- p.setPen(outline); +- p.setBrush(fill); + p.drawRoundedRect(rect, h / 2, h / 2); + + p.setPen(Qt::black); +@@ -500,16 +498,13 @@ void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter & + } + + void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, +- QColor fill, QColor outline, int h, double start, +- double end, int y, const ViewItemPaintParams &pp, int row_title_width) const ++ int h, double start, double end, int y, const ViewItemPaintParams &pp, ++ int row_title_width) const + { + const double top = y + .5 - h / 2; + const double bottom = y + .5 + h / 2; + const vector annotations = a.annotations(); + +- p.setPen(outline); +- p.setBrush(fill); +- + // If the two ends are within 1 pixel, draw a vertical line + if (start + 1.0 > end) { + p.drawLine(QPointF(start, top), QPointF(start, bottom)); +diff --git a/pv/view/decodetrace.hpp b/pv/view/decodetrace.hpp +index fb14ae0..eb011e7 100644 +--- a/pv/view/decodetrace.hpp ++++ b/pv/view/decodetrace.hpp +@@ -138,11 +138,10 @@ private: + QPainter &p, int h, int y, size_t base_colour) const; + + void draw_instant(const pv::data::decode::Annotation &a, QPainter &p, +- QColor fill, QColor outline, int h, double x, int y) const; ++ int h, double x, int y) const; + + void draw_range(const pv::data::decode::Annotation &a, QPainter &p, +- QColor fill, QColor outline, int h, double start, +- double end, int y, const ViewItemPaintParams &pp, ++ int h, double start, double end, int y, const ViewItemPaintParams &pp, + int row_title_width) const; + + void draw_error(QPainter &p, const QString &message, +-- +2.4.3 + diff --git a/0010-MainWindow-Try-to-use-any-available-device-aside-fro.patch b/0010-MainWindow-Try-to-use-any-available-device-aside-fro.patch new file mode 100644 index 0000000..950137e --- /dev/null +++ b/0010-MainWindow-Try-to-use-any-available-device-aside-fro.patch @@ -0,0 +1,60 @@ +From b926e4eeef6db657601ebd4bbededdf9d329cdd6 Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Sat, 6 Feb 2016 18:07:05 +0100 +Subject: [PATCH 10/13] MainWindow: Try to use any available device aside from + demo + +Currently, PV will only try to use the previously used device. +However, when first running PV, it will default to demo as +there is no previously used device. In this case, we still +want to use whatever device we can get our hands on so that +the user can start using PV immediately. +--- + pv/mainwindow.cpp | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) + +diff --git a/pv/mainwindow.cpp b/pv/mainwindow.cpp +index 912ed60..6507133 100644 +--- a/pv/mainwindow.cpp ++++ b/pv/mainwindow.cpp +@@ -567,8 +567,9 @@ void MainWindow::select_init_device() + QSettings settings; + map dev_info; + list key_list; ++ shared_ptr device; + +- // Re-select last used device if possible. ++ // Re-select last used device if possible but only if it's not demo + settings.beginGroup("Device"); + key_list.push_back("vendor"); + key_list.push_back("model"); +@@ -586,8 +587,24 @@ void MainWindow::select_init_device() + dev_info.insert(std::make_pair(key, value)); + } + +- const shared_ptr device = +- device_manager_.find_device_from_info(dev_info); ++ if (dev_info.count("model") > 0) ++ if (dev_info.at("model").find("Demo device") == std::string::npos) ++ device = device_manager_.find_device_from_info(dev_info); ++ ++ // When we can't find a device similar to the one we used last ++ // time and there is at least one device aside from demo, use it ++ if (!device) { ++ for (shared_ptr dev : device_manager_.devices()) { ++ dev_info = device_manager_.get_device_info(dev); ++ ++ if (dev_info.count("model") > 0) ++ if (dev_info.at("model").find("Demo device") == std::string::npos) { ++ device = dev; ++ break; ++ } ++ } ++ } ++ + select_device(device); + update_device_list(); + +-- +2.4.3 + diff --git a/0011-DecoderStack-Make-decoder-sessions-terminate-after-r.patch b/0011-DecoderStack-Make-decoder-sessions-terminate-after-r.patch new file mode 100644 index 0000000..9c07d61 --- /dev/null +++ b/0011-DecoderStack-Make-decoder-sessions-terminate-after-r.patch @@ -0,0 +1,55 @@ +From cc10c40992278034a7d7648d34f19ff6743710db Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Tue, 9 Feb 2016 11:58:36 +0100 +Subject: [PATCH 11/13] DecoderStack: Make decoder sessions terminate after + running + +Currently, SRD sessions aren't terminating after all data +has been decoded, leaving the decode thread in a state +where it's waiting for more data. +This would be okay if an acquisition was still ongoing but +when the acquisition has been stopped, there will never be +more data. When a new acquisition is started, the previous +decode sessions will be terminated and then new ones will +be started. This is the reason why this behavior wasn't +an issue up until now. + +However, the fix for #181 requires that the decode thread +terminates or else the global SRD lock will never be +released. +--- + pv/data/decoderstack.cpp | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/pv/data/decoderstack.cpp b/pv/data/decoderstack.cpp +index 2668df2..51d4bae 100644 +--- a/pv/data/decoderstack.cpp ++++ b/pv/data/decoderstack.cpp +@@ -282,11 +282,22 @@ uint64_t DecoderStack::max_sample_count() const + optional DecoderStack::wait_for_data() const + { + unique_lock input_lock(input_mutex_); ++ ++ // Do wait if we decoded all samples but we're still capturing ++ // Do not wait if we're done capturing + while (!interrupt_ && !frame_complete_ && +- samples_decoded_ >= sample_count_) ++ (samples_decoded_ >= sample_count_) && ++ (session_.get_capture_state() != Session::Stopped)) { ++ + input_cond_.wait(input_lock); ++ } ++ ++ // Return value is valid if we're not aborting the decode, + return boost::make_optional(!interrupt_ && +- (samples_decoded_ < sample_count_ || !frame_complete_), ++ // and there's more work to do... ++ (samples_decoded_ < sample_count_ || !frame_complete_) && ++ // and if the end of the data hasn't been reached yet ++ (!((samples_decoded_ >= sample_count_) && (session_.get_capture_state() == Session::Stopped))), + sample_count_); + } + +-- +2.4.3 + diff --git a/0012-Fix-181-by-changing-the-global-decode-lock-into-an-S.patch b/0012-Fix-181-by-changing-the-global-decode-lock-into-an-S.patch new file mode 100644 index 0000000..9544ac0 --- /dev/null +++ b/0012-Fix-181-by-changing-the-global-decode-lock-into-an-S.patch @@ -0,0 +1,78 @@ +From a1a3656b4e18cb9fc078a51bf4256066ee307620 Mon Sep 17 00:00:00 2001 +From: Soeren Apel +Date: Tue, 9 Feb 2016 14:48:31 +0100 +Subject: [PATCH 12/13] Fix #181 by changing the global decode lock into an SRD + lock + +The global decode was insufficient insofar as it didn't +prevent a newly started decode thread from interjecting its +own decode operations. When this happens, something goes +haywire somewhere and Python crashes. + +Until the underlying cause is fixed, this global SRD lock +forces one decoder thread to finish before another one can +start. + +While this is a bit inconvenient for wanting to decode as +the acquisition is going on, it currently is the only +working option. +--- + pv/data/decoderstack.cpp | 6 ++++-- + pv/data/decoderstack.hpp | 8 ++++---- + 2 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/pv/data/decoderstack.cpp b/pv/data/decoderstack.cpp +index 51d4bae..5935473 100644 +--- a/pv/data/decoderstack.cpp ++++ b/pv/data/decoderstack.cpp +@@ -57,7 +57,7 @@ const double DecoderStack::DecodeThreshold = 0.2; + const int64_t DecoderStack::DecodeChunkLength = 4096; + const unsigned int DecoderStack::DecodeNotifyPeriod = 65536; + +-mutex DecoderStack::global_decode_mutex_; ++mutex DecoderStack::global_srd_mutex_; + + DecoderStack::DecoderStack(pv::Session &session, + const srd_decoder *const dec) : +@@ -312,7 +312,6 @@ void DecoderStack::decode_data( + + for (int64_t i = 0; !interrupt_ && i < sample_count; + i += chunk_sample_count) { +- lock_guard decode_lock(global_decode_mutex_); + + const int64_t chunk_end = min( + i + chunk_sample_count, sample_count); +@@ -344,6 +343,9 @@ void DecoderStack::decode_proc() + + assert(segment_); + ++ // Prevent any other decode threads from accessing libsigrokdecode ++ lock_guard srd_lock(global_srd_mutex_); ++ + // Create the session + srd_session_new(&session); + assert(session); +diff --git a/pv/data/decoderstack.hpp b/pv/data/decoderstack.hpp +index 64ce13b..e2bf1bd 100644 +--- a/pv/data/decoderstack.hpp ++++ b/pv/data/decoderstack.hpp +@@ -140,12 +140,12 @@ private: + double samplerate_; + + /** +- * This mutex prevents more than one decode operation occuring +- * concurrently. ++ * This mutex prevents more than one thread from accessing ++ * libsigrokdecode concurrently. + * @todo A proper solution should be implemented to allow multiple +- * decode operations. ++ * decode operations in parallel. + */ +- static std::mutex global_decode_mutex_; ++ static std::mutex global_srd_mutex_; + + std::list< std::shared_ptr > stack_; + +-- +2.4.3 + diff --git a/pulseview.spec b/pulseview.spec index 3dfcaf0..354d14c 100644 --- a/pulseview.spec +++ b/pulseview.spec @@ -1,12 +1,28 @@ Name: pulseview Version: 0.3.0 -Release: 0%{?dist} +Release: 1%{?dist} Summary: Signal acquisition and analysis GUI for sigrok # Combined GPLv3+ (libsigrok and libsigrokdecode) and GPLv2+ (pulseview) License: GPLv3+ URL: http://www.sigrok.org Source0: %{url}/download/source/%{name}/%{name}-%{version}.tar.gz - +# Zero-day patches after 0.3.0 release. Extract using: +# $ git clone git://sigrok.org/pulseview.git +# $ cd pulseview +# $ git checkout a1a3656b4e18cb9fc078a51bf4256066ee307620 +# $ git format-patch pulseview-0.3.0 +Patch0: 0001-View-Honor-ENABLE_DECODE-compiler-switch.patch +Patch1: 0002-Fix-733-Open-import-files-using-binary-mode.patch +Patch2: 0003-Fix-unit-tests-and-prevent-warnings.patch +Patch3: 0004-Fix-737-by-adding-the-override-specifier-where-neede.patch +Patch4: 0005-Fix-clang-warning-shifting-a-negative-signed-value-i.patch +Patch5: 0006-Fix-745-by-improving-the-draw_annotations-block-draw.patch +Patch6: 0007-DecodeTrace-Try-to-keep-annotation-labels-within-the.patch +Patch7: 0008-DecodeTrace-Let-annotation-labels-be-pushed-aside-by.patch +Patch8: 0009-DecodeTrace-Remove-unnecessary-parameters.patch +Patch9: 0010-MainWindow-Try-to-use-any-available-device-aside-fro.patch +Patch10: 0011-DecoderStack-Make-decoder-sessions-terminate-after-r.patch +Patch11: 0012-Fix-181-by-changing-the-global-decode-lock-into-an-S.patch BuildRequires: libsigrok-cxx-devel BuildRequires: libsigrokdecode-devel >= 0.4.0 BuildRequires: qt-devel @@ -24,8 +40,7 @@ libraries under the hood. %prep -%setup -q - +%autosetup -p1 %build %cmake -DCMAKE_BUILD_TYPE=Release @@ -57,13 +72,18 @@ update-desktop-database > /dev/null 2>&1 || : /usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %files -%doc README COPYING +%doc README +%license COPYING %{_mandir}/man1/%{name}.1* %{_bindir}/%{name} %{_datadir}/applications/%{name}.desktop %{_datadir}/icons/hicolor/48x48/apps/sigrok-logo-notext.png %changelog +* Sat Feb 13 2016 Till Maas - 0.3.0-1 +- Bring in zero-day upstream patches that fix build issues +- Use "license" macro instead of "doc" for COPYING + * Sat Feb 06 2016 Alexandru Gagniuc - 0.3.0-0 - Update to pulseview 0.3.0 - Bump libsigrokdecode-devel requirement to 0.4.0