Fixed indeterminate progress bars on GTK+. This specific fix also avoids any future panics caused by Go and GTK+ racing by doing the pulsing all on GTK+.

This commit is contained in:
Pietro Gagliardi 2014-07-01 13:47:23 -04:00
parent e04e5f5cad
commit 2a7152339f
1 changed files with 22 additions and 42 deletions

View File

@ -5,10 +5,11 @@
package ui
import (
"time"
"unsafe"
)
// #include "gtk_unix.h"
// extern gboolean our_pulse_callback(gpointer);
import "C"
type sysData struct {
@ -16,7 +17,7 @@ type sysData struct {
widget *C.GtkWidget
container *C.GtkWidget // for moving
pulse chan bool // for sysData.progressPulse()
pulseTimer C.guint // for indeterminate progress bars
clickCounter clickCounter // for Areas
// we probably don't need to save these, but we'll do so for sysData.preferredSize() just in case
areawidth int
@ -216,54 +217,33 @@ func (s *sysData) delete(index int) {
classTypes[s.ctype].delete(s.widget, index)
}
// With GTK+, we must manually pulse the indeterminate progressbar ourselves. This goroutine does that.
func (s *sysData) progressPulse() {
// TODO this could probably be done differently...
pulse := func() {
// TODO
// touitask(func() {
// gtk_progress_bar_pulse(s.widget)
// })
}
// With GTK+, we must manually pulse the indeterminate progressbar ourselves.
// To ensure pulsing runs on the main lop and doesn't cause any other weird racy things, we'll use g_timeout_add().
// Zenity 3.4 does this too (https://git.gnome.org/browse/zenity/tree/src/progress.c?id=3.4.0).
// The following is Zenity 3.4's pulse rate.
const pulseRate = 100 // in milliseconds
var ticker *time.Ticker
var tickchan <-chan time.Time
// the pulse rate used by Zenity (https://git.gnome.org/browse/zenity/tree/src/progress.c#n69 for blob cbffe08e8337ba1375a0ac7210eff5a2e4313bb8)
const pulseRate = 100 * time.Millisecond
for {
select {
case start := <-s.pulse:
if start {
ticker = time.NewTicker(pulseRate)
tickchan = ticker.C
pulse() // start the pulse animation now, not 100ms later
} else {
if ticker != nil {
ticker.Stop()
}
ticker = nil
tickchan = nil
s.pulse <- true // notify sysData.setProgress()
}
case <-tickchan:
pulse()
}
}
//export our_pulse_callback
func our_pulse_callback(data C.gpointer) C.gboolean {
// TODO this can be called when closing the window
s := (*sysData)(unsafe.Pointer(data))
gtk_progress_bar_pulse(s.widget)
return C.TRUE // continue processing
}
func (s *sysData) setProgress(percent int) {
if s.pulse == nil {
s.pulse = make(chan bool)
go s.progressPulse()
if s.pulseTimer != 0 { // kill current timer
// TODO only if not indeterminate already?
C.g_source_remove(s.pulseTimer)
s.pulseTimer = 0
}
if percent == -1 {
s.pulse <- true
gtk_progress_bar_pulse(s.widget) // start animation now
s.pulseTimer = C.g_timeout_add(pulseRate,
C.GSourceFunc(C.our_pulse_callback),
C.gpointer(unsafe.Pointer(s)))
return
}
s.pulse <- false
<-s.pulse // wait for sysData.progressPulse() to register that
gtk_progress_bar_set_fraction(s.widget, percent)
}