interp_unix.go 19 KB

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