After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 635961 - 'notify' signal does not fire often enough
'notify' signal does not fire often enough
Status: RESOLVED FIXED
Product: libchamplain
Classification: Core
Component: view
0.6.x
Other Linux
: Normal normal
: ---
Assigned To: libchamplain-maint
libchamplain-maint
Depends on:
Blocks:
 
 
Reported: 2010-11-28 00:09 UTC by Robert Bruce Park
Modified: 2011-01-12 03:05 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Robert Bruce Park 2010-11-28 00:09:09 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.
Comment 1 Robert Bruce Park 2011-01-05 17:28:01 UTC
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!
Comment 2 Robert Bruce Park 2011-01-09 07:40:08 UTC
Oooooh, commit 	4d86199 makes this even better! Thanks Jiri! ;-)
Comment 3 Jiri Techet 2011-01-10 22:23:15 UTC
(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.
Comment 4 Robert Bruce Park 2011-01-12 03:05:46 UTC
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!