[pypy-commit] pypy default: Add implementation of _tkinter, using cffi bindings.
amauryfa
noreply at buildbot.pypy.org
Thu Jun 13 18:21:04 CEST 2013
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch:
Changeset: r64872:2c9002e840f0
Date: 2013-06-13 14:06 +0200
http://bitbucket.org/pypy/pypy/changeset/2c9002e840f0/
Log: Add implementation of _tkinter, using cffi bindings.
diff --git a/lib_pypy/_tkinter/__init__.py b/lib_pypy/_tkinter/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_tkinter/__init__.py
@@ -0,0 +1,43 @@
+# _tkinter package -- low-level interface to libtk and libtcl.
+#
+# This is an internal module, applications should "import Tkinter" instead.
+#
+# This version is based on cffi, and is a translation of _tkinter.c
+# from CPython, version 2.7.4.
+
+class TclError(Exception):
+ pass
+
+from .tklib import tklib, tkffi
+from .app import TkApp
+
+TK_VERSION = tkffi.string(tklib.get_tk_version())
+TCL_VERSION = tkffi.string(tklib.get_tcl_version())
+
+READABLE = tklib.TCL_READABLE
+WRITABLE = tklib.TCL_WRITABLE
+EXCEPTION = tklib.TCL_EXCEPTION
+
+def create(screenName=None, baseName=None, className=None,
+ interactive=False, wantobjects=False, wantTk=True,
+ sync=False, use=None):
+ return TkApp(screenName, baseName, className,
+ interactive, wantobjects, wantTk, sync, use)
+
+def _flatten(item):
+ def _flatten1(output, item, depth):
+ if depth > 1000:
+ raise ValueError("nesting too deep in _flatten")
+ if not isinstance(item, (list, tuple)):
+ raise TypeError("argument must be sequence")
+ # copy items to output tuple
+ for o in item:
+ if isinstance(o, (list, tuple)):
+ _flatten1(output, o, depth + 1)
+ elif o is not None:
+ output.append(o)
+
+ result = []
+ _flatten1(result, item, 0)
+ return tuple(result)
+
diff --git a/lib_pypy/_tkinter/app.py b/lib_pypy/_tkinter/app.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_tkinter/app.py
@@ -0,0 +1,389 @@
+# The TkApp class.
+
+from .tklib import tklib, tkffi
+from . import TclError
+from .tclobj import TclObject, FromObj, AsObj, TypeCache
+
+import sys
+
+def varname_converter(input):
+ if isinstance(input, TclObject):
+ return input.string
+ return input
+
+
+def Tcl_AppInit(app):
+ if tklib.Tcl_Init(app.interp) == tklib.TCL_ERROR:
+ app.raiseTclError()
+ skip_tk_init = tklib.Tcl_GetVar(
+ app.interp, "_tkinter_skip_tk_init", tklib.TCL_GLOBAL_ONLY)
+ if skip_tk_init and tkffi.string(skip_tk_init) == "1":
+ return
+
+ if tklib.Tk_Init(app.interp) == tklib.TCL_ERROR:
+ app.raiseTclError()
+
+class _CommandData(object):
+ def __new__(cls, app, name, func):
+ self = object.__new__(cls)
+ self.app = app
+ self.name = name
+ self.func = func
+ handle = tkffi.new_handle(self)
+ app._commands[name] = handle # To keep the command alive
+ return tkffi.cast("ClientData", handle)
+
+ @tkffi.callback("Tcl_CmdProc")
+ def PythonCmd(clientData, interp, argc, argv):
+ self = tkffi.from_handle(clientData)
+ assert self.app.interp == interp
+ try:
+ args = [tkffi.string(arg) for arg in argv[1:argc]]
+ result = self.func(*args)
+ obj = AsObj(result)
+ tklib.Tcl_SetObjResult(interp, obj)
+ except:
+ self.app.errorInCmd = True
+ self.app.exc_info = sys.exc_info()
+ return tklib.TCL_ERROR
+ else:
+ return tklib.TCL_OK
+
+ @tkffi.callback("Tcl_CmdDeleteProc")
+ def PythonCmdDelete(clientData):
+ self = tkffi.from_handle(clientData)
+ app = self.app
+ del app._commands[self.name]
+ return
+
+
+class TkApp(object):
+ def __new__(cls, screenName, baseName, className,
+ interactive, wantobjects, wantTk, sync, use):
+ if not wantobjects:
+ raise NotImplementedError("wantobjects=True only")
+ self = object.__new__(cls)
+ self.interp = tklib.Tcl_CreateInterp()
+ self._wantobjects = wantobjects
+ self.threaded = bool(tklib.Tcl_GetVar2Ex(
+ self.interp, "tcl_platform", "threaded",
+ tklib.TCL_GLOBAL_ONLY))
+ self.thread_id = tklib.Tcl_GetCurrentThread()
+ self.dispatching = False
+ self.quitMainLoop = False
+ self.errorInCmd = False
+
+ self._typeCache = TypeCache()
+ self._commands = {}
+
+ # Delete the 'exit' command, which can screw things up
+ tklib.Tcl_DeleteCommand(self.interp, "exit")
+
+ if screenName is not None:
+ tklib.Tcl_SetVar2(self.interp, "env", "DISPLAY", screenName,
+ tklib.TCL_GLOBAL_ONLY)
+
+ if interactive:
+ tklib.Tcl_SetVar(self.interp, "tcl_interactive", "1",
+ tklib.TCL_GLOBAL_ONLY)
+ else:
+ tklib.Tcl_SetVar(self.interp, "tcl_interactive", "0",
+ tklib.TCL_GLOBAL_ONLY)
+
+ # This is used to get the application class for Tk 4.1 and up
+ argv0 = className.lower()
+ tklib.Tcl_SetVar(self.interp, "argv0", argv0,
+ tklib.TCL_GLOBAL_ONLY)
+
+ if not wantTk:
+ tklib.Tcl_SetVar(self.interp, "_tkinter_skip_tk_init", "1",
+ tklib.TCL_GLOBAL_ONLY)
+
+ # some initial arguments need to be in argv
+ if sync or use:
+ args = ""
+ if sync:
+ args += "-sync"
+ if use:
+ if sync:
+ args += " "
+ args += "-use " + use
+
+ tklib.Tcl_SetVar(self.interp, "argv", args,
+ tklib.TCL_GLOBAL_ONLY)
+
+ Tcl_AppInit(self)
+ # EnableEventHook()
+ return self
+
+ def __del__(self):
+ tklib.Tcl_DeleteInterp(self.interp)
+ # DisableEventHook()
+
+ def raiseTclError(self):
+ if self.errorInCmd:
+ self.errorInCmd = False
+ raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
+ raise TclError(tkffi.string(tklib.Tcl_GetStringResult(self.interp)))
+
+ def wantobjects(self):
+ return self._wantobjects
+
+ def _check_tcl_appartment(self):
+ if self.threaded and self.thread_id != tklib.Tcl_GetCurrentThread():
+ raise RuntimeError("Calling Tcl from different appartment")
+
+ def loadtk(self):
+ # We want to guard against calling Tk_Init() multiple times
+ err = tklib.Tcl_Eval(self.interp, "info exists tk_version")
+ if err == tklib.TCL_ERROR:
+ self.raiseTclError()
+ tk_exists = tklib.Tcl_GetStringResult(self.interp)
+ if not tk_exists or tkffi.string(tk_exists) != "1":
+ err = tklib.Tk_Init(self.interp)
+ if err == tklib.TCL_ERROR:
+ self.raiseTclError()
+
+ def _var_invoke(self, func, *args, **kwargs):
+ if self.threaded and self.thread_id != tklib.Tcl_GetCurrentThread():
+ # The current thread is not the interpreter thread.
+ # Marshal the call to the interpreter thread, then wait
+ # for completion.
+ raise NotImplementedError("Call from another thread")
+ return func(*args, **kwargs)
+
+ def _getvar(self, name1, name2=None, global_only=False):
+ name1 = varname_converter(name1)
+ if not name2:
+ name2 = tkffi.NULL
+ flags=tklib.TCL_LEAVE_ERR_MSG
+ if global_only:
+ flags |= tklib.TCL_GLOBAL_ONLY
+ res = tklib.Tcl_GetVar2Ex(self.interp, name1, name2, flags)
+ if not res:
+ self.raiseTclError()
+ assert self._wantobjects
+ return FromObj(self, res)
+
+ def _setvar(self, name1, value, global_only=False):
+ name1 = varname_converter(name1)
+ newval = AsObj(value)
+ flags=tklib.TCL_LEAVE_ERR_MSG
+ if global_only:
+ flags |= tklib.TCL_GLOBAL_ONLY
+ res = tklib.Tcl_SetVar2Ex(self.interp, name1, tkffi.NULL,
+ newval, flags)
+ if not res:
+ self.raiseTclError()
+
+ def _unsetvar(self, name1, name2=None, global_only=False):
+ name1 = varname_converter(name1)
+ if not name2:
+ name2 = tkffi.NULL
+ flags=tklib.TCL_LEAVE_ERR_MSG
+ if global_only:
+ flags |= tklib.TCL_GLOBAL_ONLY
+ res = tklib.Tcl_UnsetVar2(self.interp, name1, name2, flags)
+ if res == tklib.TCL_ERROR:
+ self.raiseTclError()
+
+ def getvar(self, name1, name2=None):
+ return self._var_invoke(self._getvar, name1, name2)
+
+ def globalgetvar(self, name1, name2=None):
+ return self._var_invoke(self._getvar, name1, name2, global_only=True)
+
+ def setvar(self, name1, value):
+ return self._var_invoke(self._setvar, name1, value)
+
+ def globalsetvar(self, name1, value):
+ return self._var_invoke(self._setvar, name1, value, global_only=True)
+
+ def unsetvar(self, name1, name2=None):
+ return self._var_invoke(self._unsetvar, name1, name2)
+
+ def globalunsetvar(self, name1, name2=None):
+ return self._var_invoke(self._unsetvar, name1, name2, global_only=True)
+
+ # COMMANDS
+
+ def createcommand(self, cmdName, func):
+ if not callable(func):
+ raise TypeError("command not callable")
+
+ if self.threaded and self.thread_id != tklib.Tcl_GetCurrentThread():
+ raise NotImplementedError("Call from another thread")
+
+ clientData = _CommandData(self, cmdName, func)
+
+ if self.threaded and self.thread_id != tklib.Tcl_GetCurrentThread():
+ raise NotImplementedError("Call from another thread")
+
+ res = tklib.Tcl_CreateCommand(
+ self.interp, cmdName, _CommandData.PythonCmd,
+ clientData, _CommandData.PythonCmdDelete)
+ if not res:
+ raise TclError("can't create Tcl command")
+
+ def deletecommand(self, cmdName):
+ if self.threaded and self.thread_id != tklib.Tcl_GetCurrentThread():
+ raise NotImplementedError("Call from another thread")
+
+ res = tklib.Tcl_DeleteCommand(self.interp, cmdName)
+ if res == -1:
+ raise TclError("can't delete Tcl command")
+
+ def call(self, *args):
+ flags = tklib.TCL_EVAL_DIRECT | tklib.TCL_EVAL_GLOBAL
+
+ # If args is a single tuple, replace with contents of tuple
+ if len(args) == 1 and isinstance(args[0], tuple):
+ args = args[0]
+
+ if self.threaded and self.thread_id != tklib.Tcl_GetCurrentThread():
+ # We cannot call the command directly. Instead, we must
+ # marshal the parameters to the interpreter thread.
+ raise NotImplementedError("Call from another thread")
+
+ objects = tkffi.new("Tcl_Obj*[]", len(args))
+ argc = len(args)
+ try:
+ for i, arg in enumerate(args):
+ if arg is None:
+ argc = i
+ break
+ obj = AsObj(arg)
+ tklib.Tcl_IncrRefCount(obj)
+ objects[i] = obj
+
+ res = tklib.Tcl_EvalObjv(self.interp, argc, objects, flags)
+ if res == tklib.TCL_ERROR:
+ self.raiseTclError()
+ else:
+ result = self._callResult()
+ finally:
+ for obj in objects:
+ if obj:
+ tklib.Tcl_DecrRefCount(obj)
+ return result
+
+ def _callResult(self):
+ assert self._wantobjects
+ value = tklib.Tcl_GetObjResult(self.interp)
+ # Not sure whether the IncrRef is necessary, but something
+ # may overwrite the interpreter result while we are
+ # converting it.
+ tklib.Tcl_IncrRefCount(value)
+ res = FromObj(self, value)
+ tklib.Tcl_DecrRefCount(value)
+ return res
+
+ def eval(self, script):
+ self._check_tcl_appartment()
+ res = tklib.Tcl_Eval(self.interp, script)
+ if res == tklib.TCL_ERROR:
+ self.raiseTclError()
+ return tkffi.string(tklib.Tcl_GetStringResult(self.interp))
+
+ def evalfile(self, filename):
+ self._check_tcl_appartment()
+ res = tklib.Tcl_EvalFile(self.interp, filename)
+ if res == tklib.TCL_ERROR:
+ self.raiseTclError()
+ return tkffi.string(tklib.Tcl_GetStringResult(self.interp))
+
+ def split(self, arg):
+ if isinstance(arg, tuple):
+ return self._splitObj(arg)
+ else:
+ return self._split(arg)
+
+ def splitlist(self, arg):
+ if isinstance(arg, tuple):
+ return arg
+ if isinstance(arg, unicode):
+ arg = arg.encode('utf8')
+
+ argc = tkffi.new("int*")
+ argv = tkffi.new("char***")
+ res = tklib.Tcl_SplitList(self.interp, arg, argc, argv)
+ if res == tklib.TCL_ERROR:
+ self.raiseTclError()
+
+ result = tuple(tkffi.string(argv[0][i])
+ for i in range(argc[0]))
+ tklib.Tcl_Free(argv[0])
+ return result
+
+ def _splitObj(self, arg):
+ if isinstance(arg, tuple):
+ size = len(arg)
+ # Recursively invoke SplitObj for all tuple items.
+ # If this does not return a new object, no action is
+ # needed.
+ result = None
+ newelems = (self._splitObj(elem) for elem in arg)
+ for elem, newelem in zip(arg, newelems):
+ if elem is not newelem:
+ return newelems
+ elif isinstance(arg, str):
+ argc = tkffi.new("int*")
+ argv = tkffi.new("char***")
+ res = tklib.Tcl_SplitList(tkffi.NULL, arg, argc, argv)
+ if res == tklib.TCL_ERROR:
+ return arg
+ tklib.Tcl_Free(argv[0])
+ if argc[0] > 1:
+ return self._split(arg)
+ return arg
+
+ def _split(self, arg):
+ argc = tkffi.new("int*")
+ argv = tkffi.new("char***")
+ res = tklib.Tcl_SplitList(tkffi.NULL, arg, argc, argv)
+ if res == tklib.TCL_ERROR:
+ # Not a list.
+ # Could be a quoted string containing funnies, e.g. {"}.
+ # Return the string itself.
+ return arg
+
+ try:
+ if argc[0] == 0:
+ return ""
+ elif argc[0] == 1:
+ return argv[0][0]
+ else:
+ return (self._split(argv[0][i])
+ for i in range(argc[0]))
+ finally:
+ tklib.Tcl_Free(argv[0])
+
+ def getboolean(self, s):
+ if isinstance(s, int):
+ return s
+ v = tkffi.new("int*")
+ res = tklib.Tcl_GetBoolean(self.interp, s, v)
+ if res == tklib.TCL_ERROR:
+ self.raiseTclError()
+
+ def mainloop(self, threshold):
+ self._check_tcl_appartment()
+ self.dispatching = True
+ while (tklib.Tk_GetNumMainWindows() > threshold and
+ not self.quitMainLoop and not self.errorInCmd):
+
+ if self.threaded:
+ result = tklib.Tcl_DoOneEvent(0)
+ else:
+ raise NotImplementedError("TCL configured without threads")
+
+ if result < 0:
+ break
+ self.dispatching = False
+ self.quitMainLoop = False
+ if self.errorInCmd:
+ self.errorInCmd = False
+ raise self.exc_info[0], self.exc_info[1], self.exc_info[2]
+
+ def quit(self):
+ self.quitMainLoop = True
diff --git a/lib_pypy/_tkinter/tclobj.py b/lib_pypy/_tkinter/tclobj.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_tkinter/tclobj.py
@@ -0,0 +1,114 @@
+# TclObject, conversions with Python objects
+
+from .tklib import tklib, tkffi
+
+class TypeCache(object):
+ def __init__(self):
+ self.BooleanType = tklib.Tcl_GetObjType("boolean")
+ self.ByteArrayType = tklib.Tcl_GetObjType("bytearray")
+ self.DoubleType = tklib.Tcl_GetObjType("double")
+ self.IntType = tklib.Tcl_GetObjType("int")
+ self.ListType = tklib.Tcl_GetObjType("list")
+ self.ProcBodyType = tklib.Tcl_GetObjType("procbody")
+ self.StringType = tklib.Tcl_GetObjType("string")
+
+
+def FromObj(app, value):
+ """Convert a TclObj pointer into a Python object."""
+ typeCache = app._typeCache
+ if not value.typePtr:
+ buf = tkffi.buffer(value.bytes, value.length)
+ result = buf[:]
+ # If the result contains any bytes with the top bit set, it's
+ # UTF-8 and we should decode it to Unicode.
+ try:
+ result.decode('ascii')
+ except UnicodeDecodeError:
+ result = result.decode('utf8')
+ return result
+
+ elif value.typePtr == typeCache.BooleanType:
+ return result
+ elif value.typePtr == typeCache.ByteArrayType:
+ return result
+ elif value.typePtr == typeCache.DoubleType:
+ return value.internalRep.doubleValue
+ elif value.typePtr == typeCache.IntType:
+ return value.internalRep.longValue
+ elif value.typePtr == typeCache.ListType:
+ size = tkffi.new('int*')
+ status = tklib.Tcl_ListObjLength(app.interp, value, size)
+ if status == tklib.TCL_ERROR:
+ app.raiseTclError()
+ result = []
+ tcl_elem = tkffi.new("Tcl_Obj**")
+ for i in range(size[0]):
+ status = tklib.Tcl_ListObjIndex(app.interp,
+ value, i, tcl_elem)
+ if status == tklib.TCL_ERROR:
+ app.raiseTclError()
+ result.append(FromObj(app, tcl_elem[0]))
+ return tuple(result)
+ elif value.typePtr == typeCache.ProcBodyType:
+ return result
+ elif value.typePtr == typeCache.StringType:
+ buf = tklib.Tcl_GetUnicode(value)
+ length = tklib.Tcl_GetCharLength(value)
+ buf = tkffi.buffer(tkffi.cast("char*", buf), length*2)[:]
+ return buf.decode('utf-16')
+
+ return TclObject(value)
+
+def AsObj(value):
+ if isinstance(value, str):
+ return tklib.Tcl_NewStringObj(value, len(value))
+ elif isinstance(value, bool):
+ return tklib.Tcl_NewBooleanObj(value)
+ elif isinstance(value, int):
+ return tklib.Tcl_NewLongObj(value)
+ elif isinstance(value, float):
+ return tklib.Tcl_NewDoubleObj(value)
+ elif isinstance(value, tuple):
+ argv = tkffi.new("Tcl_Obj*[]", len(value))
+ for i in range(len(value)):
+ argv[i] = AsObj(value[i])
+ return tklib.Tcl_NewListObj(len(value), argv)
+ elif isinstance(value, unicode):
+ encoded = value.encode('utf-16')[2:]
+ buf = tkffi.new("char[]", encoded)
+ inbuf = tkffi.cast("Tcl_UniChar*", buf)
+ return tklib.Tcl_NewUnicodeObj(buf, len(encoded)/2)
+ elif isinstance(value, TclObject):
+ tklib.Tcl_IncrRefCount(value._value)
+ return value._value
+ else:
+ return AsObj(str(value))
+
+class TclObject(object):
+ def __new__(cls, value):
+ self = object.__new__(cls)
+ tklib.Tcl_IncrRefCount(value)
+ self._value = value
+ self._string = None
+ return self
+
+ def __del__(self):
+ tklib.Tcl_DecrRefCount(self._value)
+
+ def __str__(self):
+ if self._string and isinstance(self._string, str):
+ return self._string
+ return tkffi.string(tklib.Tcl_GetString(self._value))
+
+ @property
+ def string(self):
+ if self._string is None:
+ length = tkffi.new("int*")
+ s = tklib.Tcl_GetStringFromObj(self._value, length)
+ value = tkffi.buffer(s, length[0])[:]
+ try:
+ value.decode('ascii')
+ except UnicodeDecodeError:
+ value = value.decode('utf8')
+ self._string = value
+ return self._string
diff --git a/lib_pypy/_tkinter/tklib.py b/lib_pypy/_tkinter/tklib.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_tkinter/tklib.py
@@ -0,0 +1,114 @@
+# C bindings with libtcl and libtk.
+
+from cffi import FFI
+
+tkffi = FFI()
+
+tkffi.cdef("""
+char *get_tk_version();
+char *get_tcl_version();
+#define TCL_READABLE ...
+#define TCL_WRITABLE ...
+#define TCL_EXCEPTION ...
+#define TCL_ERROR ...
+#define TCL_OK ...
+
+#define TCL_LEAVE_ERR_MSG ...
+#define TCL_GLOBAL_ONLY ...
+#define TCL_EVAL_DIRECT ...
+#define TCL_EVAL_GLOBAL ...
+
+typedef unsigned short Tcl_UniChar;
+typedef ... Tcl_Interp;
+typedef ...* Tcl_ThreadId;
+typedef ...* Tcl_Command;
+
+typedef struct Tcl_ObjType {
+ char *name;
+ ...;
+} Tcl_ObjType;
+typedef struct Tcl_Obj {
+ char *bytes;
+ int length;
+ Tcl_ObjType *typePtr;
+ union { /* The internal representation: */
+ long longValue; /* - an long integer value. */
+ double doubleValue; /* - a double-precision floating value. */
+ struct { /* - internal rep as two pointers. */
+ void *ptr1;
+ void *ptr2;
+ } twoPtrValue;
+ } internalRep;
+ ...;
+} Tcl_Obj;
+
+Tcl_Interp *Tcl_CreateInterp();
+void Tcl_DeleteInterp(Tcl_Interp* interp);
+int Tcl_Init(Tcl_Interp* interp);
+int Tk_Init(Tcl_Interp* interp);
+
+void Tcl_Free(char* ptr);
+
+const char *Tcl_SetVar(Tcl_Interp* interp, const char* varName, const char* newValue, int flags);
+const char *Tcl_SetVar2(Tcl_Interp* interp, const char* name1, const char* name2, const char* newValue, int flags);
+const char *Tcl_GetVar(Tcl_Interp* interp, const char* varName, int flags);
+Tcl_Obj *Tcl_SetVar2Ex(Tcl_Interp* interp, const char* name1, const char* name2, Tcl_Obj* newValuePtr, int flags);
+Tcl_Obj *Tcl_GetVar2Ex(Tcl_Interp* interp, const char* name1, const char* name2, int flags);
+int Tcl_UnsetVar2(Tcl_Interp* interp, const char* name1, const char* name2, int flags);
+const Tcl_ObjType *Tcl_GetObjType(const char* typeName);
+
+Tcl_Obj *Tcl_NewStringObj(const char* bytes, int length);
+Tcl_Obj *Tcl_NewUnicodeObj(const Tcl_UniChar* unicode, int numChars);
+Tcl_Obj *Tcl_NewLongObj(long longValue);
+Tcl_Obj *Tcl_NewBooleanObj(int boolValue);
+Tcl_Obj *Tcl_NewDoubleObj(double doubleValue);
+
+void Tcl_IncrRefCount(Tcl_Obj* objPtr);
+void Tcl_DecrRefCount(Tcl_Obj* objPtr);
+
+int Tcl_GetBoolean(Tcl_Interp* interp, const char* src, int* boolPtr);
+char *Tcl_GetString(Tcl_Obj* objPtr);
+char *Tcl_GetStringFromObj(Tcl_Obj* objPtr, int* lengthPtr);
+
+Tcl_UniChar *Tcl_GetUnicode(Tcl_Obj* objPtr);
+int Tcl_GetCharLength(Tcl_Obj* objPtr);
+
+Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj* const objv[]);
+int Tcl_ListObjLength(Tcl_Interp* interp, Tcl_Obj* listPtr, int* intPtr);
+int Tcl_ListObjIndex(Tcl_Interp* interp, Tcl_Obj* listPtr, int index, Tcl_Obj** objPtrPtr);
+int Tcl_SplitList(Tcl_Interp* interp, char* list, int* argcPtr, const char*** argvPtr);
+
+int Tcl_Eval(Tcl_Interp* interp, const char* script);
+int Tcl_EvalFile(Tcl_Interp* interp, const char* filename);
+int Tcl_EvalObjv(Tcl_Interp* interp, int objc, Tcl_Obj** objv, int flags);
+Tcl_Obj *Tcl_GetObjResult(Tcl_Interp* interp);
+const char *Tcl_GetStringResult(Tcl_Interp* interp);
+void Tcl_SetObjResult(Tcl_Interp* interp, Tcl_Obj* objPtr);
+
+typedef void* ClientData;
+typedef int Tcl_CmdProc(
+ ClientData clientData,
+ Tcl_Interp *interp,
+ int argc,
+ const char *argv[]);
+typedef void Tcl_CmdDeleteProc(
+ ClientData clientData);
+Tcl_Command Tcl_CreateCommand(Tcl_Interp* interp, const char* cmdName, Tcl_CmdProc proc, ClientData clientData, Tcl_CmdDeleteProc deleteProc);
+int Tcl_DeleteCommand(Tcl_Interp* interp, const char* cmdName);
+
+Tcl_ThreadId Tcl_GetCurrentThread();
+int Tcl_DoOneEvent(int flags);
+
+int Tk_GetNumMainWindows();
+""")
+
+tklib = tkffi.verify("""
+#include <tcl.h>
+#include <tk.h>
+
+char *get_tk_version() { return TK_VERSION; }
+char *get_tcl_version() { return TCL_VERSION; }
+""",
+include_dirs=['/usr/include/tcl'],
+libraries=['tcl', 'tk'],
+)
More information about the pypy-commit
mailing list