2

私は最近、4 年前の Manfred Mahlow の記事に出くわしました。記事「Glade を使用して Forth で GTK+ アプリケーションを作成する」では、シグナル ハンドラーに触れ、Forth は使用できず、C のみで作成できると述べました。私の問題はまだ小さなものだと思いますが、困惑しています。どんな提案にも非常に感謝しています。次に、アドレスにダッシュを使用せずにマーロウ氏にメールを送信する方法を誰かが知っている場合は、それを聞いてみたい.

Linux バージョンのSwiftForthを使用してカスタム ウィンドウを作成し、キーを押してそのウィンドウに書き込むアプリケーションを作成しています。私の目標は、Charles Moore のcolorForthを実装し、強化され、よりユーザーフレンドリーになることです。GTK+についてほとんど知らずに使用することにしましたが、コールバック (シグナル ハンドラー) 以外は成功しています。コードは全部で 2 ページしかないので、ここに置きます。

\ ------------------------ 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 コードが行うことをシミュレートする方法があることを願っています。

私は、このブレークスルーを達成するにはあと 1 つのハードルがあると感じています。誰かがいくつかの提案や私が見るべき場所を送ってくれたら、とても感謝しています.

4

1 に答える 1

3

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:実行する一時的な Forth 環境を確立するラッパーを作成CB.DELETE.EVENTします。コールバックに指定されたパラメーターにアクセスするには、SwiftForth のマニュアルを参照してください。もちろん、他のコールバックも同様に調整する必要があります。

注: SwiftForth は特定の方法で入力を処理します。他の Forf システムは、コールバック入力パラメーターの処理方法が異なります。しかし、一般的には、リターン スタックに盲目的に依存しない方がよいでしょう。常に Forth のドキュメントを確認してください。

import-library ワードは、Forth 環境での非 Forth 関数の実行を容易にしますが、逆に、外部コンテキストでの Forth ワードの実行は、コールバック ワードで行われます。これらは、シグナル ハンドラー、完了ハンドラー、例外ハンドラー、POSIX スレッドの開始ルーチン、Objective-C クラスのメソッド実装などを可能にします。 SwiftForth、VFX、iForth、MacForth、iMops、Gforth などの OS で実行される多くの Forth システムForth コールバックを作成する方法を提供します。したがって、ここで Forth を使用できないという主張は反駁されていると思います。この Forth+GTK の例を参照してください。

ところで、私は SwiftForth OS X で適合コードを実行しました。OK ;-)

于 2014-12-15T19:45:14.107 に答える