Обратные вызовы GTK+ Forth

Недавно я наткнулся на статью Манфреда Махлоу четырехлетней давности, которая была близка к решению моей проблемы. В статье «Использование Glade для создания приложений GTK+ в Forth» затрагивались обработчики сигналов, утверждая, что для их создания нельзя использовать Forth, а только C. Я думаю, что моя проблема остается небольшой, но я в тупике, я был бы очень признателен за любые предложения. Во-вторых, если кто-нибудь знает, как отправить электронное письмо мистеру Малову, не используя тире в адресе, я был бы рад это услышать.

Я пишу приложение, используя Linux-версию SwiftForth, чтобы создать собственное окно и получать нажатия клавиш. и написать в это окно. Моя цель — внедрить colorForth Чарльза Мура, улучшенный и удобный для пользователя. Я решил использовать GTK+, мало что о нем зная, но мне это удалось, если не считать обратные вызовы (обработчики сигналов). Во всем этом всего две страницы кода, поэтому я помещаю его здесь:

\ ------------------------ COLOR FORTH -----------------------

ANEW TASK-COLORFORTH

LIBRARY  /usr/lib/i386-linux-gnu/libgtk-3.so.0.1000.8

FUNCTION: gtk_window_new ( code -- addr )
FUNCTION: gtk_widget_destroy ( wptr -- )
FUNCTION: gtk_window_close ( wptr -- )
FUNCTION: gtk_widget_show  ( wptr -- )
FUNCTION: gtk_init  ( -- )
FUNCTION: gtk_window_set_decorated ( wptr flag -- )
FUNCTION: gtk_window_move  ( wptr x y -- )
\ FUNCTION: gtk_widget_new  ( n addr -- )  ( try 0 0 )
\ FUNCTION: gtk_widget_map  ( wptr -- )
\ FUNCTION: gtk_widget_show_all  ( wptr -- )
FUNCTION: gtk_window_get_screen  ( wptr -- wgptr )
\ FUNCTION: gtk_window_present  ( wptr -- )
FUNCTION: gtk_window_set_title ( wptr TitlePtr -- )
FUNCTION: gtk_window_resize ( wptr width height -- )
FUNCTION: gtk_widget_modify_bg ( wptr state cptr -- )
\ FUNCTION: gtk_widget_modify_fg ( wptr state cptr -- )
FUNCTION: gtk_widget_modify_text ( wptr state cptr -- )
FUNCTION: gtk_widget_modify_base ( wptr statre cptr -- )
FUNCTION: g_signal_connect_data ( wptr name callback data 0 0 -- )
FUNCTION: gtk_main ( -- )
FUNCTION: gtk_main_quit ( -- )
FUNCTION: gtk_widget_set_events ( wptr flag -- )

LIBRARY  /usr/lib/i386-linux-gnu/libgdk-3.so.0.1000.8
FUNCTION: gdk_event_get_keyval ( eptr kptr -- )
FUNCTION: gdk_event_get_state ( eptr sptr -- )
FUNCTION: gdk_event_get_event_type ( eptr -- type ) ( requires GET.RETURN )

\ LIBRARY  /usr/lib/i386-linux-gnu/libgio-2.0.so.0.4000.0
\ LIBRARY /lib/i386-linux-gnu/libglib-2.0.so.0.4000.0
\ LIBRARY /usr/lib/i386-linux-gnu/libpango-1.0.so.0.3600.3
\ LIBRARY /usr/lib/i386-linux-gnu/libatk-1.0.so.0.21009.1
\ LIBRARY /usr/lib/i386-linux-gnu/libgobject-2.0.so.0.4000.0
\ LIBRARY /usr/lib/i386-linux-gnu/libgdk_pixbuf-2.0.so.0.3000.7

VARIABLE Window-Ptr
VARIABLE Event-Ptr
VARIABLE KeyVal
VARIABLE KeyState

Z" ColorForth"         VALUE Title
Z" key_press_event"    VALUE Keypress-Name
Z" delete_event"       VALUE Delete-Event-Name
Z" destroy"            VALUE Destroy-Name

CREATE Background 0 , 0 H, 0 H, $2000 H,
CREATE Black 0 , 0 H, 0 H, 0 H,
CREATE White 0 , $E000 H, $E000 H, $8000 H,

\ ----------------------------------------------------------------

ICODE LEAVE.FALSE
    EAX EAX SUB
    RET
END-CODE

ICODE GET.RETURN
    4 # EBP SUB
    EBX 0 [EBP] MOV
    EAX EBX MOV
    RET
END-CODE

         \  This may be the part where I am having problems

: SHUTDOWN
    Window-Ptr @   DUP  gtk_window_close
    gtk_widget_destroy
;

: CB.DELETE.EVENT ( wptr data -- false to destroy )
    RDROP RDROP             ( assuming 2 paramaters on Rstack and return -1 )
    LEAVE.FALSE
;

: CB.DESTROY     ( wptr data -- )
    RDROP RDROP                        ( two parameters here )
    gtk_main_quit
;

