← Архив: Common Lisp

GUI: рационализаторское предложение

Author: · 04.03.2013 00:04
· original author: klimenko.serj
Господа Лисперы, проблема с GUI  в свободных реализациях, насколько я понимаю, уже давно находится в подвешенном состоянии.
Предлагаю ее решать.
И решать таким образом: из существующих проектов выбрать что-то одно, довериться мейнтейнеру в направлении развития и всем сообществом на это дело насесть (здесь конечно возникает давно известный вопрос к сообществу о его жизнеспособности, эта задача - повод решить его).
Кто за - поднимите руки ;)
Из существующего на сегодняшний день:
cl-gtk2 - насколько понимаю заброшен.
gtk-cffi - вроде развивается, но, насколько я понимаю, его почему-то не берут в quicklisp.
lambda-gtk - хз,
cells-gtk - хз,
common-qt - читал много гневных отзывов на тему сишного стиля.
ltk - примитивен.
P.S. я бы подключился к gtk-cffi... но это первое впечатление, хотелось бы узнать ваше мнение )
· original author: dmitrys99
Основная сложность перевода ГУИ библиотек в их сложности (простите за тавтологию).
Дело даже не в том, чтобы единожды сделать перевод с C/C++ на Lisp (или другой язык, если говорить в общем случае).
Трудность состоит в том, чтобы это поддерживать в дальнейшем.
А для этого нужен какой-то механизм перевода, какой-то скрипт/утилита, которая большую часть работы делала бы за программиста.
Я делал несколько попыток перевода ГУИ библиотек на другие языки (по мере изучения языков и библиотек).
ИМХО, самый разумный путь (если заниматься не только переводом библиотеки, но и пытаться что-то писать еще), 
это использовать подходы для создания биндингов, которые предлагает сама библиотека.
Самый удобный способ, который я видел - это тот, который используется в библиотеке Qt, а именно Smoke library.
На его основе построены CommonQt и QtRuby. Мне там все понравилось за исключением того, что я не смог понять, 
как это все строится в Windows. Для *nix - пожалуйста. В Windows у меня не получилось построить smoke.
Нечто подобное есть и для gtk, я давно уже не занимался этим вопросом.
Самая развитая безусловно Qt, но она написана на C++ и требует прослойки на C++.
GTK проще в разы, написана на C. Не знаю как в третьей версии, но во второй были довольно большие сложности 
с регулярностью структуры классов, т.е. парсер было писать достаточно сложно, много исключительных случаев.
wxWidgets как-то слабо развивается. Остальные выглядят откровенно плохо.
Или, если выглядят хорошо (например, JUCE), написаны на C++ и вообще непонятно, как это заставить работать в другой среде.
Есть еще EQL, но уж как-то больно она игрушечная получается, да и ECL многие вещи ограничивает, у меня мало что получилось сделать.
Например, я так и не смог добиться, чтобы открывался файл с кириллическими символами в пути.
Резюме:
Развивать это направление надо, важно только, чтобы голова была холодная, потому как тема весьма непростая.
· original author: andy128k
GObject Introspection решает проблему биндингов не только для GUI.
Вот тут https://github.com/andy128k/cl-gobject-introspection я пытался начинать, но терпения не хватило.
· original author: michael.filonenko
GUI очень не хватает.
Есть ещё библиотека iup, но биндингов к ней нет. Сама библиотека неплоха. Умеет в гриды 100500 ячеек.
ГУЙ хотелось бы на клосе, как в капи или кг.
Для коммерческого проекта, мне думается, дешевле взять лв/капи.
 
· original author: dmitrys99
https://github.com/ryanmelt/qtbindings
я про этот проект не знал, можно посмотреть.
· original author: Menschenkindlein
Вот тут https://github.com/andy128k/cl-gobject-introspection я пытался начинать, но терпения не хватило.

