Недавно я наткнулся на статью Манфреда Махлоу четырехлетней давности, которая была близка к решению моей проблемы. В статье «Использование 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, при необходимости на ассемблере.
Я чувствую, что я в одном барьере от совершения этого прорыва, и если кто-нибудь может прислать несколько предложений или мест, где я мог бы искать, я был бы очень признателен.
g_signal_connect
, так как это макрос C. Настоящий обработчик —g_signal_connect_data
. - person ntd   schedule 02.11.2014