interp_windows.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. // Copyright 2018 visualfc. All rights reserved.
  2. package interp
  3. //go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output zinterp_windows.go interp_windows.go
  4. import (
  5. "errors"
  6. "fmt"
  7. "image"
  8. "image/color"
  9. "image/draw"
  10. "os"
  11. "syscall"
  12. "unsafe"
  13. )
  14. //NOTE: BytePtrToString replace cgo C.GoStringN
  15. type Tcl_Interp struct{}
  16. type Tcl_ThreadId struct{}
  17. type Tcl_Obj struct{}
  18. type Tcl_Command struct{}
  19. type Tk_PhotoHandle struct{}
  20. type Tcl_WideInt int64
  21. type Tcl_Double float64
  22. type Tcl_Event struct {
  23. Proc uintptr
  24. NextPtr *Tcl_Event
  25. }
  26. type Tk_PhotoImageBlock struct {
  27. pixelPtr *byte
  28. width int32
  29. height int32
  30. pitch int32
  31. pixelSize int32
  32. offset [4]int32
  33. }
  34. // windows api calls
  35. //sys Tcl_CreateInterp() (interp *Tcl_Interp) = tcl86t.Tcl_CreateInterp
  36. //sys Tcl_DeleteInterp(interp *Tcl_Interp) = tcl86t.Tcl_DeleteInterp
  37. //sys Tcl_Alloc(size uint) (r *Tcl_Event) = tcl86t.Tcl_Alloc
  38. //sys Tcl_Eval(interp *Tcl_Interp, script *byte) (r int32) = tcl86t.Tcl_Eval
  39. //sys Tcl_EvalEx(interp *Tcl_Interp, script *byte, length int32, flags int32) (r int32) = tcl86t.Tcl_EvalEx
  40. //sys Tcl_GetStringResult(interp *Tcl_Interp) (ret *byte) = tcl86t.Tcl_GetStringResult
  41. //sys Tcl_GetObjResult(interp *Tcl_Interp) (obj *Tcl_Obj) = tcl86t.Tcl_GetObjResult
  42. //sys Tcl_GetWideIntFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *Tcl_WideInt) (status int32) = tcl86t.Tcl_GetWideIntFromObj
  43. //-sys Tcl_GetLongFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *int) (status int32) = tcl86t.Tcl_GetLongFromObj
  44. //sys Tcl_GetDoubleFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *Tcl_Double) (status int32) = tcl86t.Tcl_GetDoubleFromObj
  45. //sys Tcl_GetBooleanFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *int32) (status int32) = tcl86t.Tcl_GetBooleanFromObj
  46. //sys Tcl_GetStringFromObj(obj *Tcl_Obj, length *int32) (ret *byte) = tcl86t.Tcl_GetStringFromObj
  47. //sys Tcl_NewWideIntObj(value Tcl_WideInt) (obj *Tcl_Obj) = tcl86t.Tcl_NewWideIntObj
  48. //-sys Tcl_NewLongObj(value int) (obj *Tcl_Obj) = tcl86t.Tcl_NewLongObj
  49. //sys Tcl_NewDoubleObj(value Tcl_Double) (obj *Tcl_Obj) = tcl86t.Tcl_NewDoubleObj
  50. //sys Tcl_NewBooleanObj(value int32) (obj *Tcl_Obj) = tcl86t.Tcl_NewBooleanObj
  51. //sys Tcl_NewStringObj(bytes *byte, length int32) (obj *Tcl_Obj) = tcl86t.Tcl_NewStringObj
  52. //sys Tcl_Init(interp *Tcl_Interp) (r int32) = tcl86t.Tcl_Init
  53. //sys Tcl_GetCurrentThread() (threadid *Tcl_ThreadId) = tcl86t.Tcl_GetCurrentThread
  54. //sys Tcl_ThreadQueueEvent(threadId *Tcl_ThreadId, evPtr *Tcl_Event, positon Tcl_QueuePosition) = tcl86t.Tcl_ThreadQueueEvent
  55. //sys Tcl_ThreadAlert(threadId *Tcl_ThreadId) = tcl86t.Tcl_ThreadAlert
  56. //sys Tcl_CreateObjCommand(interp *Tcl_Interp, cmdName *byte, proc uintptr, clientData uintptr, deleteProc uintptr) (cmd *Tcl_Command) = tcl86t.Tcl_CreateObjCommand
  57. //sys Tcl_CreateCommand(interp *Tcl_Interp, cmdName *byte, proc uintptr, clientData uintptr, deleteProc uintptr) (cmd *Tcl_Command) = tcl86t.Tcl_CreateCommand
  58. //sys Tcl_SetObjResult(interp *Tcl_Interp, resultObjPtr *Tcl_Obj) = tcl86t.Tcl_SetObjResult
  59. //sys Tcl_WrongNumArgs(interp *Tcl_Interp, objc int32, objv uintptr, message *byte) = tcl86t.Tcl_WrongNumArgs
  60. //sys Tcl_NewListObj(objc int, objv **Tcl_Obj)(obj *Tcl_Obj) = tcl86t.Tcl_NewListObj
  61. //sys Tcl_ListObjLength(interp *Tcl_Interp, listobj *Tcl_Obj, length *int32) (status int32) = tcl86t.Tcl_ListObjLength
  62. //sys Tcl_ListObjIndex(interp *Tcl_Interp, listobj *Tcl_Obj, index int32, out **Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjIndex
  63. //sys Tcl_ListObjGetElements(interp *Tcl_Interp, listobj *Tcl_Obj, objc *int32, objv ***Tcl_Obj)(status int32) = tcl86t.Tcl_ListObjGetElements
  64. //sys Tcl_SetListObj(listobj *Tcl_Obj, objc int, objv **Tcl_Obj) = tcl86t.Tcl_SetListObj
  65. //sys Tcl_ListObjAppendElement(interp *Tcl_Interp, listobj *Tcl_Obj, obj *Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjAppendElement
  66. //sys Tcl_ListObjReplace(interp *Tcl_Interp, listobj *Tcl_Obj, first int32, count int32, objc int32, objv **Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjReplace
  67. //sys Tcl_GetVar2Ex(interp *Tcl_Interp,part1 *byte, part2 *byte, flags int32) (obj *Tcl_Obj) = tcl86t.Tcl_GetVar2Ex
  68. //sys Tcl_SetVar(interp *Tcl_Interp,name *byte, value *byte, flags int32) (r *byte) = tcl86t.Tcl_SetVar
  69. //sys Tcl_SetVar2Ex(interp *Tcl_Interp,part1 *byte, part2 *byte, value *Tcl_Obj, flags int32) (r *byte) = tcl86t.Tcl_SetVar2Ex
  70. //sys Tcl_UnsetVar(interp *Tcl_Interp,part1 *byte, flags int32) (status int32) = tcl86t.Tcl_UnsetVar
  71. //sys Tk_Init(interp *Tcl_Interp) (r int32) = tk86t.Tk_Init
  72. //sys Tk_MainLoop() = tk86t.Tk_MainLoop
  73. //sys Tk_FindPhoto(interp *Tcl_Interp, imageName *byte) (handle *Tk_PhotoHandle) = tk86t.Tk_FindPhoto
  74. //sys Tk_PhotoBlank(handle *Tk_PhotoHandle) = tk86t.Tk_PhotoBlank
  75. //sys Tk_PhotoSetSize(interp *Tcl_Interp,handle *Tk_PhotoHandle, width int32, height int32) (status int32) = tk86t.Tk_PhotoSetSize
  76. //sys Tk_PhotoGetSize(hanlde *Tk_PhotoHandle, widthPtr *int32, heightPtr *int32) = tk86t.Tk_PhotoGetSize
  77. //sys Tk_PhotoExpand(interp *Tcl_Interp,handle *Tk_PhotoHandle, width int32, height int32) (status int32) = tk86t.Tk_PhotoExpand
  78. //sys Tk_PhotoGetImage(handle *Tk_PhotoHandle, blockPtr *Tk_PhotoImageBlock) (status int32) = tk86t.Tk_PhotoGetImage
  79. //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
  80. //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
  81. func init() {
  82. err := modtcl86t.Load()
  83. if err != nil {
  84. modtcl86t.Name = "tcl86.dll"
  85. modtk86t.Name = "tk86.dll"
  86. }
  87. }
  88. var (
  89. mainLoopThreadId *Tcl_ThreadId
  90. )
  91. func _go_async_event_handler(ev *Tcl_Event, flags int32) int {
  92. if flags != TCL_ALL_EVENTS {
  93. return 0
  94. }
  95. if fn, ok := globalAsyncEvent.Load(unsafe.Pointer(ev)); ok {
  96. fn.(func())()
  97. globalAsyncEvent.Delete(unsafe.Pointer(ev))
  98. }
  99. return 1
  100. }
  101. func IsMainThread() bool {
  102. return Tcl_GetCurrentThread() == mainLoopThreadId
  103. }
  104. func async_send_event(tid *Tcl_ThreadId, fn func()) {
  105. var ev *Tcl_Event
  106. ev = Tcl_Alloc(uint(unsafe.Sizeof(*ev)))
  107. ev.Proc = syscall.NewCallbackCDecl(_go_async_event_handler)
  108. ev.NextPtr = nil
  109. globalAsyncEvent.Store(unsafe.Pointer(ev), fn)
  110. Tcl_ThreadQueueEvent(tid, ev, TCL_QUEUE_TAIL)
  111. Tcl_ThreadAlert(tid)
  112. }
  113. func Async(fn func()) {
  114. if fn == nil {
  115. return
  116. }
  117. async_send_event(mainLoopThreadId, fn)
  118. }
  119. func MainLoop(fn func()) {
  120. mainLoopThreadId = Tcl_GetCurrentThread()
  121. if fn != nil {
  122. fn()
  123. }
  124. Tk_MainLoop()
  125. mainLoopThreadId = nil
  126. }
  127. type Interp struct {
  128. interp *Tcl_Interp
  129. supportTk86 bool
  130. }
  131. func NewInterp() (*Interp, error) {
  132. err := modtcl86t.Load()
  133. if err != nil {
  134. return nil, err
  135. }
  136. interp := Tcl_CreateInterp()
  137. if interp == nil {
  138. return nil, errors.New("Tcl_CreateInterp failed")
  139. }
  140. return &Interp{interp, false}, nil
  141. }
  142. func (p *Interp) SupportTk86() bool {
  143. return p.supportTk86
  144. }
  145. func (p *Interp) InitTcl(tcl_library string) error {
  146. if tcl_library != "" {
  147. p.Eval(fmt.Sprintf("set tcl_library {%s}", tcl_library))
  148. }
  149. if Tcl_Init(p.interp) != TCL_OK {
  150. err := errors.New("Tcl_Init failed")
  151. return err
  152. }
  153. return nil
  154. }
  155. func (p *Interp) InitTk(tk_library string) error {
  156. err := modtk86t.Load()
  157. if err != nil {
  158. return err
  159. }
  160. if tk_library != "" {
  161. p.Eval(fmt.Sprintf("set tk_library {%s}", tk_library))
  162. }
  163. if Tk_Init(p.interp) != TCL_OK {
  164. err := errors.New("Tk_Init failed")
  165. return err
  166. }
  167. p.supportTk86 = p.TkVersion() >= "8.6"
  168. return nil
  169. }
  170. func (p *Interp) Destroy() error {
  171. if p == nil || p.interp == nil {
  172. return os.ErrInvalid
  173. }
  174. Tcl_DeleteInterp(p.interp)
  175. p.interp = nil
  176. return nil
  177. }
  178. func BytePtrToString(data *byte, length int32) string {
  179. if length == 0 {
  180. return ""
  181. }
  182. p := (*[1 << 30]byte)(unsafe.Pointer(data))[:length]
  183. a := make([]byte, length)
  184. copy(a, p)
  185. return string(a)
  186. }
  187. func (p *Interp) GetObjResult() *Obj {
  188. obj := Tcl_GetObjResult(p.interp)
  189. return &Obj{obj, p.interp}
  190. }
  191. func (p *Interp) GetListObjResult() *ListObj {
  192. return &ListObj{Tcl_GetObjResult(p.interp), p.interp}
  193. }
  194. func (p *Interp) Eval(script string) error {
  195. s, err := syscall.BytePtrFromString(script)
  196. if err != nil {
  197. return err
  198. }
  199. if Tcl_EvalEx(p.interp, s, int32(len(script)), 0) != TCL_OK {
  200. err := errors.New(p.GetStringResult())
  201. return err
  202. }
  203. return nil
  204. }
  205. //typedef int (Tcl_ObjCmdProc) (ClientData clientData, *Tcl_Interp *interp, int objc, struct *Tcl_Obj *const *objv);
  206. func _go_tcl_objcmd_proc(clientData uintptr, interp *Tcl_Interp, objc int, objv unsafe.Pointer) int {
  207. objs := (*(*[1 << 20]*Tcl_Obj)(objv))[1:objc]
  208. var args []string
  209. for _, obj := range objs {
  210. args = append(args, objToString(interp, obj))
  211. }
  212. result, err := globalCommandMap.Invoke(clientData, args)
  213. if err != nil {
  214. cs, _ := syscall.BytePtrFromString(err.Error())
  215. Tcl_WrongNumArgs(interp, 1, uintptr(objv), cs)
  216. return TCL_ERROR
  217. }
  218. if result != "" {
  219. Tcl_SetObjResult(interp, stringToObj(result))
  220. }
  221. return TCL_OK
  222. }
  223. //typedef void (Tcl_CmdDeleteProc) (ClientData clientData);
  224. func _go_tcl_cmddelete_proc(clientData uintptr) int {
  225. globalCommandMap.UnRegister(clientData)
  226. return 0
  227. }
  228. func _go_tcl_action_proc(id uintptr, interp *Tcl_Interp, objc int, objv unsafe.Pointer) int {
  229. objs := (*(*[1 << 20]*Tcl_Obj)(objv))[1:objc]
  230. var args []string
  231. for _, obj := range objs {
  232. args = append(args, objToString(interp, obj))
  233. }
  234. err := globalActionMap.Invoke(id, args)
  235. if err != nil {
  236. cs, _ := syscall.BytePtrFromString(err.Error())
  237. Tcl_WrongNumArgs(interp, 1, uintptr(objv), cs)
  238. return TCL_ERROR
  239. }
  240. return TCL_OK
  241. }
  242. func _go_tcl_actiono_delete_proc(id uintptr) int {
  243. globalActionMap.UnRegister(id)
  244. return 0
  245. }
  246. //Tcl_Command Tcl_CreateObjCommand(*Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
  247. func (p *Interp) CreateCommand(name string, fn func([]string) (string, error)) (uintptr, error) {
  248. s, err := syscall.BytePtrFromString(name)
  249. if err != nil {
  250. return 0, err
  251. }
  252. id := globalCommandMap.Register(fn)
  253. cmd := Tcl_CreateObjCommand(p.interp, s, syscall.NewCallbackCDecl(_go_tcl_objcmd_proc), id, syscall.NewCallbackCDecl(_go_tcl_cmddelete_proc))
  254. if cmd == nil {
  255. err := fmt.Errorf("CreateCommand %v failed", name)
  256. return 0, err
  257. }
  258. return id, nil
  259. }
  260. func (p *Interp) InvokeCommand(id uintptr, args []string) (string, error) {
  261. return globalCommandMap.Invoke(id, args)
  262. }
  263. func (p *Interp) CreateAction(name string, action func([]string)) (uintptr, error) {
  264. s, err := syscall.BytePtrFromString(name)
  265. if err != nil {
  266. return 0, err
  267. }
  268. id := globalActionMap.Register(action)
  269. cmd := Tcl_CreateObjCommand(p.interp, s, syscall.NewCallbackCDecl(_go_tcl_action_proc), id, syscall.NewCallbackCDecl(_go_tcl_actiono_delete_proc))
  270. if cmd == nil {
  271. err := fmt.Errorf("CreateAction %v failed", name)
  272. return 0, err
  273. }
  274. return id, nil
  275. }
  276. func (p *Interp) InvokeAction(id uintptr, args []string) error {
  277. return globalActionMap.Invoke(id, args)
  278. }
  279. const (
  280. TCL_LEAVE_ERR_MSG = 0x200
  281. TCL_GLOBAL_ONLY = 1
  282. TCL_NAMESPACE_ONLY = 2
  283. TCL_APPEND_VALUE = 4
  284. TCL_LIST_ELEMENT = 8
  285. )
  286. func (p *Interp) GetVar(name string, global bool) *Obj {
  287. cname, err := syscall.BytePtrFromString(name)
  288. if err != nil {
  289. return nil
  290. }
  291. var flag int32 = TCL_LEAVE_ERR_MSG
  292. if global {
  293. flag |= TCL_GLOBAL_ONLY
  294. }
  295. obj := Tcl_GetVar2Ex(p.interp, cname, nil, flag)
  296. if obj == nil {
  297. return nil
  298. }
  299. return &Obj{obj, p.interp}
  300. }
  301. func (p *Interp) GetList(name string, global bool) *ListObj {
  302. return (*ListObj)(p.GetVar(name, global))
  303. }
  304. func (p *Interp) SetStringList(name string, list []string, global bool) error {
  305. obj := NewListObj(p)
  306. obj.AppendStringList(list)
  307. return p.SetVarObj(name, (*Obj)(obj), global)
  308. }
  309. func (p *Interp) AppendStringListList(name string, list []string, global bool) error {
  310. cname, err := syscall.BytePtrFromString(name)
  311. if err != nil {
  312. return err
  313. }
  314. var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT
  315. if global {
  316. flag |= TCL_GLOBAL_ONLY
  317. }
  318. for _, value := range list {
  319. cvalue, _ := syscall.BytePtrFromString(value)
  320. Tcl_SetVar(p.interp, cname, cvalue, flag)
  321. }
  322. return nil
  323. }
  324. func (p *Interp) AppendStringList(name string, value string, global bool) error {
  325. cname, err := syscall.BytePtrFromString(name)
  326. if err != nil {
  327. return err
  328. }
  329. cvalue, err := syscall.BytePtrFromString(value)
  330. if err != nil {
  331. return err
  332. }
  333. var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT
  334. if global {
  335. flag |= TCL_GLOBAL_ONLY
  336. }
  337. r := Tcl_SetVar(p.interp, cname, cvalue, flag)
  338. if r == nil {
  339. return p.GetErrorResult()
  340. }
  341. return nil
  342. }
  343. func (p *Interp) SetVarObj(name string, obj *Obj, global bool) error {
  344. if obj == nil {
  345. return os.ErrInvalid
  346. }
  347. cname, err := syscall.BytePtrFromString(name)
  348. if err != nil {
  349. return err
  350. }
  351. var flag int32 = TCL_LEAVE_ERR_MSG
  352. if global {
  353. flag |= TCL_GLOBAL_ONLY
  354. }
  355. r := Tcl_SetVar2Ex(p.interp, cname, nil, obj.obj, flag)
  356. if r == nil {
  357. return p.GetErrorResult()
  358. }
  359. return nil
  360. }
  361. func (p *Interp) SetVarListObj(name string, obj *ListObj, global bool) error {
  362. return p.SetVarObj(name, (*Obj)(obj), global)
  363. }
  364. func (p *Interp) SetStringVar(name string, value string, global bool) error {
  365. cname, err := syscall.BytePtrFromString(name)
  366. if err != nil {
  367. return err
  368. }
  369. cvalue, err := syscall.BytePtrFromString(value)
  370. if err != nil {
  371. return err
  372. }
  373. var flag int32 = TCL_LEAVE_ERR_MSG
  374. if global {
  375. flag |= TCL_GLOBAL_ONLY
  376. }
  377. r := Tcl_SetVar(p.interp, cname, cvalue, flag)
  378. if r == nil {
  379. return p.GetErrorResult()
  380. }
  381. return nil
  382. }
  383. func (p *Interp) AppendStringVar(name string, value string, global bool) error {
  384. cname, err := syscall.BytePtrFromString(name)
  385. if err != nil {
  386. return err
  387. }
  388. cvalue, err := syscall.BytePtrFromString(value)
  389. if err != nil {
  390. return err
  391. }
  392. var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
  393. if global {
  394. flag |= TCL_GLOBAL_ONLY
  395. }
  396. r := Tcl_SetVar(p.interp, cname, cvalue, flag)
  397. if r == nil {
  398. return p.GetErrorResult()
  399. }
  400. return nil
  401. }
  402. func (p *Interp) UnsetVar(name string, global bool) error {
  403. cname, err := syscall.BytePtrFromString(name)
  404. if err != nil {
  405. return err
  406. }
  407. var flag int32 = TCL_LEAVE_ERR_MSG
  408. if global {
  409. flag |= TCL_GLOBAL_ONLY
  410. }
  411. r := Tcl_UnsetVar(p.interp, cname, flag)
  412. if r != TCL_OK {
  413. return p.GetErrorResult()
  414. }
  415. return nil
  416. }
  417. type Obj struct {
  418. obj *Tcl_Obj
  419. interp *Tcl_Interp
  420. }
  421. func NewRawObj(obj *Tcl_Obj, interp *Tcl_Interp) *Obj {
  422. return &Obj{obj, interp}
  423. }
  424. func (o *Obj) ToFloat64() float64 {
  425. var out Tcl_Double
  426. status := Tcl_GetDoubleFromObj(o.interp, o.obj, &out)
  427. if status == TCL_OK {
  428. return float64(out)
  429. }
  430. return 0
  431. }
  432. func (o *Obj) ToInt64() int64 {
  433. var out Tcl_WideInt
  434. status := Tcl_GetWideIntFromObj(o.interp, o.obj, &out)
  435. if status == TCL_OK {
  436. return int64(out)
  437. }
  438. return 0
  439. }
  440. func (o *Obj) ToInt() int {
  441. return int(o.ToInt64())
  442. }
  443. func (o *Obj) ToUint() uint {
  444. return uint(o.ToInt64())
  445. }
  446. func (o *Obj) ToBool() bool {
  447. var out int32
  448. status := Tcl_GetBooleanFromObj(o.interp, o.obj, &out)
  449. if status == TCL_OK {
  450. return out == 1
  451. }
  452. return false
  453. }
  454. func (o *Obj) ToString() string {
  455. var n int32
  456. out := Tcl_GetStringFromObj(o.obj, &n)
  457. return BytePtrToString(out, n)
  458. }
  459. func NewStringObj(value string, p *Interp) *Obj {
  460. s, err := syscall.BytePtrFromString(value)
  461. if err != nil {
  462. return nil
  463. }
  464. return &Obj{Tcl_NewStringObj(s, int32(len(value))), p.interp}
  465. }
  466. //NOTE: Tcl_NewDoubleObj test error on windows
  467. func NewFloat64Obj(value float64, p *Interp) *Obj {
  468. //return &Obj{Tcl_NewDoubleObj(Tcl_Double(value)), p.interp}
  469. return NewStringObj(fmt.Sprintf("%v", value), p)
  470. }
  471. //NOTE: Tcl_NewWideIntObj test error on windows 32 bit
  472. func NewInt64Obj(value int64, p *Interp) *Obj {
  473. return NewStringObj(fmt.Sprintf("%v", value), p)
  474. //return &Obj{Tcl_NewWideIntObj(Tcl_WideInt(value)), p.interp}
  475. }
  476. //NOTE: use int to string for amd64/i386
  477. func NewIntObj(value int, p *Interp) *Obj {
  478. return NewStringObj(fmt.Sprintf("%v", value), p)
  479. // return &Obj{Tcl_NewLongObj(value), p.interp}
  480. }
  481. func NewBoolObj(value bool, p *Interp) *Obj {
  482. if value {
  483. return &Obj{Tcl_NewBooleanObj(1), p.interp}
  484. } else {
  485. return &Obj{Tcl_NewBooleanObj(0), p.interp}
  486. }
  487. }
  488. func objToString(interp *Tcl_Interp, obj *Tcl_Obj) string {
  489. var n int32
  490. out := Tcl_GetStringFromObj(obj, &n)
  491. return BytePtrToString(out, n)
  492. //return C.GoStringN((*C.char)(unsafe.Pointer(out)), (C.int)(n))
  493. }
  494. func stringToObj(value string) *Tcl_Obj {
  495. s, err := syscall.BytePtrFromString(value)
  496. if err != nil {
  497. return nil
  498. }
  499. return Tcl_NewStringObj(s, int32(len(value)))
  500. }
  501. type ListObj Obj
  502. func NewListObj(p *Interp) *ListObj {
  503. o := Tcl_NewListObj(0, nil)
  504. return &ListObj{o, p.interp}
  505. }
  506. func (o *ListObj) Length() int {
  507. var length int32
  508. Tcl_ListObjLength(o.interp, o.obj, &length)
  509. return int(length)
  510. }
  511. func (o *ListObj) IndexObj(index int) *Obj {
  512. var obj *Tcl_Obj
  513. r := Tcl_ListObjIndex(o.interp, o.obj, int32(index), &obj)
  514. if r != TCL_OK || obj == nil {
  515. return nil
  516. }
  517. return &Obj{obj, o.interp}
  518. }
  519. func (o *ListObj) IndexString(index int) string {
  520. var obj *Tcl_Obj
  521. r := Tcl_ListObjIndex(o.interp, o.obj, int32(index), &obj)
  522. if r != TCL_OK || obj == nil {
  523. return ""
  524. }
  525. return objToString(o.interp, obj)
  526. }
  527. func (o *ListObj) ToObjList() (list []*Obj) {
  528. var objs **Tcl_Obj
  529. var objnum int32
  530. Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
  531. if objnum == 0 {
  532. return
  533. }
  534. lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
  535. for _, v := range lst {
  536. list = append(list, &Obj{v, o.interp})
  537. }
  538. return
  539. }
  540. func (o *ListObj) ToStringList() (list []string) {
  541. var objs **Tcl_Obj
  542. var objnum int32
  543. Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
  544. if objnum == 0 {
  545. return
  546. }
  547. lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
  548. var n int32
  549. for _, obj := range lst {
  550. out := Tcl_GetStringFromObj(obj, &n)
  551. list = append(list, BytePtrToString(out, n))
  552. }
  553. return
  554. }
  555. func (o *ListObj) ToIntList() (list []int) {
  556. var objs **Tcl_Obj
  557. var objnum int32
  558. Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
  559. if objnum == 0 {
  560. return
  561. }
  562. lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
  563. var out Tcl_WideInt
  564. for _, obj := range lst {
  565. Tcl_GetWideIntFromObj(o.interp, obj, &out)
  566. list = append(list, int(out))
  567. }
  568. return
  569. }
  570. func (o *ListObj) SetStringList(list []string) {
  571. Tcl_SetListObj(o.obj, 0, nil)
  572. o.AppendStringList(list)
  573. }
  574. func (o *ListObj) AppendStringList(list []string) {
  575. for _, v := range list {
  576. cs, _ := syscall.BytePtrFromString(v)
  577. obj := Tcl_NewStringObj(cs, int32(len(v)))
  578. Tcl_ListObjAppendElement(o.interp, o.obj, obj)
  579. }
  580. }
  581. func (o *ListObj) AppendObj(obj *Obj) bool {
  582. if obj == nil {
  583. return false
  584. }
  585. Tcl_ListObjAppendElement(o.interp, o.obj, obj.obj)
  586. return true
  587. }
  588. func (o *ListObj) AppendString(s string) {
  589. Tcl_ListObjAppendElement(o.interp, o.obj, stringToObj(s))
  590. }
  591. func (o *ListObj) InsertObj(index int, obj *Obj) {
  592. Tcl_ListObjReplace(o.interp, o.obj, int32(index), 0, 1, &obj.obj)
  593. }
  594. func (o *ListObj) InsertString(index int, s string) {
  595. obj := stringToObj(s)
  596. Tcl_ListObjReplace(o.interp, o.obj, int32(index), 0, 1, &obj)
  597. }
  598. func (o *ListObj) SetIndexObj(index int, obj *Obj) bool {
  599. if obj == nil {
  600. return false
  601. }
  602. Tcl_ListObjReplace(o.interp, o.obj, int32(index), 1, 1, &obj.obj)
  603. return true
  604. }
  605. func (o *ListObj) SetIndexString(index int, s string) {
  606. obj := stringToObj(s)
  607. Tcl_ListObjReplace(o.interp, o.obj, int32(index), 1, 1, &obj)
  608. }
  609. func (o *ListObj) Remove(first int, count int) {
  610. Tcl_ListObjReplace(o.interp, o.obj, int32(first), int32(count), 0, nil)
  611. }
  612. type Photo struct {
  613. handle *Tk_PhotoHandle
  614. interp *Interp
  615. }
  616. func FindPhoto(interp *Interp, imageName string) *Photo {
  617. cs, err := syscall.BytePtrFromString(imageName)
  618. if err != nil {
  619. return nil
  620. }
  621. handle := Tk_FindPhoto(interp.interp, cs)
  622. if handle == nil {
  623. return nil
  624. }
  625. return &Photo{handle, interp}
  626. }
  627. func (p *Photo) Blank() {
  628. Tk_PhotoBlank(p.handle)
  629. }
  630. func (p *Photo) SetSize(width int, height int) error {
  631. status := Tk_PhotoSetSize(p.interp.interp, p.handle, int32(width), int32(height))
  632. if status != TCL_OK {
  633. return p.interp.GetErrorResult()
  634. }
  635. return nil
  636. }
  637. func (p *Photo) Size() (int, int) {
  638. var width, height int32
  639. Tk_PhotoGetSize(p.handle, &width, &height)
  640. return int(width), int(height)
  641. }
  642. func (p *Photo) Expand(width int, height int) error {
  643. status := Tk_PhotoExpand(p.interp.interp, p.handle, int32(width), int32(height))
  644. if status != TCL_OK {
  645. return p.interp.GetErrorResult()
  646. }
  647. return nil
  648. }
  649. func (p *Photo) ToImage() image.Image {
  650. var block Tk_PhotoImageBlock
  651. Tk_PhotoGetImage(p.handle, &block)
  652. if block.width == 0 || block.height == 0 {
  653. return nil
  654. }
  655. r := image.Rect(0, 0, int(block.width), int(block.height))
  656. //pix := GoBytes(unsafe.Pointer(block.pixelPtr), int(4*block.width*block.height))
  657. //pix := make([]uint8
  658. img := image.NewNRGBA(r)
  659. data := (*([1 << 20]byte))(unsafe.Pointer(block.pixelPtr))[:4*block.width*block.height]
  660. copy(img.Pix, data)
  661. return img
  662. }
  663. const (
  664. TK_PHOTO_COMPOSITE_OVERLAY = 0
  665. TK_PHOTO_COMPOSITE_SET = 1
  666. )
  667. func (p *Photo) PutImage(img image.Image, tk85alphacolor color.Color) error {
  668. if img == nil || img.Bounds().Empty() {
  669. return os.ErrInvalid
  670. }
  671. width := img.Bounds().Dx()
  672. height := img.Bounds().Dy()
  673. var block Tk_PhotoImageBlock
  674. if p.interp.supportTk86 {
  675. dstImage, ok := img.(*image.NRGBA)
  676. if !ok {
  677. dstImage = image.NewNRGBA(img.Bounds())
  678. draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
  679. }
  680. block = Tk_PhotoImageBlock{
  681. &dstImage.Pix[0],
  682. int32(width),
  683. int32(height),
  684. int32(dstImage.Stride),
  685. 4,
  686. [...]int32{0, 1, 2, 3},
  687. }
  688. } else {
  689. var r, g, b uint8
  690. if tk85alphacolor != nil {
  691. clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
  692. r, g, b = clr.R, clr.G, clr.B
  693. }
  694. dstImage := image.NewRGBA(img.Bounds())
  695. for i := 0; i < len(dstImage.Pix); i += 4 {
  696. dstImage.Pix[i+0] = r
  697. dstImage.Pix[i+1] = g
  698. dstImage.Pix[i+2] = b
  699. dstImage.Pix[i+3] = 0xff
  700. }
  701. draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
  702. block = Tk_PhotoImageBlock{
  703. &dstImage.Pix[0],
  704. int32(width),
  705. int32(height),
  706. int32(dstImage.Stride),
  707. 4,
  708. [...]int32{0, 1, 2, 3},
  709. }
  710. }
  711. status := Tk_PhotoPutBlock(p.interp.interp, p.handle, &block, 0, 0,
  712. int32(img.Bounds().Dx()), int32(img.Bounds().Dy()),
  713. TK_PHOTO_COMPOSITE_SET)
  714. if status != TCL_OK {
  715. return p.interp.GetErrorResult()
  716. }
  717. return nil
  718. }
  719. func (p *Photo) PutZoomedImage(img image.Image, zoomX, zoomY, subsampleX, subsampleY int, tk85alphacolor color.Color) error {
  720. if img == nil || img.Bounds().Empty() {
  721. return os.ErrInvalid
  722. }
  723. width := img.Bounds().Dx()
  724. height := img.Bounds().Dy()
  725. var block Tk_PhotoImageBlock
  726. if p.interp.supportTk86 {
  727. dstImage, ok := img.(*image.NRGBA)
  728. if !ok {
  729. dstImage = image.NewNRGBA(img.Bounds())
  730. draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
  731. }
  732. block = Tk_PhotoImageBlock{
  733. &dstImage.Pix[0],
  734. int32(width),
  735. int32(height),
  736. int32(dstImage.Stride),
  737. 4,
  738. [...]int32{0, 1, 2, 3},
  739. }
  740. } else {
  741. var r, g, b uint8
  742. if tk85alphacolor != nil {
  743. clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
  744. r, g, b = clr.R, clr.G, clr.B
  745. }
  746. dstImage := image.NewRGBA(img.Bounds())
  747. for i := 0; i < len(dstImage.Pix); i += 4 {
  748. dstImage.Pix[i+0] = r
  749. dstImage.Pix[i+1] = g
  750. dstImage.Pix[i+2] = b
  751. dstImage.Pix[i+3] = 0xff
  752. }
  753. draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
  754. block = Tk_PhotoImageBlock{
  755. &dstImage.Pix[0],
  756. int32(width),
  757. int32(height),
  758. int32(dstImage.Stride),
  759. 4,
  760. [...]int32{0, 1, 2, 3},
  761. }
  762. }
  763. status := Tk_PhotoPutZoomedBlock(p.interp.interp, p.handle, &block,
  764. 0, 0, int32(width), int32(height),
  765. int32(zoomX), int32(zoomY), int32(subsampleX), int32(subsampleY),
  766. TK_PHOTO_COMPOSITE_SET)
  767. if status != TCL_OK {
  768. return p.interp.GetErrorResult()
  769. }
  770. return nil
  771. }