|
|
@@ -0,0 +1,861 @@
|
|
|
+// Copyright 2018 visualfc. All rights reserved.
|
|
|
+
|
|
|
+package interp
|
|
|
+
|
|
|
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output zinterp_windows.go interp_windows.go
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "fmt"
|
|
|
+ "image"
|
|
|
+ "image/color"
|
|
|
+ "image/draw"
|
|
|
+ "os"
|
|
|
+ "syscall"
|
|
|
+ "unsafe"
|
|
|
+)
|
|
|
+
|
|
|
+//NOTE: BytePtrToString replace cgo C.GoStringN
|
|
|
+
|
|
|
+type Tcl_Interp struct{}
|
|
|
+type Tcl_ThreadId struct{}
|
|
|
+type Tcl_Obj struct{}
|
|
|
+type Tcl_Command struct{}
|
|
|
+type Tk_PhotoHandle struct{}
|
|
|
+
|
|
|
+type Tcl_WideInt int64
|
|
|
+type Tcl_Double float64
|
|
|
+
|
|
|
+type Tcl_Event struct {
|
|
|
+ Proc uintptr
|
|
|
+ NextPtr *Tcl_Event
|
|
|
+}
|
|
|
+
|
|
|
+type Tk_PhotoImageBlock struct {
|
|
|
+ pixelPtr *byte
|
|
|
+ width int32
|
|
|
+ height int32
|
|
|
+ pitch int32
|
|
|
+ pixelSize int32
|
|
|
+ offset [4]int32
|
|
|
+}
|
|
|
+
|
|
|
+// windows api calls
|
|
|
+
|
|
|
+//sys Tcl_CreateInterp() (interp *Tcl_Interp) = tcl86t.Tcl_CreateInterp
|
|
|
+//sys Tcl_DeleteInterp(interp *Tcl_Interp) = tcl86t.Tcl_DeleteInterp
|
|
|
+
|
|
|
+//sys Tcl_Alloc(size uint) (r *Tcl_Event) = tcl86t.Tcl_Alloc
|
|
|
+//sys Tcl_Eval(interp *Tcl_Interp, script *byte) (r int32) = tcl86t.Tcl_Eval
|
|
|
+//sys Tcl_EvalEx(interp *Tcl_Interp, script *byte, length int32, flags int32) (r int32) = tcl86t.Tcl_EvalEx
|
|
|
+//sys Tcl_GetStringResult(interp *Tcl_Interp) (ret *byte) = tcl86t.Tcl_GetStringResult
|
|
|
+//sys Tcl_GetObjResult(interp *Tcl_Interp) (obj *Tcl_Obj) = tcl86t.Tcl_GetObjResult
|
|
|
+//sys Tcl_GetWideIntFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *Tcl_WideInt) (status int32) = tcl86t.Tcl_GetWideIntFromObj
|
|
|
+//-sys Tcl_GetLongFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *int) (status int32) = tcl86t.Tcl_GetLongFromObj
|
|
|
+//sys Tcl_GetDoubleFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *Tcl_Double) (status int32) = tcl86t.Tcl_GetDoubleFromObj
|
|
|
+//sys Tcl_GetBooleanFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *int32) (status int32) = tcl86t.Tcl_GetBooleanFromObj
|
|
|
+//sys Tcl_GetStringFromObj(obj *Tcl_Obj, length *int32) (ret *byte) = tcl86t.Tcl_GetStringFromObj
|
|
|
+//sys Tcl_NewWideIntObj(value Tcl_WideInt) (obj *Tcl_Obj) = tcl86t.Tcl_NewWideIntObj
|
|
|
+//-sys Tcl_NewLongObj(value int) (obj *Tcl_Obj) = tcl86t.Tcl_NewLongObj
|
|
|
+//sys Tcl_NewDoubleObj(value Tcl_Double) (obj *Tcl_Obj) = tcl86t.Tcl_NewDoubleObj
|
|
|
+//sys Tcl_NewBooleanObj(value int32) (obj *Tcl_Obj) = tcl86t.Tcl_NewBooleanObj
|
|
|
+//sys Tcl_NewStringObj(bytes *byte, length int32) (obj *Tcl_Obj) = tcl86t.Tcl_NewStringObj
|
|
|
+//sys Tcl_Init(interp *Tcl_Interp) (r int32) = tcl86t.Tcl_Init
|
|
|
+//sys Tcl_GetCurrentThread() (threadid *Tcl_ThreadId) = tcl86t.Tcl_GetCurrentThread
|
|
|
+//sys Tcl_ThreadQueueEvent(threadId *Tcl_ThreadId, evPtr *Tcl_Event, positon Tcl_QueuePosition) = tcl86t.Tcl_ThreadQueueEvent
|
|
|
+//sys Tcl_ThreadAlert(threadId *Tcl_ThreadId) = tcl86t.Tcl_ThreadAlert
|
|
|
+//sys Tcl_CreateObjCommand(interp *Tcl_Interp, cmdName *byte, proc uintptr, clientData uintptr, deleteProc uintptr) (cmd *Tcl_Command) = tcl86t.Tcl_CreateObjCommand
|
|
|
+//sys Tcl_CreateCommand(interp *Tcl_Interp, cmdName *byte, proc uintptr, clientData uintptr, deleteProc uintptr) (cmd *Tcl_Command) = tcl86t.Tcl_CreateCommand
|
|
|
+//sys Tcl_SetObjResult(interp *Tcl_Interp, resultObjPtr *Tcl_Obj) = tcl86t.Tcl_SetObjResult
|
|
|
+//sys Tcl_WrongNumArgs(interp *Tcl_Interp, objc int32, objv uintptr, message *byte) = tcl86t.Tcl_WrongNumArgs
|
|
|
+//sys Tcl_NewListObj(objc int, objv **Tcl_Obj)(obj *Tcl_Obj) = tcl86t.Tcl_NewListObj
|
|
|
+//sys Tcl_ListObjLength(interp *Tcl_Interp, listobj *Tcl_Obj, length *int32) (status int32) = tcl86t.Tcl_ListObjLength
|
|
|
+//sys Tcl_ListObjIndex(interp *Tcl_Interp, listobj *Tcl_Obj, index int32, out **Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjIndex
|
|
|
+//sys Tcl_ListObjGetElements(interp *Tcl_Interp, listobj *Tcl_Obj, objc *int32, objv ***Tcl_Obj)(status int32) = tcl86t.Tcl_ListObjGetElements
|
|
|
+//sys Tcl_SetListObj(listobj *Tcl_Obj, objc int, objv **Tcl_Obj) = tcl86t.Tcl_SetListObj
|
|
|
+//sys Tcl_ListObjAppendElement(interp *Tcl_Interp, listobj *Tcl_Obj, obj *Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjAppendElement
|
|
|
+//sys Tcl_ListObjReplace(interp *Tcl_Interp, listobj *Tcl_Obj, first int32, count int32, objc int32, objv **Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjReplace
|
|
|
+//sys Tcl_GetVar2Ex(interp *Tcl_Interp,part1 *byte, part2 *byte, flags int32) (obj *Tcl_Obj) = tcl86t.Tcl_GetVar2Ex
|
|
|
+//sys Tcl_SetVar(interp *Tcl_Interp,name *byte, value *byte, flags int32) (r *byte) = tcl86t.Tcl_SetVar
|
|
|
+//sys Tcl_SetVar2Ex(interp *Tcl_Interp,part1 *byte, part2 *byte, value *Tcl_Obj, flags int32) (r *byte) = tcl86t.Tcl_SetVar2Ex
|
|
|
+//sys Tcl_UnsetVar(interp *Tcl_Interp,part1 *byte, flags int32) (status int32) = tcl86t.Tcl_UnsetVar
|
|
|
+
|
|
|
+//sys Tk_Init(interp *Tcl_Interp) (r int32) = tk86t.Tk_Init
|
|
|
+//sys Tk_MainLoop() = tk86t.Tk_MainLoop
|
|
|
+//sys Tk_FindPhoto(interp *Tcl_Interp, imageName *byte) (handle *Tk_PhotoHandle) = tk86t.Tk_FindPhoto
|
|
|
+//sys Tk_PhotoBlank(handle *Tk_PhotoHandle) = tk86t.Tk_PhotoBlank
|
|
|
+//sys Tk_PhotoSetSize(interp *Tcl_Interp,handle *Tk_PhotoHandle, width int32, height int32) (status int32) = tk86t.Tk_PhotoSetSize
|
|
|
+//sys Tk_PhotoGetSize(hanlde *Tk_PhotoHandle, widthPtr *int32, heightPtr *int32) = tk86t.Tk_PhotoGetSize
|
|
|
+//sys Tk_PhotoExpand(interp *Tcl_Interp,handle *Tk_PhotoHandle, width int32, height int32) (status int32) = tk86t.Tk_PhotoExpand
|
|
|
+//sys Tk_PhotoGetImage(handle *Tk_PhotoHandle, blockPtr *Tk_PhotoImageBlock) (status int32) = tk86t.Tk_PhotoGetImage
|
|
|
+//sys Tk_PhotoPutBlock(interp *Tcl_Interp, handle *Tk_PhotoHandle,blockPtr *Tk_PhotoImageBlock, x int32, y int32, width int32, height int32, compRule int32) (status int32) = tk86t.Tk_PhotoPutBlock
|
|
|
+//sys Tk_PhotoPutZoomedBlock(interp *Tcl_Interp, handle *Tk_PhotoHandle,blockPtr *Tk_PhotoImageBlock, x int32, y int32, width int32, height int32, zoomX int32, zoomY int32, subsampleX int32, subsampleY int32, compRule int32) (status int32) = tk86t.Tk_PhotoPutZoomedBlock
|
|
|
+
|
|
|
+func init() {
|
|
|
+ err := modtcl86t.Load()
|
|
|
+ if err != nil {
|
|
|
+ modtcl86t.Name = "tcl86.dll"
|
|
|
+ modtk86t.Name = "tk86.dll"
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+var (
|
|
|
+ mainLoopThreadId *Tcl_ThreadId
|
|
|
+)
|
|
|
+
|
|
|
+func _go_async_event_handler(ev *Tcl_Event, flags int32) int {
|
|
|
+ if flags != TCL_ALL_EVENTS {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+ if fn, ok := globalAsyncEvent.Load(unsafe.Pointer(ev)); ok {
|
|
|
+ fn.(func())()
|
|
|
+ globalAsyncEvent.Delete(unsafe.Pointer(ev))
|
|
|
+ }
|
|
|
+ return 1
|
|
|
+}
|
|
|
+
|
|
|
+func IsMainThread() bool {
|
|
|
+ return Tcl_GetCurrentThread() == mainLoopThreadId
|
|
|
+}
|
|
|
+
|
|
|
+func async_send_event(tid *Tcl_ThreadId, fn func()) {
|
|
|
+ var ev *Tcl_Event
|
|
|
+ ev = Tcl_Alloc(uint(unsafe.Sizeof(*ev)))
|
|
|
+ ev.Proc = syscall.NewCallbackCDecl(_go_async_event_handler)
|
|
|
+ ev.NextPtr = nil
|
|
|
+ globalAsyncEvent.Store(unsafe.Pointer(ev), fn)
|
|
|
+ Tcl_ThreadQueueEvent(tid, ev, TCL_QUEUE_TAIL)
|
|
|
+ Tcl_ThreadAlert(tid)
|
|
|
+}
|
|
|
+
|
|
|
+func Async(fn func()) {
|
|
|
+ if fn == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ async_send_event(mainLoopThreadId, fn)
|
|
|
+}
|
|
|
+
|
|
|
+func MainLoop(fn func()) {
|
|
|
+ mainLoopThreadId = Tcl_GetCurrentThread()
|
|
|
+ if fn != nil {
|
|
|
+ fn()
|
|
|
+ }
|
|
|
+ Tk_MainLoop()
|
|
|
+ mainLoopThreadId = nil
|
|
|
+}
|
|
|
+
|
|
|
+type Interp struct {
|
|
|
+ interp *Tcl_Interp
|
|
|
+ supportTk86 bool
|
|
|
+}
|
|
|
+
|
|
|
+func NewInterp() (*Interp, error) {
|
|
|
+ err := modtcl86t.Load()
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ interp := Tcl_CreateInterp()
|
|
|
+ if interp == nil {
|
|
|
+ return nil, errors.New("Tcl_CreateInterp failed")
|
|
|
+ }
|
|
|
+ return &Interp{interp, false}, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) SupportTk86() bool {
|
|
|
+ return p.supportTk86
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) InitTcl(tcl_library string) error {
|
|
|
+ if tcl_library != "" {
|
|
|
+ p.Eval(fmt.Sprintf("set tcl_library {%s}", tcl_library))
|
|
|
+ }
|
|
|
+ if Tcl_Init(p.interp) != TCL_OK {
|
|
|
+ err := errors.New("Tcl_Init failed")
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) InitTk(tk_library string) error {
|
|
|
+ err := modtk86t.Load()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if tk_library != "" {
|
|
|
+ p.Eval(fmt.Sprintf("set tk_library {%s}", tk_library))
|
|
|
+ }
|
|
|
+ if Tk_Init(p.interp) != TCL_OK {
|
|
|
+ err := errors.New("Tk_Init failed")
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ p.supportTk86 = p.TkVersion() >= "8.6"
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) Destroy() error {
|
|
|
+ if p == nil || p.interp == nil {
|
|
|
+ return os.ErrInvalid
|
|
|
+ }
|
|
|
+ Tcl_DeleteInterp(p.interp)
|
|
|
+ p.interp = nil
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func BytePtrToString(data *byte, length int32) string {
|
|
|
+ if length == 0 {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+ p := (*[1 << 30]byte)(unsafe.Pointer(data))[:length]
|
|
|
+ a := make([]byte, length)
|
|
|
+ copy(a, p)
|
|
|
+ return string(a)
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) GetObjResult() *Obj {
|
|
|
+ obj := Tcl_GetObjResult(p.interp)
|
|
|
+ return &Obj{obj, p.interp}
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) GetListObjResult() *ListObj {
|
|
|
+ return &ListObj{Tcl_GetObjResult(p.interp), p.interp}
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) Eval(script string) error {
|
|
|
+ s, err := syscall.BytePtrFromString(script)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if Tcl_EvalEx(p.interp, s, int32(len(script)), 0) != TCL_OK {
|
|
|
+ err := errors.New(p.GetStringResult())
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+//typedef int (Tcl_ObjCmdProc) (ClientData clientData, *Tcl_Interp *interp, int objc, struct *Tcl_Obj *const *objv);
|
|
|
+func _go_tcl_objcmd_proc(clientData uintptr, interp *Tcl_Interp, objc int, objv unsafe.Pointer) int {
|
|
|
+ objs := (*(*[1 << 20]*Tcl_Obj)(objv))[1:objc]
|
|
|
+ var args []string
|
|
|
+ for _, obj := range objs {
|
|
|
+ args = append(args, objToString(interp, obj))
|
|
|
+ }
|
|
|
+ result, err := globalCommandMap.Invoke(clientData, args)
|
|
|
+ if err != nil {
|
|
|
+ cs, _ := syscall.BytePtrFromString(err.Error())
|
|
|
+ Tcl_WrongNumArgs(interp, 1, uintptr(objv), cs)
|
|
|
+ return TCL_ERROR
|
|
|
+ }
|
|
|
+ if result != "" {
|
|
|
+ Tcl_SetObjResult(interp, stringToObj(result))
|
|
|
+ }
|
|
|
+ return TCL_OK
|
|
|
+}
|
|
|
+
|
|
|
+//typedef void (Tcl_CmdDeleteProc) (ClientData clientData);
|
|
|
+func _go_tcl_cmddelete_proc(clientData uintptr) int {
|
|
|
+ globalCommandMap.UnRegister(clientData)
|
|
|
+ return 0
|
|
|
+}
|
|
|
+
|
|
|
+func _go_tcl_action_proc(id uintptr, interp *Tcl_Interp, objc int, objv unsafe.Pointer) int {
|
|
|
+ objs := (*(*[1 << 20]*Tcl_Obj)(objv))[1:objc]
|
|
|
+ var args []string
|
|
|
+ for _, obj := range objs {
|
|
|
+ args = append(args, objToString(interp, obj))
|
|
|
+ }
|
|
|
+ err := globalActionMap.Invoke(id, args)
|
|
|
+ if err != nil {
|
|
|
+ cs, _ := syscall.BytePtrFromString(err.Error())
|
|
|
+ Tcl_WrongNumArgs(interp, 1, uintptr(objv), cs)
|
|
|
+ return TCL_ERROR
|
|
|
+ }
|
|
|
+ return TCL_OK
|
|
|
+}
|
|
|
+
|
|
|
+func _go_tcl_actiono_delete_proc(id uintptr) int {
|
|
|
+ globalActionMap.UnRegister(id)
|
|
|
+ return 0
|
|
|
+}
|
|
|
+
|
|
|
+//Tcl_Command Tcl_CreateObjCommand(*Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
|
|
|
+func (p *Interp) CreateCommand(name string, fn func([]string) (string, error)) (uintptr, error) {
|
|
|
+ s, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return 0, err
|
|
|
+ }
|
|
|
+ id := globalCommandMap.Register(fn)
|
|
|
+ cmd := Tcl_CreateObjCommand(p.interp, s, syscall.NewCallbackCDecl(_go_tcl_objcmd_proc), id, syscall.NewCallbackCDecl(_go_tcl_cmddelete_proc))
|
|
|
+ if cmd == nil {
|
|
|
+ err := fmt.Errorf("CreateCommand %v failed", name)
|
|
|
+ return 0, err
|
|
|
+ }
|
|
|
+ return id, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) InvokeCommand(id uintptr, args []string) (string, error) {
|
|
|
+ return globalCommandMap.Invoke(id, args)
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) CreateAction(name string, action func([]string)) (uintptr, error) {
|
|
|
+ s, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return 0, err
|
|
|
+ }
|
|
|
+ id := globalActionMap.Register(action)
|
|
|
+ cmd := Tcl_CreateObjCommand(p.interp, s, syscall.NewCallbackCDecl(_go_tcl_action_proc), id, syscall.NewCallbackCDecl(_go_tcl_actiono_delete_proc))
|
|
|
+ if cmd == nil {
|
|
|
+ err := fmt.Errorf("CreateAction %v failed", name)
|
|
|
+ return 0, err
|
|
|
+ }
|
|
|
+ return id, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) InvokeAction(id uintptr, args []string) error {
|
|
|
+ return globalActionMap.Invoke(id, args)
|
|
|
+}
|
|
|
+
|
|
|
+const (
|
|
|
+ TCL_LEAVE_ERR_MSG = 0x200
|
|
|
+ TCL_GLOBAL_ONLY = 1
|
|
|
+ TCL_NAMESPACE_ONLY = 2
|
|
|
+ TCL_APPEND_VALUE = 4
|
|
|
+ TCL_LIST_ELEMENT = 8
|
|
|
+)
|
|
|
+
|
|
|
+func (p *Interp) GetVar(name string, global bool) *Obj {
|
|
|
+ cname, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ var flag int32 = TCL_LEAVE_ERR_MSG
|
|
|
+ if global {
|
|
|
+ flag |= TCL_GLOBAL_ONLY
|
|
|
+ }
|
|
|
+ obj := Tcl_GetVar2Ex(p.interp, cname, nil, flag)
|
|
|
+ if obj == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return &Obj{obj, p.interp}
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) GetList(name string, global bool) *ListObj {
|
|
|
+ return (*ListObj)(p.GetVar(name, global))
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) SetStringList(name string, list []string, global bool) error {
|
|
|
+ obj := NewListObj(p)
|
|
|
+ obj.AppendStringList(list)
|
|
|
+ return p.SetVarObj(name, (*Obj)(obj), global)
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) AppendStringListList(name string, list []string, global bool) error {
|
|
|
+ cname, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT
|
|
|
+ if global {
|
|
|
+ flag |= TCL_GLOBAL_ONLY
|
|
|
+ }
|
|
|
+ for _, value := range list {
|
|
|
+ cvalue, _ := syscall.BytePtrFromString(value)
|
|
|
+ Tcl_SetVar(p.interp, cname, cvalue, flag)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) AppendStringList(name string, value string, global bool) error {
|
|
|
+ cname, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ cvalue, err := syscall.BytePtrFromString(value)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT
|
|
|
+ if global {
|
|
|
+ flag |= TCL_GLOBAL_ONLY
|
|
|
+ }
|
|
|
+ r := Tcl_SetVar(p.interp, cname, cvalue, flag)
|
|
|
+ if r == nil {
|
|
|
+ return p.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) SetVarObj(name string, obj *Obj, global bool) error {
|
|
|
+ if obj == nil {
|
|
|
+ return os.ErrInvalid
|
|
|
+ }
|
|
|
+ cname, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ var flag int32 = TCL_LEAVE_ERR_MSG
|
|
|
+ if global {
|
|
|
+ flag |= TCL_GLOBAL_ONLY
|
|
|
+ }
|
|
|
+ r := Tcl_SetVar2Ex(p.interp, cname, nil, obj.obj, flag)
|
|
|
+ if r == nil {
|
|
|
+ return p.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) SetVarListObj(name string, obj *ListObj, global bool) error {
|
|
|
+ return p.SetVarObj(name, (*Obj)(obj), global)
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) SetStringVar(name string, value string, global bool) error {
|
|
|
+ cname, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ cvalue, err := syscall.BytePtrFromString(value)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ var flag int32 = TCL_LEAVE_ERR_MSG
|
|
|
+ if global {
|
|
|
+ flag |= TCL_GLOBAL_ONLY
|
|
|
+ }
|
|
|
+ r := Tcl_SetVar(p.interp, cname, cvalue, flag)
|
|
|
+ if r == nil {
|
|
|
+ return p.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) AppendStringVar(name string, value string, global bool) error {
|
|
|
+ cname, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ cvalue, err := syscall.BytePtrFromString(value)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
|
|
|
+ if global {
|
|
|
+ flag |= TCL_GLOBAL_ONLY
|
|
|
+ }
|
|
|
+ r := Tcl_SetVar(p.interp, cname, cvalue, flag)
|
|
|
+ if r == nil {
|
|
|
+ return p.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Interp) UnsetVar(name string, global bool) error {
|
|
|
+ cname, err := syscall.BytePtrFromString(name)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ var flag int32 = TCL_LEAVE_ERR_MSG
|
|
|
+ if global {
|
|
|
+ flag |= TCL_GLOBAL_ONLY
|
|
|
+ }
|
|
|
+ r := Tcl_UnsetVar(p.interp, cname, flag)
|
|
|
+ if r != TCL_OK {
|
|
|
+ return p.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+type Obj struct {
|
|
|
+ obj *Tcl_Obj
|
|
|
+ interp *Tcl_Interp
|
|
|
+}
|
|
|
+
|
|
|
+func NewRawObj(obj *Tcl_Obj, interp *Tcl_Interp) *Obj {
|
|
|
+ return &Obj{obj, interp}
|
|
|
+}
|
|
|
+
|
|
|
+func (o *Obj) ToFloat64() float64 {
|
|
|
+ var out Tcl_Double
|
|
|
+ status := Tcl_GetDoubleFromObj(o.interp, o.obj, &out)
|
|
|
+ if status == TCL_OK {
|
|
|
+ return float64(out)
|
|
|
+ }
|
|
|
+ return 0
|
|
|
+}
|
|
|
+
|
|
|
+func (o *Obj) ToInt64() int64 {
|
|
|
+ var out Tcl_WideInt
|
|
|
+ status := Tcl_GetWideIntFromObj(o.interp, o.obj, &out)
|
|
|
+ if status == TCL_OK {
|
|
|
+ return int64(out)
|
|
|
+ }
|
|
|
+ return 0
|
|
|
+}
|
|
|
+
|
|
|
+func (o *Obj) ToInt() int {
|
|
|
+ return int(o.ToInt64())
|
|
|
+}
|
|
|
+
|
|
|
+func (o *Obj) ToUint() uint {
|
|
|
+ return uint(o.ToInt64())
|
|
|
+}
|
|
|
+
|
|
|
+func (o *Obj) ToBool() bool {
|
|
|
+ var out int32
|
|
|
+ status := Tcl_GetBooleanFromObj(o.interp, o.obj, &out)
|
|
|
+ if status == TCL_OK {
|
|
|
+ return out == 1
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+func (o *Obj) ToString() string {
|
|
|
+ var n int32
|
|
|
+ out := Tcl_GetStringFromObj(o.obj, &n)
|
|
|
+ return BytePtrToString(out, n)
|
|
|
+}
|
|
|
+
|
|
|
+func NewStringObj(value string, p *Interp) *Obj {
|
|
|
+ s, err := syscall.BytePtrFromString(value)
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return &Obj{Tcl_NewStringObj(s, int32(len(value))), p.interp}
|
|
|
+}
|
|
|
+
|
|
|
+//NOTE: Tcl_NewDoubleObj test error on windows
|
|
|
+func NewFloat64Obj(value float64, p *Interp) *Obj {
|
|
|
+ //return &Obj{Tcl_NewDoubleObj(Tcl_Double(value)), p.interp}
|
|
|
+ return NewStringObj(fmt.Sprintf("%v", value), p)
|
|
|
+}
|
|
|
+
|
|
|
+//NOTE: Tcl_NewWideIntObj test error on windows 32 bit
|
|
|
+func NewInt64Obj(value int64, p *Interp) *Obj {
|
|
|
+ return NewStringObj(fmt.Sprintf("%v", value), p)
|
|
|
+ //return &Obj{Tcl_NewWideIntObj(Tcl_WideInt(value)), p.interp}
|
|
|
+}
|
|
|
+
|
|
|
+//NOTE: use int to string for amd64/i386
|
|
|
+func NewIntObj(value int, p *Interp) *Obj {
|
|
|
+ return NewStringObj(fmt.Sprintf("%v", value), p)
|
|
|
+ // return &Obj{Tcl_NewLongObj(value), p.interp}
|
|
|
+}
|
|
|
+
|
|
|
+func NewBoolObj(value bool, p *Interp) *Obj {
|
|
|
+ if value {
|
|
|
+ return &Obj{Tcl_NewBooleanObj(1), p.interp}
|
|
|
+ } else {
|
|
|
+ return &Obj{Tcl_NewBooleanObj(0), p.interp}
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func objToString(interp *Tcl_Interp, obj *Tcl_Obj) string {
|
|
|
+ var n int32
|
|
|
+ out := Tcl_GetStringFromObj(obj, &n)
|
|
|
+ return BytePtrToString(out, n)
|
|
|
+ //return C.GoStringN((*C.char)(unsafe.Pointer(out)), (C.int)(n))
|
|
|
+}
|
|
|
+
|
|
|
+func stringToObj(value string) *Tcl_Obj {
|
|
|
+ s, err := syscall.BytePtrFromString(value)
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return Tcl_NewStringObj(s, int32(len(value)))
|
|
|
+}
|
|
|
+
|
|
|
+type ListObj Obj
|
|
|
+
|
|
|
+func NewListObj(p *Interp) *ListObj {
|
|
|
+ o := Tcl_NewListObj(0, nil)
|
|
|
+ return &ListObj{o, p.interp}
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) Length() int {
|
|
|
+ var length int32
|
|
|
+ Tcl_ListObjLength(o.interp, o.obj, &length)
|
|
|
+ return int(length)
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) IndexObj(index int) *Obj {
|
|
|
+ var obj *Tcl_Obj
|
|
|
+ r := Tcl_ListObjIndex(o.interp, o.obj, int32(index), &obj)
|
|
|
+ if r != TCL_OK || obj == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return &Obj{obj, o.interp}
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) IndexString(index int) string {
|
|
|
+ var obj *Tcl_Obj
|
|
|
+ r := Tcl_ListObjIndex(o.interp, o.obj, int32(index), &obj)
|
|
|
+ if r != TCL_OK || obj == nil {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+ return objToString(o.interp, obj)
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) ToObjList() (list []*Obj) {
|
|
|
+ var objs **Tcl_Obj
|
|
|
+ var objnum int32
|
|
|
+ Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
|
|
|
+ if objnum == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
|
|
|
+ for _, v := range lst {
|
|
|
+ list = append(list, &Obj{v, o.interp})
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) ToStringList() (list []string) {
|
|
|
+ var objs **Tcl_Obj
|
|
|
+ var objnum int32
|
|
|
+ Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
|
|
|
+ if objnum == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
|
|
|
+ var n int32
|
|
|
+ for _, obj := range lst {
|
|
|
+ out := Tcl_GetStringFromObj(obj, &n)
|
|
|
+ list = append(list, BytePtrToString(out, n))
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) ToIntList() (list []int) {
|
|
|
+ var objs **Tcl_Obj
|
|
|
+ var objnum int32
|
|
|
+ Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
|
|
|
+ if objnum == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
|
|
|
+ var out Tcl_WideInt
|
|
|
+ for _, obj := range lst {
|
|
|
+ Tcl_GetWideIntFromObj(o.interp, obj, &out)
|
|
|
+ list = append(list, int(out))
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) SetStringList(list []string) {
|
|
|
+ Tcl_SetListObj(o.obj, 0, nil)
|
|
|
+ o.AppendStringList(list)
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) AppendStringList(list []string) {
|
|
|
+ for _, v := range list {
|
|
|
+ cs, _ := syscall.BytePtrFromString(v)
|
|
|
+ obj := Tcl_NewStringObj(cs, int32(len(v)))
|
|
|
+ Tcl_ListObjAppendElement(o.interp, o.obj, obj)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) AppendObj(obj *Obj) bool {
|
|
|
+ if obj == nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ Tcl_ListObjAppendElement(o.interp, o.obj, obj.obj)
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) AppendString(s string) {
|
|
|
+ Tcl_ListObjAppendElement(o.interp, o.obj, stringToObj(s))
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) InsertObj(index int, obj *Obj) {
|
|
|
+ Tcl_ListObjReplace(o.interp, o.obj, int32(index), 0, 1, &obj.obj)
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) InsertString(index int, s string) {
|
|
|
+ obj := stringToObj(s)
|
|
|
+ Tcl_ListObjReplace(o.interp, o.obj, int32(index), 0, 1, &obj)
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) SetIndexObj(index int, obj *Obj) bool {
|
|
|
+ if obj == nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ Tcl_ListObjReplace(o.interp, o.obj, int32(index), 1, 1, &obj.obj)
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) SetIndexString(index int, s string) {
|
|
|
+ obj := stringToObj(s)
|
|
|
+ Tcl_ListObjReplace(o.interp, o.obj, int32(index), 1, 1, &obj)
|
|
|
+}
|
|
|
+
|
|
|
+func (o *ListObj) Remove(first int, count int) {
|
|
|
+ Tcl_ListObjReplace(o.interp, o.obj, int32(first), int32(count), 0, nil)
|
|
|
+}
|
|
|
+
|
|
|
+type Photo struct {
|
|
|
+ handle *Tk_PhotoHandle
|
|
|
+ interp *Interp
|
|
|
+}
|
|
|
+
|
|
|
+func FindPhoto(interp *Interp, imageName string) *Photo {
|
|
|
+ cs, err := syscall.BytePtrFromString(imageName)
|
|
|
+ if err != nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ handle := Tk_FindPhoto(interp.interp, cs)
|
|
|
+ if handle == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return &Photo{handle, interp}
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Photo) Blank() {
|
|
|
+ Tk_PhotoBlank(p.handle)
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Photo) SetSize(width int, height int) error {
|
|
|
+ status := Tk_PhotoSetSize(p.interp.interp, p.handle, int32(width), int32(height))
|
|
|
+ if status != TCL_OK {
|
|
|
+ return p.interp.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Photo) Size() (int, int) {
|
|
|
+ var width, height int32
|
|
|
+ Tk_PhotoGetSize(p.handle, &width, &height)
|
|
|
+ return int(width), int(height)
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Photo) Expand(width int, height int) error {
|
|
|
+ status := Tk_PhotoExpand(p.interp.interp, p.handle, int32(width), int32(height))
|
|
|
+ if status != TCL_OK {
|
|
|
+ return p.interp.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Photo) ToImage() image.Image {
|
|
|
+ var block Tk_PhotoImageBlock
|
|
|
+ Tk_PhotoGetImage(p.handle, &block)
|
|
|
+ if block.width == 0 || block.height == 0 {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ r := image.Rect(0, 0, int(block.width), int(block.height))
|
|
|
+ //pix := GoBytes(unsafe.Pointer(block.pixelPtr), int(4*block.width*block.height))
|
|
|
+ //pix := make([]uint8
|
|
|
+ img := image.NewNRGBA(r)
|
|
|
+ data := (*([1 << 20]byte))(unsafe.Pointer(block.pixelPtr))[:4*block.width*block.height]
|
|
|
+ copy(img.Pix, data)
|
|
|
+ return img
|
|
|
+}
|
|
|
+
|
|
|
+const (
|
|
|
+ TK_PHOTO_COMPOSITE_OVERLAY = 0
|
|
|
+ TK_PHOTO_COMPOSITE_SET = 1
|
|
|
+)
|
|
|
+
|
|
|
+func (p *Photo) PutImage(img image.Image, tk85alphacolor color.Color) error {
|
|
|
+ if img == nil || img.Bounds().Empty() {
|
|
|
+ return os.ErrInvalid
|
|
|
+ }
|
|
|
+ width := img.Bounds().Dx()
|
|
|
+ height := img.Bounds().Dy()
|
|
|
+ var block Tk_PhotoImageBlock
|
|
|
+ if p.interp.supportTk86 {
|
|
|
+ dstImage, ok := img.(*image.NRGBA)
|
|
|
+ if !ok {
|
|
|
+ dstImage = image.NewNRGBA(img.Bounds())
|
|
|
+ draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
|
|
|
+ }
|
|
|
+ block = Tk_PhotoImageBlock{
|
|
|
+ &dstImage.Pix[0],
|
|
|
+ int32(width),
|
|
|
+ int32(height),
|
|
|
+ int32(dstImage.Stride),
|
|
|
+ 4,
|
|
|
+ [...]int32{0, 1, 2, 3},
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ var r, g, b uint8
|
|
|
+ if tk85alphacolor != nil {
|
|
|
+ clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
|
|
|
+ r, g, b = clr.R, clr.G, clr.B
|
|
|
+ }
|
|
|
+ dstImage := image.NewRGBA(img.Bounds())
|
|
|
+ for i := 0; i < len(dstImage.Pix); i += 4 {
|
|
|
+ dstImage.Pix[i+0] = r
|
|
|
+ dstImage.Pix[i+1] = g
|
|
|
+ dstImage.Pix[i+2] = b
|
|
|
+ dstImage.Pix[i+3] = 0xff
|
|
|
+ }
|
|
|
+ draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
|
|
|
+ block = Tk_PhotoImageBlock{
|
|
|
+ &dstImage.Pix[0],
|
|
|
+ int32(width),
|
|
|
+ int32(height),
|
|
|
+ int32(dstImage.Stride),
|
|
|
+ 4,
|
|
|
+ [...]int32{0, 1, 2, 3},
|
|
|
+ }
|
|
|
+ }
|
|
|
+ status := Tk_PhotoPutBlock(p.interp.interp, p.handle, &block, 0, 0,
|
|
|
+ int32(img.Bounds().Dx()), int32(img.Bounds().Dy()),
|
|
|
+ TK_PHOTO_COMPOSITE_SET)
|
|
|
+ if status != TCL_OK {
|
|
|
+ return p.interp.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Photo) PutZoomedImage(img image.Image, zoomX, zoomY, subsampleX, subsampleY int, tk85alphacolor color.Color) error {
|
|
|
+ if img == nil || img.Bounds().Empty() {
|
|
|
+ return os.ErrInvalid
|
|
|
+ }
|
|
|
+ width := img.Bounds().Dx()
|
|
|
+ height := img.Bounds().Dy()
|
|
|
+ var block Tk_PhotoImageBlock
|
|
|
+ if p.interp.supportTk86 {
|
|
|
+ dstImage, ok := img.(*image.NRGBA)
|
|
|
+ if !ok {
|
|
|
+ dstImage = image.NewNRGBA(img.Bounds())
|
|
|
+ draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
|
|
|
+ }
|
|
|
+ block = Tk_PhotoImageBlock{
|
|
|
+ &dstImage.Pix[0],
|
|
|
+ int32(width),
|
|
|
+ int32(height),
|
|
|
+ int32(dstImage.Stride),
|
|
|
+ 4,
|
|
|
+ [...]int32{0, 1, 2, 3},
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ var r, g, b uint8
|
|
|
+ if tk85alphacolor != nil {
|
|
|
+ clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
|
|
|
+ r, g, b = clr.R, clr.G, clr.B
|
|
|
+ }
|
|
|
+ dstImage := image.NewRGBA(img.Bounds())
|
|
|
+ for i := 0; i < len(dstImage.Pix); i += 4 {
|
|
|
+ dstImage.Pix[i+0] = r
|
|
|
+ dstImage.Pix[i+1] = g
|
|
|
+ dstImage.Pix[i+2] = b
|
|
|
+ dstImage.Pix[i+3] = 0xff
|
|
|
+ }
|
|
|
+ draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
|
|
|
+ block = Tk_PhotoImageBlock{
|
|
|
+ &dstImage.Pix[0],
|
|
|
+ int32(width),
|
|
|
+ int32(height),
|
|
|
+ int32(dstImage.Stride),
|
|
|
+ 4,
|
|
|
+ [...]int32{0, 1, 2, 3},
|
|
|
+ }
|
|
|
+ }
|
|
|
+ status := Tk_PhotoPutZoomedBlock(p.interp.interp, p.handle, &block,
|
|
|
+ 0, 0, int32(width), int32(height),
|
|
|
+ int32(zoomX), int32(zoomY), int32(subsampleX), int32(subsampleY),
|
|
|
+ TK_PHOTO_COMPOSITE_SET)
|
|
|
+ if status != TCL_OK {
|
|
|
+ return p.interp.GetErrorResult()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|