GNOME Bugzilla – Bug 635961
'notify' signal does not fire often enough
Last modified: 2011-01-12 03:05:46 UTC
My application provides a crosshair that displays directly at map center, and a text label that displays the map center coordinates. Obviously, these two items need to be updated frequently to stay accurate (if the stage changes it's size due to a user resize event, I need to reposition the crosshair, and if the user moves the map view, I need to update the coordinates). Up until now, I have naively been connecting to the 'paint' signal to do both of these things, since that seemed like the only way to update as frequently as possible, and there were never any problems. However, I recently learned about the 'notify' signal (which was quite well hidden in the GTK documentation), and I thought it would be a good way to reduce the number of calls to my signal handlers without letting the display go stale. So, for starters, this worked like a charm: self.stage.connect('notify::height', self.position_crosshair) self.stage.connect('notify::width', self.position_crosshair) It had exactly the intended result. The crosshair only updates it's position when it needs to, and not "constantly all the time always." The problem I'm having is with my latitude/longitude label. This mostly works as expected: self.map_view.connect('notify::latitude', self.display_coords) self.map_view.connect('notify::longitude', self.display_coords) But the precision is terrible! If I do one long click+drag on the map, the signal fires every 100m or so, but it's actually possible to make a series of short drags to move a great distance before the signal fires. I was able to move almost an entire kilometer before it fired, just by moving in very small increments. Playing with this a bit, I realize that the same problem existed before when I was connected to the 'paint' signal handler, I just didn't notice it then. The label was updating with a furious frequency, but it was just setting the same imprecise value over and over until a minimum threshhold of movement was achieved. This bug also affects the behavior of ChamplainView.get_coords_at(x, y). I implemented a method to move the map view using arrow keys that looks like this: x = self.map_view.get_width() / 2 y = self.map_view.get_height() / 2 # moves by 1/5 (40% of half) screen length in the given direction if keyval == Gdk.keyval_from_name("Left"): x *= 0.6 elif keyval == Gdk.keyval_from_name("Up"): y *= 0.6 elif keyval == Gdk.keyval_from_name("Right"): x *= 1.4 elif keyval == Gdk.keyval_from_name("Down"): y *= 1.4 lat, lon = self.map_view.get_coords_at(int(x), int(y))[1:3] if self.valid_coords(lat, lon): self.map_view.center_on(lat, lon) This code works as intended, but if I want to make shorter, more precise movements, what'll happen is that the map view doesn't move by a large enough amount to trigger the notify signal, and so even if the map view has moved, get_coords_at will give stale results (eg, results as if the map hadn't moved previously). The effect of this is that the method works once, but then if you try to move in the same direction again, it doesn't go anywhere, and if you try to move in a different direction, it's as if you jump back to the starting point and then move relatively to there. I haven't tested terribly thoroughly to figure out exactly what the threshold is, but I can if you want me to. My only suggestion for a solution is that if you need to limit the number of times that the notify signal fires, limit it by time rather than distance. Limit it to maybe 10 times per second or so, that way even if only a subtle movement is made, my map label and get_coords_at can both be more accurate. Thanks.
Had a look at this again and it seems to be fixed in latest git. I can't remember who it was on the mailing list who said they were working on this, but thanks!
Oooooh, commit 4d86199 makes this even better! Thanks Jiri! ;-)
(In reply to comment #1) > Had a look at this again and it seems to be fixed in latest git. I can't > remember who it was on the mailing list who said they were working on this, but > thanks! Well, at the time you wrote this there was no fix committed ;-). I hope the current implementation is precise enough - while panning, you should get at least 4 signals a second and there should be an additional signal fired when panning stops.
Hahah, I'm not crazy I swear! ;-) The current behavior is excellent Jiri. It fires immediately and it fires with (at least) 0.00001 degree precision, which means that my little coordinate label actor smoothly displays updates down to it's lowest degree of precision, which is the best that I could possibly ask for. Thanks again!