func (ir *interpreter) unregister_commands(name string) error { if _, ok := ir.methods[name]; !ok { return errors.New("gothic: trying to unregister a non-existent method set") } val := ir.methods[name] t := reflect.TypeOf(val) for i, n := 0, t.NumMethod(); i < n; i++ { m := t.Method(i) if !strings.HasPrefix(m.Name, "TCL") { continue } subname := m.Name[3:] if strings.HasPrefix(m.Name, "TCL_") { subname = m.Name[4:] } cname := C.CString(name + "::" + subname) status := C.Tcl_DeleteCommand(ir.C, cname) C.free(unsafe.Pointer(cname)) if status != C.TCL_OK { return errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } } delete(ir.methods, name) for _, id := range ir.method_handles[name] { ir.handles.free_handle(id) } delete(ir.method_handles, name) return nil }
func (ir *interpreter) eval(script []byte) error { if len(script) == 0 { return nil } status := C.Tcl_EvalEx(ir.C, (*C.char)(unsafe.Pointer(&script[0])), C.int(len(script)), 0) if status != C.TCL_OK { return errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } return nil }
func (ir *Interpreter) UnregisterChannel(name string) { if _, ok := ir.channels[name]; !ok { return } cname := C.CString(name) status := C.Tcl_DeleteCommand(ir.C, cname) C.free_string(cname) if status != C.TCL_OK { panic(C.GoString(C.Tcl_GetStringResult(ir.C))) } }
func (ir *interpreter) eval(args ...interface{}) error { ir.cmdbuf.Reset() fmt.Fprint(&ir.cmdbuf, args...) ir.cmdbuf.WriteByte(0) status := C.Tcl_Eval(ir.C, (*C.char)(unsafe.Pointer(&ir.cmdbuf.Bytes()[0]))) if status != C.TCL_OK { return errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } return nil }
func NewInterpreter() (*Interpreter, os.Error) { ir := &Interpreter{ C: C.Tcl_CreateInterp(), callbacks: make(map[string]interface{}), channels: make(map[string]interface{}), valuesbuf: make([]reflect.Value, 0, 10), queue: make(chan string, 50), } status := C.Tcl_Init(ir.C) if status != C.TCL_OK { return nil, os.NewError(C.GoString(C.Tcl_GetStringResult(ir.C))) } status = C.Tk_Init(ir.C) if status != C.TCL_OK { return nil, os.NewError(C.GoString(C.Tcl_GetStringResult(ir.C))) } return ir, nil }
func (ir *interpreter) unregister_command(name string) error { if _, ok := ir.commands[name]; !ok { return errors.New("gothic: trying to unregister a non-existent command") } cname := C.CString(name) status := C.Tcl_DeleteCommand(ir.C, cname) C.free(unsafe.Pointer(cname)) if status != C.TCL_OK { return errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } return nil }
func new_interpreter(init interface{}) (*interpreter, error) { ir := &interpreter{ C: C.Tcl_CreateInterp(), errfilt: func(err error) error { return err }, commands: make(map[string]interface{}), methods: make(map[string]interface{}), method_handles: make(map[string][]int), valuesbuf: make([]reflect.Value, 0, 10), queue: make(chan async_action, 50), thread: C.Tcl_GetCurrentThread(), } C.Tcl_FindExecutable(C.CString(os.Args[0])) switch realinit := init.(type) { case string: err := ir.eval([]byte(realinit)) if err != nil { panic(err) } case func(*interpreter): realinit(ir) } status := C.Tcl_Init(ir.C) if status != C.TCL_OK { return nil, errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } status = C.Tk_Init(ir.C) if status != C.TCL_OK { return nil, errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } ir.id = global_handles.get_handle_for_value(ir) runtime.SetFinalizer(ir, release_interpreter) return ir, nil }
func (ir *interpreter) upload_image(name string, img image.Image) error { var buf bytes.Buffer err := sprintf(&buf, "image create photo %{}", name) if err != nil { return err } nrgba, ok := img.(*image.NRGBA) if !ok { // let's do it slowpoke bounds := img.Bounds() nrgba = image.NewNRGBA(bounds) for x := 0; x < bounds.Max.X; x++ { for y := 0; y < bounds.Max.Y; y++ { nrgba.Set(x, y, img.At(x, y)) } } } cname := C.CString(name) handle := C.Tk_FindPhoto(ir.C, cname) if handle == nil { err := ir.eval(buf.Bytes()) if err != nil { return err } handle = C.Tk_FindPhoto(ir.C, cname) if handle == nil { return errors.New("failed to create an image handle") } } C.free(unsafe.Pointer(cname)) block := C.Tk_PhotoImageBlock{ (*C.uchar)(unsafe.Pointer(&nrgba.Pix[0])), C.int(nrgba.Rect.Max.X), C.int(nrgba.Rect.Max.Y), C.int(nrgba.Stride), 4, [...]C.int{0, 1, 2, 3}, } status := C.Tk_PhotoPutBlock(ir.C, handle, &block, 0, 0, C.int(nrgba.Rect.Max.X), C.int(nrgba.Rect.Max.Y), C.TK_PHOTO_COMPOSITE_SET) // alpha should be non-zero or you may get peculiar slowdowns // Note: C.TK_PHOTO_COMPOSITE_OVERLAY would overlay an existing image if status != C.TCL_OK { return errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } return nil }
func (ir *interpreter) set(name string, value interface{}) error { obj := go_value_to_tcl_obj(value, ir) if obj == nil { return errors.New("gothic: cannot convert Go value to TCL object") } cname := C.CString(name) obj = C.Tcl_SetVar2Ex(ir.C, cname, nil, obj, C.TCL_LEAVE_ERR_MSG) C.free(unsafe.Pointer(cname)) if obj == nil { return errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } return nil }
func new_interpreter() (*interpreter, error) { ir := &interpreter{ C: C.Tcl_CreateInterp(), errfilt: func(err error) error { return err }, commands: make(map[string]interface{}), channels: make(map[string]interface{}), valuesbuf: make([]reflect.Value, 0, 10), queue: make(chan async_action, 50), thread: C.Tcl_GetCurrentThread(), } status := C.Tcl_Init(ir.C) if status != C.TCL_OK { return nil, errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } status = C.Tk_Init(ir.C) if status != C.TCL_OK { return nil, errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } return ir, nil }
func (ir *Interpreter) NewIntVar(name string) *IntVar { iv := new(IntVar) iv.ir = ir iv.name = name iv.data = 0 cname := C.CString(name) status := C.Tcl_LinkVar(ir.C, cname, (*C.char)(unsafe.Pointer(&iv.data)), C.TCL_LINK_WIDE_INT) C.free_string(cname) if status != C.TCL_OK { panic(C.GoString(C.Tcl_GetStringResult(ir.C))) } return iv }
func (ir *Interpreter) NewFloatVar(name string) *FloatVar { fv := new(FloatVar) fv.ir = ir fv.name = name fv.data = 0.0 cname := C.CString(name) status := C.Tcl_LinkVar(ir.C, cname, (*C.char)(unsafe.Pointer(&fv.data)), C.TCL_LINK_DOUBLE) C.free_string(cname) if status != C.TCL_OK { panic(C.GoString(C.Tcl_GetStringResult(ir.C))) } return fv }
func (ir *Interpreter) NewStringVar(name string) *StringVar { sv := new(StringVar) sv.ir = ir sv.name = name sv.data = C.Tcl_Alloc(1) (*((*[alot]byte)(unsafe.Pointer(sv.data))))[0] = 0 cname := C.CString(name) status := C.Tcl_LinkVar(ir.C, cname, (*C.char)(unsafe.Pointer(&sv.data)), C.TCL_LINK_STRING) C.free_string(cname) if status != C.TCL_OK { panic(C.GoString(C.Tcl_GetStringResult(ir.C))) } return sv }
func (ir *Interpreter) Eval(args ...string) { for _, arg := range args { ir.cmdbuf.WriteString(arg) ir.cmdbuf.WriteString(" ") } s := ir.cmdbuf.String() ir.cmdbuf.Reset() if debug { println(s) } cs := C.CString(s) status := C.Tcl_Eval(ir.C, cs) C.free_string(cs) if status != C.TCL_OK { fmt.Fprintln(os.Stderr, C.GoString(C.Tcl_GetStringResult(ir.C))) } }
func (ir *interpreter) tcl_obj_to_go_value(obj *C.Tcl_Obj, v reflect.Value) error { var status C.int switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: var out C.Tcl_WideInt status = C.Tcl_GetWideIntFromObj(ir.C, obj, &out) if status == C.TCL_OK { v.SetInt(int64(out)) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: var out C.Tcl_WideInt status = C.Tcl_GetWideIntFromObj(ir.C, obj, &out) if status == C.TCL_OK { v.SetUint(uint64(out)) } case reflect.String: var n C.int out := C.Tcl_GetStringFromObj(obj, &n) v.SetString(C.GoStringN(out, n)) case reflect.Float32, reflect.Float64: var out C.double status = C.Tcl_GetDoubleFromObj(ir.C, obj, &out) if status == C.TCL_OK { v.SetFloat(float64(out)) } case reflect.Bool: var out C.int status = C.Tcl_GetBooleanFromObj(ir.C, obj, &out) if status == C.TCL_OK { v.SetBool(out == 1) } default: return fmt.Errorf("gothic: cannot convert TCL object to Go type: %s", v.Type()) } if status != C.TCL_OK { return errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } return nil }
func (ir *interpreter) upload_image(name string, img image.Image) error { nrgba, ok := img.(*image.NRGBA) if !ok { // let's do it slowpoke bounds := img.Bounds() nrgba = image.NewNRGBA(bounds) for x := 0; x < bounds.Max.X; x++ { for y := 0; y < bounds.Max.Y; y++ { nrgba.Set(x, y, img.At(x, y)) } } } cname := C.CString(name) handle := C.Tk_FindPhoto(ir.C, cname) if handle == nil { ir.eval("image create photo ", name) handle = C.Tk_FindPhoto(ir.C, cname) if handle == nil { return errors.New("failed to create an image handle") } } C.free(unsafe.Pointer(cname)) block := C.Tk_PhotoImageBlock{ (*C.uchar)(unsafe.Pointer(&nrgba.Pix[0])), C.int(nrgba.Rect.Max.X), C.int(nrgba.Rect.Max.Y), C.int(nrgba.Stride), 4, [...]C.int{0, 1, 2, 3}, } status := C.Tk_PhotoPutBlock(ir.C, handle, &block, 0, 0, C.int(nrgba.Rect.Max.X), C.int(nrgba.Rect.Max.Y), C.TK_PHOTO_COMPOSITE_SET) if status != C.TCL_OK { return errors.New(C.GoString(C.Tcl_GetStringResult(ir.C))) } return nil }