PageRenderTime 99ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 2ms

/ext/tk/tcltklib.c

https://github.com/diabolo/ruby
C | 10842 lines | 8381 code | 1565 blank | 896 comment | 1327 complexity | 0afc1ec549089c571b0f78f3bdf3af26 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * tcltklib.c
  3. * Aug. 27, 1997 Y. Shigehiro
  4. * Oct. 24, 1997 Y. Matsumoto
  5. */
  6. #define TCLTKLIB_RELEASE_DATE "2010-05-31"
  7. /* #define CREATE_RUBYTK_KIT */
  8. #include "ruby.h"
  9. #ifdef HAVE_RUBY_ENCODING_H
  10. #include "ruby/encoding.h"
  11. #endif
  12. #ifndef RUBY_VERSION
  13. #define RUBY_VERSION "(unknown version)"
  14. #endif
  15. #ifndef RUBY_RELEASE_DATE
  16. #define RUBY_RELEASE_DATE "unknown release-date"
  17. #endif
  18. #ifdef RUBY_VM
  19. static VALUE rb_thread_critical; /* dummy */
  20. int rb_thread_check_trap_pending();
  21. #else
  22. /* use rb_thread_critical on Ruby 1.8.x */
  23. #include "rubysig.h"
  24. #endif
  25. #if !defined(RSTRING_PTR)
  26. #define RSTRING_PTR(s) (RSTRING(s)->ptr)
  27. #define RSTRING_LEN(s) (RSTRING(s)->len)
  28. #endif
  29. #if !defined(RARRAY_PTR)
  30. #define RARRAY_PTR(s) (RARRAY(s)->ptr)
  31. #define RARRAY_LEN(s) (RARRAY(s)->len)
  32. #endif
  33. #ifdef OBJ_UNTRUST
  34. #define RbTk_OBJ_UNTRUST(x) do {OBJ_TAINT(x); OBJ_UNTRUST(x);} while (0)
  35. #else
  36. #define RbTk_OBJ_UNTRUST(x) OBJ_TAINT(x)
  37. #endif
  38. #if defined(HAVE_RB_PROC_NEW) && !defined(RUBY_VM)
  39. /* Ruby 1.8 :: rb_proc_new() was hidden from intern.h at 2008/04/22 */
  40. extern VALUE rb_proc_new _((VALUE (*)(ANYARGS/* VALUE yieldarg[, VALUE procarg] */), VALUE));
  41. #endif
  42. #undef EXTERN /* avoid conflict with tcl.h of tcl8.2 or before */
  43. #include <stdio.h>
  44. #ifdef HAVE_STDARG_PROTOTYPES
  45. #include <stdarg.h>
  46. #define va_init_list(a,b) va_start(a,b)
  47. #else
  48. #include <varargs.h>
  49. #define va_init_list(a,b) va_start(a)
  50. #endif
  51. #include <string.h>
  52. #if !defined HAVE_VSNPRINTF && !defined vsnprintf
  53. # ifdef WIN32
  54. /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
  55. # define vsnprintf _vsnprintf
  56. # else
  57. # ifdef HAVE_RUBY_RUBY_H
  58. # include "ruby/missing.h"
  59. # else
  60. # include "missing.h"
  61. # endif
  62. # endif
  63. #endif
  64. #include <tcl.h>
  65. #include <tk.h>
  66. #ifndef HAVE_RUBY_NATIVE_THREAD_P
  67. #define ruby_native_thread_p() is_ruby_native_thread()
  68. #undef RUBY_USE_NATIVE_THREAD
  69. #else
  70. #define RUBY_USE_NATIVE_THREAD 1
  71. #endif
  72. #ifndef HAVE_RB_ERRINFO
  73. #define rb_errinfo() (ruby_errinfo+0) /* cannot be l-value */
  74. #else
  75. VALUE rb_errinfo(void);
  76. #endif
  77. #ifndef HAVE_RB_SAFE_LEVEL
  78. #define rb_safe_level() (ruby_safe_level+0)
  79. #endif
  80. #ifndef HAVE_RB_SOURCEFILE
  81. #define rb_sourcefile() (ruby_sourcefile+0)
  82. #endif
  83. #include "stubs.h"
  84. #ifndef TCL_ALPHA_RELEASE
  85. #define TCL_ALPHA_RELEASE 0 /* "alpha" */
  86. #define TCL_BETA_RELEASE 1 /* "beta" */
  87. #define TCL_FINAL_RELEASE 2 /* "final" */
  88. #endif
  89. static struct {
  90. int major;
  91. int minor;
  92. int type; /* ALPHA==0, BETA==1, FINAL==2 */
  93. int patchlevel;
  94. } tcltk_version = {0, 0, 0, 0};
  95. static void
  96. set_tcltk_version()
  97. {
  98. if (tcltk_version.major) return;
  99. Tcl_GetVersion(&(tcltk_version.major),
  100. &(tcltk_version.minor),
  101. &(tcltk_version.patchlevel),
  102. &(tcltk_version.type));
  103. }
  104. #if TCL_MAJOR_VERSION >= 8
  105. # ifndef CONST84
  106. # if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 4 /* Tcl8.0.x -- 8.4b1 */
  107. # define CONST84
  108. # else /* unknown (maybe TCL_VERSION >= 8.5) */
  109. # ifdef CONST
  110. # define CONST84 CONST
  111. # else
  112. # define CONST84
  113. # endif
  114. # endif
  115. # endif
  116. #else /* TCL_MAJOR_VERSION < 8 */
  117. # ifdef CONST
  118. # define CONST84 CONST
  119. # else
  120. # define CONST
  121. # define CONST84
  122. # endif
  123. #endif
  124. #ifndef CONST86
  125. # if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 5 /* Tcl8.0.x -- 8.5.x */
  126. # define CONST86
  127. # else
  128. # define CONST86 CONST84
  129. # endif
  130. #endif
  131. /* copied from eval.c */
  132. #define TAG_RETURN 0x1
  133. #define TAG_BREAK 0x2
  134. #define TAG_NEXT 0x3
  135. #define TAG_RETRY 0x4
  136. #define TAG_REDO 0x5
  137. #define TAG_RAISE 0x6
  138. #define TAG_THROW 0x7
  139. #define TAG_FATAL 0x8
  140. /* for ruby_debug */
  141. #define DUMP1(ARG1) if (ruby_debug) { fprintf(stderr, "tcltklib: %s\n", ARG1); fflush(stderr); }
  142. #define DUMP2(ARG1, ARG2) if (ruby_debug) { fprintf(stderr, "tcltklib: ");\
  143. fprintf(stderr, ARG1, ARG2); fprintf(stderr, "\n"); fflush(stderr); }
  144. #define DUMP3(ARG1, ARG2, ARG3) if (ruby_debug) { fprintf(stderr, "tcltklib: ");\
  145. fprintf(stderr, ARG1, ARG2, ARG3); fprintf(stderr, "\n"); fflush(stderr); }
  146. /*
  147. #define DUMP1(ARG1)
  148. #define DUMP2(ARG1, ARG2)
  149. #define DUMP3(ARG1, ARG2, ARG3)
  150. */
  151. /* release date */
  152. static const char tcltklib_release_date[] = TCLTKLIB_RELEASE_DATE;
  153. /* finalize_proc_name */
  154. static const char finalize_hook_name[] = "INTERP_FINALIZE_HOOK";
  155. static void ip_finalize _((Tcl_Interp*));
  156. static int at_exit = 0;
  157. #ifdef HAVE_RUBY_ENCODING_H
  158. static VALUE cRubyEncoding;
  159. /* encoding */
  160. static int ENCODING_INDEX_UTF8;
  161. static int ENCODING_INDEX_BINARY;
  162. #endif
  163. static VALUE ENCODING_NAME_UTF8;
  164. static VALUE ENCODING_NAME_BINARY;
  165. static VALUE create_dummy_encoding_for_tk_core _((VALUE, VALUE, VALUE));
  166. static VALUE create_dummy_encoding_for_tk _((VALUE, VALUE));
  167. static int update_encoding_table _((VALUE, VALUE, VALUE));
  168. static VALUE encoding_table_get_name_core _((VALUE, VALUE, VALUE));
  169. static VALUE encoding_table_get_obj_core _((VALUE, VALUE, VALUE));
  170. static VALUE encoding_table_get_name _((VALUE, VALUE));
  171. static VALUE encoding_table_get_obj _((VALUE, VALUE));
  172. static VALUE create_encoding_table _((VALUE));
  173. static VALUE ip_get_encoding_table _((VALUE));
  174. /* for callback break & continue */
  175. static VALUE eTkCallbackReturn;
  176. static VALUE eTkCallbackBreak;
  177. static VALUE eTkCallbackContinue;
  178. static VALUE eLocalJumpError;
  179. static VALUE eTkLocalJumpError;
  180. static VALUE eTkCallbackRetry;
  181. static VALUE eTkCallbackRedo;
  182. static VALUE eTkCallbackThrow;
  183. static VALUE tcltkip_class;
  184. static ID ID_at_enc;
  185. static ID ID_at_interp;
  186. static ID ID_encoding_name;
  187. static ID ID_encoding_table;
  188. static ID ID_stop_p;
  189. static ID ID_alive_p;
  190. static ID ID_kill;
  191. static ID ID_join;
  192. static ID ID_value;
  193. static ID ID_call;
  194. static ID ID_backtrace;
  195. static ID ID_message;
  196. static ID ID_at_reason;
  197. static ID ID_return;
  198. static ID ID_break;
  199. static ID ID_next;
  200. static ID ID_to_s;
  201. static ID ID_inspect;
  202. static VALUE ip_invoke_real _((int, VALUE*, VALUE));
  203. static VALUE ip_invoke _((int, VALUE*, VALUE));
  204. static VALUE ip_invoke_with_position _((int, VALUE*, VALUE, Tcl_QueuePosition));
  205. static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE));
  206. static VALUE callq_safelevel_handler _((VALUE, VALUE));
  207. /* Tcl's object type */
  208. #if TCL_MAJOR_VERSION >= 8
  209. static const char Tcl_ObjTypeName_ByteArray[] = "bytearray";
  210. static CONST86 Tcl_ObjType *Tcl_ObjType_ByteArray;
  211. static const char Tcl_ObjTypeName_String[] = "string";
  212. static CONST86 Tcl_ObjType *Tcl_ObjType_String;
  213. #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1)
  214. #define IS_TCL_BYTEARRAY(obj) ((obj)->typePtr == Tcl_ObjType_ByteArray)
  215. #define IS_TCL_STRING(obj) ((obj)->typePtr == Tcl_ObjType_String)
  216. #define IS_TCL_VALID_STRING(obj) ((obj)->bytes != (char*)NULL)
  217. #endif
  218. #endif
  219. #ifndef HAVE_RB_HASH_LOOKUP
  220. #define rb_hash_lookup rb_hash_aref
  221. #endif
  222. /* safe Tcl_Eval and Tcl_GlobalEval */
  223. static int
  224. #ifdef HAVE_PROTOTYPES
  225. tcl_eval(Tcl_Interp *interp, const char *cmd)
  226. #else
  227. tcl_eval(interp, cmd)
  228. Tcl_Interp *interp;
  229. const char *cmd; /* don't have to be writable */
  230. #endif
  231. {
  232. char *buf = strdup(cmd);
  233. int ret;
  234. Tcl_AllowExceptions(interp);
  235. ret = Tcl_Eval(interp, buf);
  236. free(buf);
  237. return ret;
  238. }
  239. #undef Tcl_Eval
  240. #define Tcl_Eval tcl_eval
  241. static int
  242. #ifdef HAVE_PROTOTYPES
  243. tcl_global_eval(Tcl_Interp *interp, const char *cmd)
  244. #else
  245. tcl_global_eval(interp, cmd)
  246. Tcl_Interp *interp;
  247. const char *cmd; /* don't have to be writable */
  248. #endif
  249. {
  250. char *buf = strdup(cmd);
  251. int ret;
  252. Tcl_AllowExceptions(interp);
  253. ret = Tcl_GlobalEval(interp, buf);
  254. free(buf);
  255. return ret;
  256. }
  257. #undef Tcl_GlobalEval
  258. #define Tcl_GlobalEval tcl_global_eval
  259. /* Tcl_{Incr|Decr}RefCount for tcl7.x or earlier */
  260. #if TCL_MAJOR_VERSION < 8
  261. #define Tcl_IncrRefCount(obj) (1)
  262. #define Tcl_DecrRefCount(obj) (1)
  263. #endif
  264. /* Tcl_GetStringResult for tcl7.x or earlier */
  265. #if TCL_MAJOR_VERSION < 8
  266. #define Tcl_GetStringResult(interp) ((interp)->result)
  267. #endif
  268. /* Tcl_[GS]etVar2Ex for tcl8.0 */
  269. #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
  270. static Tcl_Obj *
  271. Tcl_GetVar2Ex(interp, name1, name2, flags)
  272. Tcl_Interp *interp;
  273. CONST char *name1;
  274. CONST char *name2;
  275. int flags;
  276. {
  277. Tcl_Obj *nameObj1, *nameObj2 = NULL, *retObj;
  278. nameObj1 = Tcl_NewStringObj((char*)name1, -1);
  279. Tcl_IncrRefCount(nameObj1);
  280. if (name2) {
  281. nameObj2 = Tcl_NewStringObj((char*)name2, -1);
  282. Tcl_IncrRefCount(nameObj2);
  283. }
  284. retObj = Tcl_ObjGetVar2(interp, nameObj1, nameObj2, flags);
  285. if (name2) {
  286. Tcl_DecrRefCount(nameObj2);
  287. }
  288. Tcl_DecrRefCount(nameObj1);
  289. return retObj;
  290. }
  291. static Tcl_Obj *
  292. Tcl_SetVar2Ex(interp, name1, name2, newValObj, flags)
  293. Tcl_Interp *interp;
  294. CONST char *name1;
  295. CONST char *name2;
  296. Tcl_Obj *newValObj;
  297. int flags;
  298. {
  299. Tcl_Obj *nameObj1, *nameObj2 = NULL, *retObj;
  300. nameObj1 = Tcl_NewStringObj((char*)name1, -1);
  301. Tcl_IncrRefCount(nameObj1);
  302. if (name2) {
  303. nameObj2 = Tcl_NewStringObj((char*)name2, -1);
  304. Tcl_IncrRefCount(nameObj2);
  305. }
  306. retObj = Tcl_ObjSetVar2(interp, nameObj1, nameObj2, newValObj, flags);
  307. if (name2) {
  308. Tcl_DecrRefCount(nameObj2);
  309. }
  310. Tcl_DecrRefCount(nameObj1);
  311. return retObj;
  312. }
  313. #endif
  314. /* from tkAppInit.c */
  315. #if TCL_MAJOR_VERSION < 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 4)
  316. # if !defined __MINGW32__ && !defined __BORLANDC__
  317. /*
  318. * The following variable is a special hack that is needed in order for
  319. * Sun shared libraries to be used for Tcl.
  320. */
  321. extern int matherr();
  322. int *tclDummyMathPtr = (int *) matherr;
  323. # endif
  324. #endif
  325. /*---- module TclTkLib ----*/
  326. struct invoke_queue {
  327. Tcl_Event ev;
  328. int argc;
  329. #if TCL_MAJOR_VERSION >= 8
  330. Tcl_Obj **argv;
  331. #else /* TCL_MAJOR_VERSION < 8 */
  332. char **argv;
  333. #endif
  334. VALUE interp;
  335. int *done;
  336. int safe_level;
  337. VALUE result;
  338. VALUE thread;
  339. };
  340. struct eval_queue {
  341. Tcl_Event ev;
  342. char *str;
  343. int len;
  344. VALUE interp;
  345. int *done;
  346. int safe_level;
  347. VALUE result;
  348. VALUE thread;
  349. };
  350. struct call_queue {
  351. Tcl_Event ev;
  352. VALUE (*func)();
  353. int argc;
  354. VALUE *argv;
  355. VALUE interp;
  356. int *done;
  357. int safe_level;
  358. VALUE result;
  359. VALUE thread;
  360. };
  361. void
  362. invoke_queue_mark(struct invoke_queue *q)
  363. {
  364. rb_gc_mark(q->interp);
  365. rb_gc_mark(q->result);
  366. rb_gc_mark(q->thread);
  367. }
  368. void
  369. eval_queue_mark(struct eval_queue *q)
  370. {
  371. rb_gc_mark(q->interp);
  372. rb_gc_mark(q->result);
  373. rb_gc_mark(q->thread);
  374. }
  375. void
  376. call_queue_mark(struct call_queue *q)
  377. {
  378. int i;
  379. for(i = 0; i < q->argc; i++) {
  380. rb_gc_mark(q->argv[i]);
  381. }
  382. rb_gc_mark(q->interp);
  383. rb_gc_mark(q->result);
  384. rb_gc_mark(q->thread);
  385. }
  386. static VALUE eventloop_thread;
  387. static Tcl_Interp *eventloop_interp;
  388. #ifdef RUBY_USE_NATIVE_THREAD
  389. Tcl_ThreadId tk_eventloop_thread_id; /* native thread ID of Tcl interpreter */
  390. #endif
  391. static VALUE eventloop_stack;
  392. static int window_event_mode = ~0;
  393. static VALUE watchdog_thread;
  394. Tcl_Interp *current_interp;
  395. /* thread control strategy */
  396. /* multi-tk works with the following settings only ???
  397. : CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1
  398. : USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0
  399. : DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0
  400. */
  401. #ifdef RUBY_USE_NATIVE_THREAD
  402. #define CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1
  403. #define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0
  404. #define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 1
  405. #else /* ! RUBY_USE_NATIVE_THREAD */
  406. #define CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1
  407. #define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0
  408. #define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0
  409. #endif
  410. #if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
  411. static int have_rb_thread_waiting_for_value = 0;
  412. #endif
  413. /*
  414. * 'event_loop_max' is a maximum events which the eventloop processes in one
  415. * term of thread scheduling. 'no_event_tick' is the count-up value when
  416. * there are no event for processing.
  417. * 'timer_tick' is a limit of one term of thread scheduling.
  418. * If 'timer_tick' == 0, then not use the timer for thread scheduling.
  419. */
  420. #ifdef RUBY_USE_NATIVE_THREAD
  421. #define DEFAULT_EVENT_LOOP_MAX 800/*counts*/
  422. #define DEFAULT_NO_EVENT_TICK 10/*counts*/
  423. #define DEFAULT_NO_EVENT_WAIT 1/*milliseconds ( 1 -- 999 ) */
  424. #define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */
  425. #define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */
  426. #define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */
  427. #else /* ! RUBY_USE_NATIVE_THREAD */
  428. #define DEFAULT_EVENT_LOOP_MAX 800/*counts*/
  429. #define DEFAULT_NO_EVENT_TICK 10/*counts*/
  430. #define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */
  431. #define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */
  432. #define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */
  433. #define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */
  434. #endif
  435. #define EVENT_HANDLER_TIMEOUT 100/*milliseconds*/
  436. static int event_loop_max = DEFAULT_EVENT_LOOP_MAX;
  437. static int no_event_tick = DEFAULT_NO_EVENT_TICK;
  438. static int no_event_wait = DEFAULT_NO_EVENT_WAIT;
  439. static int timer_tick = DEFAULT_TIMER_TICK;
  440. static int req_timer_tick = DEFAULT_TIMER_TICK;
  441. static int run_timer_flag = 0;
  442. static int event_loop_wait_event = 0;
  443. static int event_loop_abort_on_exc = 1;
  444. static int loop_counter = 0;
  445. static int check_rootwidget_flag = 0;
  446. /* call ruby interpreter */
  447. #if TCL_MAJOR_VERSION >= 8
  448. static int ip_ruby_eval _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*));
  449. static int ip_ruby_cmd _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*));
  450. #else /* TCL_MAJOR_VERSION < 8 */
  451. static int ip_ruby_eval _((ClientData, Tcl_Interp *, int, char **));
  452. static int ip_ruby_cmd _((ClientData, Tcl_Interp *, int, char **));
  453. #endif
  454. struct cmd_body_arg {
  455. VALUE receiver;
  456. ID method;
  457. VALUE args;
  458. };
  459. /*----------------------------*/
  460. /* use Tcl internal functions */
  461. /*----------------------------*/
  462. #ifndef TCL_NAMESPACE_DEBUG
  463. #define TCL_NAMESPACE_DEBUG 0
  464. #endif
  465. #if TCL_NAMESPACE_DEBUG
  466. #if TCL_MAJOR_VERSION >= 8
  467. EXTERN struct TclIntStubs *tclIntStubsPtr;
  468. #endif
  469. /*-- Tcl_GetCurrentNamespace --*/
  470. #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 5
  471. /* Tcl7.x doesn't have namespace support. */
  472. /* Tcl8.5+ has definition of Tcl_GetCurrentNamespace() in tclDecls.h */
  473. # ifndef Tcl_GetCurrentNamespace
  474. EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace _((Tcl_Interp *));
  475. # endif
  476. # if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS)
  477. # ifndef Tcl_GetCurrentNamespace
  478. # ifndef FunctionNum_of_GetCurrentNamespace
  479. #define FunctionNum_of_GetCurrentNamespace 124
  480. # endif
  481. struct DummyTclIntStubs_for_GetCurrentNamespace {
  482. int magic;
  483. struct TclIntStubHooks *hooks;
  484. void (*func[FunctionNum_of_GetCurrentNamespace])();
  485. Tcl_Namespace * (*tcl_GetCurrentNamespace) _((Tcl_Interp *));
  486. };
  487. #define Tcl_GetCurrentNamespace \
  488. (((struct DummyTclIntStubs_for_GetCurrentNamespace *)tclIntStubsPtr)->tcl_GetCurrentNamespace)
  489. # endif
  490. # endif
  491. #endif
  492. /* namespace check */
  493. /* ip_null_namespace(Tcl_Interp *interp) */
  494. #if TCL_MAJOR_VERSION < 8
  495. #define ip_null_namespace(interp) (0)
  496. #else /* support namespace */
  497. #define ip_null_namespace(interp) \
  498. (Tcl_GetCurrentNamespace(interp) == (Tcl_Namespace *)NULL)
  499. #endif
  500. /* rbtk_invalid_namespace(tcltkip *ptr) */
  501. #if TCL_MAJOR_VERSION < 8
  502. #define rbtk_invalid_namespace(ptr) (0)
  503. #else /* support namespace */
  504. #define rbtk_invalid_namespace(ptr) \
  505. ((ptr)->default_ns == (Tcl_Namespace*)NULL || Tcl_GetCurrentNamespace((ptr)->ip) != (ptr)->default_ns)
  506. #endif
  507. /*-- Tcl_PopCallFrame & Tcl_PushCallFrame --*/
  508. #if TCL_MAJOR_VERSION >= 8
  509. # ifndef CallFrame
  510. typedef struct CallFrame {
  511. Tcl_Namespace *nsPtr;
  512. int dummy1;
  513. int dummy2;
  514. char *dummy3;
  515. struct CallFrame *callerPtr;
  516. struct CallFrame *callerVarPtr;
  517. int level;
  518. char *dummy7;
  519. char *dummy8;
  520. int dummy9;
  521. char* dummy10;
  522. } CallFrame;
  523. # endif
  524. # if !defined(TclGetFrame) && !defined(TclGetFrame_TCL_DECLARED)
  525. EXTERN int TclGetFrame _((Tcl_Interp *, CONST char *, CallFrame **));
  526. # endif
  527. # if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS)
  528. # ifndef TclGetFrame
  529. # ifndef FunctionNum_of_GetFrame
  530. #define FunctionNum_of_GetFrame 32
  531. # endif
  532. struct DummyTclIntStubs_for_GetFrame {
  533. int magic;
  534. struct TclIntStubHooks *hooks;
  535. void (*func[FunctionNum_of_GetFrame])();
  536. int (*tclGetFrame) _((Tcl_Interp *, CONST char *, CallFrame **));
  537. };
  538. #define TclGetFrame \
  539. (((struct DummyTclIntStubs_for_GetFrame *)tclIntStubsPtr)->tclGetFrame)
  540. # endif
  541. # endif
  542. # if !defined(Tcl_PopCallFrame) && !defined(Tcl_PopCallFrame_TCL_DECLARED)
  543. EXTERN void Tcl_PopCallFrame _((Tcl_Interp *));
  544. EXTERN int Tcl_PushCallFrame _((Tcl_Interp *, Tcl_CallFrame *, Tcl_Namespace *, int));
  545. # endif
  546. # if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS)
  547. # ifndef Tcl_PopCallFrame
  548. # ifndef FunctionNum_of_PopCallFrame
  549. #define FunctionNum_of_PopCallFrame 128
  550. # endif
  551. struct DummyTclIntStubs_for_PopCallFrame {
  552. int magic;
  553. struct TclIntStubHooks *hooks;
  554. void (*func[FunctionNum_of_PopCallFrame])();
  555. void (*tcl_PopCallFrame) _((Tcl_Interp *));
  556. int (*tcl_PushCallFrame) _((Tcl_Interp *, Tcl_CallFrame *, Tcl_Namespace *, int));
  557. };
  558. #define Tcl_PopCallFrame \
  559. (((struct DummyTclIntStubs_for_PopCallFrame *)tclIntStubsPtr)->tcl_PopCallFrame)
  560. #define Tcl_PushCallFrame \
  561. (((struct DummyTclIntStubs_for_PopCallFrame *)tclIntStubsPtr)->tcl_PushCallFrame)
  562. # endif
  563. # endif
  564. #else /* Tcl7.x */
  565. # ifndef CallFrame
  566. typedef struct CallFrame {
  567. Tcl_HashTable varTable;
  568. int level;
  569. int argc;
  570. char **argv;
  571. struct CallFrame *callerPtr;
  572. struct CallFrame *callerVarPtr;
  573. } CallFrame;
  574. # endif
  575. # ifndef Tcl_CallFrame
  576. #define Tcl_CallFrame CallFrame
  577. # endif
  578. # if !defined(TclGetFrame) && !defined(TclGetFrame_TCL_DECLARED)
  579. EXTERN int TclGetFrame _((Tcl_Interp *, CONST char *, CallFrame **));
  580. # endif
  581. # if !defined(Tcl_PopCallFrame) && !defined(Tcl_PopCallFrame_TCL_DECLARED)
  582. typedef struct DummyInterp {
  583. char *dummy1;
  584. char *dummy2;
  585. int dummy3;
  586. Tcl_HashTable dummy4;
  587. Tcl_HashTable dummy5;
  588. Tcl_HashTable dummy6;
  589. int numLevels;
  590. int maxNestingDepth;
  591. CallFrame *framePtr;
  592. CallFrame *varFramePtr;
  593. } DummyInterp;
  594. static void
  595. Tcl_PopCallFrame(interp)
  596. Tcl_Interp *interp;
  597. {
  598. DummyInterp *iPtr = (DummyInterp*)interp;
  599. CallFrame *frame = iPtr->varFramePtr;
  600. /* **** DUMMY **** */
  601. iPtr->framePtr = frame.callerPtr;
  602. iPtr->varFramePtr = frame.callerVarPtr;
  603. return TCL_OK;
  604. }
  605. /* dummy */
  606. #define Tcl_Namespace char
  607. static int
  608. Tcl_PushCallFrame(interp, framePtr, nsPtr, isProcCallFrame)
  609. Tcl_Interp *interp;
  610. Tcl_CallFrame *framePtr;
  611. Tcl_Namespace *nsPtr;
  612. int isProcCallFrame;
  613. {
  614. DummyInterp *iPtr = (DummyInterp*)interp;
  615. CallFrame *frame = (CallFrame *)framePtr;
  616. /* **** DUMMY **** */
  617. Tcl_InitHashTable(&frame.varTable, TCL_STRING_KEYS);
  618. if (iPtr->varFramePtr != NULL) {
  619. frame.level = iPtr->varFramePtr->level + 1;
  620. } else {
  621. frame.level = 1;
  622. }
  623. frame.callerPtr = iPtr->framePtr;
  624. frame.callerVarPtr = iPtr->varFramePtr;
  625. iPtr->framePtr = &frame;
  626. iPtr->varFramePtr = &frame;
  627. return TCL_OK;
  628. }
  629. # endif
  630. #endif
  631. #endif /* TCL_NAMESPACE_DEBUG */
  632. /*---- class TclTkIp ----*/
  633. struct tcltkip {
  634. Tcl_Interp *ip; /* the interpreter */
  635. #if TCL_NAMESPACE_DEBUG
  636. Tcl_Namespace *default_ns; /* default namespace */
  637. #endif
  638. #ifdef RUBY_USE_NATIVE_THREAD
  639. Tcl_ThreadId tk_thread_id; /* native thread ID of Tcl interpreter */
  640. #endif
  641. int has_orig_exit; /* has original 'exit' command ? */
  642. Tcl_CmdInfo orig_exit_info; /* command info of original 'exit' command */
  643. int ref_count; /* reference count of rbtk_preserve_ip call */
  644. int allow_ruby_exit; /* allow exiting ruby by 'exit' function */
  645. int return_value; /* return value */
  646. };
  647. static struct tcltkip *
  648. get_ip(self)
  649. VALUE self;
  650. {
  651. struct tcltkip *ptr;
  652. Data_Get_Struct(self, struct tcltkip, ptr);
  653. if (ptr == 0) {
  654. /* rb_raise(rb_eTypeError, "uninitialized TclTkIp"); */
  655. return((struct tcltkip *)NULL);
  656. }
  657. if (ptr->ip == (Tcl_Interp*)NULL) {
  658. /* rb_raise(rb_eRuntimeError, "deleted IP"); */
  659. return((struct tcltkip *)NULL);
  660. }
  661. return ptr;
  662. }
  663. static int
  664. deleted_ip(ptr)
  665. struct tcltkip *ptr;
  666. {
  667. if (!ptr || !ptr->ip || Tcl_InterpDeleted(ptr->ip)
  668. #if TCL_NAMESPACE_DEBUG
  669. || rbtk_invalid_namespace(ptr)
  670. #endif
  671. ) {
  672. DUMP1("ip is deleted");
  673. return 1;
  674. }
  675. return 0;
  676. }
  677. /* increment/decrement reference count of tcltkip */
  678. static int
  679. rbtk_preserve_ip(ptr)
  680. struct tcltkip *ptr;
  681. {
  682. ptr->ref_count++;
  683. if (ptr->ip == (Tcl_Interp*)NULL) {
  684. /* deleted IP */
  685. ptr->ref_count = 0;
  686. } else {
  687. Tcl_Preserve((ClientData)ptr->ip);
  688. }
  689. return(ptr->ref_count);
  690. }
  691. static int
  692. rbtk_release_ip(ptr)
  693. struct tcltkip *ptr;
  694. {
  695. ptr->ref_count--;
  696. if (ptr->ref_count < 0) {
  697. ptr->ref_count = 0;
  698. } else if (ptr->ip == (Tcl_Interp*)NULL) {
  699. /* deleted IP */
  700. ptr->ref_count = 0;
  701. } else {
  702. Tcl_Release((ClientData)ptr->ip);
  703. }
  704. return(ptr->ref_count);
  705. }
  706. static VALUE
  707. #ifdef HAVE_STDARG_PROTOTYPES
  708. create_ip_exc(VALUE interp, VALUE exc, const char *fmt, ...)
  709. #else
  710. create_ip_exc(interp, exc, fmt, va_alist)
  711. VALUE interp:
  712. VALUE exc;
  713. const char *fmt;
  714. va_dcl
  715. #endif
  716. {
  717. va_list args;
  718. char buf[BUFSIZ];
  719. VALUE einfo;
  720. struct tcltkip *ptr = get_ip(interp);
  721. va_init_list(args,fmt);
  722. vsnprintf(buf, BUFSIZ, fmt, args);
  723. buf[BUFSIZ - 1] = '\0';
  724. va_end(args);
  725. einfo = rb_exc_new2(exc, buf);
  726. rb_ivar_set(einfo, ID_at_interp, interp);
  727. if (ptr) {
  728. Tcl_ResetResult(ptr->ip);
  729. }
  730. return einfo;
  731. }
  732. /*-------------------------------------------------------*/
  733. #if defined CREATE_RUBYTK_KIT || defined CREATE_RUBYKIT
  734. /* Tcl/Tk stubs may work, but probably it is meaningless. */
  735. #if defined USE_TCL_STUBS || defined USE_TK_STUBS
  736. # error Not support Tcl/Tk stubs with Ruby/Tk-Kit or Rubykit.
  737. #endif
  738. #ifndef KIT_INCLUDES_TK
  739. # define KIT_INCLUDES_TK 1
  740. #endif
  741. /* #define KIT_INCLUDES_ITCL 1 */
  742. /* #define KIT_INCLUDES_THREAD 1 */
  743. #ifdef KIT_INCLUDES_ITCL
  744. Tcl_AppInitProc Itcl_Init;
  745. #endif
  746. Tcl_AppInitProc Mk4tcl_Init, Vfs_Init, Rechan_Init, Zlib_Init;
  747. #if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION < 85
  748. Tcl_AppInitProc Pwb_Init;
  749. #endif
  750. #if defined TCL_THREADS && defined KIT_INCLUDES_THREAD
  751. Tcl_AppInitProc Thread_Init;
  752. #endif
  753. #ifdef _WIN32
  754. Tcl_AppInitProc Dde_Init, Registry_Init;
  755. #endif
  756. static const char *tcltklib_filepath = "[info nameofexecutable]";
  757. static char *rubytkkit_preInitCmd = (char *)NULL;
  758. static const char *rubytkkit_preInitCmd_head = "set ::rubytkkit_exe [list ";
  759. static const char *rubytkkit_preInitCmd_tail =
  760. "]\n"
  761. /*=== following init scripts are quoted from kitInit.c of Tclkit ===*/
  762. /* Tclkit license terms ---
  763. LICENSE
  764. The Tclkit-specific sources are license free, they just have a copyright.
  765. Hold the author(s) harmless and any lawful use is permitted.
  766. This does *not* apply to any of the sources of the other major Open Source
  767. Software used in Tclkit, which each have very liberal BSD/MIT-like licenses:
  768. Tcl/Tk, Incrtcl, Metakit, TclVFS, Zlib
  769. */
  770. #ifdef _WIN32_WCE
  771. /* silly hack to get wince port to launch, some sort of std{in,out,err} problem
  772. */
  773. "open /kitout.txt a; open /kitout.txt a; open /kitout.txt a\n"
  774. /* this too seems to be needed on wince - it appears to be related to the above
  775. */
  776. "catch {rename source ::tcl::source}\n"
  777. "proc source file {\n"
  778. "set old [info script]\n"
  779. "info script $file\n"
  780. "set fid [open $file]\n"
  781. "set data [read $fid]\n"
  782. "close $fid\n"
  783. "set code [catch {uplevel 1 $data} res]\n"
  784. "info script $old\n"
  785. "if {$code == 2} { set code 0 }\n"
  786. "return -code $code $res\n"
  787. "}\n"
  788. #endif
  789. "proc tclKitInit {} {\n"
  790. "rename tclKitInit {}\n"
  791. "load {} Mk4tcl\n"
  792. #if defined KIT_VFS_WRITABLE && !defined CREATE_RUBYKIT
  793. /* running command cannot open itself for writing */
  794. "mk::file open exe $::rubytkkit_exe\n"
  795. #else
  796. "mk::file open exe $::rubytkkit_exe -readonly\n"
  797. #endif
  798. "set n [mk::select exe.dirs!0.files name boot.tcl]\n"
  799. "if {$n != \"\"} {\n"
  800. "set s [mk::get exe.dirs!0.files!$n contents]\n"
  801. "if {![string length $s]} { error \"empty boot.tcl\" }\n"
  802. "catch {load {} zlib}\n"
  803. "if {[mk::get exe.dirs!0.files!$n size] != [string length $s]} {\n"
  804. "set s [zlib decompress $s]\n"
  805. "}\n"
  806. "} else {\n"
  807. "set f [open setup.tcl]\n"
  808. "set s [read $f]\n"
  809. "close $f\n"
  810. "}\n"
  811. "uplevel #0 $s\n"
  812. #ifdef _WIN32
  813. "package ifneeded dde 1.3.1 {load {} dde}\n"
  814. "package ifneeded registry 1.1.5 {load {} registry}\n"
  815. #endif
  816. "}\n"
  817. "tclKitInit"
  818. ;
  819. #if 0
  820. /* Not use this script.
  821. It's a memo to support an initScript for Tcl interpreters in the future. */
  822. static const char initScript[] =
  823. "if {[file isfile [file join $::rubytkkit_exe main.tcl]]} {\n"
  824. "if {[info commands console] != {}} { console hide }\n"
  825. "set tcl_interactive 0\n"
  826. "incr argc\n"
  827. "set argv [linsert $argv 0 $argv0]\n"
  828. "set argv0 [file join $::rubytkkit_exe main.tcl]\n"
  829. "} else continue\n"
  830. ;
  831. #endif
  832. #if !defined(TclSetPreInitScript) && !defined(TclSetPreInitScript_TCL_DECLARED)
  833. EXTERN char* TclSetPreInitScript _((char *));
  834. #endif
  835. static char*
  836. setup_preInitCmd(const char *path)
  837. {
  838. int head_len, path_len, tail_len;
  839. char *ptr;
  840. head_len = strlen(rubytkkit_preInitCmd_head);
  841. path_len = strlen(path);
  842. tail_len = strlen(rubytkkit_preInitCmd_tail);
  843. rubytkkit_preInitCmd = ALLOC_N(char, head_len + path_len + tail_len + 1);
  844. ptr = rubytkkit_preInitCmd;
  845. memcpy(ptr, rubytkkit_preInitCmd_head, head_len);
  846. ptr += head_len;
  847. memcpy(ptr, path, path_len);
  848. ptr += path_len;
  849. memcpy(ptr, rubytkkit_preInitCmd_tail, tail_len);
  850. ptr += tail_len;
  851. *ptr = '\0';
  852. return TclSetPreInitScript(rubytkkit_preInitCmd);
  853. }
  854. static void
  855. init_static_tcltk_packages()
  856. {
  857. #ifdef KIT_INCLUDES_ITCL
  858. Tcl_StaticPackage(0, "Itcl", Itcl_Init, NULL);
  859. #endif
  860. Tcl_StaticPackage(0, "Mk4tcl", Mk4tcl_Init, NULL);
  861. #if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION < 85
  862. Tcl_StaticPackage(0, "pwb", Pwb_Init, NULL);
  863. #endif
  864. Tcl_StaticPackage(0, "rechan", Rechan_Init, NULL);
  865. Tcl_StaticPackage(0, "vfs", Vfs_Init, NULL);
  866. Tcl_StaticPackage(0, "zlib", Zlib_Init, NULL);
  867. #if defined TCL_THREADS && defined KIT_INCLUDES_THREAD
  868. Tcl_StaticPackage(0, "Thread", Thread_Init, NULL);
  869. #endif
  870. #ifdef _WIN32
  871. Tcl_StaticPackage(0, "dde", Dde_Init, NULL);
  872. Tcl_StaticPackage(0, "registry", Registry_Init, NULL);
  873. #endif
  874. #ifdef KIT_INCLUDES_TK
  875. Tcl_StaticPackage(0, "Tk", Tk_Init, Tk_SafeInit);
  876. #endif
  877. }
  878. /* SetExecName -- Hack to get around Tcl bug 1224888. */
  879. void SetExecName(Tcl_Interp *interp) {
  880. /* dummy */
  881. }
  882. #endif /* defined CREATE_RUBYTK_KIT || defined CREATE_RUBYKIT */
  883. static int
  884. call_tclkit_init_script(Tcl_Interp *interp)
  885. {
  886. #if 0
  887. /* Currently, nothing do in this function.
  888. It's a memo (quoted from kitInit.c of Tclkit)
  889. to support an initScript for Tcl interpreters in the future. */
  890. if (Tcl_Eval(interp, initScript) == TCL_OK) {
  891. Tcl_Obj* path = TclGetStartupScriptPath();
  892. TclSetStartupScriptPath(Tcl_GetObjResult(interp));
  893. if (path == NULL)
  894. Tcl_Eval(interp, "incr argc -1; set argv [lrange $argv 1 end]");
  895. }
  896. #endif
  897. return 1;
  898. }
  899. /**********************************************************************/
  900. /* stub status */
  901. static void
  902. tcl_stubs_check()
  903. {
  904. if (!tcl_stubs_init_p()) {
  905. int st = ruby_tcl_stubs_init();
  906. switch(st) {
  907. case TCLTK_STUBS_OK:
  908. break;
  909. case NO_TCL_DLL:
  910. rb_raise(rb_eLoadError, "tcltklib: fail to open tcl_dll");
  911. case NO_FindExecutable:
  912. rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_FindExecutable");
  913. case NO_CreateInterp:
  914. rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_CreateInterp()");
  915. case NO_DeleteInterp:
  916. rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_DeleteInterp()");
  917. case FAIL_CreateInterp:
  918. rb_raise(rb_eRuntimeError, "tcltklib: fail to create a new IP to call Tcl_InitStubs()");
  919. case FAIL_Tcl_InitStubs:
  920. rb_raise(rb_eRuntimeError, "tcltklib: fail to Tcl_InitStubs()");
  921. default:
  922. rb_raise(rb_eRuntimeError, "tcltklib: unknown error(%d) on ruby_tcl_stubs_init()", st);
  923. }
  924. }
  925. }
  926. static VALUE
  927. tcltkip_init_tk(interp)
  928. VALUE interp;
  929. {
  930. struct tcltkip *ptr = get_ip(interp);
  931. #if TCL_MAJOR_VERSION >= 8
  932. int st;
  933. if (Tcl_IsSafe(ptr->ip)) {
  934. DUMP1("Tk_SafeInit");
  935. st = ruby_tk_stubs_safeinit(ptr->ip);
  936. switch(st) {
  937. case TCLTK_STUBS_OK:
  938. break;
  939. case NO_Tk_Init:
  940. return rb_exc_new2(rb_eLoadError,
  941. "tcltklib: can't find Tk_SafeInit()");
  942. case FAIL_Tk_Init:
  943. return create_ip_exc(interp, rb_eRuntimeError,
  944. "tcltklib: fail to Tk_SafeInit(). %s",
  945. Tcl_GetStringResult(ptr->ip));
  946. case FAIL_Tk_InitStubs:
  947. return create_ip_exc(interp, rb_eRuntimeError,
  948. "tcltklib: fail to Tk_InitStubs(). %s",
  949. Tcl_GetStringResult(ptr->ip));
  950. default:
  951. return create_ip_exc(interp, rb_eRuntimeError,
  952. "tcltklib: unknown error(%d) on ruby_tk_stubs_safeinit", st);
  953. }
  954. } else {
  955. DUMP1("Tk_Init");
  956. st = ruby_tk_stubs_init(ptr->ip);
  957. switch(st) {
  958. case TCLTK_STUBS_OK:
  959. break;
  960. case NO_Tk_Init:
  961. return rb_exc_new2(rb_eLoadError,
  962. "tcltklib: can't find Tk_Init()");
  963. case FAIL_Tk_Init:
  964. return create_ip_exc(interp, rb_eRuntimeError,
  965. "tcltklib: fail to Tk_Init(). %s",
  966. Tcl_GetStringResult(ptr->ip));
  967. case FAIL_Tk_InitStubs:
  968. return create_ip_exc(interp, rb_eRuntimeError,
  969. "tcltklib: fail to Tk_InitStubs(). %s",
  970. Tcl_GetStringResult(ptr->ip));
  971. default:
  972. return create_ip_exc(interp, rb_eRuntimeError,
  973. "tcltklib: unknown error(%d) on ruby_tk_stubs_init", st);
  974. }
  975. }
  976. #else /* TCL_MAJOR_VERSION < 8 */
  977. DUMP1("Tk_Init");
  978. if (ruby_tk_stubs_init(ptr->ip) != TCLTK_STUBS_OK) {
  979. return rb_exc_new2(rb_eRuntimeError, ptr->ip->result);
  980. }
  981. #endif
  982. #ifdef RUBY_USE_NATIVE_THREAD
  983. ptr->tk_thread_id = Tcl_GetCurrentThread();
  984. #endif
  985. return Qnil;
  986. }
  987. /* treat excetiopn on Tcl side */
  988. static VALUE rbtk_pending_exception;
  989. static int rbtk_eventloop_depth = 0;
  990. static int rbtk_internal_eventloop_handler = 0;
  991. static int
  992. pending_exception_check0()
  993. {
  994. volatile VALUE exc = rbtk_pending_exception;
  995. if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) {
  996. DUMP1("find a pending exception");
  997. if (rbtk_eventloop_depth > 0
  998. || rbtk_internal_eventloop_handler > 0
  999. ) {
  1000. return 1; /* pending */
  1001. } else {
  1002. rbtk_pending_exception = Qnil;
  1003. if (rb_obj_is_kind_of(exc, eTkCallbackRetry)) {
  1004. DUMP1("pending_exception_check0: call rb_jump_tag(retry)");
  1005. rb_jump_tag(TAG_RETRY);
  1006. } else if (rb_obj_is_kind_of(exc, eTkCallbackRedo)) {
  1007. DUMP1("pending_exception_check0: call rb_jump_tag(redo)");
  1008. rb_jump_tag(TAG_REDO);
  1009. } else if (rb_obj_is_kind_of(exc, eTkCallbackThrow)) {
  1010. DUMP1("pending_exception_check0: call rb_jump_tag(throw)");
  1011. rb_jump_tag(TAG_THROW);
  1012. }
  1013. rb_exc_raise(exc);
  1014. }
  1015. } else {
  1016. return 0;
  1017. }
  1018. }
  1019. static int
  1020. pending_exception_check1(thr_crit_bup, ptr)
  1021. int thr_crit_bup;
  1022. struct tcltkip *ptr;
  1023. {
  1024. volatile VALUE exc = rbtk_pending_exception;
  1025. if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) {
  1026. DUMP1("find a pending exception");
  1027. if (rbtk_eventloop_depth > 0
  1028. || rbtk_internal_eventloop_handler > 0
  1029. ) {
  1030. return 1; /* pending */
  1031. } else {
  1032. rbtk_pending_exception = Qnil;
  1033. if (ptr != (struct tcltkip *)NULL) {
  1034. /* Tcl_Release(ptr->ip); */
  1035. rbtk_release_ip(ptr);
  1036. }
  1037. rb_thread_critical = thr_crit_bup;
  1038. if (rb_obj_is_kind_of(exc, eTkCallbackRetry)) {
  1039. DUMP1("pending_exception_check1: call rb_jump_tag(retry)");
  1040. rb_jump_tag(TAG_RETRY);
  1041. } else if (rb_obj_is_kind_of(exc, eTkCallbackRedo)) {
  1042. DUMP1("pending_exception_check1: call rb_jump_tag(redo)");
  1043. rb_jump_tag(TAG_REDO);
  1044. } else if (rb_obj_is_kind_of(exc, eTkCallbackThrow)) {
  1045. DUMP1("pending_exception_check1: call rb_jump_tag(throw)");
  1046. rb_jump_tag(TAG_THROW);
  1047. }
  1048. rb_exc_raise(exc);
  1049. }
  1050. } else {
  1051. return 0;
  1052. }
  1053. }
  1054. /* call original 'exit' command */
  1055. static void
  1056. call_original_exit(ptr, state)
  1057. struct tcltkip *ptr;
  1058. int state;
  1059. {
  1060. int thr_crit_bup;
  1061. Tcl_CmdInfo *info;
  1062. #if TCL_MAJOR_VERSION >= 8
  1063. Tcl_Obj *cmd_obj;
  1064. Tcl_Obj *state_obj;
  1065. #endif
  1066. DUMP1("original_exit is called");
  1067. if (!(ptr->has_orig_exit)) return;
  1068. thr_crit_bup = rb_thread_critical;
  1069. rb_thread_critical = Qtrue;
  1070. Tcl_ResetResult(ptr->ip);
  1071. info = &(ptr->orig_exit_info);
  1072. /* memory allocation for arguments of this command */
  1073. #if TCL_MAJOR_VERSION >= 8
  1074. state_obj = Tcl_NewIntObj(state);
  1075. Tcl_IncrRefCount(state_obj);
  1076. if (info->isNativeObjectProc) {
  1077. Tcl_Obj **argv;
  1078. #define USE_RUBY_ALLOC 0
  1079. #if USE_RUBY_ALLOC
  1080. argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3);
  1081. #else /* not USE_RUBY_ALLOC */
  1082. argv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * 3);
  1083. #if 0 /* use Tcl_Preserve/Release */
  1084. Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
  1085. #endif
  1086. #endif
  1087. cmd_obj = Tcl_NewStringObj("exit", 4);
  1088. Tcl_IncrRefCount(cmd_obj);
  1089. argv[0] = cmd_obj;
  1090. argv[1] = state_obj;
  1091. argv[2] = (Tcl_Obj *)NULL;
  1092. ptr->return_value
  1093. = (*(info->objProc))(info->objClientData, ptr->ip, 2, argv);
  1094. Tcl_DecrRefCount(cmd_obj);
  1095. #if USE_RUBY_ALLOC
  1096. xfree(argv);
  1097. #else /* not USE_RUBY_ALLOC */
  1098. #if 0 /* use Tcl_EventuallyFree */
  1099. Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
  1100. #else
  1101. #if 0 /* use Tcl_Preserve/Release */
  1102. Tcl_Release((ClientData)argv); /* XXXXXXXX */
  1103. #else
  1104. /* free(argv); */
  1105. ckfree((char*)argv);
  1106. #endif
  1107. #endif
  1108. #endif
  1109. #undef USE_RUBY_ALLOC
  1110. } else {
  1111. /* string interface */
  1112. CONST84 char **argv;
  1113. #define USE_RUBY_ALLOC 0
  1114. #if USE_RUBY_ALLOC
  1115. argv = ALLOC_N(char *, 3); /* XXXXXXXXXX */
  1116. #else /* not USE_RUBY_ALLOC */
  1117. argv = (CONST84 char **)ckalloc(sizeof(char *) * 3);
  1118. #if 0 /* use Tcl_Preserve/Release */
  1119. Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
  1120. #endif
  1121. #endif
  1122. argv[0] = "exit";
  1123. /* argv[1] = Tcl_GetString(state_obj); */
  1124. argv[1] = Tcl_GetStringFromObj(state_obj, (int*)NULL);
  1125. argv[2] = (char *)NULL;
  1126. ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, 2, argv);
  1127. #if USE_RUBY_ALLOC
  1128. xfree(argv);
  1129. #else /* not USE_RUBY_ALLOC */
  1130. #if 0 /* use Tcl_EventuallyFree */
  1131. Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
  1132. #else
  1133. #if 0 /* use Tcl_Preserve/Release */
  1134. Tcl_Release((ClientData)argv); /* XXXXXXXX */
  1135. #else
  1136. /* free(argv); */
  1137. ckfree((char*)argv);
  1138. #endif
  1139. #endif
  1140. #endif
  1141. #undef USE_RUBY_ALLOC
  1142. }
  1143. Tcl_DecrRefCount(state_obj);
  1144. #else /* TCL_MAJOR_VERSION < 8 */
  1145. {
  1146. /* string interface */
  1147. char **argv;
  1148. #define USE_RUBY_ALLOC 0
  1149. #if USE_RUBY_ALLOC
  1150. argv = (char **)ALLOC_N(char *, 3);
  1151. #else /* not USE_RUBY_ALLOC */
  1152. argv = (char **)ckalloc(sizeof(char *) * 3);
  1153. #if 0 /* use Tcl_Preserve/Release */
  1154. Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
  1155. #endif
  1156. #endif
  1157. argv[0] = "exit";
  1158. argv[1] = RSTRING_PTR(rb_fix2str(INT2NUM(state), 10));
  1159. argv[2] = (char *)NULL;
  1160. ptr->return_value = (*(info->proc))(info->clientData, ptr->ip,
  1161. 2, argv);
  1162. #if USE_RUBY_ALLOC
  1163. xfree(argv);
  1164. #else /* not USE_RUBY_ALLOC */
  1165. #if 0 /* use Tcl_EventuallyFree */
  1166. Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
  1167. #else
  1168. #if 0 /* use Tcl_Preserve/Release */
  1169. Tcl_Release((ClientData)argv); /* XXXXXXXX */
  1170. #else
  1171. /* free(argv); */
  1172. ckfree(argv);
  1173. #endif
  1174. #endif
  1175. #endif
  1176. #undef USE_RUBY_ALLOC
  1177. }
  1178. #endif
  1179. DUMP1("complete original_exit");
  1180. rb_thread_critical = thr_crit_bup;
  1181. }
  1182. /* Tk_ThreadTimer */
  1183. static Tcl_TimerToken timer_token = (Tcl_TimerToken)NULL;
  1184. /* timer callback */
  1185. static void _timer_for_tcl _((ClientData));
  1186. static void
  1187. _timer_for_tcl(clientData)
  1188. ClientData clientData;
  1189. {
  1190. int thr_crit_bup;
  1191. /* struct invoke_queue *q, *tmp; */
  1192. /* VALUE thread; */
  1193. DUMP1("call _timer_for_tcl");
  1194. thr_crit_bup = rb_thread_critical;
  1195. rb_thread_critical = Qtrue;
  1196. Tcl_DeleteTimerHandler(timer_token);
  1197. run_timer_flag = 1;
  1198. if (timer_tick > 0) {
  1199. timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl,
  1200. (ClientData)0);
  1201. } else {
  1202. timer_token = (Tcl_TimerToken)NULL;
  1203. }
  1204. rb_thread_critical = thr_crit_bup;
  1205. /* rb_thread_schedule(); */
  1206. /* tick_counter += event_loop_max; */
  1207. }
  1208. #ifdef RUBY_USE_NATIVE_THREAD
  1209. #if USE_TOGGLE_WINDOW_MODE_FOR_IDLE
  1210. static int
  1211. toggle_eventloop_window_mode_for_idle()
  1212. {
  1213. if (window_event_mode & TCL_IDLE_EVENTS) {
  1214. /* idle -> event */
  1215. window_event_mode |= TCL_WINDOW_EVENTS;
  1216. window_event_mode &= ~TCL_IDLE_EVENTS;
  1217. return 1;
  1218. } else {
  1219. /* event -> idle */
  1220. window_event_mode |= TCL_IDLE_EVENTS;
  1221. window_event_mode &= ~TCL_WINDOW_EVENTS;
  1222. return 0;
  1223. }
  1224. }
  1225. #endif
  1226. #endif
  1227. static VALUE
  1228. set_eventloop_window_mode(self, mode)
  1229. VALUE self;
  1230. VALUE mode;
  1231. {
  1232. rb_secure(4);
  1233. if (RTEST(mode)) {
  1234. window_event_mode = ~0;
  1235. } else {
  1236. window_event_mode = ~TCL_WINDOW_EVENTS;
  1237. }
  1238. return mode;
  1239. }
  1240. static VALUE
  1241. get_eventloop_window_mode(self)
  1242. VALUE self;
  1243. {
  1244. if ( ~window_event_mode ) {
  1245. return Qfalse;
  1246. } else {
  1247. return Qtrue;
  1248. }
  1249. }
  1250. static VALUE
  1251. set_eventloop_tick(self, tick)
  1252. VALUE self;
  1253. VALUE tick;
  1254. {
  1255. int ttick = NUM2INT(tick);
  1256. int thr_crit_bup;
  1257. rb_secure(4);
  1258. if (ttick < 0) {
  1259. rb_raise(rb_eArgError,
  1260. "timer-tick parameter must be 0 or positive number");
  1261. }
  1262. thr_crit_bup = rb_thread_critical;
  1263. rb_thread_critical = Qtrue;
  1264. /* delete old timer callback */
  1265. Tcl_DeleteTimerHandler(timer_token);
  1266. timer_tick = req_timer_tick = ttick;
  1267. if (timer_tick > 0) {
  1268. /* start timer callback */
  1269. timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl,
  1270. (ClientData)0);
  1271. } else {
  1272. timer_token = (Tcl_TimerToken)NULL;
  1273. }
  1274. rb_thread_critical = thr_crit_bup;
  1275. return tick;
  1276. }
  1277. static VALUE
  1278. get_eventloop_tick(self)
  1279. VALUE self;
  1280. {
  1281. return INT2NUM(timer_tick);
  1282. }
  1283. static VALUE
  1284. ip_set_eventloop_tick(self, tick)
  1285. VALUE self;
  1286. VALUE tick;
  1287. {
  1288. struct tcltkip *ptr = get_ip(self);
  1289. /* ip is deleted? */
  1290. if (deleted_ip(ptr)) {
  1291. return get_eventloop_tick(self);
  1292. }
  1293. if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) {
  1294. /* slave IP */
  1295. return get_eventloop_tick(self);
  1296. }
  1297. return set_eventloop_tick(self, tick);
  1298. }
  1299. static VALUE
  1300. ip_get_eventloop_tick(self)
  1301. VALUE self;
  1302. {
  1303. return get_eventloop_tick(self);
  1304. }
  1305. static VALUE
  1306. set_no_event_wait(self, wait)
  1307. VALUE self;
  1308. VALUE wait;
  1309. {
  1310. int t_wait = NUM2INT(wait);
  1311. rb_secure(4);
  1312. if (t_wait <= 0) {
  1313. rb_raise(rb_eArgError,
  1314. "no_event_wait parameter must be positive number");
  1315. }
  1316. no_event_wait = t_wait;
  1317. return wait;
  1318. }
  1319. static VALUE
  1320. get_no_event_wait(self)
  1321. VALUE self;
  1322. {
  1323. return INT2NUM(no_event_wait);
  1324. }
  1325. static VALUE
  1326. ip_set_no_event_wait(self, wait)
  1327. VALUE self;
  1328. VALUE wait;
  1329. {
  1330. struct tcltkip *ptr = get_ip(self);
  1331. /* ip is deleted? */
  1332. if (deleted_ip(ptr)) {
  1333. return get_no_event_wait(self);
  1334. }
  1335. if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) {
  1336. /* slave IP */
  1337. return get_no_event_wait(self);
  1338. }
  1339. return set_no_event_wait(self, wait);
  1340. }
  1341. static VALUE
  1342. ip_get_no_event_wait(self)
  1343. VALUE self;
  1344. {
  1345. return get_no_event_wait(self);
  1346. }
  1347. static VALUE
  1348. set_eventloop_weight(self, loop_max, no_event)
  1349. VALUE self;
  1350. VALUE loop_max;
  1351. VALUE no_event;
  1352. {
  1353. int lpmax = NUM2INT(loop_max);
  1354. int no_ev = NUM2INT(no_event);
  1355. rb_secure(4);
  1356. if (lpmax <= 0 || no_ev <= 0) {
  1357. rb_raise(rb_eArgError, "weight parameters must be positive numbers");
  1358. }
  1359. event_loop_max = lpmax;
  1360. no_event_tick = no_ev;
  1361. return rb_ary_new3(2, loop_max, no_event);
  1362. }
  1363. static VALUE
  1364. get_eventloop_weight(self)
  1365. VALUE self;
  1366. {
  1367. return rb_ary_new3(2, INT2NUM(event_loop_max), INT2NUM(no_event_tick));
  1368. }
  1369. static VALUE
  1370. ip_set_eventloop_weight(self, loop_max, no_event)
  1371. VALUE self;
  1372. VALUE loop_max;
  1373. VALUE no_event;
  1374. {
  1375. struct tcltkip *ptr = get_ip(self);
  1376. /* ip is deleted? */
  1377. if (deleted_ip(ptr)) {
  1378. return get_eventloop_weight(self);
  1379. }
  1380. if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) {
  1381. /* slave IP */
  1382. return get_eventloop_weight(self);
  1383. }
  1384. return set_eventloop_weight(self, loop_max, no_event);
  1385. }
  1386. static VALUE
  1387. ip_get_eventloop_weight(self)
  1388. VALUE self;
  1389. {
  1390. return get_eventloop_weight(self);
  1391. }
  1392. static VALUE
  1393. set_max_block_time(self, time)
  1394. VALUE self;
  1395. VALUE time;
  1396. {
  1397. struct Tcl_Time tcl_time;
  1398. VALUE divmod;
  1399. switch(TYPE(time)) {
  1400. case T_FIXNUM:
  1401. case T_BIGNUM:
  1402. /* time is micro-second value */
  1403. divmod = rb_funcall(time, rb_intern("divmod"), 1, LONG2NUM(1000000));
  1404. tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]);
  1405. tcl_time.usec = NUM2LONG(RARRAY_PTR(divmod)[1]);
  1406. break;
  1407. case T_FLOAT:
  1408. /* time is second value */
  1409. divmod = rb_funcall(time, rb_intern("divmod"), 1, INT2FIX(1));
  1410. tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]);
  1411. tcl_time.usec = (long)(NUM2DBL(RARRAY_PTR(divmod)[1]) * 1000000);
  1412. default:
  1413. {
  1414. VALUE tmp = rb_funcall(time, ID_inspect, 0, 0);
  1415. rb_raise(rb_eArgError, "invalid value for time: '%s'",
  1416. StringValuePtr(tmp));
  1417. }
  1418. }
  1419. Tcl_SetMaxBlockTime(&tcl_time);
  1420. return Qnil;
  1421. }
  1422. static VALUE
  1423. lib_evloop_thread_p(self)
  1424. VALUE self;
  1425. {
  1426. if (NIL_P(eventloop_thread)) {
  1427. return Qnil; /* no eventloop */
  1428. } else if (rb_thread_current() == eventloop_thread) {
  1429. return Qtrue; /* is eventloop */
  1430. } else {
  1431. return Qfalse; /* not eventloop */
  1432. }
  1433. }
  1434. static VALUE
  1435. lib_evloop_abort_on_exc(self)
  1436. VALUE self;
  1437. {
  1438. if (event_loop_abort_on_exc > 0) {
  1439. return Qtrue;
  1440. } else if (event_loop_abort_on_exc == 0) {
  1441. return Qfalse;
  1442. } else {
  1443. return Qnil;
  1444. }
  1445. }
  1446. static VALUE
  1447. ip_evloop_abort_on_exc(self)
  1448. VALUE self;
  1449. {
  1450. return lib_evloop_abort_on_exc(self);
  1451. }
  1452. static VALUE
  1453. lib_evloop_abort_on_exc_set(self, val)
  1454. VALUE self, val;
  1455. {
  1456. rb_secure(4);
  1457. if (RTEST(val)) {
  1458. event_loop_abort_on_exc = 1;
  1459. } else if (NIL_P(val)) {
  1460. event_loop_abort_on_exc = -1;
  1461. } else {
  1462. event_loop_abort_on_exc = 0;
  1463. }
  1464. return lib_evloop_abort_on_exc(self);
  1465. }
  1466. static VALUE
  1467. ip_evloop_abort_on_exc_set(self, val)
  1468. VALUE self, val;
  1469. {
  1470. struct tcltkip *ptr = get_ip(self);
  1471. rb_secure(4);
  1472. /* ip is deleted? */
  1473. if (deleted_ip(ptr)) {
  1474. return lib_evloop_abort_on_exc(self);
  1475. }
  1476. if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) {
  1477. /* slave IP */
  1478. return lib_evloop_abort_on_exc(self);
  1479. }
  1480. return lib_evloop_abort_on_exc_set(self, val);
  1481. }
  1482. static VALUE
  1483. lib_num_of_mainwindows_core(self, argc, argv)
  1484. VALUE self;
  1485. int argc; /* dummy */
  1486. VALUE *argv; /* dummy */
  1487. {
  1488. if (tk_stubs_init_p()) {
  1489. return INT2FIX(Tk_GetNumMainWindows());
  1490. } else {
  1491. return INT2FIX(0);
  1492. }
  1493. }
  1494. static VALUE
  1495. lib_num_of_mainwindows(self)
  1496. VALUE self;
  1497. {
  1498. #ifdef RUBY_USE_NATIVE_THREAD /* Ruby 1.9+ !!! */
  1499. return tk_funcall(lib_num_of_mainwindows_core, 0, (VALUE*)NULL, self);
  1500. #else
  1501. return lib_num_of_mainwindows_core(self, 0, (VALUE*)NULL);
  1502. #endif
  1503. }
  1504. #ifdef RUBY_USE_NATIVE_THREAD /* Ruby 1.9+ !!! */
  1505. static VALUE
  1506. #ifdef HAVE_PROTOTYPES
  1507. call_DoOneEvent_core(VALUE flag_val)
  1508. #else
  1509. call_DoOneEvent_core(flag_val)
  1510. VALUE flag_val;
  1511. #endif
  1512. {
  1513. int flag;
  1514. flag = FIX2INT(flag_val);
  1515. if (Tcl_DoOneEvent(flag)) {
  1516. return Qtrue;
  1517. } else {
  1518. return Qfalse;
  1519. }
  1520. }
  1521. static VALUE
  1522. #ifdef HAVE_PROTOTYPES
  1523. call_DoOneEvent(VALUE flag_val)
  1524. #else
  1525. call_DoOneEvent(flag_val)
  1526. VALUE flag_val;
  1527. #endif
  1528. {
  1529. return tk_funcall(call_DoOneEvent_core, 0, (VALUE*)NULL, flag_val);
  1530. }
  1531. #else /* Ruby 1.8- */
  1532. static VALUE
  1533. #ifdef HAVE_PROTOTYPES
  1534. call_DoOneEvent(VALUE flag_val)
  1535. #else
  1536. call_DoOneEvent(flag_val)
  1537. VALUE flag_val;
  1538. #endif
  1539. {
  1540. int flag;
  1541. flag = FIX2INT(flag_val);
  1542. if (Tcl_DoOneEvent(flag)) {
  1543. return Qtrue;
  1544. } else {
  1545. return Qfalse;
  1546. }
  1547. }
  1548. #endif
  1549. static VALUE
  1550. #ifdef HAVE_PROTOTYPES
  1551. eventloop_sleep(VALUE dummy)
  1552. #else
  1553. eventloop_sleep(dummy)
  1554. VALUE dummy;
  1555. #endif
  1556. {
  1557. struct timeval t;
  1558. if (no_event_wait <= 0) {
  1559. return Qnil;
  1560. }
  1561. t.tv_sec = 0;
  1562. t.tv_usec = (long)(no_event_wait*1000.0);
  1563. #ifdef HAVE_NATIVETHREAD
  1564. #ifndef RUBY_USE_NATIVE_THREAD
  1565. if (!ruby_native_thread_p()) {
  1566. rb_bug("cross-thread violation on eventloop_sleep()");
  1567. }
  1568. #endif
  1569. #endif
  1570. DUMP2("eventloop_sleep: rb_thread_wait_for() at thread : %lx", rb_thread_current());
  1571. rb_thread_wait_for(t);
  1572. DUMP2("eventloop_sleep: finish at thread : %lx", rb_thread_current());
  1573. #ifdef HAVE_NATIVETHREAD
  1574. #ifndef RUBY_USE_NATIVE_THREAD
  1575. if (!ruby_native_thread_p()) {
  1576. rb_bug("cross-thread violation on eventloop_sleep()");
  1577. }
  1578. #endif
  1579. #endif
  1580. return Qnil;
  1581. }
  1582. #define USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 0
  1583. #if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG
  1584. static int
  1585. get_thread_alone_check_flag()
  1586. {
  1587. #ifdef RUBY_USE_NATIVE_THREAD
  1588. return 0;
  1589. #else
  1590. set_tcltk_version();
  1591. if (tcltk_version.major < 8) {
  1592. /* Tcl/Tk 7.x */
  1593. return 1;
  1594. } else if (tcltk_version.major == 8) {
  1595. if (tcltk_version.minor < 5) {
  1596. /* Tcl/Tk 8.0 - 8.4 */
  1597. return 1;
  1598. } else if (tcltk_version.minor == 5) {
  1599. if (tcltk_version.type < TCL_FINAL_RELEASE) {
  1600. /* Tcl/Tk 8.5a? - 8.5b? */
  1601. return 1;
  1602. } else {
  1603. /* Tcl/Tk 8.5.x */
  1604. return 0;
  1605. }
  1606. } else {
  1607. /* Tcl/Tk 8.6 - 8.9 ?? */
  1608. return 0;
  1609. }
  1610. } else {
  1611. /* Tcl/Tk 9+ ?? */
  1612. return 0;
  1613. }
  1614. #endif
  1615. }
  1616. #endif
  1617. #define TRAP_CHECK() do { \
  1618. if (trap_check(check_var) == 0) return 0; \
  1619. } while (0)
  1620. static int
  1621. trap_check(int *check_var)
  1622. {
  1623. DUMP1("trap check");
  1624. #ifdef RUBY_VM
  1625. if (rb_thread_check_trap_pending()) {
  1626. if (check_var != (int*)NULL) {
  1627. /* wait command */
  1628. return 0;
  1629. }
  1630. else {
  1631. rb_thread_check_ints();
  1632. }
  1633. }
  1634. #else
  1635. if (rb_trap_pending) {
  1636. run_timer_flag = 0;
  1637. if (rb_prohibit_interrupt || check_var != (int*)NULL) {
  1638. /* pending or on wait command */
  1639. return 0;
  1640. } else {
  1641. rb_trap_exec();
  1642. }
  1643. }
  1644. #endif
  1645. return 1;
  1646. }
  1647. static int
  1648. check_eventloop_interp()
  1649. {
  1650. DUMP1("check eventloop_interp");
  1651. if (eventloop_interp != (Tcl_Interp*)NULL
  1652. && Tcl_InterpDeleted(eventloop_interp)) {
  1653. DUMP2("eventloop_interp(%p) was deleted", eventloop_interp);
  1654. return 1;
  1655. }
  1656. return 0;
  1657. }
  1658. static int
  1659. lib_eventloop_core(check_root, update_flag, check_var, interp)
  1660. int check_root;
  1661. int update_flag;
  1662. int *check_var;
  1663. Tcl_Interp *interp;
  1664. {
  1665. volatile VALUE current = eventloop_thread;
  1666. int found_event = 1;
  1667. int event_flag;
  1668. struct timeval t;
  1669. int thr_crit_bup;
  1670. int status;
  1671. int depth = rbtk_eventloop_depth;
  1672. #if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG
  1673. int thread_alone_check_flag = 1;
  1674. #endif
  1675. if (update_flag) DUMP1("update loop start!!");
  1676. t.tv_sec = 0;
  1677. t.tv_usec = (long)(no_event_wait*1000.0);
  1678. Tcl_DeleteTimerHandler(timer_token);
  1679. run_timer_flag = 0;
  1680. if (timer_tick > 0) {
  1681. thr_crit_bup = rb_thread_critical;
  1682. rb_thread_critical = Qtrue;
  1683. timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl,
  1684. (ClientData)0);
  1685. rb_thread_critical = thr_crit_bup;
  1686. } else {
  1687. timer_token = (Tcl_TimerToken)NULL;
  1688. }
  1689. #if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG
  1690. /* version check */
  1691. thread_alone_check_flag = get_thread_alone_check_flag();
  1692. #endif
  1693. for(;;) {
  1694. if (check_eventloop_interp()) return 0;
  1695. #if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG
  1696. if (thread_alone_check_flag && rb_thread_alone()) {
  1697. #else
  1698. if (rb_thread_alone()) {
  1699. #endif
  1700. DUMP1("no other thread");
  1701. event_loop_wait_event = 0;
  1702. if (update_flag) {
  1703. event_flag = update_flag | TCL_DONT_WAIT; /* for safety */
  1704. } else {
  1705. event_flag = TCL_ALL_EVENTS;
  1706. /* event_flag = TCL_ALL_EVENTS | TCL_DONT_WAIT; */
  1707. }
  1708. if (timer_tick == 0 && update_flag == 0) {
  1709. ti

Large files files are truncated, but you can click here to view the full file