{"id":44532995,"url":"https://github.com/jamescook/tk-ng","last_synced_at":"2026-02-13T18:40:57.178Z","repository":{"id":331043047,"uuid":"1124960379","full_name":"jamescook/tk-ng","owner":"jamescook","description":"Tk interface module using tcltklib","archived":false,"fork":false,"pushed_at":"2026-02-05T11:18:03.000Z","size":28434,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-05T21:47:38.847Z","etag":null,"topics":["ruby","tcl-tk","tcltk"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"ruby/tk","license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamescook.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-29T23:15:59.000Z","updated_at":"2026-02-05T11:18:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"598255bf-c694-4268-97b0-cfbf13f1c393","html_url":"https://github.com/jamescook/tk-ng","commit_stats":null,"previous_names":["jamescook/tk9"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jamescook/tk-ng","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescook%2Ftk-ng","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescook%2Ftk-ng/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescook%2Ftk-ng/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescook%2Ftk-ng/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamescook","download_url":"https://codeload.github.com/jamescook/tk-ng/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamescook%2Ftk-ng/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29414282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-13T06:24:03.484Z","status":"ssl_error","status_checked_at":"2026-02-13T06:23:12.830Z","response_time":78,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ruby","tcl-tk","tcltk"],"created_at":"2026-02-13T18:40:55.454Z","updated_at":"2026-02-13T18:40:57.173Z","avatar_url":"https://github.com/jamescook.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tk-ng\n\nTk interface module for Ruby.\n\nFork of [ruby/tk](https://github.com/ruby/tk) with Tcl/Tk 8.6 and 9.x support. Modernized for Ruby 3.2+.\n\n**[API Documentation](https://jamescook.github.io/tk-ng/)**\n\n## Features\n\n- Full Tcl/Tk 8.6 and 9.x compatibility\n- New Tcl 9 widget options (e.g., `placeholder` for Entry/Combobox)\n- Background work API for responsive UIs (Thread/Ractor modes)\n- Visual regression testing for both Tcl versions\n\n## Supported Platforms\n\n- **macOS** - Tested on macOS with Homebrew Tcl/Tk\n- **Linux** - Tested on Ubuntu/Debian with system Tcl/Tk\n- **Windows** - Tested on Windows with MSYS2/RubyInstaller (see [Windows Setup](docs/WINDOWS_SETUP.md))\n\nRequires Ruby 3.2+ and Tcl/Tk 8.6 or 9.x.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'tk-ng'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install tk-ng\n\nYou may need to set options when using `gem install` so that the gem can find the Tcl/Tk headers and library:\n\n    $ gem install tk-ng -- \\\n        --with-tcl-include='/path/to/tcl/header/directory' \\\n        --with-tk-include='/path/to/tk/header/directory' \\\n        --with-tcl-lib='/path/to/tcl/shared/library/directory' \\\n        --with-tk-lib='/path/to/tk/shared/library/directory'\n\n## Usage\n\n```ruby\nrequire 'tk'\n\nroot = TkRoot.new { title \"Hello, Tk9!\" }\nTkLabel.new(root) { text \"Works with Tcl/Tk 8.6 and 9.x\" }.pack\nTk.mainloop\n```\n\nNote: You still `require 'tk'` - the gem name is `tk-ng` but the library interface is unchanged.\n\n## Background Work API\n\nTk applications need to keep the UI responsive while doing CPU-intensive work. The `Tk.background_work` API provides a simple way to run work in threads or Ractors with automatic UI integration.\n\n```ruby\nrequire 'tk'\n\n# Run work in background, stream results to UI\ntask = Tk.background_work(files) do |t, data|\n  data.each { |file| t.yield(process(file)) }\nend.on_progress do |result|\n  @log.insert(:end, \"#{result}\\n\")\nend.on_done do\n  puts \"Finished!\"\nend\n\n# Control the task\ntask.pause   # Pause work (call t.check_pause in work block)\ntask.resume  # Resume paused work\ntask.stop    # Stop completely\n```\n\nCallbacks (`on_progress`, `on_done`) can be chained in any order. Work starts automatically when the first callback is attached.\n\n**Important:** The work block runs in a background thread/Ractor and cannot access Tk directly. Use `t.yield()` to send results to `on_progress`, which runs on the main thread where Tk is available.\n\n### Modes\n\nSet the concurrency mode globally or per-task:\n\n```ruby\n# Default is auto-selected: :ractor on Ruby 4.x+, :thread on Ruby 3.x\nTk.background_work_mode = :thread   # Background thread (GVL-bound)\nTk.background_work_mode = :ractor   # True parallelism\n\n# Per-task override\nTk.background_work(data, mode: :thread) { |t, d| ... }\n```\n\n- **`:thread`** - Uses Ruby threads. Work shares the GVL with UI. Pause/resume always works.\n- **`:ractor`** - Uses Ractors for true parallelism. [Data must be shareable](https://docs.ruby-lang.org/en/4.0/language/ractor_md.html#label-Shareable+procs). Best throughput on Ruby 4.x.\n\n### Pause Support\n\nFor pause/resume to work, your work block must periodically check for pause requests:\n\n```ruby\nTk.background_work(items) do |t, data|\n  data.each_slice(100) do |batch|\n    t.check_pause  # Block here if paused\n    batch.each { |item| t.yield(process(item)) }\n  end\nend\n```\n\nSee [`sample/threading_demo.rb`](sample/threading_demo.rb) for a complete file hasher example, and [`sample/background_work_demo.rb`](sample/background_work_demo.rb) for a simple visual demo of UI responsiveness.\n\nFor detailed best practices, common pitfalls, and troubleshooting, see [**docs/BACKGROUND_WORK.md**](docs/BACKGROUND_WORK.md).\n\n## Documentation\n\n### Read this first\n\nIf you want to use Ruby/Tk (tk.rb and so on), you must have tcltklib.so\nwhich is working correctly. When you have some troubles on compiling,\nplease read [README.tcltklib].\n\nEven if there is a tcltklib.so on your Ruby library directory, it will not\nwork without Tcl/Tk libraries (e.g. libtcl9.0.so) on your environment.\nYou must also check that your Tcl/Tk is installed properly.\n\n### Manual\n\n- [Manual tcltklib](MANUAL_tcltklib.eng)\n\n### Other documents\n\n[README.tcltklib] for compilation instructions.\n\n[README.fork] is a note on forking.\n\n[README.macosx-aqua] is about MacOS X Aqua usage.\n\n[README.tcltklib]: README.tcltklib\n[README.fork]: README.fork\n[README.macosx-aqua]: README.macosx-aqua\n\n## Backwards Incompatible Changes\n\nThis fork removes legacy code that was complex, rarely used, or incompatible with modern systems.\n\n### Removed Libraries\n\n- **`multi-tk.rb`** - Removed. The ThreadGroup-based multi-interpreter dispatch (~3500 lines) added significant complexity. For multiple interpreters, use explicit calls: `interp.after(1000) { }` instead of relying on magic dispatch.\n\n- **`remote-tk.rb`** - Removed. Depended on multi-tk.rb for controlling Tk interpreters in other processes.\n\n- **`thread_tk.rb`** - Removed. Allowed running Tk mainloop on a background thread, which doesn't work on macOS (Tk requires the main thread).\n\n- **`RUN_EVENTLOOP_ON_MAIN_THREAD`** - Removed. Tk now always runs on the main thread. The background thread machinery (~100 lines) that allowed running Tk in IRB on non-macOS has been removed. Run Tk code in scripts, not REPLs.\n\n### Removed Tcl Extension Wrappers\n\nRuby wrappers for various Tcl extensions (BLT, itcl/itk/iwidgets, tcllib, tktable, treectrl, etc.) have been removed. These wrappers relied on internal APIs that no longer exist or wrapped extensions that are deprecated/unmaintained upstream.\n\nSee [lib/tkextlib/SUPPORT_STATUS](lib/tkextlib/SUPPORT_STATUS) for the full list and each extension's `DEPRECATED.md` for details.\n\n**Using Tcl packages directly:** If you install a Tcl extension, you can still use it via `Tk.tk_call`:\n\n```ruby\n# Load a Tcl package\nTk.tk_call('package', 'require', 'tablelist')\n\n# Call its commands\nTk.tk_call('tablelist::tablelist', '.t', '-columns', '3 Name 0 Age 0 City')\n```\n\n### Changed Behavior\n\n- **`TkCore::INTERP`** - Deprecated. Accessing this constant emits a warning. Use `TkCore.interp` instead, which raises an error if multiple interpreters exist (preventing ambiguous \"which interpreter?\" bugs).\n\n- **Encoding machinery** - Simplified. Modern Tcl (8.1+) and Ruby use UTF-8 natively, so the complex encoding conversion code was removed.\n\n### Removed Methods\n\n- **`TclTkIp#encoding_table`** - Removed. Raises `NotImplementedError` with explanation.\n\n- **`TclTkIp#_make_menu_embeddable`** - Removed. This was a 2006-era workaround that accessed Tk's private internal structs. Use `TkMenubutton` for packable menu buttons.\n\n### Removed: Japanized Tk Support\n\nThe `JAPANIZED_TK` constant and all related code has been removed. This was for a patched \"Japanized Tcl/Tk\" distribution (Tcl 7.6/Tk 4.2 - see `sample/demos-en/doc.org/README.JP`) that added a `kanji` command for Japanese text support before Tcl/Tk had proper Unicode handling.\n\nRemoved APIs:\n- `Tk::JAPANIZED_TK` constant\n- `Tk.show_kinsoku`, `Tk.add_kinsoku`, `Tk.delete_kinsoku` methods\n- `latinfont`, `asciifont`, `kanjifont` pseudo-options\n- `font_configure`, `latinfont_configure`, `kanjifont_configure` methods\n\nTcl 8.1 (April 1999) added native Unicode support ([Tcl chronology](https://wiki.tcl-lang.org/page/Tcl+chronology)). Use standard `font` options with UTF-8 strings.\n\n### Modernized: TkFont Class\n\nThe original `TkFont` class (~2340 lines) has been replaced with a modern implementation (~200 lines) that creates named Tcl fonts.\n\n```ruby\n# Create fonts\nfont = TkFont.new('Helvetica 12 bold')\nfont = TkFont.new(family: 'Courier', size: 14)\nlabel = TkLabel.new(root, font: font)\n\n# Modify font - all widgets using it update automatically\nfont.family = 'Times'\nfont.size = 18\n\n# Modify via widget accessor\nlabel.font.family = 'Arial'\n\n# Class methods\nTkFont.families        # list available font families\nTkFont.measure(font, text)  # measure text width in pixels\n```\n\nNamed Tcl fonts propagate changes to all widgets using them, so changing `font.size = 24` updates every widget configured with that font.\n\n**Not supported**: Features from the old TkFont like `TkNamedFont`, `latinfont`/`kanjifont` compound fonts, and `font_configure` methods have been removed.\n\n### Deprecated Internal APIs\n\nThe `__*_optkeys` methods in `TkConfigMethod` are deprecated and will be removed:\n\n- `__numval_optkeys`, `__boolval_optkeys`, `__strval_optkeys`, `__listval_optkeys`\n- `__val2ruby_optkeys`, `__ruby2val_optkeys`\n- `__tkvariable_optkeys`, `__font_optkeys`\n\n**Migration**: Use the declarative `option` DSL instead:\n\n```ruby\n# Old way (deprecated)\nclass MyWidget \u003c TkWindow\n  def __boolval_optkeys\n    super() + ['myoption']\n  end\nend\n\n# New way\nclass MyWidget \u003c TkWindow\n  option :myoption, type: :boolean\nend\n```\n\nThe public API (`cget`, `configure`, `configinfo`) is unchanged.\n\n### Removed: `TkItemConfigMethod` module\n\nThe `TkItemConfigMethod` module (from `lib/tk/itemconfig.rb`) has been removed. Its functionality has been merged into `Tk::ItemOptionDSL::InstanceMethods`, which is automatically included when you `extend Tk::ItemOptionDSL`.\n\nIf your code explicitly required `tk/itemconfig` or included `TkItemConfigMethod`, update it to use `Tk::ItemOptionDSL` instead. See `lib/tk/item_option_dsl.rb` for the replacement API.\n\n### Removed: `__IGNORE_UNKNOWN_CONFIGURE_OPTION__`\n\nThe global flag `TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__` has been removed. This flag silently swallowed errors when `configure` or `cget` encountered unknown widget options - a design that hid bugs and made debugging difficult.\n\nIf you need to handle version-specific options, check the version explicitly:\n\n```ruby\n# Not recommended, but if you must:\nbegin\n  widget.configure(maybe_invalid: value)\nrescue TclTkLib::TclError\n  # handle or ignore\nend\n```\n\n### Removed: `GET_CONFIGINFO_AS_ARRAY` constant\n\nThe `TkComm::GET_CONFIGINFO_AS_ARRAY` and `TkComm::GET_CONFIGINFOwoRES_AS_ARRAY` constants have been removed. These controlled whether `configinfo` returned arrays or hashes - unnecessary complexity since arrays were the default and hash mode was rarely used.\n\n`configinfo` now always returns arrays:\n```ruby\nwidget.configinfo(:text)  # =\u003e [\"text\", \"text\", \"Text\", \"\", \"Hello\"]\nwidget.configinfo         # =\u003e [[\"text\", ...], [\"width\", ...], ...]\n```\n\nUse `current_configinfo` for a hash of current values:\n```ruby\nwidget.current_configinfo(:text)  # =\u003e {\"text\" =\u003e \"Hello\"}\nwidget.current_configinfo         # =\u003e {\"text\" =\u003e \"Hello\", \"width\" =\u003e 100, ...}\n```\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies.\n\n### Running Tests\n\nDocker is the preferred way to run tests (avoids Tk windows popping up):\n\n```bash\nrake docker:test                              # Run tests in container\nrake docker:test TEST=test/test_tk_font.rb    # Single file\nrake docker:test:all                          # Full suite with extensions\n```\n\nFor local testing:\n```bash\nrake test                                     # Runs with real Tk windows\n```\n\n### Tcl Version\n\nTests run against Tcl 9.0 by default. To test against 8.6:\n\n```bash\nTCL_VERSION=8.6 rake docker:test\n```\n\nTo install this gem onto your local machine, run `bundle exec rake install`.\n\n## Known Limitations\n\n- **fork()** - Calling `fork()` after `require 'tk'` is unsupported. Crashes on macOS; may work on Linux if you fork *before* requiring Tk.\n- **Ractors on Ruby 3.x** - Ractor mode for `Tk.background_work` requires Ruby 4+ (no non-blocking `Ractor.receive` in 3.x). Use thread mode on Ruby 3.x (the default).\n\n## Contributing\n\nContributions are welcome on GitHub at https://github.com/jamescook/tk-ng.\n\n## License\n\nThe gem is available as open source under the terms of the [Ruby license](LICENSE) (BSD-2-Clause or Ruby License).\n\nThis is a fork of [ruby/tk](https://github.com/ruby/tk). Original authors: SHIBATA Hiroshi, Nobuyoshi Nakada, Jeremy Evans.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamescook%2Ftk-ng","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamescook%2Ftk-ng","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamescook%2Ftk-ng/lists"}