Господа Лисперы, проблема с GUI в свободных реализациях, насколько я понимаю, уже давно находится в подвешенном состоянии.
Предлагаю ее решать.
И решать таким образом: из существующих проектов выбрать что-то одно, довериться мейнтейнеру в направлении развития и всем сообществом на это дело насесть (здесь конечно возникает давно известный вопрос к сообществу о его жизнеспособности, эта задача - повод решить его).
Кто за - поднимите руки ;)
Из существующего на сегодняшний день:
cl-gtk2 - насколько понимаю заброшен.
gtk-cffi - вроде развивается, но, насколько я понимаю, его почему-то не берут в quicklisp.
lambda-gtk - хз,
cells-gtk - хз,
common-qt - читал много гневных отзывов на тему сишного стиля.
ltk - примитивен.
P.S. я бы подключился к gtk-cffi... но это первое впечатление, хотелось бы узнать ваше мнение )
Основная сложность перевода ГУИ библиотек в их сложности (простите за тавтологию).
Дело даже не в том, чтобы единожды сделать перевод с C/C++ на Lisp (или другой язык, если говорить в общем случае).
Трудность состоит в том, чтобы это поддерживать в дальнейшем.
А для этого нужен какой-то механизм перевода, какой-то скрипт/утилита, которая большую часть работы делала бы за программиста.
Я делал несколько попыток перевода ГУИ библиотек на другие языки (по мере изучения языков и библиотек).
ИМХО, самый разумный путь (если заниматься не только переводом библиотеки, но и пытаться что-то писать еще),
это использовать подходы для создания биндингов, которые предлагает сама библиотека.
Самый удобный способ, который я видел - это тот, который используется в библиотеке Qt, а именно Smoke library.
На его основе построены CommonQt и QtRuby. Мне там все понравилось за исключением того, что я не смог понять,
как это все строится в Windows. Для *nix - пожалуйста. В Windows у меня не получилось построить smoke.
Нечто подобное есть и для gtk, я давно уже не занимался этим вопросом.
Самая развитая безусловно Qt, но она написана на C++ и требует прослойки на C++.
GTK проще в разы, написана на C. Не знаю как в третьей версии, но во второй были довольно большие сложности
с регулярностью структуры классов, т.е. парсер было писать достаточно сложно, много исключительных случаев.
wxWidgets как-то слабо развивается. Остальные выглядят откровенно плохо.
Или, если выглядят хорошо (например, JUCE), написаны на C++ и вообще непонятно, как это заставить работать в другой среде.
Есть еще EQL, но уж как-то больно она игрушечная получается, да и ECL многие вещи ограничивает, у меня мало что получилось сделать.
Например, я так и не смог добиться, чтобы открывался файл с кириллическими символами в пути.
Резюме:
Развивать это направление надо, важно только, чтобы голова была холодная, потому как тема весьма непростая.
GObject Introspection решает проблему биндингов не только для GUI.
Вот тут https://github.com/andy128k/cl-gobject-introspection я пытался начинать, но терпения не хватило.
GUI очень не хватает.
Есть ещё библиотека iup, но биндингов к ней нет. Сама библиотека неплоха. Умеет в гриды 100500 ячеек.
ГУЙ хотелось бы на клосе, как в капи или кг.
Для коммерческого проекта, мне думается, дешевле взять лв/капи.
https://github.com/ryanmelt/qtbindingsя про этот проект не знал, можно посмотреть.
>
Вот тут https://github.com/andy128k/cl-gobject-introspection я пытался начинать, но терпения не хватило.
Видел что-то похожее недавнее https://github.com/ekd123/gi-cffi-prototypeАга. Заходил недавно https://github.com/andy128k/cl-gobject-introspection/issues/1
Таки решил сам пилить...
> cl-gtk2 - насколько понимаю заброшен.
cl-gtk2 просто офигителен. Взяли бы, да и пилили кому надо ;)
А что там? Просто некому делать, или некая фундаментальная проблема закралась?
> gtk-cffi
Что это из себя? Ясно, что обычные биндинги к C функциям никому не нужны. Нужно что-то на CLOS
Да, видимо в настоящий момент дешевле брать LW/CLOS.
Но раз уж мы говорим о халяве и возможной точке приложений усилий, как вам такой подход - взять некий обычный/простой/низкоуровневый биндинг к Си функциям (скорее всего самым лучшим вариантом будет gtk-cffi) и делать свободную реализацию CAPI ?
>> gtk-cffi
>Что это из себя?
https://github.com/Kalimehtar/gtk-cffi
В readme:
"(setf (parent widget) new-parent)"
насколько я понимаю, это первый шажок к "что-то на CLOS"...
до сих пор не могу понять: оно в quicklisp частично??? почему?
andy128k,
в gtk-cffi есть что-то посвященное g-object. Как оно пересекается с Вашим проектом?(не делаете ли вы одно и тоже?)
и еще https://github.com/ekd123/gi-cffi-prototype, насколько я понимаю автор этого проекта и спрашивал вас: "any activity on this project?"
...похоже на NIH синдром...
В квиклиспе оно частично потому что Зак на дебиане стейбл, а там нет гтк3.
> фундаментальная проблема закралась?
1. gtk2 в то время как gtk3 уже шагает по планете;
2. Компиляция в образ всех классов и методов в образ.
В GObject есть подобие интроспекции. На ней и сделаны cl-gtk2 и gtk-cffi.
Но в G-мире давно от этого подхода отказались.
Сейчас подход такой: для сишной библиотеки создаётся бинарный файл typelib, содержащий метаинформацию об API.
Загляните в каталог /usr/lib/girepository-1.0/, у меня там более ста файлов. И это не только GTK, есть там и GStreamer, и Webkit, и даже Rhythmbox.
Как минимум эта метаинформация используется в биндингах для Vala и Python.
libgirepository -- это, по-сути, библиотека-парсер typelib-файлов. Собственно, мой проект -- это биндинг к ней.
Следующий шаг (едва затронутый): генерировать классы/функции/методы на основании этой инфы на лету.
PyGObject именно так и делает. Всё генерирует по мере надобности. Ну и есть у него немного ручного кода (overrides) https://git.gnome.org/browse/pygobject/tree/gi/overrides для редких случаев, когда генерируемое поведение не чем-то устраивает.
Ага. NIH во все поля :)
gtk-cffi на GTK3.
Без компиляции методов в образ как будешь делать defmethod для потомков? И в gtk-cffi можно при большом желании делать загрузку, например, gtk-cffi-button или gtk-cffi-window. Будут только нужные классы (от которых зависит запрашиваемый класс).
> Сейчас подход такой: для сишной библиотеки создаётся бинарный файл typelib, содержащий метаинформацию об API.
Там плохое API. Нет информации для написания наследников класса (например вместо ListStore на порядок быстрее использовать лисповый массив). Приходится некоторые параметры указывать дважды. Например, TreeModel.GetValue будет требовать явной инициализации GValue. GtkTreeView.EnableDragDest в параметрах требует отдельно массив targets. отдельно его длину.
В целом, для неподдерживаемых библиотек я сейчас тоже допиливаю gi-cffi в рамках gtk-cffi (все базовые объекты используются из gtk-cffi, а если чего не описано, то берётся из g-object-introspection).
> до сих пор не могу понять: оно в quicklisp частично??? почему?
На сегодня уже в quicklisp полностью.
> довериться мейнтейнеру в направлении развития
Могу рассказать про принципы gtk-cffi.
1. CLOS. Все сишные методы в обёртках defmethod, что позволяет, во-первых, иметь одну функцию на несколько классов, во-вторых (что важнее), при необходимости добавлять :before :after :around, где нужно. Все имена методов имеют короткое имя, которое строится из сишного путём удаления имени библиотеки (gtk) и имени класса. Если получившееся имя конфликтует со стандартной библиотекой или методом с другим числом обязательных параметров, то к имени обратно добавляется имя класса.
2. properties вычисляются динамически (у GObject есть интроспекция). Для работы с ними используется аксессор property: (property object :width) или (setf (property object :width) ...).
3. Если у сишной функции несколько выходных параметров, то они возвращаются в списке, если вместе описывают одну сущность или в values, если описывают независимые.
4. Если сишная структура представляет простой объект, то на стороне лиспа она представляется строкой или списком. Пример: GtkTreePath (список), GdkRGBA (строка), PangoFont (строка, хотя здесь может переделаю), GList (список), GSLists (список).
Уточнение к п.4: не является GObject, не имеет открытой структуры, но имеет взаимнооднозначное представлениею
> Там плохое API
Именно по этому и существуют overrides в PyGObject.
> На сегодня уже в quicklisp полностью.
после (ql:update-all-dists)
(ql:quickload "gtk-cffi")
; Evaluation aborted on #<QUICKLISP-CLIENT:SYSTEM-NOT-FOUND {1005B0D8C3}>.
или я торможу...((
кстати..еще вопросик по gtk-cffi... половина систем под лицензией LLGPL вторая под BSD...в чем хитрость?
> или я торможу...((
Кстати, да... Сейчас багрепорт сделаю. Просто автор quicklisp мне отписался, что добавил. Я глянул, что что-то появилось по (ql:system-apropos "gtk-cffi") и не вчитывался.
> в чем хитрость?
Сам gtk-cffi под LGPL. Но все поддерживающие библиотеки (вплоть до GDK) под BSD.
Смысл в том, что идея CLOS для всего, а также именование методов короткими именами -- достаточно спорные. Не хочу мешать использовать наработки, если кто-то захочет использовать низкоуровневый слой для биндинга с другой структурой (например, тот же g-object-introspection требует работающего GObject).
В ветке по Scheme вы упомянули
http://www.tecgraf.puc-rio.br/iup/
На первый взгляд неплохая штука...
вы писали "Предлагаю пилить биндинги к нему", если речь идет о CL, я готов присоединиться )
А чем не устраивает подход ltk? На мой взгляд самый разумный подход к GUI, разделение в лучших традициях model-view. И, главное, что расширить его достаточно легко, благодаря текстовому протоколу.
Возможно ltk чреват проблемами с производительностью.
Единственной ситуацией где это встанет боком, я вижу только мультимедиа, вроде игр. Здесь надо подумать, возможно удастся как-то встроить, например, cl-opengl.
Да, вроде неплохая библиотека. Основное удобство заключается, как мне думается, в простоте сишного интерфейса, и соответветственно возможность тесной интеграции с клосом и прочими лисповыми плюшками. Кроме того они там тейблвью на 100500 ячеек вроде не боятся, в отличие от кути.
Прошу прощения за поднятие "древней" ветки.
Ну что, за биндинг к iup кто-нибудь взялся? Из-за короткого имени гугл ничего вменяемого не находит.
Бесполезно пилить биндинг того, что уже есть. Рынок сложился. Каких-то сногсшибательных преимуществ биндинг не даст.
Извини, возможно я после работы совсем не соображаю. Но ты вот что и кому сейчас хотел сказать? :)
Тебе:) ГУИ биндингов куча, толку нет.
yyk: Прошу прощения за поднятие "древней" ветки....
Последнее время не было времени ) собираюсь браться.
michael.filonenko: ГУИ биндингов куча, толку нет....
что же бедным нам без ГУИ делать?
Каких-то сногсшибательных преимуществ биндинг не даст.
речь ведь не о преимуществах, а о более-менее юзабильной библиотеке для CL.
Что-то я этот IUP ни в одном линуксе найти не могу. Или как пакет называется?
Варант с g-object-introspection до состояния HelloWorld дошёл. Можно оценить, что получилось на https://github.com/andy128k/cl-gobject-introspection/blob/master/test/hello.lisp
Итак,
cl-iup также доведен до состояния helloworld ))
ссылка:
https://github.com/klimenko-serj/cl-iupпокаместь это просто биндинги + 3 макроса немного упрощающие работу.
также имеется пример "типа helloworld" с несколькими компонентами.
Желающим поучаствовать, поругать, похвалить, подкинуть пару идей буду очень рад )))
P.S.:
"Что-то я этот IUP ни в одном линуксе найти не могу."Действительно, его надо качать с
сайта(там же можно найти документацию и примеры на Си) и ставить через скрипт. А в Винде - просто скопировать dll-ки в system32.
Да, и еще одно:
в Винде оно не работает через emacs+slime виснет после вызова(cffi) IupOpen. (под никсами все норм.)
Запустил пример под SBCL/Linux, но пришлоть поправить iup-defcallback: во-первых, если писать
(defmacro iup-defcallback (name args body)
(let ((cb-name (gensym)))
`(progn
(defmacro ,name () (cffi:callback ,cb-name))
(cffi:defcallback ,cb-name :int ,args ,body))))gensym cb-name'а уже не будет связан с коллбеком в месте раскрытия name. Нужно интернеть сгенерированное имя.
Во-вторых, name раскрывается в результат выполнения cffi:callback - адрес коллбека; его нельзя сохранить в fasl, и SBCL отказывается компилировать такой файл. В-третьих, вместо defmacro в данном случае имеет смысл использовать define-symbol-macro.
В итоге получается
(defmacro iup-defcallback (name args body)
(let ((cb-name (intern (concatenate 'string "%" (string name) (string '#:-callback)))))
`(progn
(cffi:defcallback ,cb-name :int ,args ,body)
(define-symbol-macro ,name (cffi:callback ,cb-name)))))и в примере
(IupSetCallback *msg-btn* "ACTION" msg-cb)вместо
(IupSetCallback *msg-btn* "ACTION" (msg-cb))Да, я уже столкнулся с тем, что
"cffi:callback - адрес коллбека; его нельзя сохранить в fasl". И с тем что символ нужно интернить.
Решил (покаместь) немного по другому:
(defmacro iup-defcallback (name args &body body)
(let ((cb-name (gensym "iup-cb"))
(fn-args (get-fn-args args)))
`(progn
(defun ,name ,fn-args ,@body)
(cffi:defcallback ,cb-name :int ,args ,@body)
(setf (get ',name 'cb) (lambda () (cffi:get-callback ',cb-name))))))(defmacro iup-defcallback-default (name args &body body)
`(iup-defcallback ,name ,args
(progn
,@body
IUP_DEFAULT)))(defmacro iup-callback (name)
`(funcall (get ',name 'cb)))(defmacro iup-set-callback (ih name callbck)
`(iupSetCallback ,ih ,name (iup-callback ,callbck)))Идея в том, чтоб callback был доступен как функция.
Возможно, я не прав (тут возникает некоторая путаница между iupSetCallback и iup-set-callback)
(iup-defcallback cb () ...)(IupSetCallback ih "ACTION" (iup-callback cb));; или
(iup-set-callback "ACTION" ih cb);; но зато, где угодно в коде
(cb) ; вызовет наш callback как функцию
Ваш же вариант мне нравится тем, что он максимально приближает меня к изначальному синтаксису IUP.
В общем, я еще не решил...
Я пока еще не совсем представляю(а точнее - совсем не представляю), какой должен быть интерфейс к этому делу...
CLOS? какой-нибудь DSL? пара макросов в качестве обертки?
Пока склоняюсь к DSL...но ,опять же, готов выслушать предложения и советы.
define-symbol-macro не конфликтует с defun. Можно
`
(progn
(defun ,name ,fn-args ,@body)
(cffi:defcallback ,cb-name :int ,args ,@body)
(define-symbol-macro ,name (cffi:callback ,cb-name)))
> Я пока еще не совсем представляю (а точнее - совсем не представляю), какой должен быть интерфейс к этому делу...Экспериментируйте, и покажите, что получится.
Спасибо, я об этом не подумал.
В процессе развития биндингов к
IUP пришел к выводу, что это
бессмысленно по нескольким причинам:
- IUP под Linux опирается на gtk, а под Win - WinAPI, тогда как существует gtk, которая работает и там и там.
- "IUP ни в одном линуксе" не лежит в репозиториях, его надо ставить через скрипт.
- в IUP для подключения дополнительных компонент libiupcontrols требуются другие библиотеки компании Tachgraph (libcd, ..etc...), которые также как и IUP требуют отдельной процедуры установки(через скрипт)
В связи с этим у меня вопрос к
Monk:
Можно ли поучаствовать в ваших проектах (gtk-cffi и/или cl-gobject-introspection) и каким образом?
Вроде как можно традиционно: клон и пулл-реквесты :)
клон и пулл-реквесты :) да-да, я слыхал о таком подходе ;)
речь не об этом, у меня к вам вопрос о направлении в разработке.
Грубо говоря, возможно ли наметить какой-нибудь TODO-list?
P.S.: можно почтой "klimenko.serj at gmail.com".
> Можно ли поучаствовать в ваших проектах (gtk-cffi и/или cl-gobject-introspection) и каким образом?
Можно. Например, писать примеры, которые должны работать, но не работают. Или указывать какими конструкциями пользоваться неудобно (и как было бы удобно).
> Грубо говоря, возможно ли наметить какой-нибудь TODO-list?
Да.
В почту тоже написал.
https://github.com/andy128k/cl-gobject-introspection готов
Весь интерфейс проиллюстрирован в https://github.com/andy128k/cl-gobject-introspection/blob/master/test/hello.lisp
Есть функции, объекты, свойства, сигналы...
Если чего-то не хватает, пишите.
Добавил документацию на https://github.com/andy128k/cl-gobject-introspectionТеперь чётко описано, что должно работать (без реверс-инжиниринга из исходников).
Пожалуйста, если есть время, потестируйте. Очень нужны тесты вида "это не работает или работает не так, как описано".
Хочу попробовать упоминаемые библиотеки. Возникло несколько вопросов:
А с какой версией gobject тестировалась cl-object-introspection?
С какими версиями gtk-* библиотек тестировалась gtk-cffi?
Как работают gtk-библиотеки и биндинги к ним, на "форточках"?
Правильно ли я понимаю, что с версией gtk+ 2.24.x биндинги работать точно не будут.
Просто для винды стабильный релиз набора библиотек именно такой версии. А хотелось бы именно кроссплатформености.
Monk дал мне
эту ссылкуа у меня все никак руки не дойдут попробовать (
Вау, по-крайней мере загрузилась. В процессе загрузки, выявилась только одна простенькая проблема: система хочет одну из ("libgirepository-1.0.dll" "libgirepository-1.0.0.dll"), а в gtk/ только libgirepository-1.0-1.dll