summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-06-28 21:40:44 -0400
committerPietro Gagliardi <[email protected]>2014-06-28 21:40:44 -0400
commit385993792f62f47c4164466ee1d5248b0921b0a5 (patch)
tree6b97f4541568f6651ea010579dc2f249713be134
parentaffc65a5a402534527c4d4fbc5b381b5b1283445 (diff)
Migrated the GTK+ backend to the new API.
-rw-r--r--callbacks_unix.go7
-rw-r--r--dialog_unix.go89
-rw-r--r--sysdata_unix.go234
-rw-r--r--uitask_unix.go30
4 files changed, 107 insertions, 253 deletions
diff --git a/callbacks_unix.go b/callbacks_unix.go
index ff3e3b9..717150c 100644
--- a/callbacks_unix.go
+++ b/callbacks_unix.go
@@ -27,8 +27,9 @@ import "C"
func our_window_delete_event_callback(widget *C.GtkWidget, event *C.GdkEvent, what C.gpointer) C.gboolean {
// called when the user tries to close the window
s := (*sysData)(unsafe.Pointer(what))
- s.signal()
- return C.TRUE // do not close the window
+ b := false // TODO
+ s.close(&b)
+ return togbool(!b) // ! because TRUE means don't close
}
var window_delete_event_callback = C.GCallback(C.our_window_delete_event_callback)
@@ -52,7 +53,7 @@ var window_configure_event_callback = C.GCallback(C.our_window_configure_event_c
func our_button_clicked_callback(button *C.GtkButton, what C.gpointer) {
// called when the user clicks a button
s := (*sysData)(unsafe.Pointer(what))
- s.signal()
+ s.event()
}
var button_clicked_callback = C.GCallback(C.our_button_clicked_callback)
diff --git a/dialog_unix.go b/dialog_unix.go
index f22f1c6..9728e2a 100644
--- a/dialog_unix.go
+++ b/dialog_unix.go
@@ -9,7 +9,6 @@ import (
)
// #include "gtk_unix.h"
-// extern void our_dialog_response_callback(GtkDialog *, gint, gpointer);
// /* because cgo seems to choke on ... */
// /* parent will be NULL if there is no parent, so this is fine */
// static inline GtkWidget *gtkNewMsgBox(GtkWindow *parent, GtkMessageType type, GtkButtonsType buttons, char *title, char *text)
@@ -23,6 +22,11 @@ import (
// }
import "C"
+// the actual type of these constants is GtkResponseType but gtk_dialog_run() returns a gint
+var dialogResponses = map[C.gint]Response{
+ C.GTK_RESPONSE_OK: OK,
+}
+
// dialog performs the bookkeeping involved for having a GtkDialog behave the way we want.
type dialog struct {
parent *Window
@@ -30,13 +34,12 @@ type dialog struct {
hadgroup C.gboolean
prevgroup *C.GtkWindowGroup
newgroup *C.GtkWindowGroup
- result chan int
+ result Response
}
func mkdialog(parent *Window) *dialog {
return &dialog{
parent: parent,
- result: make(chan int),
}
}
@@ -59,36 +62,6 @@ func (d *dialog) prepare() {
}
}
-func (d *dialog) run(mk func() *C.GtkWidget) {
- d.prepare()
- box := mk()
- if d.parent == dialogWindow {
- go func() {
- res := make(chan C.gint)
- defer close(res)
- uitask <- func() {
- r := C.gtk_dialog_run((*C.GtkDialog)(unsafe.Pointer(box)))
- d.cleanup(box)
- res <- r
- }
- d.send(<-res)
- }()
- return
- }
- // otherwise just connect the delete signal
- g_signal_connect_pointer(box, "response", dialog_response_callback, unsafe.Pointer(d))
- C.gtk_widget_show_all(box)
-}
-
-//export our_dialog_response_callback
-func our_dialog_response_callback(box *C.GtkDialog, res C.gint, data C.gpointer) {
- d := (*dialog)(unsafe.Pointer(data))
- d.cleanup((*C.GtkWidget)(unsafe.Pointer(box)))
- go d.send(res) // send on another goroutine, like everything else
-}
-
-var dialog_response_callback = C.GCallback(C.our_dialog_response_callback)
-
func (d *dialog) cleanup(box *C.GtkWidget) {
// have to explicitly close the dialog box, otherwise wacky things will happen
C.gtk_widget_destroy(box)
@@ -101,43 +74,33 @@ func (d *dialog) cleanup(box *C.GtkWidget) {
}
}
-func (d *dialog) send(res C.gint) {
- // this is where processing would go
- d.result <- int(res)
+func (d *dialog) run(mk func() *C.GtkWidget) {
+ d.prepare()
+ box := mk()
+ r := C.gtk_dialog_run((*C.GtkDialog)(unsafe.Pointer(box)))
+ d.cleanup(box)
+ d.result = dialogResponses[r]
}
-func _msgBox(parent *Window, primarytext string, secondarytext string, msgtype C.GtkMessageType, buttons C.GtkButtonsType) (result chan int) {
- result = make(chan int)
+func _msgBox(parent *Window, primarytext string, secondarytext string, msgtype C.GtkMessageType, buttons C.GtkButtonsType) (response Response) {
d := mkdialog(parent)
- uitask <- func() {
- cprimarytext := C.CString(primarytext)
- defer C.free(unsafe.Pointer(cprimarytext))
- csecondarytext := (*C.char)(nil)
- if secondarytext != "" {
- csecondarytext = C.CString(secondarytext)
- defer C.free(unsafe.Pointer(csecondarytext))
- }
- d.run(func() *C.GtkWidget {
- return C.gtkNewMsgBox(d.pwin, msgtype, buttons, cprimarytext, csecondarytext)
- })
+ cprimarytext := C.CString(primarytext)
+ defer C.free(unsafe.Pointer(cprimarytext))
+ csecondarytext := (*C.char)(nil)
+ if secondarytext != "" {
+ csecondarytext = C.CString(secondarytext)
+ defer C.free(unsafe.Pointer(csecondarytext))
}
+ d.run(func() *C.GtkWidget {
+ return C.gtkNewMsgBox(d.pwin, msgtype, buttons, cprimarytext, csecondarytext)
+ })
return d.result
}
-func (w *Window) msgBox(primarytext string, secondarytext string) (done chan struct{}) {
- done = make(chan struct{})
- go func() {
- <-_msgBox(w, primarytext, secondarytext, C.GtkMessageType(C.GTK_MESSAGE_OTHER), C.GtkButtonsType(C.GTK_BUTTONS_OK))
- done <- struct{}{}
- }()
- return done
+func (w *Window) msgBox(primarytext string, secondarytext string) {
+ _msgBox(w, primarytext, secondarytext, C.GtkMessageType(C.GTK_MESSAGE_OTHER), C.GtkButtonsType(C.GTK_BUTTONS_OK))
}
-func (w *Window) msgBoxError(primarytext string, secondarytext string) (done chan struct{}) {
- done = make(chan struct{})
- go func() {
- <-_msgBox(w, primarytext, secondarytext, C.GtkMessageType(C.GTK_MESSAGE_ERROR), C.GtkButtonsType(C.GTK_BUTTONS_OK))
- done <- struct{}{}
- }()
- return done
+func (w *Window) msgBoxError(primarytext string, secondarytext string) {
+ _msgBox(w, primarytext, secondarytext, C.GtkMessageType(C.GTK_MESSAGE_ERROR), C.GtkButtonsType(C.GTK_BUTTONS_OK))
}
diff --git a/sysdata_unix.go b/sysdata_unix.go
index 7814fb3..b39df50 100644
--- a/sysdata_unix.go
+++ b/sysdata_unix.go
@@ -118,42 +118,30 @@ var classTypes = [nctypes]*classData{
func (s *sysData) make(window *sysData) error {
ct := classTypes[s.ctype]
- ret := make(chan *C.GtkWidget)
- defer close(ret)
- uitask <- func() {
- if s.alternate {
- ret <- ct.makeAlt()
- return
- }
- ret <- ct.make()
+ if s.alternate {
+ s.widget = ct.makeAlt()
+ } else {
+ s.widget = ct.make()
}
- s.widget = <-ret
if window == nil {
- uitask <- func() {
- fixed := gtkNewWindowLayout()
- gtk_container_add(s.widget, fixed)
- for signame, sigfunc := range ct.signals {
- g_signal_connect(s.widget, signame, sigfunc, s)
- }
- ret <- fixed
+ fixed := gtkNewWindowLayout()
+ gtk_container_add(s.widget, fixed)
+ for signame, sigfunc := range ct.signals {
+ g_signal_connect(s.widget, signame, sigfunc, s)
}
- s.container = <-ret
+ s.container = fixed
} else {
s.container = window.container
- uitask <- func() {
- gtkAddWidgetToLayout(s.container, s.widget)
- for signame, sigfunc := range ct.signals {
- g_signal_connect(s.widget, signame, sigfunc, s)
- }
- if ct.child != nil {
- child := ct.child(s.widget)
- for signame, sigfunc := range ct.childsigs {
- g_signal_connect(child, signame, sigfunc, s)
- }
+ gtkAddWidgetToLayout(s.container, s.widget)
+ for signame, sigfunc := range ct.signals {
+ g_signal_connect(s.widget, signame, sigfunc, s)
+ }
+ if ct.child != nil {
+ child := ct.child(s.widget)
+ for signame, sigfunc := range ct.childsigs {
+ g_signal_connect(child, signame, sigfunc, s)
}
- ret <- nil
}
- <-ret
}
return nil
}
@@ -170,35 +158,17 @@ func (s *sysData) firstShow() error {
}
func (s *sysData) show() {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- gtk_widget_show(s.widget)
- s.resetposition()
- ret <- struct{}{}
- }
- <-ret
+ gtk_widget_show(s.widget)
+ s.resetposition()
}
func (s *sysData) hide() {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- gtk_widget_hide(s.widget)
- s.resetposition()
- ret <- struct{}{}
- }
- <-ret
+ gtk_widget_hide(s.widget)
+ s.resetposition()
}
func (s *sysData) setText(text string) {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- classTypes[s.ctype].setText(s.widget, text)
- ret <- struct{}{}
- }
- <-ret
+ classTypes[s.ctype].setText(s.widget, text)
}
func (s *sysData) setRect(x int, y int, width int, height int, winheight int) error {
@@ -208,103 +178,51 @@ func (s *sysData) setRect(x int, y int, width int, height int, winheight int) er
}
func (s *sysData) isChecked() bool {
- ret := make(chan bool)
- defer close(ret)
- uitask <- func() {
- ret <- gtk_toggle_button_get_active(s.widget)
- }
- return <-ret
+ return gtk_toggle_button_get_active(s.widget)
}
func (s *sysData) text() string {
- ret := make(chan string)
- defer close(ret)
- uitask <- func() {
- ret <- classTypes[s.ctype].text(s.widget)
- }
- return <-ret
+ return classTypes[s.ctype].text(s.widget)
}
func (s *sysData) append(what string) {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- classTypes[s.ctype].append(s.widget, what)
- ret <- struct{}{}
- }
- <-ret
+ classTypes[s.ctype].append(s.widget, what)
}
func (s *sysData) insertBefore(what string, before int) {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- classTypes[s.ctype].insert(s.widget, before, what)
- ret <- struct{}{}
- }
- <-ret
+ classTypes[s.ctype].insert(s.widget, before, what)
}
func (s *sysData) selectedIndex() int {
- ret := make(chan int)
- defer close(ret)
- uitask <- func() {
- ret <- classTypes[s.ctype].selected(s.widget)
- }
- return <-ret
+ return classTypes[s.ctype].selected(s.widget)
}
func (s *sysData) selectedIndices() []int {
- ret := make(chan []int)
- defer close(ret)
- uitask <- func() {
- ret <- classTypes[s.ctype].selMulti(s.widget)
- }
- return <-ret
+ return classTypes[s.ctype].selMulti(s.widget)
}
func (s *sysData) selectedTexts() []string {
- ret := make(chan []string)
- defer close(ret)
- uitask <- func() {
- ret <- classTypes[s.ctype].smtexts(s.widget)
- }
- return <-ret
+ return classTypes[s.ctype].smtexts(s.widget)
}
func (s *sysData) setWindowSize(width int, height int) error {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- // does not take window geometry into account (and cannot, since the window manager won't give that info away)
- // thanks to TingPing in irc.gimp.net/#gtk+
- gtk_window_resize(s.widget, width, height)
- ret <- struct{}{}
- }
- <-ret
+ // does not take window geometry into account (and cannot, since the window manager won't give that info away)
+ // thanks to TingPing in irc.gimp.net/#gtk+
+ gtk_window_resize(s.widget, width, height)
return nil
}
func (s *sysData) delete(index int) {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- classTypes[s.ctype].delete(s.widget, index)
- ret <- struct{}{}
- }
- <-ret
+ 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() {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
+ touitask(func() {
gtk_progress_bar_pulse(s.widget)
- ret <- struct{}{}
- }
- <-ret
+ })
}
var ticker *time.Ticker
@@ -345,78 +263,44 @@ func (s *sysData) setProgress(percent int) {
}
s.pulse <- false
<-s.pulse // wait for sysData.progressPulse() to register that
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- gtk_progress_bar_set_fraction(s.widget, percent)
- ret <- struct{}{}
- }
- <-ret
+ gtk_progress_bar_set_fraction(s.widget, percent)
}
func (s *sysData) len() int {
- ret := make(chan int)
- defer close(ret)
- uitask <- func() {
- ret <- classTypes[s.ctype].len(s.widget)
- }
- return <-ret
+ return classTypes[s.ctype].len(s.widget)
}
func (s *sysData) setAreaSize(width int, height int) {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- c := gtkAreaGetControl(s.widget)
- gtk_widget_set_size_request(c, width, height)
- s.areawidth = width // for sysData.preferredSize()
- s.areaheight = height
- C.gtk_widget_queue_draw(c)
- ret <- struct{}{}
- }
- <-ret
+ c := gtkAreaGetControl(s.widget)
+ gtk_widget_set_size_request(c, width, height)
+ s.areawidth = width // for sysData.preferredSize()
+ s.areaheight = height
+ C.gtk_widget_queue_draw(c)
}
+// TODO should this be made safe? (TODO move to area.go)
func (s *sysData) repaintAll() {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- c := gtkAreaGetControl(s.widget)
- C.gtk_widget_queue_draw(c)
- ret <- struct{}{}
- }
- <-ret
+ c := gtkAreaGetControl(s.widget)
+ C.gtk_widget_queue_draw(c)
}
func (s *sysData) center() {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- if C.gtk_widget_get_visible(s.widget) == C.FALSE {
- // hint to the WM to make it centered when it is shown again
- // thanks to Jasper in irc.gimp.net/#gtk+
- C.gtk_window_set_position(togtkwindow(s.widget), C.GTK_WIN_POS_CENTER)
- } else {
- var width, height C.gint
+ if C.gtk_widget_get_visible(s.widget) == C.FALSE {
+ // hint to the WM to make it centered when it is shown again
+ // thanks to Jasper in irc.gimp.net/#gtk+
+ C.gtk_window_set_position(togtkwindow(s.widget), C.GTK_WIN_POS_CENTER)
+ } else {
+ var width, height C.gint
- s.resetposition()
- //we should be able to use gravity to simplify this, but it doesn't take effect immediately, and adding show calls does nothing (thanks Jasper in irc.gimp.net/#gtk+)
- C.gtk_window_get_size(togtkwindow(s.widget), &width, &height)
- C.gtk_window_move(togtkwindow(s.widget),
- (C.gdk_screen_width() / 2) - (width / 2),
- (C.gdk_screen_height() / 2) - (width / 2))
- }
- ret <- struct{}{}
+ s.resetposition()
+ //we should be able to use gravity to simplify this, but it doesn't take effect immediately, and adding show calls does nothing (thanks Jasper in irc.gimp.net/#gtk+)
+ C.gtk_window_get_size(togtkwindow(s.widget), &width, &height)
+ C.gtk_window_move(togtkwindow(s.widget),
+ (C.gdk_screen_width() / 2) - (width / 2),
+ (C.gdk_screen_height() / 2) - (width / 2))
}
- <-ret
}
func (s *sysData) setChecked(checked bool) {
- ret := make(chan struct{})
- defer close(ret)
- uitask <- func() {
- gtk_toggle_button_set_active(s.widget, checked)
- ret <- struct{}{}
- }
- <-ret
+ gtk_toggle_button_set_active(s.widget, checked)
}
diff --git a/uitask_unix.go b/uitask_unix.go
index 030f096..a8cabd2 100644
--- a/uitask_unix.go
+++ b/uitask_unix.go
@@ -6,7 +6,6 @@ package ui
import (
"fmt"
- "runtime"
)
// #cgo pkg-config: gtk+-3.0
@@ -15,19 +14,32 @@ import "C"
var uitask chan func()
-func ui(main func()) error {
- runtime.LockOSThread()
-
- uitask = make(chan func())
+func uiinit() error {
err := gtk_init()
if err != nil {
return fmt.Errorf("gtk_init() failed: %v", err)
}
+ // do this only on success, just to be safe
+ uitask = make(chan func())
+ return nil
+}
+
+func ui() {
// thanks to tristan and Daniel_S in irc.gimp.net/#gtk
// see our_idle_callback in callbacks_unix.go for details
go func() {
- for f := range uitask {
+ for {
+ var f func()
+
+ select {
+ case f = <-uitask:
+ // do nothing
+ case <-Stop:
+ f = func() {
+ C.gtk_main_quit()
+ }
+ }
done := make(chan struct{})
gdk_threads_add_idle(&gtkIdleOp{
what: f,
@@ -38,11 +50,5 @@ func ui(main func()) error {
}
}()
- go func() {
- main()
- uitask <- gtk_main_quit
- }()
-
C.gtk_main()
- return nil
}