Module: Teek
- Defined in:
- lib/teek.rb,
lib/teek/wm.rb,
lib/teek/photo.rb,
lib/teek/winfo.rb,
lib/teek/widget.rb,
lib/teek/dialogs.rb,
lib/teek/version.rb,
lib/teek/debugger.rb,
lib/teek/platform.rb,
lib/teek/ractor_support.rb,
lib/teek/background_none.rb,
lib/teek/menu_interceptor.rb,
lib/teek/background_thread.rb,
lib/teek/callback_registry.rb,
lib/teek/background_ractor4x.rb,
lib/teek/command_interceptors.rb,
lib/teek/tag_bind_interceptor.rb,
lib/teek/canvas_bind_interceptor.rb,
lib/teek/method_coverage_service.rb,
ext/teek/tcltkbridge.c
Overview
Standalone platform detection — no dependencies on the rest of Teek. Safe to require from extconf.rb or any context where the full gem isn't loaded yet.
Defined Under Namespace
Modules: BackgroundNone, BackgroundRactor4x, BackgroundThread, CanvasBindInterceptor, MenuInterceptor, RELEASE_TYPE, TagBindInterceptor Classes: AmbiguousCommandError, App, BackgroundWork, CallbackRegistry, CommandInterceptors, Debugger, EventSource, Interp, MethodCoverageService, Photo, Platform, RactorStream, RepeatingTimer, TclError, Widget, Winfo, Wm
Constant Summary collapse
- WIDGET_COMMANDS =
%w[ button label frame entry text canvas listbox scrollbar scale spinbox menu menubutton message panedwindow labelframe checkbutton radiobutton toplevel ttk::button ttk::label ttk::frame ttk::entry ttk::combobox ttk::checkbutton ttk::radiobutton ttk::scale ttk::scrollbar ttk::spinbox ttk::separator ttk::sizegrip ttk::progressbar ttk::notebook ttk::panedwindow ttk::labelframe ttk::menubutton ttk::treeview ].freeze
- VERSION =
"0.2.0"- WINDOW_EVENTS =
Event flags as constants
INT2NUM(TCL_WINDOW_EVENTS)
- FILE_EVENTS =
INT2NUM(TCL_FILE_EVENTS)
- TIMER_EVENTS =
INT2NUM(TCL_TIMER_EVENTS)
- IDLE_EVENTS =
INT2NUM(TCL_IDLE_EVENTS)
- ALL_EVENTS =
INT2NUM(TCL_ALL_EVENTS)
- DONT_WAIT =
INT2NUM(TCL_DONT_WAIT)
- CALLBACK_BREAK =
:App#register_callback catch/throw)
Callback control flow symbols (used by Teek
- CALLBACK_CONTINUE =
ID2SYM(rb_intern("teek_continue"))
- CALLBACK_RETURN =
ID2SYM(rb_intern("teek_return"))
Class Method Summary collapse
-
._register_event_source(fn_ptr, data_ptr, interval) ⇒ Object
Teek._register_event_source(check_fn_ptr, client_data_ptr, interval_ms) -> EventSource.
- .bool_to_tcl(val) ⇒ Object
-
.get_version ⇒ Object
--------------------------------------------------------- TclTkLib.get_version - Get Tcl version as [major, minor, type, patchlevel].
-
.in_callback? ⇒ Boolean
--------------------------------------------------------- TclTkLib.in_callback? - Check if currently inside a Tk callback.
-
.make_list(*args) ⇒ Object
Module functions for Tcl value conversion (no interpreter needed).
- .platform ⇒ Object
-
.split_list(list_str) ⇒ Object
--------------------------------------------------------- Teek.split_list(str) - Parse Tcl list into Ruby array.
-
.tcl_to_bool(str) ⇒ Object
--------------------------------------------------------- Teek.tcl_to_bool(str) - Convert Tcl boolean string to Ruby true/false.
Class Method Details
._register_event_source(fn_ptr, data_ptr, interval) ⇒ Object
Teek._register_event_source(check_fn_ptr, client_data_ptr, interval_ms) -> EventSource
Registers a C function as a Tcl event source. The function will be called on every event loop iteration with no Ruby overhead.
check_fn_ptr: Integer — address of a C function with signature void()(void) client_data_ptr: Integer — address passed to check_fn (0 for NULL) interval_ms: Integer — max block time in ms (e.g. 16 for ~60fps)
Returns an opaque EventSource object. Hold a reference to keep it alive. Call #unregister or let GC collect it to remove the event source.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'ext/teek/tkeventsource.c', line 117
static VALUE
teek_register_event_source(VALUE self, VALUE fn_ptr, VALUE data_ptr, VALUE interval)
{
struct event_source *es;
VALUE obj;
int ms;
/* Validate */
event_source_check_fn fn = (event_source_check_fn)(uintptr_t)NUM2ULL(fn_ptr);
if (!fn) {
rb_raise(rb_eArgError, "check_fn_ptr must not be NULL");
}
ms = NUM2INT(interval);
if (ms < 1) ms = 1;
/* Allocate and populate */
obj = TypedData_Make_Struct(cEventSource, struct event_source, &event_source_type, es);
es->check_fn = fn;
es->client_data = (void *)(uintptr_t)NUM2ULL(data_ptr);
es->max_block.sec = ms / 1000;
es->max_block.usec = (ms % 1000) * 1000;
es->registered = 0;
/* Register with Tcl */
Tcl_CreateEventSource(es_setup_proc, es_check_proc, (ClientData)es);
es->registered = 1;
return obj;
}
|
.bool_to_tcl(val) ⇒ Object
75 76 77 |
# File 'lib/teek.rb', line 75 def self.bool_to_tcl(val) val ? "1" : "0" end |
.get_version ⇒ Object
TclTkLib.get_version - Get Tcl version as [major, minor, type, patchlevel]
WHY COMPILE-TIME MACROS INSTEAD OF Tcl_GetVersion()?
With stubs enabled (-DUSE_TCL_STUBS), Tcl_GetVersion() becomes a macro that dereferences tclStubsPtr->tcl_GetVersion. But tclStubsPtr is NULL until Tcl_InitStubs() is called - which requires an interpreter.
So the "proper" API to get the version needs an interpreter to exist first. That's backwards - callers often want version info before deciding whether to create an interpreter.
The workaround: use the compile-time macros from tcl.h directly. These are just #defines, no stubs table needed. The version reported is what we compiled against, which must match the runtime major version (stubs enforce this). Minor/patch may differ at runtime - use TclTkIp#tcl_version for the exact runtime patchlevel.
1433 1434 1435 1436 1437 1438 1439 1440 1441 |
# File 'ext/teek/tcltkbridge.c', line 1433
static VALUE
lib_get_version(VALUE self)
{
return rb_ary_new3(4,
INT2NUM(TCL_MAJOR_VERSION),
INT2NUM(TCL_MINOR_VERSION),
INT2NUM(TCL_RELEASE_LEVEL),
INT2NUM(TCL_RELEASE_SERIAL));
}
|
.in_callback? ⇒ Boolean
TclTkLib.in_callback? - Check if currently inside a Tk callback
Used to detect unsafe operations (exit/destroy from callback).
1407 1408 1409 1410 1411 |
# File 'ext/teek/tcltkbridge.c', line 1407
static VALUE
lib_in_callback_p(VALUE self)
{
return rbtk_callback_depth > 0 ? Qtrue : Qfalse;
}
|
.make_list(*args) ⇒ Object
Module functions for Tcl value conversion (no interpreter needed)
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 |
# File 'ext/teek/tcltkbridge.c', line 1260
static VALUE
teek_make_list(int argc, VALUE *argv, VALUE self)
{
struct make_list_state st;
if (argc == 0) return rb_utf8_str_new_cstr("");
st.listobj = Tcl_NewListObj(0, NULL);
Tcl_IncrRefCount(st.listobj);
st.argc = argc;
st.argv = argv;
return rb_ensure(make_list_body, (VALUE)&st,
make_list_cleanup, (VALUE)&st);
}
|
.platform ⇒ Object
26 27 28 |
# File 'lib/teek/platform.rb', line 26 def self.platform @platform ||= Platform.new end |
.split_list(list_str) ⇒ Object
Teek.split_list(str) - Parse Tcl list into Ruby array
Module function — uses utility_interp for error reporting. Single C call instead of N+1 eval round-trips. Returns array of strings (does not recursively parse nested lists).
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 |
# File 'ext/teek/tcltkbridge.c', line 1284
static VALUE
teek_split_list(VALUE self, VALUE list_str)
{
Tcl_Obj *listobj;
Tcl_Size objc;
Tcl_Obj **objv;
VALUE ary;
Tcl_Size i;
int result;
if (NIL_P(list_str)) {
return rb_ary_new();
}
StringValue(list_str);
if (RSTRING_LEN(list_str) == 0) {
return rb_ary_new();
}
/* Create Tcl object from Ruby string */
listobj = Tcl_NewStringObj(RSTRING_PTR(list_str), RSTRING_LEN(list_str));
Tcl_IncrRefCount(listobj);
/* Use utility_interp for error reporting */
result = Tcl_ListObjGetElements(utility_interp, listobj, &objc, &objv);
if (result != TCL_OK) {
const char *msg = Tcl_GetStringResult(utility_interp);
Tcl_DecrRefCount(listobj);
rb_raise(eTclError, "invalid Tcl list: %s", msg);
}
/* Convert to Ruby array of strings */
ary = rb_ary_new2(objc);
for (i = 0; i < objc; i++) {
Tcl_Size len;
const char *str = Tcl_GetStringFromObj(objv[i], &len);
rb_ary_push(ary, rb_utf8_str_new(str, len));
}
Tcl_DecrRefCount(listobj);
return ary;
}
|
.tcl_to_bool(str) ⇒ Object
Teek.tcl_to_bool(str) - Convert Tcl boolean string to Ruby true/false
Uses Tcl_GetBooleanFromObj which recognizes: true/false, yes/no, on/off, 1/0 (case-insensitive) and any numeric value (0 = false, non-zero = true)
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 |
# File 'ext/teek/tcltkbridge.c', line 1200
static VALUE
teek_tcl_to_bool(VALUE self, VALUE str)
{
Tcl_Obj *obj;
int bval;
StringValue(str);
obj = Tcl_NewStringObj(RSTRING_PTR(str), RSTRING_LEN(str));
Tcl_IncrRefCount(obj);
if (Tcl_GetBooleanFromObj(utility_interp, obj, &bval) != TCL_OK) {
const char *msg = Tcl_GetStringResult(utility_interp);
Tcl_DecrRefCount(obj);
rb_raise(eTclError, "%s", msg);
}
Tcl_DecrRefCount(obj);
return bval ? Qtrue : Qfalse;
}
|