Видел что-то похожее недавнее https://github.com/ekd123/gi-cffi-prototype
· original author: andy128k
Ага. Заходил недавно https://github.com/andy128k/cl-gobject-introspection/issues/1
Таки решил сам пилить...
· original author: shamaz.mazum
> cl-gtk2 - насколько понимаю заброшен.
cl-gtk2 просто офигителен. Взяли бы, да и пилили кому надо ;)
А что там? Просто некому делать, или некая фундаментальная проблема закралась?
> gtk-cffi
Что это из себя? Ясно, что обычные биндинги к C функциям никому не нужны. Нужно что-то на CLOS
· original author: LinkFly
Да, видимо в настоящий момент дешевле брать LW/CLOS.
Но раз уж мы говорим о халяве и возможной точке приложений усилий, как вам такой подход - взять некий обычный/простой/низкоуровневый биндинг к Си функциям (скорее всего самым лучшим вариантом будет gtk-cffi) и делать свободную реализацию CAPI ?
· original author: klimenko.serj
>> 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 синдром...
· original author: michael.filonenko
В квиклиспе оно частично потому что Зак на дебиане стейбл, а там нет гтк3.
· original author: andy128k
> фундаментальная проблема закралась?
1. gtk2 в то время как gtk3 уже шагает по планете;
2. Компиляция в образ всех классов и методов в образ.
· original author: andy128k
В 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 во все поля :)
· original author: LinkFly
Хм... очень интересно!
· original author: Monk
gtk-cffi на GTK3.
Без компиляции методов в образ как будешь делать defmethod для потомков? И в gtk-cffi можно при большом желании делать загрузку, например, gtk-cffi-button или gtk-cffi-window. Будут только нужные классы (от которых зависит запрашиваемый класс).
· original author: Monk
> Сейчас подход такой: для сишной библиотеки создаётся бинарный файл typelib, содержащий метаинформацию об API.
Там плохое API. Нет информации для написания наследников класса (например вместо ListStore на порядок быстрее использовать лисповый массив). Приходится некоторые параметры указывать дважды. Например, TreeModel.GetValue будет требовать явной инициализации GValue. GtkTreeView.EnableDragDest в параметрах требует отдельно массив targets. отдельно его длину.
В целом, для неподдерживаемых библиотек я сейчас тоже допиливаю gi-cffi в рамках gtk-cffi (все базовые объекты используются из gtk-cffi, а если чего не описано, то берётся из g-object-introspection).
· original author: Monk
> до сих пор не могу понять: оно в quicklisp частично??? почему?
На сегодня уже в quicklisp полностью.
· original author: Monk
> довериться мейнтейнеру в направлении развития
Могу рассказать про принципы 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 (список).
· original author: Monk
Уточнение к п.4: не является GObject, не имеет открытой структуры, но имеет взаимнооднозначное представлениею
· original author: andy128k
> Там плохое API
Именно по этому и существуют overrides в PyGObject.
· original author: klimenko.serj
> На сегодня уже в quicklisp полностью.
после (ql:update-all-dists)
(ql:quickload "gtk-cffi")
; Evaluation aborted on #<QUICKLISP-CLIENT:SYSTEM-NOT-FOUND {1005B0D8C3}>.
или я торможу...((
· original author: klimenko.serj
кстати..еще вопросик по gtk-cffi... половина систем под лицензией LLGPL вторая под BSD...в чем хитрость?
· original author: Monk
> или я торможу...((
Кстати, да... Сейчас багрепорт сделаю. Просто автор quicklisp мне отписался, что добавил. Я глянул, что что-то появилось по (ql:system-apropos "gtk-cffi") и не вчитывался.
· original author: Monk
> в чем хитрость?
Сам gtk-cffi под LGPL. Но все поддерживающие библиотеки (вплоть до GDK) под BSD.
Смысл в том, что идея CLOS для всего,  а также именование методов короткими именами -- достаточно спорные. Не хочу мешать использовать наработки, если кто-то захочет использовать низкоуровневый слой для биндинга с другой структурой (например, тот же g-object-introspection требует работающего GObject).
· original author: klimenko.serj
В ветке по Scheme вы упомянули
http://www.tecgraf.puc-rio.br/iup/
На первый взгляд неплохая штука...
вы писали "Предлагаю пилить биндинги к нему", если речь идет о CL, я готов присоединиться )
· original author: necto
А чем не устраивает подход ltk? На мой взгляд самый разумный подход к GUI, разделение в лучших традициях model-view. И, главное, что расширить его достаточно легко, благодаря текстовому протоколу.
Возможно ltk чреват проблемами с производительностью.
Единственной ситуацией где это встанет боком, я вижу только мультимедиа, вроде игр. Здесь надо подумать, возможно удастся как-то встроить, например, cl-opengl.
· original author: michael.filonenko
Да, вроде неплохая библиотека. Основное удобство заключается, как мне думается, в простоте сишного интерфейса, и соответветственно возможность тесной интеграции с клосом и прочими лисповыми плюшками. Кроме того они там тейблвью на 100500 ячеек вроде не боятся, в отличие от кути.
· original author: yyk
Прошу прощения за поднятие "древней" ветки.
Ну что, за биндинг к iup кто-нибудь взялся? Из-за короткого имени гугл ничего вменяемого не находит.
· original author: michael.filonenko
Бесполезно пилить биндинг того, что уже есть. Рынок сложился. Каких-то сногсшибательных преимуществ биндинг не даст.
· original author: yyk
Извини, возможно я после работы совсем не соображаю. Но ты вот что и кому сейчас хотел сказать? :)
· original author: michael.filonenko
Тебе:) ГУИ биндингов куча, толку нет.
· original author: klimenko.serj
  yyk: Прошу прощения за поднятие "древней" ветки....
Последнее время не было времени ) собираюсь браться.
  michael.filonenko: ГУИ биндингов куча, толку нет....
