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