← Архив: Common Lisp

Пара вопросов по cl-gobject-introspection

Author: · 29.10.2015 00:52
· original author: motopeh
В cl-gir есть пример, копипастю его сюда:
(defvar *gtk* (gir:ffi "Gtk")) (defun main () (gir:invoke (*gtk* 'init) nil) (let ((window (gir:invoke (*gtk* "Window" 'new) (gir:nget *gtk* "WindowType" :toplevel))) (button (gir:invoke (*gtk* "Button" 'new-with-label) "Hello, world!"))) (gir::g-signal-connect-data (gir::object-this window) "destroy" (cffi:foreign-symbol-pointer "gtk_main_quit") (cffi:null-pointer) (cffi:null-pointer) 0) (gir:connect button :clicked (lambda (button) (setf (gir:property button 'label) "OK"))) (gir:invoke (window 'add) button) (gir:invoke (window 'show-all)) (gir:invoke (*gtk* 'main))))
Я вижу тут две привязки к сигналам destroy и clicked. Нельзя ли
destroy также связать через gir:connect? Можно ли получать доступ к
функциям gtk_main_quit через *gtk* и вызвать её?
У меня (gir:nget *gtk* 'main-quit) достаёт вроде что-то, но
(gir:invoke (*gtk* 'main-quit)) как-то непонятно работает.
· original author: Monk
> Нельзя ли destroy также связать через gir:connect? Можно ли получать доступ к функциям gtk_main_quit через *gtk* и вызвать её?

Можно. Здесь пример такой, чтобы продемонстрировать разные варианты привязки: низкий уровень через g-signal-connect-data и высокий через connect

Должно работать и так:
(defvar *gtk* (gir:ffi "Gtk"))
(defun main ()
  (gir:invoke (*gtk* 'init) nil)
  (let ((window (gir:invoke (*gtk* "Window" 'new)
                            (gir:nget *gtk* "WindowType" :toplevel)
)
)

        (button (gir:invoke (*gtk* "Button" 'new-with-label) "Hello, world!"))
)

    (gir:connect window :destroy
                 (lambda (window)
                   (gir:invoke (*gtk* 'main-quit))
)
)

    (gir:connect button :clicked
                 (lambda (button)
                   (setf (gir:property button 'label) "OK")
)
)

    (gir:invoke (window 'add) button)
    (gir:invoke (window 'show-all))
    (gir:invoke (*gtk* 'main))
)
)
· original author: motopeh
Вроде так раньше пробовал - не работало. Сейчас работает. Странно.
· original author: motopeh
Не работало, потому что я пытался закрыть окошко по нажатию кнопки вот так:
(gir:connect button :clicked (lambda (button) (declare (ignore button)) (gir:invoke (*gtk* 'main-quit))))
А вот так работает:
(gir:connect button :clicked (lambda (button) (declare (ignore button)) (gir:invoke (window 'destroy))))
· original author: motopeh
Пытаюсь банально нарисовать окошко с белым холстом, чтобы на нём
вволю рисовать через cairo (из-за любви к inkscape) и чтобы рисование
и обработка событий управлялось из sbcl. По соображениям
перспективности выбрал cl-gobject-introspection. Опыт в таких делах -
реализация того же самого через rpc к matplotlib. В уровне пониже
опыта никакого.
Прототип упёрся пока на таком коде:
(defun main () (gir:invoke (*gtk* 'init) nil) (let ((window (gir:invoke (*gtk* "Window" 'new) (gir:nget *gtk* "WindowType" :toplevel))) (drawing-area (gir:invoke (*gtk* "DrawingArea" 'new)))) (setf (gir:property window 'title) "Hello world!") (gir:connect window :destroy (lambda (win) (declare (ignore win)) (gir:invoke (*gtk* 'main-quit)))) (gir:connect drawing-area :draw (lambda (drawing-area cairo))) (gir:invoke (window 'add) drawing-area) (gir:invoke (window 'show-all)) (gir:invoke (*gtk* 'main)))) Вроде cairo уже доступно, но ничего не удаётся сделать. Либо
вызываемые функции отсутствуют либо вообще ничего не понятно. С
перезапуском перекомпилированной функции обычно получаю ошибки
выделенной памяти - приходится перезапускать sbcl. Привычной
интерактивной разработки никакой.
Вижу не очень понятные функции в пакете gir. Пытался их щупать как-то
так:
(let ((x (gir:invoke (*gtk* "DrawingArea" 'new)))) (gir:object-info-get-properties (slot-value (slot-value x 'class) 'object-info))) Потом SBCL улетает куда-то далеко - только kill -KILL спасает. Что-то
я не так делаю?
Есть идея взять пример на vala, переделать всё в виде динамичесой
библиотеки. Параллельно вкуривая в CFFI мало-помалу реализовать что
надо. Может быть cl-gobject-introspection пока ещё сыроват и такой
вариант лучше?
· original author: motopeh
Оказывается надо ещё кэш с fasl-ми подчищать - тогда sbcl ругаться начинает нормально:
(let ((x (gir:invoke (*gtk* "DrawingArea" 'new)))) (gir:invoke (*gtk* 'init) nil) (prog1 (gir:function-info-get-symbol (first (gir:object-info-get-methods (slot-value (slot-value x 'class) 'gir::info)))) (gir:invoke (*gtk* 'main-quit))))
· original author: motopeh
В общем пошло дело. Непонятно только почему
(let ((x (gir:invoke (*gtk* "DrawingArea" 'new)))) (gir:invoke (x "get_allocation")))
возвращает nil когда с "get_allocated_width" и "get_allocated_height" всё нормально.
· original author: motopeh
А что с cairo делать. Оказывается это просто указатель.
Методы подобные тем, что из README не работают:
(defun main () (gir:invoke (*gtk* 'init) nil) (let ((window (gir:invoke (*gtk* "Window" 'new) (gir:nget *gtk* "WindowType" :toplevel))) (drawing-area (gir:invoke (*gtk* "DrawingArea" 'new)))) (setf (gir:property window 'title) "Hello world!") (gir:connect window :destroy (lambda (win) (declare (ignore win)) (gir:invoke (*gtk* 'main-quit)))) (gir:connect drawing-area :draw (lambda (drawing-area c) (declare (ignorable drawing-area c)) (let ((cairo (gir:invoke (*cairo* "Context" 'new) c))) (setf *q* cairo)))) (gir:invoke (window 'add) drawing-area) (gir:invoke (window 'show-all)) (gir:invoke (*gtk* 'main))))
· original author: Monk
> А что с cairo делать. Оказывается это просто указатель
В смысле (gir:invoke (*cairo* "Context" 'new) c) возвращает просто указатель?
· original author: motopeh
Это в прошлых примерах. Здесь c - это просто указатель. Чтобы работать в том же стиле надо его перевести
него в объект класса Cairo.Context. Я пользовался примером из README

4.1. Pointer to object


Это в прошлых примерах символ cairo получает значение указателя.
· original author: motopeh
В данном случае выпадает при (funcall (gir:nget *cairo* "Context") c) то что funcall нужно что-то
funcallable. А с new: "Bad FFI constructor name"
· original author: motopeh
Попробовал (gir::make-struct (gir:nget *cairo* "Context") c). Вроде объект получается, но толку от него никакого:
 нужные методы к нему отсутствуют.
· original author: Monk
Попробуй (gir::build-object-ptr (gir:nget *cairo* "Context") c).
· original author: motopeh
(let ((cairo (gir::build-object-ptr (gir:nget *cairo* "Context") c))) (setf *q* (gir:nget cairo "arc")))выдаёт:
The value #S(GIR::STRUCT-CLASS :INFO # :SIGNALS (NIL) :FIELDS-DICT NIL :CONSTRUCTOR-CACHE # :METHOD-CACHE #) is not of type GIR::OBJECT-CLASS.
· original author: Monk
> GIR::STRUCT-CLASS
Это всё-таки структура. Тогда (gir::build-struct-ptr (gir:nget *cairo* "Context") c).
· original author: motopeh
gir:nget у структуры привычных методов "line_to", "arc" не находит.
· original author: motopeh
Вообще вроде всё верно ничего особого в gir-файле cairo нет.
Только вот вроде в PyGTK и у vala вроде те же механизмы и у них всё работает.
Такая работа достигается через грубые хаки cairo?
· original author: Monk
vala не использует gir. Она просто компилируется в Си+GTK. PyGTK -- тоже.
Полный аналог: https://github.com/Kalimehtar/gtk-cffi
· original author: Monk
А у тебя точно есть cairo-1.0.typelib
И ты его точно подключил?
· original author: motopeh
cairo-1.0.typelib есть.
Подключение в норме:
GIR-TEST> *cairo* #S(GIR::NAMESPACE :NAME "cairo" :VERSION NIL :INTERFACE-CACHE #) GIR-TEST> (gir:nget *cairo* "Content") # GIR-TEST>
· original author: Monk
Да. Увидел. https://github.com/GNOME/gobject-introspection/blob/master/gir/cairo-1.0.gir.in вообще почти пустой.
· original author: Monk
PyGObject использует http://www.cairographics.org/pycairo/
Так там для питона биндинг вообще на Си написан.
В общем:  (quicklisp:quickload :cl-cairo2)
· original author: motopeh
Не понял. Функции из cl-cairo2 должны работать с полученным указателем
из сигнала draw?
· original author: Monk
> Функции из cl-cairo2 должны работать с полученным указателем
из сигнала draw?
Конечно. (make-instance 'cl-cairo2:context :pointer c) и вперёд!
· original author: motopeh
Всё работает! Рисует! Спасибо большое!
· original author: motopeh
Что-то не пойму: а как присоединиться к событию нажатия клавиш, движений и кликов мыши
при том что надо постоянно знать где курсор находится на drawing-area?
· original author: Monk
http://www.opennet.ru/docs/RUS/gtk_plus/x2447.html