что же бедным нам без ГУИ делать?
 Каких-то сногсшибательных преимуществ биндинг не даст.
речь ведь не о преимуществах, а о более-менее юзабильной библиотеке для CL.
 
· original author: Monk
Что-то я этот IUP ни в одном линуксе найти не могу. Или как пакет называется?
· original author: Monk
Варант с g-object-introspection до состояния HelloWorld дошёл. Можно оценить, что получилось на https://github.com/andy128k/cl-gobject-introspection/blob/master/test/hello.lisp
· original author: klimenko.serj
Итак, cl-iup также доведен до состояния helloworld ))
ссылка: https://github.com/klimenko-serj/cl-iup
покаместь это просто биндинги + 3 макроса немного упрощающие работу.
также имеется пример "типа helloworld" с несколькими компонентами.
Желающим поучаствовать, поругать, похвалить, подкинуть пару идей буду очень рад )))
P.S.: "Что-то я этот IUP ни в одном линуксе найти не могу."
Действительно, его надо качать с сайта(там же можно найти документацию и примеры на Си) и ставить через скрипт. А в Винде - просто скопировать dll-ки в system32.
· original author: klimenko.serj
Да, и еще одно:
в Винде оно не работает через emacs+slime виснет после вызова(cffi) IupOpen. (под никсами все норм.)
· original author: orivej
Запустил пример под 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))
· original author: klimenko.serj
Да, я уже столкнулся с тем, что "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...но ,опять же, готов выслушать предложения и советы.
· original author: orivej
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))
)


> Я пока еще не совсем представляю (а точнее - совсем не представляю), какой должен быть интерфейс к этому делу...
Экспериментируйте, и покажите, что получится.
· original author: klimenko.serj
Спасибо, я об этом не подумал.
· original author: klimenko.serj
В процессе развития биндингов к IUP пришел к выводу, что это бессмысленно по нескольким причинам:
  • IUP под Linux опирается на gtk, а под Win - WinAPI, тогда как существует gtk, которая работает и там и там.
  • "IUP ни в одном линуксе" не лежит в репозиториях, его надо ставить через скрипт.
  • в IUP для подключения дополнительных компонент libiupcontrols требуются другие библиотеки компании Tachgraph (libcd, ..etc...), которые также как и IUP требуют отдельной процедуры установки(через скрипт)
В связи с этим у меня вопрос к Monk:
Можно ли поучаствовать в ваших проектах (gtk-cffi и/или cl-gobject-introspection) и каким образом?

· original author: andy128k
Вроде как можно традиционно: клон и пулл-реквесты :)
· original author: klimenko.serj
клон и пулл-реквесты :) да-да, я слыхал о таком подходе ;)
речь не об этом, у меня к вам вопрос о направлении в разработке.
Грубо говоря, возможно ли наметить какой-нибудь TODO-list?
P.S.: можно почтой "klimenko.serj at gmail.com".
· original author: Monk
> Можно ли поучаствовать в ваших проектах (gtk-cffi и/или cl-gobject-introspection) и каким образом?
Можно. Например, писать примеры, которые должны работать, но не работают. Или указывать какими конструкциями пользоваться неудобно (и как было бы удобно).
> Грубо говоря, возможно ли наметить какой-нибудь TODO-list?
Да.
В почту тоже написал.
· original author: Monk
https://github.com/andy128k/cl-gobject-introspection готов
Весь интерфейс проиллюстрирован в https://github.com/andy128k/cl-gobject-introspection/blob/master/test/hello.lisp
Есть функции, объекты, свойства, сигналы...
Если чего-то не хватает, пишите.
· original author: andy128k
Wow!
· original author: Monk
Добавил документацию на https://github.com/andy128k/cl-gobject-introspectionТеперь чётко описано, что должно работать (без реверс-инжиниринга из исходников).
Пожалуйста, если есть время, потестируйте. Очень нужны тесты вида "это не работает или работает не так, как описано".
· original author: LinkFly
Хочу попробовать упоминаемые библиотеки. Возникло несколько вопросов:
А с какой версией gobject тестировалась cl-object-introspection?
С какими версиями gtk-* библиотек тестировалась gtk-cffi?
Как работают gtk-библиотеки и биндинги к ним, на "форточках"?
Правильно ли я понимаю, что с версией gtk+ 2.24.x биндинги работать точно не будут.
Просто для винды стабильный релиз набора библиотек именно такой версии. А хотелось бы именно кроссплатформености.
· original author: klimenko.serj
Monk дал мне эту ссылку
а у меня все никак руки не дойдут попробовать (
· original author: LinkFly
Вау, по-крайней мере загрузилась. В процессе загрузки, выявилась только одна простенькая проблема: система хочет одну из ("libgirepository-1.0.dll" "libgirepository-1.0.0.dll"), а в gtk/ только libgirepository-1.0-1.dll