: CB.KEYPRESS   ( wptr eptr data -- )     ( assuming 3 parameters on Rstack )
    Window-Ptr @ .  R> . R> . R> .   R@   (  This for diagnosis – eventually )
    SHUTDOWN                              ( goes to a [SWITCH )
;

: STARTUP   ( -- )
    Window-Ptr OFF  Event-Ptr OFF
    gtk_init
    0 gtk_window_new ?DUP    ( 0 = GTK_WINDOW_TOPLEVEL )
      IF DUP Window-Ptr !
         DUP 1024 gtk_widget_set_events       ( 1024 for Keypress signals )
         DUP Title gtk_window_set_title
         DUP 1280 850 gtk_window_resize
         DUP 0 gtk_window_set_decorated
         DUP 0 Background gtk_widget_modify_bg
         DUP Delete-Event-Name  [ ' CB.DELETE.EVENT +ORIGIN ] LITERAL  0
           0 0  g_signal_connect_data
         DUP Destroy-Name  [ ' CB.DESTROY +ORIGIN ] LITERAL 0
           0 0  g_signal_connect_data
         DUP Keypress-Name  [ ' CB.KEYPRESS +ORIGIN ] LITERAL 0
           0 0  g_signal_connect_data
         gtk_widget_show
      THEN
      gtk_main
;

Я не мог использовать обычный g_signal_connect, потому что я не мог найти его ни в одной библиотеке, которая у меня есть. Если он появится, я бы использовал его, так как код проще. Однако этот код компилируется, и когда я набираю STARTUP, он делает именно это. Окно есть, как я указал, сигналы установлены, но нажатие любой клавиши приводит к сбою SwiftForth с "ошибкой сегментации".

Как видите, я передаю абсолютный адрес обработчика функции подключения сигнала. Я также пытался поместить этот адрес в переменную и передать его как указатель, но это приводит к ошибке GTK+.

При написании обработчиков я предполагал, что они будут работать как любой библиотечный вызов. Входные параметры будут находиться в стеке возврата, предоставляемом GTK по мере выполнения кода обработчика, и я должен помещать все возвраты в EAX. Но этот анализ может быть ошибочным. Возможно, я неправильно подготавливаю адрес или неправильные параметры обработчика, или у меня совершенно неправильная концепция.

Я надеюсь, что, несмотря на заявление о том, что обработчики должны быть на языке C, есть какой-то способ смоделировать то, что должен делать код C, при необходимости на ассемблере.

Я чувствую, что я в одном барьере от совершения этого прорыва, и если кто-нибудь может прислать несколько предложений или мест, где я мог бы искать, я был бы очень признателен.


person TCG    schedule 25.10.2014    source источник
comment
На вашем месте я бы попытался свести задачу к минимальному количеству строк. Может быть, просто обратный вызов, gtk_init, gtk_window_new и вызов g_signal_connect_data. Также сделайте то же самое на C и проанализируйте дизассемблирование.   -  person Lars Brinkhoff    schedule 25.10.2014
comment
Вы не нашли g_signal_connect, так как это макрос C. Настоящий обработчик — g_signal_connect_data.   -  person ntd    schedule 02.11.2014


Ответы (1)


FUNCTION: g_signal_connect_data ( wptr name callback data 0 0 -- ) Я вижу, вы используете такие вещи, как ' CB.DELETE.EVENT +ORIGIN для передачи в качестве параметра обратного вызова.

Разве вы не должны использовать обратный вызов Forth для начала? Ваш CB.DELETE.EVENT (и другие) нуждается в Forth-контексте и ожидает его.

В SwiftForth это может быть достигнуто с помощью

' CB.DELETE.EVENT 2 CB: *CB.DELETE>EVENT

Передайте *CB.DELETE>EVENT в качестве параметра обратного вызова для g_signal_connect_data

CB: создает оболочку вокруг CB.DELETE.EVENT, которая устанавливает временную среду Forth для запуска. См. руководство SwiftForth для доступа к параметрам, заданным для обратных вызовов. Конечно, другие обратные вызовы должны быть адаптированы аналогичным образом.

Примечание. SwiftForth обрабатывает ввод особым образом. Другие системы Forth отличаются тем, как они обрабатывают входные параметры обратного вызова. Но в целом хорошо не зависеть слепо от стека возврата. Всегда проверяйте документацию Forth.

В то время как слова библиотеки импорта облегчают выполнение функций, отличных от Forth, в среде Forth, обратное, запуская слова Forth во внешнем контексте, выполняется с помощью слов обратного вызова. Они позволяют использовать обработчики сигналов, обработчики завершения, обработчики исключений, процедуру запуска для потоков POSIX, реализации методов для классов Objective-C и т. д. и т. д. Многие системы Forth работают под управлением ОС, таких как SwiftForth, VFX, iForth, MacForth, iMops и Gforth. предоставить способы создания обратных вызовов Forth. Таким образом, любое утверждение о том, что Форт не может быть здесь использован, я думаю, опровергнуто. См. этот пример Forth + GTK.

Кстати, я запустил адаптированный код в SwiftForth OS X. ОК ;-)

person roelf    schedule 15.12.2014
comment
Я ценю ваши измененные комментарии. - person TCG; 20.12.2014