2014-02-16 15:43:48 -06:00
// +build !windows,!darwin,!plan9
// 16 february 2014
2014-03-12 20:55:45 -05:00
2014-02-19 10:41:10 -06:00
package ui
2014-02-16 15:43:48 -06:00
import (
"unsafe"
)
/ *
cgo doesn ' t support calling Go functions by default ; we have to mark them for export . Not a problem , except arguments to GTK + callbacks depend on the callback itself . Since we ' re generating callback functions as simple closures of one type , this file will wrap the generated callbacks in the appropriate callback type . We pass the actual generated pointer to the extra data parameter of the callback .
2014-02-16 16:09:58 -06:00
2014-03-12 19:00:29 -05:00
while we ' re at it the callback for our idle function will be handled here too
2014-02-16 15:43:48 -06:00
* /
2014-03-16 09:34:12 -05:00
// #include "gtk_unix.h"
2014-03-14 19:03:02 -05:00
// extern gboolean our_window_delete_event_callback(GtkWidget *, GdkEvent *, gpointer);
// extern gboolean our_window_configure_event_callback(GtkWidget *, GdkEvent *, gpointer);
// extern void our_button_clicked_callback(GtkButton *, gpointer);
2014-03-12 19:00:29 -05:00
// extern gboolean our_idle_callback(gpointer);
2014-03-14 19:03:02 -05:00
// /* because cgo is flaky with macros; static inline because we have //exports */
// static inline void gSignalConnect(GtkWidget *widget, char *signal, GCallback callback, void *data) { g_signal_connect(widget, signal, callback, data); }
2014-02-16 15:43:48 -06:00
import "C"
2014-03-14 19:03:02 -05:00
//export our_window_delete_event_callback
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 ( )
2014-06-10 13:59:39 -05:00
return C . TRUE // do not close the window
2014-02-16 15:43:48 -06:00
}
2014-03-14 19:03:02 -05:00
var window_delete_event_callback = C . GCallback ( C . our_window_delete_event_callback )
//export our_window_configure_event_callback
func our_window_configure_event_callback ( widget * C . GtkWidget , event * C . GdkEvent , what C . gpointer ) C . gboolean {
// called when the window is resized
s := ( * sysData ) ( unsafe . Pointer ( what ) )
2014-06-10 13:59:39 -05:00
if s . container != nil && s . resize != nil { // wait for init
2014-03-14 19:03:02 -05:00
width , height := gtk_window_get_size ( s . widget )
// top-left is (0,0) so no need for winheight
2014-04-07 13:32:25 -05:00
s . doResize ( 0 , 0 , width , height , 0 )
2014-03-14 19:03:02 -05:00
}
2014-06-02 21:07:50 -05:00
// no need to manually redraw everything: since we use gtk_widget_set_size_request(), that queues both resize and redraw for us (thanks Company in irc.gimp.net/#gtk+)
2014-06-10 13:59:39 -05:00
return C . FALSE // continue the event chain
2014-03-14 19:03:02 -05:00
}
var window_configure_event_callback = C . GCallback ( C . our_window_configure_event_callback )
//export our_button_clicked_callback
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 ( )
}
var button_clicked_callback = C . GCallback ( C . our_button_clicked_callback )
// this is the type of the signals fields in classData; here to avoid needing to import C
type callbackMap map [ string ] C . GCallback
// this is what actually connects a signal
2014-04-01 15:30:38 -05:00
func g_signal_connect ( obj * C . GtkWidget , sig string , callback C . GCallback , sysData * sysData ) {
2014-03-14 19:03:02 -05:00
csig := C . CString ( sig )
defer C . free ( unsafe . Pointer ( csig ) )
2014-04-01 15:30:38 -05:00
C . gSignalConnect ( obj , csig , callback , unsafe . Pointer ( sysData ) )
2014-02-16 16:09:58 -06:00
}
2014-06-08 10:50:11 -05:00
func g_signal_connect_pointer ( obj * C . GtkWidget , sig string , callback C . GCallback , p unsafe . Pointer ) {
csig := C . CString ( sig )
defer C . free ( unsafe . Pointer ( csig ) )
C . gSignalConnect ( obj , csig , callback , p )
}
2014-03-14 19:03:02 -05:00
// there are two issues we solve here:
// 1) we need to make sure the uitask request gets garbage collected when we're done so as to not waste memory, but only when we're done so as to not have craziness happen
// 2) we need to make sure one idle function runs and finishes running before we start the next; otherwise we could wind up with weird things like the ret channel being closed early
// so our_idle_callback() calls the uitask function in what and sends a message back to the dispatcher over done that it finished running; the dispatcher is still holding onto the uitask function so it won't be collected
type gtkIdleOp struct {
2014-06-10 13:59:39 -05:00
what func ( )
done chan struct { }
2014-02-16 16:30:58 -06:00
}
2014-03-12 19:00:29 -05:00
//export our_idle_callback
func our_idle_callback ( what C . gpointer ) C . gboolean {
idleop := ( * gtkIdleOp ) ( unsafe . Pointer ( what ) )
idleop . what ( )
idleop . done <- struct { } { }
2014-06-10 13:59:39 -05:00
return C . FALSE // remove this idle function; we're finished
2014-03-12 19:00:29 -05:00
}
2014-03-14 19:03:02 -05:00
func gdk_threads_add_idle ( idleop * gtkIdleOp ) {
C . gdk_threads_add_idle ( C . GCallback ( C . our_idle_callback ) ,
C . gpointer ( unsafe . Pointer ( idleop ) ) )
2014-02-16 15:43:48 -06:00
}