С момента начала разработки пэт-проекта svgwidgets меня не покидала мысль выложить примеры его использования в облако.
Но всё что-то держало. Это была и работа над самим проектом, и публикация книги История моей страны. Записки военного инженера программиста, и участие в жизни «Музея СССР», прежде всего развитие его экспозиции ретро компьютеров, да и просто текущие дела в наше непростое время.
Особенно насыщенным выдался август текущего года. Помимо поездки по российской глубинке, мне посчастливилось встретиться с нашими выдающимися актерами и режиссёрами Никитой Сергеевичем Михалковым и Николаем Петровичем Бурляевым (см. скриншоты в начале статьи).
После такого насыщенного августа я с новыми впечатлениями вернулся к своей навязчивой идее, оказать помощь в реализации которой должен был проект CloudTk.
И начну я изложение с конечного результата (см. скриншот в правом нижнем углу логотипа статьи). Получить доступ к конечному результату можно и по https (не обессудьте, SSL-сертификаты - самоподписанные).
На стартовой странице фиксируется время обращения к облачному сервису, показывается текущее время, а также спешащий куда-то старый добрый паровоз. Если вы хотите увеличить скорость паровоза, то щелкните левой кнопкой мыши, а захотите остановиться – щелкните правой кнопкой.
Для перехода на страницу со списком демонстраций (скриншот Tk Application) воспользуйтесь кнопкой Перейти на демо-страницу . Для запуска приложения необходимо его выбрать, а затем нажать кнопку Submit Query . Можно выбрать пример использования svg -виджетов при разработке игры в шашки (wsvgGame). Игра – громко сказано, но очерёдность ходов игроками соблюдается и шашки можно ставить только на свободные клетки. Можете попробовать и сами всё увидите. Главным здесь было показать возможности svg -виджетов. Этой же цели служат и демонстрации wsvgButton , wsvgCanvas и wsvgGradient. Здесь же можно и расслабиться и поиграть в старый добрый тетрис (Tetris), а то и в «бильярд» (TkPool).
Для возврата на страницу приложений используйте кнопку На предыдущую страницу (<-). Для перехода со страницы Tk Application на главную страницу просто щёлкните по иконке Tcl POWERED. Но это конечный результат, а ниже будет рассказ про то, как это было достигнуто.
В качестве платформы используется Linux x86_64.
Итак, идём на страницу CloudTk. И тут выясняется, что нам потребуется TclKit и старкит CloudTk.kit. Создаём директорию для проекта, например, ~/testCloud
и скачиваем в неё старкит CloudTk.kit.
Можно также скачать и tclkit, но он будет очень древним. Правда есть online-страница для его генерации, но и здесь можно собрать tclkit только для tcl-8.6.12.
Поэтому было решено собрать tclkit самостоятельно. Это оказалось достаточно просто.
Сначала скачиваем проект:
$git clone https://github.com/rkeene/KitCreator.git
Проект размещается в директории KitCreator
.
Ниже приводится patch для KitCreator
-а.
diff -ruN KitCreator/build/test/test KitCreator-8.6.17/build/test/test
--- KitCreator/build/test/test 2025-09-25 10:55:57.345565571 +0300
+++ KitCreator-8.6.17/build/test/test 2025-09-25 10:59:42.197572433 +0300
@@ -1,6 +1,6 @@
#! /bin/bash
-VERSIONS="8.5.19 8.6.12 fossil_trunk"
+VERSIONS="8.5.19 8.6.12 8.6.17 fossil_trunk"
# Find the base directory
for x in 1 2 3 4 __fail__; do
diff -ruN KitCreator/build/web/kitcreator.vfs/index.rvt KitCreator-8.6.17/build/web/kitcreator.vfs/index.rvt
--- KitCreator/build/web/kitcreator.vfs/index.rvt 2025-09-25 10:55:57.347565571 +0300
+++ KitCreator-8.6.17/build/web/kitcreator.vfs/index.rvt 2025-09-25 11:00:54.503574640 +0300
@@ -73,6 +73,7 @@
set tcl_versions(8.6.10) 8.6.10
set tcl_versions(8.6.11) 8.6.11
set tcl_versions(8.6.12) 8.6.12
+ set tcl_versions(8.6.17) 8.6.17
set tcl_version_list [lsort -dictionary [array names tcl_versions]]
set tcl_version_selected [lindex $tcl_version_list end]
diff -ruN KitCreator/kitcreator KitCreator-8.6.17/kitcreator
--- KitCreator/kitcreator 2025-09-25 10:55:57.347565571 +0300
+++ KitCreator-8.6.17/kitcreator 2025-09-25 11:02:08.425576896 +0300
@@ -13,7 +13,7 @@
esac
# Determine which Tcl version to build
-TCLVERS="8.6.12"
+TCLVERS="8.6.17"
if echo "$1" | grep '^[0-9][0-9]*\.' >/dev/null || echo "$1" | egrep '^(cvs|fossil)_' >/dev/null; then
TCLVERS="$1"
@@ -69,7 +69,7 @@
# Add packages implied by the additional arguments
if [ -z "${KITCREATOR_PKGS}" ]; then
- KITCREATOR_PKGS="tk itcl mk4tcl"
+ KITCREATOR_PKGS="tcllib tk itcl mk4tcl"
fi
CONFIGUREEXTRA="$@"
diff -ruN KitCreator/tcl/build.sh KitCreator-8.6.17/tcl/build.sh
--- KitCreator/tcl/build.sh 2025-09-25 10:55:57.349565571 +0300
+++ KitCreator-8.6.17/tcl/build.sh 2025-09-25 11:03:27.005579294 +0300
@@ -58,6 +58,9 @@
8.6.12)
SRCHASH='26c995dd0f167e48b11961d891ee555f680c175f7173ff8cb829f4ebcde4c1a6'
;;
+ 8.6.17)
+ SRCHASH='a3903371efcce8a405c5c245d029e9f6850258a60fa3761c4d58995610949b31'
+ ;;
esac
# Set configure options for this sub-project
diff -ruN KitCreator/tcllib/build.sh KitCreator-8.6.17/tcllib/build.sh
--- KitCreator/tcllib/build.sh 2025-09-25 10:55:57.349565571 +0300
+++ KitCreator-8.6.17/tcllib/build.sh 2025-09-25 11:04:35.307581378 +0300
@@ -2,6 +2,6 @@
# BuildCompatible: KitCreator
-version='1.20'
+version='2.0'
url="http://sourceforge.net/projects/tcllib/files/tcllib/${version}/tcllib-${version}.tar.bz2"
-sha256='3a33f212f35235f9dca4425c5c5692186515be169b0b6e3ca498e7c344ea83b8'
+sha256='196c574da9218cf8dcf180f38a603e670775ddb29f191960d6f6f13f52e56b04'
diff -ruN KitCreator/tk/build.sh KitCreator-8.6.17/tk/build.sh
--- KitCreator/tk/build.sh 2025-09-25 10:55:57.351565571 +0300
+++ KitCreator-8.6.17/tk/build.sh 2025-09-25 11:05:26.135582929 +0300
@@ -58,6 +58,9 @@
8.6.12)
SRCHASH='12395c1f3fcb6bed2938689f797ea3cdf41ed5cb6c4766eec8ac949560310630'
;;
+ 8.6.17)
+ SRCHASH='e4982df6f969c08bf9dd858a6891059b4a3f50dc6c87c10abadbbe2fc4838946'
+ ;;
esac
# Set configure options for this sub-project
Сохраним патч в файле PATCH_12_17.patch
и применим его к скачанной версии KitCreator-а:
$ patch -s -p0 < PATCH_12_17.patch
Замечу, что этот патч добавляет в tclkit и пакет tcllib-2.0.
После внесения изменений заходим в директорию KitCreator
и выполняем две команды:
$sh build/pre.sh
$./kitcreator
После сборки в нашей директории найдём собранный модуль с именем tclkit-8.6.17. Запускаем его и проверяем, что мы получили именно то, что «заказывали»:
$./tclkit-8.6.17
%info tclversion
8.6
%info patchlevel
8.6.17
%package require tcllib
2.0
%exit
$
Полученный модуль копируем в /usr/local/bin
.
Убеждаемся, что на нашем компьютере установлен сервер Xvnc (TigerVNC) и оконный менеджер Matchbox.
Теперь идём в ранее созданную директорию ~/testCloud
, в которой уже лежит скачанный старкит CloudTk.kit, и создаём директорию certs для ssl-сертификатов (если не предполагается использование https, то этот пункт можно опустить). Самое простое – создать закрытый ключ и самоподписанный сертификат с помощью команды openssl:
openssl req -new -x509 -days 3650 -nodes -out certs/server.pem -keyout certs/skey.pem
…
Country Name (2 letter code) [XX]:ru
State or Province Name (full name) []:Moskouw
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:user
Common Name (eg, your name or your server's hostname) []:testCloudtk
Email Address []:vorlov@lissi.ru
Теперь выполняем команду:
/usr/local/bin/tclkit-8.6.17 CloudTk.kit
can't find package limit
Running with default file descriptor limit
/debug user "debug" password "..20+lmn+n5p"
httpd started on port 8015
secure httpd started on SSL port 8016
В том, что не найден пакет limit, ничего страшного нет.
Порты 8015 и 8016 присваиваются по умолчанию. Для явного указания портов используются параметры -port <номер порта>
и -https_порт <номер порта для https-протокола>
.
В браузере набираем http://localhost:8015/
или https://localhost:8016/
и попадаем на домашнюю страницу CloudTk.
Её следует изучить.
Но где же приложения Tk?
Чтобы попасть на страницу с игрой в «TkPool» («бильярд») следует набрать в браузере либо
http://localhost:8015/cloudtk/
либо
https://localhost:8016/cloudtk/
Следует обратить внимание на завершающую наклонную черту /
.
После нажатия на кнопку «Enter» в браузере появится страница «Tk Application» с radio-кнопкой TkPool. И если нажать на кнопку «Submit Query» , то в браузере появится и «бильярд» .
После запуска CloudTk.kit в нашей директории ~/testCloud
появились новые:
drwxr-xr-x 2 4096 сен 22 19:01 auth
drwxr-xr-x 2 4096 сен 22 19:01 conf
drwxr-xr-x 2 4096 сен 22 19:01 htdocs
drwxr-xr-x 2 4096 сен 22 19:01 log
drwxr-xr-x 11 4096 сен 22 19:01 noVNC
drwxr-xr-x 3 4096 сен 22 19:01 Tk
Заглянем в директорию Tk
. В ней содержится директория TkPool
, в которой есть файл TkStartup.tcl
. Именно в нём прописывается имя файла, с которого начинается загрузка пользовательского проекта.
По образцу и подобию директории TkPool
пользователь может добавить свои проекты.
В качестве примера приведём содержимое директории для запуска утилиты cryptoarmpkcs
из демонстрационного проекта CryptoArmPKCS7:
$ ls -Rl CryptoArmPKCS7/CryptoArmPKCS7/
alloids.tcl
card_and_pero_pkcs11_pkcs12.png
classtoken_svg.tcl
GostPfx.tcl
guipkcs_oo_svg_TEST_STtoplevel.tcl
Lcc.p12
Lrnd.p12
mainguipkcs_svg.tcl
mecrown.png
mtoken_withoutbg.png
PKCSimage
tclpkcs11.p11
TkStartup.tcl
tokens_tcl_pero_85x45.png
CryptoArmPKCS7/PKCSimage:
certificate_blue.svg
digital_signature_2.svg
signeddoc.svg
update.svg
viewcert.svg
В директории Tk/CryptoArmPKCS
находятся все файлы, которые необходимы для запуска утилиты cryptoarmpkcs
. Смотрим содержимое файла TkStartup.tcl
:
$ cat CryptoArmPKCS7/TkStartup.tcl
set ix [lsearch $argv -display]
if {$ix >= 0} {
incr ix
set env(DISPLAY) [lindex $argv $ix]
set argc 0
set argv {}
lappend auto_path [pwd]/modadd_Lin64
source [pwd]/Tk/CryptoArmPKCS7/mainguipkcs_svg.tcl
}
В нем нас интересуют две строки. Строка с командой lappend
добавляет путь к пакетам, которые необходимы для функционирования утилиты cryptoarmpkcs
. Для добавляемых пакетов мы создали директорию modadd_Lin64
в нашей ~/testCloud
.
Вторая строка с командой source
собственно и обеспечит запуск нашей утилиты, загрузив модуль mainguipkcs_svg.tcl
. При желании здесь можно предусмотреть выполнение ещё каких-то команд и передачу параметров запускаемой утилите.
В качестве примера создадим директорию для запуска утилиты train.tcl
, которую я храню с конца девяностых годов прошлого столетия.
Итак, в директории testCloud/Tk
, рядом с TkPool
, создаём новую – Train
, в которую кладём файл train.tcl
и файл TkStartup.tcl
.
Вот содержимое файла TkStartup.tcl
:
set ix [lsearch $argv -display]
if {$ix >= 0} {
incr ix
set env(DISPLAY) [lindex $argv $ix]
set argc 0
set argv {}
source [pwd]/Tk/Train/train.tcl
}
Обновите в браузере страницу http://localhost:8015/cloudtk/
– увидите radio-кнопку Train. Выберите её и можете любоваться движением старинного паровоза.
А что делать со стартовой страницей?
Тут в принципе ещё проще. В нашей тестовой директории testCloud
появилась пустая директория htdocs
и, если в ней появится файл index.tml
, то именно из него будет формироваться стартовая страница проекта. В качестве примера я приведу свой файл index.tml
:
[html::meta_charset "utf-8"]
[html::description "TclHttpd, the Tcl Web Server, is an extensible
platform for web application development."]
[html::keywords Tcl TclHttpd Tcl/Tk "Tcl Web Server" "Web Server"]
[html::author "Vladimir Orlov"]
[mypage::header "Облачные сервисы на Tcl/Tk"] \
<script type="text/javascript">
setInterval(function () {
date = new Date(),
h = date.getHours(),
m = date.getMinutes(),
s = date.getSeconds(),
h = (h < 10) ? '0' + h : h,
m = (m < 10) ? '0' + m : m,
s = (s < 10) ? '0' + s : s,
document.getElementById('time').innerHTML = "Текущее время: " + h + ':' + m + ':' + s;
}, 1000); </script>
<br>Время входа на портал: [clock format [clock seconds] -format "%B %d, %Y %H:%M:%S"] <br>
<br><span style="color:#7e5a25; font-size:14pt; border:2px solid #e1d4ae; background:#e8e3d4; padding:5px; margin: 0 0 0 100px">
<span id="time">Текущее время: [clock format [clock seconds] -format "%H:%M:%S"]</span> </span> <br>
<br><iframe src="/cloudtk/VNC?session=new&Tk=Train" height="200" width="615" name="wait_for _download" > </iframe>
<h3>Демонстрация SVG-виджетов и демо-версии сервисов</h3>
<p><button class="b1" style="border-radius:5px;background-color:cyan; font-size: 18px; margin: 0 0 0 100px "><a href="/cloudtk/">Переход на демо-страницу</button> </p>
</table>
[mypage::footer]
Сохраните приведенный код в файле ~/testCloud/htdocs/index.tml
и обновите страницу http://localhost:8015/
. Появилась новая стартовая страница. Теперь для перехода на страницу Tk Application достаточно нажать на кнопку Переход на демо-страницу. Для возврата со страницы с приложениями на стартовую страницу достаточно нажать на иконку в левом верхнем углу. Обратите внимание, что иконка в левом углу на стартовой странице и странице с приложениями одна и та же. Это связано с тем, что она задаётся по умолчанию в процедуре mepage::header
. В принципе достаточно в процедуру mepage::header
добавить умалчиваемый параметр, который бы задавал путь к иконке. Можно, конечно, получить тело процедуры (info body mepage::header
), затем его поправить и снова загрузить командой source
. Но более элегантным и полезным представляется получить доступ к исходному коду CloudTk.kit
. Для этого нам потребуется старкит sdx.kit, который можно получить по команде
wget https://chiselapp.com/user/aspect/repository/sdx/uv/sdx-20110317.kit
Для простоты переименуем полученный старкит:
mv sdx-20110317.kit sdx.kit
Теперь всё достаточно просто. Создаём временную директорию sourceCloudTk
для работы с CloudTk.kit , копируем в неё и sdx.kit
и CloudTk.kit
и переходим в созданную директорию.
Выполняем команду:
/usr/local/bin/tclkit-8.6.17 sdx.kit unwrap CloudTk.kit
В данной команде unwrap
– это команда sdx.kit для распаковки CloudTk.kit
.
После выполнения команды мы получим директорию CloudTk.vfs
, в которой находим файл /custom/mepage.tcl
. В нём находим процедуру proc mepage::header
и правим в ней две строки. В заголовок процедуры (строка 37) добавляем умалчиваемый параметр img
:
proc mepage::header {title {img="/images/tclp.gif"}}
После этого правим ссылку на картинку (строка 44):
[html::cell align=left "<a href=/><img src=[set img] border=0 alt=\"Home\"><\a>"] \
После этого снова собираем (подкоманда wrap
) CloudTk.kit
:
/usr/local/bin/tclkit-8.6.17 sdx.kit wrap CloudTk.kit
Обновлённый CloudTk.kit
копируем в ~/testCloud
.
Сохраните иконку Tk-облака со страницы https://wiki.tcl-lang.org/page/CloudTk в директорию ~/testCloud/htdocs/images
. Возвращаемся в ~/testCloud
и правим 6-ю строку, добавляю параметр с иконкой:
[mypage::header "Облачные сервисы на Tcl/Tk" "images/cloudtk-192x192.png"] \
После этого необходимо перезапустить сервер и убедиться, что новая иконка появилась на стартовой странице.
Если в приложении создаётся несколько окон (toplevel), то они будут перекрывать друг друга. Список доступных окон можно получить, щёлкнув по иконке в виде галочки в верхнем левом углу .
Чтобы отобразилось требуемое окно надо щёлкнуть по его имени в списке (см. ролик), но, фактически, отсутствует управление окнами (сменить размеры, переместить и т. п.). Но всё не так плохо.
Schelt Bron предложил простой оконный менеджер, написав при этом: «Не стесняйтесь добавлять любые улучшения непосредственно в представленный код» («Feel free to add any improvements directly to the presented code»). Я последовал его совету, и добавил в его код несколько функций. Теперь можно не только перемещать окна, но и масштабировать их (см. ролик).
С учётом этого менеджера были также переопределены функции wm state
, lower
и raise
.
Оконный менеджер оформлен как пакет wm
и добавлен в нашем примере к другим пакетам в директорию modadd_Lin64
.
Проект CloudTk очень удобно использовать для удалённой работы или удалённого обучения. Например, чтобы дать основы программирования на Tcl/Tk, использования тех же SVG-виджетов, достаточно подключить в виде сервиса консоль TkCon .
Долго думал, выкладывать куда-то исходники и бинарники, или нет. Всё же решил добавить всё описанное здесь в проект TkSVGWidgets, в директорию FofCloudTk
. В которую и положил интерпретатор tclkit-8.6.17-x86-64
, старкит sdx.kit
, пакет оконного менеджера wn
(в wmforcloud
), примеры (в Tk
) и обновлённый старкит CloudTk.kit
.