GNOME Bugzilla – Bug 109832
Lines' points change without warning
Last modified: 2014-08-02 12:48:30 UTC
Oops.. sorry about the above. I'm making an application with Gnome::Canvas, and I construct lines whose endpoints have the potential to move. So in one event handler, I do: Gnome::Canvas::Points points; points.push_back(Gnome::Art::Point(startx,starty)); points.push_back(Gnome::Art::Point(event->button.x, event->button.y)); Gnome::Canvas::Line * line = manage(new Gnome::Canvas::Line(*tmpgrp->get_canvas()->root(), points)); (*i)->lines.push_back(line); (This is done twice -- two lines are constructed at different points.) Then, in another event handler, I do this: points.push_back(p->lines[i]->property_points().get_value()[0]); points.push_back(p->lines[i]->property_points().get_value()[1]); points[!p->lines_start_here[i]] += Gnome::Art::Point(event->button.x - oldx, event->button.y - oldy); p->lines[i]->property_points().set_value(points); In other words, what I'm trying to do is make another Gnome::Canvas::Points, and alter one of the points, and then set the line's points to the altered point. But what I'm finding is that by the time I get to the first line to move it, the endpoints have already changed -- specifically, the second endpoint changes to the second endpoint of the second line. Does anyone have any ideas? I can send you the source code of the entire project, if you like.
A simple-as-possible test case might make this clearer.
OK. Here's a simple program that tries to do the same thing. It's 113 lines. #include <libgnomecanvasmm/canvas.h> #include <libgnomecanvasmm/init.h> #include <libgnomecanvasmm/line.h> #include <libgnomecanvasmm/rect.h> #include <gtkmm/window.h> #include <gtkmm/main.h> #include <iostream> #include <vector> using std::vector; using std::endl; using std::cout; class Simpletest: public Gtk::Window { public: Simpletest(); protected: vector<Gnome::Canvas::Line*> lines; Gnome::Canvas::Canvas * canvas; bool on_item_event(GdkEvent* event); }; Simpletest::Simpletest(){ canvas = manage(new Gnome::Canvas::Canvas()); add(*canvas); canvas->set_flags(Gtk::CAN_FOCUS); canvas->set_size_request(600, 400); canvas->set_center_scroll_region(false); Gnome::Canvas::Rect* rect = manage(new Gnome::Canvas::Rect(*canvas->root())); rect->property_x1() = 0.0; rect->property_y1() = 0.0; rect->property_x2() = 600.0; rect->property_y2() = 400.0; rect->property_fill_color_rgba() = 0x10308000; Gnome::Canvas::Points points; points.push_back(Gnome::Art::Point(100, 100)); points.push_back(Gnome::Art::Point(200, 200)); Gnome::Canvas::Line * line = manage(new Gnome::Canvas::Line(*canvas->root(), points)); lines.push_back(line); points[0] = Gnome::Art::Point(100, 200); points[1] = Gnome::Art::Point(200, 100); line = manage(new Gnome::Canvas::Line(*canvas->root(), points)); lines.push_back(line); rect->signal_event() .connect(slot(*this, &Simpletest::on_item_event)); canvas->update_now(); show_all(); cout << lines[0]->property_points().get_value().size() << endl; cout << lines[0]->property_points().get_value()[1].get_y() << endl; } bool Simpletest::on_item_event(GdkEvent * event){ static double startx, starty; static double oldx, oldy; static int button; static bool dragging; // cout << p->labelstring << endl; switch(event->type){ case GDK_BUTTON_PRESS: startx = event->button.x; starty = event->button.y; oldx = startx; oldy = starty; button = event->button.button; return true; break; case GDK_MOTION_NOTIFY: if(button == 1){ dragging = true; for(int i = 0; i < lines.size(); i++){ Gnome::Canvas::Points points; points.push_back(lines[i]->property_points().get_value()[0]); points.push_back(lines[i]->property_points().get_value()[1]); //points.push_back(p->lines[i]->property_points().get_value()[2]); cout << lines[i]->property_points().get_value().size() << endl; cout << points[0].get_x() << ", " << points[0].get_y() << " -> " << points[1].get_x() << ", " << points[1].get_y() << " Delta: " << event->button.x - oldx << ", " << event->button.y - oldy << endl; points[0] += Gnome::Art::Point(event->button.x - oldx, event->button.y - oldy); // cout << points.size() << endl; cout << points[0].get_x() << ", " << points[0].get_y() << " -> " << points[1].get_x() << ", " << points[1].get_y() << endl; lines[i]->property_points().set_value(points); } canvas->update_now(); cout << endl; oldx = event->button.x; oldy = event->button.y; } return true; break; case GDK_BUTTON_RELEASE: button = 0; return true; break; } return false; } int main(int argc, char * argv[]){ Gnome::Canvas::init(); Gtk::Main app(argc, argv); Simpletest sbw; app.run(sbw); return 0; } What I think should happen: The first line should print out 2. That is the first cout -- it happens at the end of the Simpletest constructor. The line.property_points().get_value() should be a vector of two points, shouldn't it? Maybe I misinterpreted the function names. The second line should be 200. lines[0] is the first line pointer, constructed from (100, 100) to (200, 200). lines[0]->property_points.get_value()[1] should be the second Gnome::Art::Point, (200, 200). Thus, the y coord should be 200. Click the blue rectangle and move it around. The lines move -- but IMMEDIATELY the first line relocates its second point to be the same as the second line's second point. This is the phenomenon I'm getting. The output shows each line's endpoints before and after the move (delta is how much they should move by). It is entirely possible that I wrote bad code.
OK, I just cut and pasted the first cout statement to right after line is created, and right after it has been pushed back, and it stays the same (not 200). Neither is it 200 if I change it to get_x(). So I'm obviously missing the point. line->property_points() returns PropertyProxy<Gnome::Canvas::Points>. line->property_points().get_value() should return Gnome::Canvas::Points, which is essentially a std::vector. Thus, when I create a line with a Gnome::Canvas::Points with two points in it, that vector should be size two, with those two points at vector[0] and vector[1]. line->property_points().get_value()[1] should be one of those points -- Gnome::Art::Point -- the second endpoint. (line->property_points().get_value()[0] remains (100, 100)) line->property_points().get_value()[1].get_y() should be the y-coord of the second endpoint of the line. Which parts of the above are wrong?
I have not read this yet. In future, please _attach_ test cases so things remain readable.
We need to investigate what happens in this set_property() line in the Gnome::Canvas::Line constructor: http://cvs.gnome.org/lxr/source/gnomemm/libgnomecanvasmm/libgnomecanvas/src/line.ccg#103
Created attachment 18494 [details] lines.cc
The attached version of the test case (lines.cc) shows the problem more clearly. It looks like GnomeCanvasLine does not take a copy of the points data, but just remembers the pointer. So in the first example you are changing data that is still used by another Line, and in my version it segfaults because the pointer is orphaned. We should probably either - Mark this as a libgnomecanvas bug. or - Document it.
We could also add a member variable to store our own copy, but that would break ABI.
The last libgnomecanvasmm code changes took place in 2008: https://git.gnome.org/browse/archive/libgnomecanvasmm/log/ This project is not under active development anymore. This project got recently archived in GNOME Git. It is currently unlikely that there will be any further active development. Closing this report as WONTFIX as part of Bugzilla Housekeeping to reflect reality. Please feel free to reopen this bug report in the future if anyone takes the responsibility for active development again.