├── .gitignore ├── src ├── examples │ ├── .gitignore │ ├── Makefile │ ├── hello.go │ └── text.go ├── .gitignore ├── layoutcalc.go ├── texteditor.go ├── window.go ├── group.go ├── input.go ├── Makefile ├── widget.go ├── fltk.h ├── fltk.go └── fltk.cxx ├── Makefile ├── .project ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | *~ 3 | -------------------------------------------------------------------------------- /src/examples/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | text 3 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | 8.out 2 | .#* 3 | [#]*# 4 | *.o 5 | *.8 6 | *.c 7 | *.so 8 | *.cgo1.go 9 | *~ 10 | _cgo_gotypes.go 11 | _obj 12 | fltk-2.0.x-r7725/* 13 | fltk-2.0.x-r7725.tar.bz2 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd src && $(MAKE) $(MFLAGS) all 3 | 4 | install: 5 | cd src && $(MAKE) $(MFLAGS) install 6 | 7 | examples: 8 | cd src && $(MAKE) $(MFLAGS) examples 9 | 10 | clean: 11 | cd src && $(MAKE) $(MFLAGS) clean 12 | -------------------------------------------------------------------------------- /src/examples/Makefile: -------------------------------------------------------------------------------- 1 | BINS = text hello 2 | pkgdir=$(GOROOT)/pkg/$(GOOS)_$(GOARCH) 3 | 4 | all: $(BINS) 5 | 6 | text hello : % : %.go $(pkgdir)/cgo_fltk.so $(pkgdir)/fltk.a 7 | 8g $@.go && 8l -o $@ $@.8 8 | 9 | clean: 10 | rm -f $(BINS) *.8 11 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | fltk-go 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/layoutcalc.go: -------------------------------------------------------------------------------- 1 | package fltk 2 | 3 | type LayoutCalc struct { 4 | X, Y, W, H int 5 | } 6 | 7 | func NewLayoutCalc(w Widgety) *LayoutCalc { 8 | return &LayoutCalc{0, 0, w.GetWidget().W(), w.GetWidget().H()} 9 | } 10 | // add a widget of h height 11 | func (l *LayoutCalc) Add(w Widgety) { 12 | l.Y += w.GetWidget().H() 13 | l.H -= w.GetWidget().H() 14 | } 15 | -------------------------------------------------------------------------------- /src/examples/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fltk" 4 | 5 | func main() { 6 | w := fltk.NewWindow(300, 180) 7 | w.Begin() 8 | b := fltk.NewWidget(20, 40, 260, 100, "Hello there!") 9 | b.Box(fltk.UP_BOX) 10 | b.LabelFont(fltk.HELVETICA_BOLD_ITALIC) 11 | b.LabelSize(36) 12 | b.LabelType(fltk.SHADOW_LABEL) 13 | w.End() 14 | w.Show([]string{}) 15 | fltk.Run(func() bool {return true}) 16 | } 17 | -------------------------------------------------------------------------------- /src/texteditor.go: -------------------------------------------------------------------------------- 1 | package fltk 2 | 3 | /* 4 | #include "fltk.h" 5 | */ 6 | import "C" 7 | import "unsafe" 8 | 9 | type TextEditor struct { 10 | Widget 11 | } 12 | 13 | func NewTextEditor(x, y, w, h int, text... string) *TextEditor { 14 | i := &TextEditor{} 15 | initWidget(i, unsafe.Pointer(C.go_fltk_new_TextEditor(C.int(x), C.int(y), C.int(w), C.int(h), cStringOpt(text)))) 16 | return i 17 | } 18 | -------------------------------------------------------------------------------- /src/window.go: -------------------------------------------------------------------------------- 1 | package fltk 2 | 3 | /* 4 | #include "fltk.h" 5 | */ 6 | import "C" 7 | import "unsafe" 8 | 9 | type Window struct { 10 | Group 11 | } 12 | 13 | func NewWindow(w, h int) *Window { 14 | win := &Window{} 15 | initWidget(win, unsafe.Pointer(C.go_fltk_new_Window(C.int(w), C.int(h)))) 16 | return win 17 | } 18 | func (w *Window) Destroy() {C.go_fltk_Window_destroy(w.ptr)} 19 | func (w *Window) Show(args []string) {C.go_fltk_Window_show(w.ptr, C.int(0), unsafe.Pointer(uintptr(0)))} 20 | func (w *Window) SetLabel(label string) {C.go_fltk_Window_set_label(w.ptr, C.CString(label))} 21 | -------------------------------------------------------------------------------- /src/group.go: -------------------------------------------------------------------------------- 1 | package fltk 2 | 3 | /* 4 | #include "fltk.h" 5 | */ 6 | import "C" 7 | import "unsafe" 8 | 9 | type Group struct { 10 | Widget 11 | } 12 | 13 | func NewPackedGroup(x, y, w, h int) *Group { 14 | win := &Group{} 15 | initWidget(win, unsafe.Pointer(C.go_fltk_new_PackedGroup(C.int(x), C.int(y), C.int(w), C.int(h)))) 16 | return win 17 | } 18 | 19 | func (g *Group) Begin() {C.go_fltk_Group_begin(g.ptr)} 20 | func (g *Group) End() {C.go_fltk_Group_end(g.ptr)} 21 | func (g *Group) Add(w Widgety) {C.go_fltk_Group_add(g.ptr, w.GetWidget().ptr)} 22 | func (g *Group) Resizable(w Widgety) {C.go_fltk_Group_resizable(g.ptr, w.GetWidget().ptr)} 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This software is licensed under the ZLIB license: 2 | 3 | Copyright (c) 2010 Bill Burdick 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. 23 | -------------------------------------------------------------------------------- /src/input.go: -------------------------------------------------------------------------------- 1 | package fltk 2 | 3 | /* 4 | #include "fltk.h" 5 | */ 6 | import "C" 7 | import "unsafe" 8 | 9 | type Input struct { 10 | Widget 11 | } 12 | 13 | func NewInput(x, y, w, h int, text... string) *Input { 14 | i := &Input{} 15 | initWidget(i, unsafe.Pointer(C.go_fltk_new_Input(C.int(x), C.int(y), C.int(w), C.int(h), cStringOpt(text)))) 16 | return i 17 | } 18 | 19 | //func (i *Input) GetText() string {return string(uintptr(unsafe.Pointer(C.go_fltk_Input_get_text(i.ptr))))} 20 | func (i *Input) GetText() string {return C.GoString(C.go_fltk_Input_get_text(i.ptr))} 21 | func (i *Input) SetText(text string) bool {return C.go_fltk_Input_set_text(i.ptr, C.CString(text)) != C.int(0)} 22 | func (i *Input) MousePosition() int {return int(C.go_fltk_Input_mouse_position(i.ptr))} 23 | func (i *Input) GetPosition() int {return int(C.go_fltk_Input_get_position(i.ptr))} 24 | func (i *Input) GetMark() int {return int(C.go_fltk_Input_get_mark(i.ptr))} 25 | func (i *Input) SetPosition(p int, m int) {C.go_fltk_Input_set_position(i.ptr, C.int(p), C.int(m))} 26 | -------------------------------------------------------------------------------- /src/examples/text.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fltk" 4 | import "fmt" 5 | import "strconv" 6 | 7 | func main() { 8 | exit := false 9 | window := fltk.NewWindow(300, 180) 10 | l := fltk.NewLayoutCalc(window) 11 | window.SetCallback(func(){exit = true; println("CLOSED"); window.Destroy()}) 12 | window.Begin() 13 | i := fltk.NewInput(l.X, l.Y, l.W, 30) 14 | l.Add(i) 15 | i.StealEvents(fltk.PUSH_MASK | fltk.DRAG_MASK | fltk.PASTE_MASK) 16 | i.SetEventHandler(func(e *fltk.Event) { 17 | if (e.Stolen) { 18 | fmt.Println("STOLE EVENT:", strconv.Itoa(e.Event), "widget:", e.Widget, "push: ", fltk.PUSH) 19 | if (e.Event == fltk.PUSH) { 20 | fmt.Println("\nMouse Position:", i.MousePosition(), "\n") 21 | } 22 | if (e.Event != fltk.PUSH && e.Event != fltk.RELEASE && e.Event != fltk.PASTE) || e.Button == 1 { 23 | fmt.Println("CONTINUING EVENT:", strconv.Itoa(e.Event), "widget:", e.Widget, "push: ", fltk.PUSH) 24 | e.Continue() 25 | } 26 | } 27 | }) 28 | fmt.Println("Editor at y: ", l.Y) 29 | e := fltk.NewTextEditor(l.X, l.Y, l.W, l.H) 30 | window.Resizable(e) 31 | window.End() 32 | window.Show([]string{}) 33 | fltk.Run(func() bool {return !exit}) 34 | } 35 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | FLTK=fltk-2.0.x-r7725 2 | FLTK_DIST=$(FLTK).tar.bz2 3 | FLTK_URL=http://ftp.funet.fi/pub/mirrors/ftp.easysw.com/pub/fltk/snapshots/$(FLTK).tar.bz2 4 | FLTK_LIB=$(FLTK)/lib/libfltk2.a 5 | 6 | examples: install 7 | (cd examples; make) 8 | 9 | # uncomment the next line to have 'make clean' remove the fltk-dist 10 | #clean: clean-fltk 11 | 12 | include $(GOROOT)/src/Make.inc 13 | 14 | TARG=fltk 15 | GOFILES=\ 16 | layoutcalc.go 17 | CGOFILES=\ 18 | fltk.go \ 19 | widget.go \ 20 | group.go \ 21 | input.go \ 22 | texteditor.go \ 23 | window.go 24 | CGO_DEPS=fltk.o 25 | 26 | CGO_LDFLAGS=fltk.o $(FLTK_LIB) -lXext -lXinerama -lXft -lX11 -lXi -lm 27 | 28 | include $(GOROOT)/src/Make.pkg 29 | 30 | fltk.o: fltk.h fltk.cxx $(FLTK_LIB) 31 | g++ -I$(FLTK) -c fltk.cxx 32 | 33 | $(CGOTARG).so: $(GCC_OFILES) $(CGO_DEPS) $(FLTK_LIB) 34 | g++ $(_CGO_CFLAGS_$(GOARCH)) -o $@ $(GCC_OFILES) $(CGO_LDFLAGS) $(_CGO_LDFLAGS_$(GOOS)) 35 | 36 | $(FLTK_LIB): $(FLTK)/config.status 37 | cd $(FLTK) && make DIRS="src $(LOCALIMAGES) images" 38 | 39 | $(FLTK)/config.status: 40 | rm -rf $(FLTK_DIST) $(FLTK) 41 | wget $(FLTK_URL) && tar xjf $(FLTK_DIST) && cd $(FLTK) && ./configure --disable-gl --disable-shared 42 | 43 | clean-fltk: 44 | rm -rf $(FLTK) 45 | 46 | clean: clean-local 47 | 48 | clean-local: 49 | (cd examples; make clean) 50 | rm -f *~ 51 | -------------------------------------------------------------------------------- /src/widget.go: -------------------------------------------------------------------------------- 1 | package fltk 2 | 3 | /* 4 | #include "fltk.h" 5 | */ 6 | import "C" 7 | import "unsafe" 8 | import "fmt" 9 | 10 | type Widget struct { 11 | ptr *C.Widget 12 | callback func() 13 | eventHandler func(*Event) 14 | } 15 | 16 | func emptyCallback() {} 17 | func emptyHandler(*Event) {} 18 | 19 | func NewWidget(x, y, w, h int, text... string) *Widget { 20 | return initWidget(&Widget{}, unsafe.Pointer(C.go_fltk_new_Widget(C.int(x), C.int(y), C.int(w), C.int(h), cStringOpt(text)))) 21 | } 22 | func (w *Widget) String() string {return fmt.Sprintf("Widget: %q", unsafe.Pointer(w.ptr))} 23 | func (w *Widget) SetCallback(f func()) { 24 | w.callback = f 25 | C.go_fltk_Widget_callback(w.ptr) 26 | } 27 | func (w *Widget) GetWidget() *Widget {return w} 28 | func (w *Widget) StealEvents(etypes int) {C.go_fltk_Widget_steal_events(w.ptr, C.int(etypes))} 29 | func (w *Widget) Box(box *C.Box) {C.go_fltk_Widget_box(w.ptr, box)} 30 | func (w *Widget) LabelFont(font *C.Font) {C.go_fltk_Widget_labelfont(w.ptr, font)} 31 | func (w *Widget) LabelSize(size int) {C.go_fltk_Widget_labelsize(w.ptr, C.int(size))} 32 | func (w *Widget) LabelType(ltype *C.LabelType) {C.go_fltk_Widget_labeltype(w.ptr, ltype)} 33 | func (w *Widget) SetEventHandler(f func(*Event)) {w.eventHandler = f} 34 | func (w *Widget) HandleCallback() {w.callback()} 35 | func (w *Widget) HandleEvent(e *Event) {w.eventHandler(e)} 36 | func (w *Widget) X() int {return int(C.go_fltk_Widget_x(w.ptr))} 37 | func (w *Widget) Y() int {return int(C.go_fltk_Widget_y(w.ptr))} 38 | func (w *Widget) W() int {return int(C.go_fltk_Widget_w(w.ptr))} 39 | func (w *Widget) H() int {return int(C.go_fltk_Widget_h(w.ptr))} 40 | func (w *Widget) ThrowFocus() {C.go_fltk_Widget_throw_focus(w.ptr)} 41 | -------------------------------------------------------------------------------- /src/fltk.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | #define TYPEDEF(type) typedef fltk::type type 3 | extern "C" { 4 | #else 5 | #define TYPEDEF(type) typedef struct type type 6 | enum { 7 | CTRL = 0x00040000, /*!< Either ctrl key held down */ 8 | ALT = 0x00080000, /*!< Either alt key held down */ 9 | META = 0x00400000, /*!< "Windows" or the "Apple" keys held down */ 10 | #if defined(__APPLE__) 11 | ACCELERATOR = CTRL, 12 | OPTION = ALT, 13 | COMMAND = META 14 | #else 15 | ACCELERATOR = ALT, //!< ALT on Windows/Linux, CTRL on OS/X, use for menu accelerators 16 | COMMAND = CTRL, //!< CTRL on Windows/Linux, META on OS/X, use for menu shortcuts 17 | OPTION = ALT|META //!< ALT|META on Windows/Linux, just ALT on OS/X, use as a drag modifier 18 | #endif 19 | }; 20 | #endif 21 | 22 | TYPEDEF(Box); 23 | TYPEDEF(Font); 24 | TYPEDEF(LabelType); 25 | TYPEDEF(Widget); 26 | TYPEDEF(Group); 27 | TYPEDEF(PackedGroup); 28 | TYPEDEF(Window); 29 | TYPEDEF(Input); 30 | TYPEDEF(TextEditor); 31 | 32 | extern Widget *go_fltk_callback_widget; 33 | extern int go_fltk_event; 34 | extern Widget *go_fltk_event_widget; 35 | extern int go_fltk_event_state; 36 | extern int go_fltk_event_button; 37 | extern int go_fltk_event_clicks; 38 | extern int go_fltk_event_dx; 39 | extern int go_fltk_event_dy; 40 | extern int go_fltk_event_key; 41 | extern int go_fltk_event_x; 42 | extern int go_fltk_event_y; 43 | extern int go_fltk_event_x_root; 44 | extern int go_fltk_event_y_root; 45 | extern int go_fltk_event_stolen; 46 | extern int go_fltk_event_return; 47 | 48 | extern void free(void *ptr); 49 | static inline void free_string(char* s) { free(s); } 50 | static inline char* to_char_ptr(void *ptr) {return (char *)ptr;} 51 | 52 | extern Box *go_fltk_get_UP_BOX(); 53 | extern Font *go_fltk_get_HELVETICA_BOLD_ITALIC(); 54 | extern LabelType *go_fltk_get_SHADOW_LABEL(); 55 | extern Window *go_fltk_new_Window(int w, int h); 56 | extern PackedGroup *go_fltk_new_PackedGroup(int x, int y, int w, int h); 57 | extern Widget *go_fltk_new_Widget(int x, int y, int w, int h, const char *text); 58 | extern Input *go_fltk_new_Input(int x, int y, int w, int h, const char *text); 59 | extern TextEditor *go_fltk_new_TextEditor(int x, int y, int w, int h, const char *text); 60 | extern void go_fltk_Widget_steal_events(Widget *w, int events); 61 | extern void go_fltk_Event_continue(); 62 | extern void go_fltk_Group_begin(Group *g); 63 | extern void go_fltk_Group_end(Group *g); 64 | extern void go_fltk_Group_add(Group *g, Widget *w); 65 | extern void go_fltk_Group_resizable(Group *g, Widget *w); 66 | extern void go_fltk_Widget_box(Widget *w, Box *box); 67 | extern void go_fltk_Widget_labelfont(Widget *w, Font *font); 68 | extern void go_fltk_Widget_labelsize(Widget *w, int size); 69 | extern void go_fltk_Widget_labeltype(Widget *w, LabelType *type); 70 | extern void go_fltk_Widget_callback(Widget *w); 71 | extern void go_fltk_Window_destroy(Window *w); 72 | extern void go_fltk_Window_show(Window *w, int argc, void *argv); 73 | extern void go_fltk_Window_set_label(Window *w, const char *label); 74 | extern int go_fltk_Widget_x(Widget *w); 75 | extern int go_fltk_Widget_y(Widget *w); 76 | extern int go_fltk_Widget_w(Widget *w); 77 | extern int go_fltk_Widget_h(Widget *w); 78 | extern void go_fltk_Widget_throw_focus(Widget *w); 79 | extern const char *go_fltk_Input_get_text(Input *in); 80 | extern int go_fltk_Input_set_text(Input *in, const char *text); 81 | extern int go_fltk_Input_mouse_position(Input *in); 82 | extern int go_fltk_Input_get_position(Input *in); 83 | extern int go_fltk_Input_get_mark(Input *in); 84 | extern void go_fltk_Input_set_position(Input *in, int p, int m); 85 | extern void go_fltk_run(); 86 | extern void go_fltk_get_event(); 87 | extern void go_fltk_continue_event(int i); 88 | 89 | #ifdef __cplusplus 90 | } 91 | #endif 92 | -------------------------------------------------------------------------------- /src/fltk.go: -------------------------------------------------------------------------------- 1 | package fltk 2 | 3 | /* 4 | #include "fltk.h" 5 | */ 6 | import "C" 7 | import "unsafe" 8 | //import "fmt" 9 | 10 | var UP_BOX *C.Box 11 | var HELVETICA_BOLD_ITALIC *C.Font 12 | var SHADOW_LABEL *C.LabelType 13 | 14 | const ( 15 | NO_EVENT = iota 16 | PUSH 17 | RELEASE 18 | ENTER 19 | LEAVE 20 | DRAG 21 | FOCUS 22 | UNFOCUS 23 | KEY 24 | KEYUP 25 | FOCUS_CHANGE 26 | MOVE 27 | SHORTCUT 28 | DEACTIVATE 29 | ACTIVATE 30 | HIDE 31 | SHOW 32 | PASTE 33 | TIMEOUT 34 | MOUSEWHEEL 35 | DND_ENTER 36 | DND_DRAG 37 | DND_LEAVE 38 | DND_RELEASE 39 | TOOLTIP 40 | ) 41 | const ( 42 | NO_EVENT_MASK = 1 << iota 43 | PUSH_MASK 44 | RELEASE_MASK 45 | ENTER_MASK 46 | LEAVE_MASK 47 | DRAG_MASK 48 | FOCUS_MASK 49 | UNFOCUS_MASK 50 | KEY_MASK 51 | KEYUP_MASK 52 | FOCUS_CHAN_MASKGE 53 | MOVE_MASK 54 | SHORTCUT_MASK 55 | DEACTIVATE_MASK 56 | ACTIVATE_MASK 57 | HIDE_MASK 58 | SHOW_MASK 59 | PASTE_MASK 60 | TIMEOUT_MASK 61 | MOUSEWHEEL_MASK 62 | DND_ENTER_MASK 63 | DND_DRAG_MASK 64 | DND_LEAVE_MASK 65 | DND_RELEASE_MASK 66 | TOOLTIP_MASK 67 | ) 68 | 69 | /*! Flags returned by event_state(), and used as the high 16 bits 70 | of Widget::add_shortcut() values (the low 16 bits are all zero, so these 71 | may be or'd with key values). 72 | 73 | The inline function BUTTON(n) will turn n (1-8) into the flag for a 74 | mouse button. 75 | */ 76 | const ( 77 | SHIFT = 1 << 16 * iota // 0x00010000, /*!< Either shift key held down */ 78 | CAPSLOCK // 0x00020000, /*!< Caps lock is toggled on */ 79 | CTRL // 0x00040000, /*!< Either ctrl key held down */ 80 | ALT // 0x00080000, /*!< Either alt key held down */ 81 | NUMLOCK // 0x00100000, /*!< Num Lock turned on */ 82 | _ 83 | META // 0x00400000, /*!< "Windows" or the "Apple" keys held down */ 84 | SCROLLLOCK // 0x00800000, /*!< Scroll Lock turned on */ 85 | BUTTON1 // 0x01000000, /*!< Left mouse button held down */ 86 | BUTTON2 // 0x02000000, /*!< Middle mouse button held down */ 87 | BUTTON3 // 0x04000000, /*!< Right mouse button held down */ 88 | ANY_BUTTON = 0x7f000000 // 0x7f000000, /*!< Any mouse button (up to 8) */ 89 | ACCELERATOR = C.ACCELERATOR //!< ALT on Windows/Linux, CTRL on OS/X, use for menu accelerators 90 | OPTION = C.OPTION //!< ALT|META on Windows/Linux, just ALT on OS/X, use as a drag modifier 91 | COMMAND = C.COMMAND //!< CTRL on Windows/Linux, META on OS/X, use for menu shortcuts 92 | ) 93 | 94 | type Event struct { 95 | Callback Widgety 96 | Widget Widgety 97 | Event int 98 | State int 99 | Button int 100 | Clicks int 101 | Dx int 102 | Dy int 103 | Key int 104 | X int 105 | Y int 106 | XRoot int 107 | YRoot int 108 | Stolen bool 109 | Return int 110 | // TimeElapsed int 111 | } 112 | 113 | func (*Event) Continue() bool{ 114 | if C.go_fltk_event_stolen != 0 { 115 | C.go_fltk_Event_continue() 116 | return true 117 | } 118 | return false 119 | } 120 | 121 | var widgets map[*C.Widget]Widgety 122 | 123 | type Widgety interface { 124 | GetWidget() *Widget 125 | String() string 126 | } 127 | 128 | func debug(args... interface{}) {} 129 | //func debug(args... interface{}) {fmt.Println(args...)} 130 | 131 | func cStringOpt(s []string) *C.char { 132 | if len(s) == 0 { 133 | return (*C.char)(unsafe.Pointer(uintptr(0))) 134 | } 135 | return C.CString(s[0]) 136 | } 137 | 138 | func init() { 139 | UP_BOX = C.go_fltk_get_UP_BOX() 140 | HELVETICA_BOLD_ITALIC = C.go_fltk_get_HELVETICA_BOLD_ITALIC() 141 | SHADOW_LABEL = C.go_fltk_get_SHADOW_LABEL() 142 | widgets = map[*C.Widget]Widgety{} 143 | Start() 144 | } 145 | func initWidget(w Widgety, p unsafe.Pointer) *Widget { 146 | w.GetWidget().ptr = (*C.Widget)(p) 147 | w.GetWidget().callback = emptyCallback 148 | w.GetWidget().eventHandler = emptyHandler 149 | widgets[w.GetWidget().ptr] = w 150 | return w.GetWidget() 151 | } 152 | func Start() { 153 | debug("started") 154 | go func() { 155 | C.go_fltk_run() 156 | debug("FLTK DONE") 157 | }() 158 | } 159 | func ReadEvent() *Event { 160 | debug("GO WAITING FOR EVENT FROM FLTK") 161 | C.go_fltk_get_event() 162 | debug("GO GOT EVENT FROM FLTK") 163 | return &Event{ 164 | widgets[C.go_fltk_callback_widget], 165 | widgets[C.go_fltk_event_widget], 166 | int(C.go_fltk_event), 167 | int(C.go_fltk_event_state), 168 | int(C.go_fltk_event_button), 169 | int(C.go_fltk_event_clicks), 170 | int(C.go_fltk_event_dx), 171 | int(C.go_fltk_event_dy), 172 | int(C.go_fltk_event_key), 173 | int(C.go_fltk_event_x), 174 | int(C.go_fltk_event_y), 175 | int(C.go_fltk_event_x_root), 176 | int(C.go_fltk_event_y_root), 177 | int(C.go_fltk_event_stolen) != 0, 178 | int(C.go_fltk_event_return), 179 | } 180 | } 181 | func ContinueEvent(used int) { 182 | debug("GO CONTINUING FLTK") 183 | C.go_fltk_continue_event(C.int(used)) 184 | } 185 | func Handle(event *Event) int { 186 | if event.Callback != nil { 187 | debug("CALLBACK") 188 | event.Callback.GetWidget().HandleCallback() 189 | } else if event.Widget != nil { 190 | debug("-- widget:", event.Widget, "event:", event.Event) 191 | event.Widget.GetWidget().HandleEvent(event) 192 | debug("-- event returned: ", event.Return) 193 | } 194 | return event.Return 195 | } 196 | func Run(while func() bool) { 197 | for (while()) {ContinueEvent(Handle(ReadEvent()))} 198 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Go FLTK](http://github.com/zot/go-fltk) 2 | ======================================== 3 | 4 | This is a simple go wrapper for [FLTK2](http://www.fltk.org/doc-2.0/html/index.html), which I did to support my Go version of Ober (based on Acme), [Gober](http://github.com/zot/Gober). It's very small and should be fairly easy to extend to support whatever other widgets and functionality you need. Please contribute changes you make. The code is licensed under the very permissive ZLIB license. FLTK2 is only somewhat supported, but I like its mouse-text behavior better than FLTK 1.3's. 5 | 6 | 7 | GOALS 8 | ===== 9 | * *Good integration with Go* -- the way this binding processes events lends itself well to Go programs (I think). since there is not call-in from C to Go, only call-out from Go to C, this runs FLTK in a separate thread in order to allow Go to intercept every event. Go FLTK operations are protected so that they are safe to use in goroutines. 10 | * *Simplicity* -- I'm trying to keep the code small, mostly in Go, generic (multipurpose, but not fat), easy to modify, and easy to extend 11 | * *Small and relatively stand-alone* -- I wanted a toolkit that only depended on basic X functionality and was relatively small so I could statially link it into the Go package. At this point, fltk.a is 121K and cgo_fltk.so is 312K. Yes, I'm sitting here with a straight face and claiming that this is "small." Widget kits are usually several megabytes, so this is small. Maybe someday this will even be a service instead of a library. 12 | 13 | 14 | LIMITED FUNCTIONALITY 15 | ===================== 16 | This wrapper is far from complete, and I'm only planning on supporting what I need to do Gober, but I welcome additions to it. In fact, at this point it hardly does anything. I'll flesh things out as I need them for Gober. 17 | 18 | 19 | USING Go FLTK 20 | ============= 21 | * fltk.Run(while func() bool) runs FLTK until while() returns false. Run() is defined like this: 22 | for (while()) {ContinueEvent(Handle(ReadEvent()))} 23 | * fltk.ReadEvent() returns the next *Event structure read 24 | * fltk.Handle(event *Event) runs the widget's event handler (if there is one) and returns what the handler returned (1 means the widget used the event, 0 means it did not) 25 | * fltk.ContinueEvent(status int) allows FLTK to continue processing. If you do not call this, the GUI will hang. 26 | 27 | By default, widgets have empty handlers, so you can treat fltk as an event stream if you like, instead of using event handlers (wait for an event, process the event yourself), which may lend itself well to using Go channels, since Go FLTK operations are safe to use in goroutines. That boils down to four ways you can deal with events: 28 | 29 | case 1, process an event after the widget handles it: 30 | 31 | user event --> widget --> go event handler 32 | 33 | case 2, process an event before the widget handles it (event stealing): 34 | 35 | user event --> go event handler [optionally: --> widget] 36 | 37 | case 3, roll your own, with default widget behavior (without an event handler): 38 | 39 | user event --> widget --> roll your own with the current event 40 | 41 | case 4, roll your own, with no default widget behavior (stealing without an event handler): 42 | 43 | user event --> roll your own with the current event [optionally: --> widget] 44 | 45 | You can install an event handler with widget.SetEventHandler() like this: 46 | 47 | input.SetEventHandler(func(e fltk.Event){println(e.Event)} 48 | 49 | Normally, the widget processes the event before Wait returns but you can "steal" events so that your event handler will get the event before the widget has a chance to process it. If you want to steal events, call widget.StealEvents() with a bit mask for the FLTK event types. There are constants for the event types and masks for them by appending _MASK to the name, like PUSH_MASK, which is just 1 << PUSH. You call StealEvents() like this: 50 | 51 | input.StealEvents((1 << PUSH_MASK) | (1 << DRAG_MASK)) 52 | 53 | There is a bool field in Event, called "Stolen" to tell you whether the event was stolen. If you want the widget to process the stolen event, just call widget.ContinueEvent(). Here is an example of an event handler that prints a message for stolen push and drag events and then continues them: 54 | 55 | i.StealEvents(fltk.PUSH_MASK | fltk.DRAG_MASK) 56 | i.SetEventHandler(func(e fltk.Event) { 57 | if (e.Stolen) { 58 | println("CONTINUING EVENT: " + strconv.Itoa(e.Event)) 59 | i.ContinueEvent() 60 | } 61 | }) 62 | 63 | There is an example program, test.go, in the "examples" directory, that steals events from a text field, like this. 64 | 65 | 66 | DEPENDENCIES 67 | ============ 68 | The make file SHOULD auto-download and unpack FLTK2 for you. When it builds the Go library, it statically links FLTK into the library so that the only dependencies are -lXext -lXinerama -lXft -lX11 -lXi -lm. 69 | 70 | This only runs under X, because of the way I build it, but FLTK purports to run on windows and macs, so if you can test that and help with the Makefile, I'd appreciate it. 71 | 72 | 73 | BUILDING 74 | ======== 75 | To build, run "make" in the top-level directory. This assumes you have g++ installed, because FLTK is written in C++ and you need to use g++ to link the library so it can resolve mangled names. 76 | 77 | To install the library, run "make install". 78 | 79 | To build the examples, run "make examples". 80 | 81 | If you want to eliminate the fltk-library from your directory, you can run "make clean-fltk". 82 | 83 | 84 | EXAMPLES 85 | ======== 86 | There are two examples: hello and text. Hello is the Hello World program from the [FLTK docs](http://www.fltk.org/doc-2.0/html/example1.html) and text is a window with a text field in it that steals the PUSH and DRAG events, printing a message and continuing the events. 87 | -------------------------------------------------------------------------------- /src/fltk.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "fltk.h" 10 | //#include 11 | 12 | //#define debugf printf 13 | #define debugf(...) 14 | #define MAX_EVENT_TYPES 25 15 | 16 | Widget *go_fltk_callback_widget = 0; 17 | Widget *go_fltk_event_widget; 18 | int go_fltk_event; 19 | int go_fltk_event_state; 20 | int go_fltk_event_button; 21 | int go_fltk_event_clicks; 22 | int go_fltk_event_dx; 23 | int go_fltk_event_dy; 24 | int go_fltk_event_key; 25 | int go_fltk_event_x; 26 | int go_fltk_event_y; 27 | int go_fltk_event_x_root; 28 | int go_fltk_event_y_root; 29 | int go_fltk_event_stolen; 30 | int go_fltk_event_return; 31 | 32 | void set_event_fields(int evt) { 33 | go_fltk_event_widget = fltk::belowmouse(); 34 | go_fltk_event = evt; 35 | go_fltk_event_state = fltk::event_state(); 36 | go_fltk_event_button = fltk::event_button(); 37 | go_fltk_event_clicks = fltk::event_clicks(); 38 | go_fltk_event_dx = fltk::event_dx(); 39 | go_fltk_event_dy = fltk::event_dy(); 40 | go_fltk_event_key = fltk::event_key(); 41 | go_fltk_event_x = fltk::event_x(); 42 | go_fltk_event_y = fltk::event_y(); 43 | go_fltk_event_x_root = fltk::event_x_root(); 44 | go_fltk_event_y_root = fltk::event_y_root(); 45 | } 46 | 47 | static void respond(int event); 48 | 49 | static void lock() { 50 | fltk::lock(); 51 | } 52 | 53 | static void unlock() { 54 | fltk::awake(); 55 | fltk::unlock(); 56 | } 57 | 58 | class EventThief { 59 | public: 60 | int stealEvents; 61 | int event; 62 | virtual int continue_event(int event) = 0; 63 | int handle(int evt) { 64 | event = evt; 65 | 66 | if (fltk::belowmouse() == dynamic_cast(this)) { 67 | bool stolen = (stealEvents & (1 << evt)) != 0; 68 | 69 | debugf("widget: %x belowmouse: %x, event:%d\n", (unsigned int)dynamic_cast(this), (unsigned int)fltk::belowmouse(), evt); 70 | if (stolen) { 71 | go_fltk_event_stolen = 1; 72 | respond(evt); 73 | return (go_fltk_event_stolen == 0 ? continue_event(evt) : go_fltk_event_return); 74 | } 75 | go_fltk_event_return = continue_event(evt); 76 | respond(evt); 77 | return go_fltk_event_return; 78 | } 79 | return continue_event(evt); 80 | } 81 | }; 82 | 83 | class GWidget : public EventThief, public fltk::Widget { 84 | public: 85 | GWidget(int x, int y, int w, int h, const char *label) : fltk::Widget(x, y, w, h, label) {} 86 | int handle(int event) {return EventThief::handle(event);} 87 | int continue_event(int event) {return fltk::Widget::handle(event);} 88 | }; 89 | 90 | class GInput : public EventThief, public fltk::Input { 91 | public: 92 | int mouse_pos; 93 | 94 | GInput(int x, int y, int w, int h, const char *label) : fltk::Input(x, y, w, h, label) {} 95 | int handle(int event) { 96 | if (event == fltk::PUSH) { 97 | mouse_pos = mouse_position(*this); 98 | } 99 | return EventThief::handle(event); 100 | } 101 | int continue_event(int event) {return fltk::Input::handle(event);} 102 | }; 103 | 104 | class GTextEditor : public EventThief, public fltk::TextEditor { 105 | public: 106 | int evt; 107 | GTextEditor(int x, int y, int w, int h, const char *label) : fltk::TextEditor(x, y, w, h, label) {} 108 | int handle(int event) {return EventThief::handle(event);} 109 | int continue_event(int event) {return fltk::TextEditor::handle(event);} 110 | }; 111 | 112 | static void notify_callback(Widget *w, void *data) { 113 | go_fltk_callback_widget = w; 114 | respond(fltk::NO_EVENT); 115 | } 116 | #define LOCK(code) fltk::lock(); debugf("API LOCKED\n"); code; fltk::awake(); fltk::unlock(); debugf("API UNLOCKED\n"); 117 | 118 | Box *go_fltk_get_UP_BOX() {LOCK(Box *b = fltk::UP_BOX;) return b;} 119 | Font *go_fltk_get_HELVETICA_BOLD_ITALIC() {LOCK(Font *f = fltk::HELVETICA_BOLD_ITALIC;) return f;} 120 | LabelType *go_fltk_get_SHADOW_LABEL() {LOCK(LabelType *t = fltk::SHADOW_LABEL;) return t;} 121 | //void go_fltk_run() {LOCK(fltk::run();)} 122 | Window *go_fltk_new_Window(int w, int h) {LOCK(Window *win = new Window(w, h);) return win;} 123 | PackedGroup *go_fltk_new_PackedGroup(int x, int y, int w, int h) {LOCK(PackedGroup *g = new PackedGroup(x, y, w, h);) return g;} 124 | Widget *go_fltk_new_Widget(int x, int y, int w, int h, const char *text) {LOCK(Widget *wid = new GWidget(x, y, w, h, text);) return wid;} 125 | Input *go_fltk_new_Input(int x, int y, int w, int h, const char *text) {LOCK(Input *i = new GInput(x, y, w, h, text);) return i;} 126 | TextEditor *go_fltk_new_TextEditor(int x, int y, int w, int h, const char *text) {LOCK(TextEditor *te = new GTextEditor(x, y, w, h, text);) return te;} 127 | //TextEditor *go_fltk_new_TextEditor(int x, int y, int w, int h, const char *text) {LOCK(TextEditor *te = new TextEditor(x, y, w, h, text);) return te;} 128 | void go_fltk_Widget_steal_events(Widget *w, int events) {LOCK(dynamic_cast(w)->stealEvents = events;)} 129 | void go_fltk_Event_continue() {LOCK(go_fltk_event_stolen = 0;)} 130 | void go_fltk_Group_begin(Group *g) {LOCK(g->begin();)} 131 | void go_fltk_Group_end(Group *g) {LOCK(g->end();)} 132 | void go_fltk_Group_add(Group *g, Widget *w) {LOCK(g->add(w);)} 133 | void go_fltk_Group_resizable(Group *g, Widget *w) {LOCK(g->resizable(w);)} 134 | void go_fltk_Window_destroy(Window *w) {LOCK(w->destroy();)} 135 | void go_fltk_Window_show(Window *w, int argc, void *argv) {LOCK(w->show(argc, (char **)argv);)} 136 | void go_fltk_Window_set_label(Window *w, const char *label) {LOCK(w->label(label);)} 137 | void go_fltk_Widget_box(Widget *w, Box *box) {LOCK(w->box(box);)} 138 | void go_fltk_Widget_callback(Widget *w) {LOCK(w->callback(notify_callback);)} 139 | void go_fltk_Widget_labelfont(Widget *w, Font *font) {LOCK(w->labelfont(font);)} 140 | void go_fltk_Widget_labelsize(Widget *w, int size) {LOCK(w->labelsize(size);)} 141 | void go_fltk_Widget_labeltype(Widget *w, LabelType *type) {LOCK(w->labeltype(type);)} 142 | int go_fltk_Widget_x(Widget *w) {LOCK(int i = w->x();) return i;} 143 | int go_fltk_Widget_y(Widget *w) {LOCK(int i = w->y();) return i;} 144 | int go_fltk_Widget_w(Widget *w) {LOCK(int i = w->w();) return i;} 145 | int go_fltk_Widget_h(Widget *w) {LOCK(int i = w->h();) return i;} 146 | void go_fltk_Widget_throw_focus(Widget *w) {LOCK(w->throw_focus());} 147 | const char *go_fltk_Input_get_text(Input *in) {LOCK(const char *t = in->text();); return t;} 148 | int go_fltk_Input_set_text(Input *in, const char *t) {LOCK(int b = in->text(t);); return b;} 149 | int go_fltk_Input_mouse_position(Input *in) {LOCK(int pos = dynamic_cast(in)->mouse_pos); return pos;} 150 | int go_fltk_Input_get_position(Input *in) {LOCK(int pos = in->position();); return pos;} 151 | int go_fltk_Input_get_mark(Input *in) {LOCK(int pos = in->mark();); return pos;} 152 | void go_fltk_Input_set_position(Input *in, int p, int m) {LOCK(in->position(p, m));} 153 | //////////////// 154 | /// CHANNELS /// 155 | //////////////// 156 | 157 | static fltk::SignalMutex eventMutex, continueMutex; 158 | static bool eventFlag = false, continueFlag = false; 159 | static bool running = false; 160 | 161 | static void respond(int evt) { 162 | if (running) { 163 | set_event_fields(evt); 164 | debugf("FLTK SENDING EVENT TO GO, UNLOCKING\n"); 165 | unlock(); 166 | eventFlag = true; 167 | eventMutex.signal(); 168 | debugf("FLTK WAITING FOR CONTINUE FROM GO\n"); 169 | while (!continueFlag) {continueMutex.wait();} 170 | continueFlag = false; 171 | debugf("FLTK GOT EVENT FROM GO, LOCKING\n"); 172 | lock(); 173 | debugf("FLTK LOCKED\n"); 174 | } 175 | } 176 | 177 | //void *go_fltk_run(void *data) { 178 | void go_fltk_run() { 179 | lock(); 180 | running = true; 181 | for (;;) { 182 | debugf("FLTK WAITING FOR EVENT\n"); 183 | fltk::wait(); 184 | } 185 | } 186 | 187 | void go_fltk_get_event() { 188 | while (!eventFlag) {eventMutex.wait();} 189 | eventFlag = false; 190 | } 191 | void go_fltk_continue_event(int i) { 192 | lock(); 193 | continueFlag = true; 194 | go_fltk_event_widget = 0; 195 | go_fltk_callback_widget = 0; 196 | go_fltk_event_return = i; 197 | unlock(); 198 | continueMutex.signal(); 199 | } 200 | --------------------------------------------------------------------------------