【问题标题】:GTK+ Forth callbacksGTK+ Forth 回调
【发布时间】:2014-12-20 21:13:39
【问题描述】:

我最近看到了四年前 Manfred Mahlow 的一篇文章,该文章几乎解决了我遇到的问题。文章“在 Forth 中使用 Glade 创建 GTK+ 应用程序”涉及到信号处理程序,指出不能使用 Forth,而只能使用 C 来创建它们。我认为我的问题仍然是一个小问题,但我很难过,我会非常感谢任何建议。其次,如果有人知道如何在地址中不使用破折号的情况下向马洛先生发送电子邮件,我很乐意听到。

我正在使用SwiftForth 的Linux 版本编写一个应用程序来创建一个自定义窗口并接收按键并写入该窗口。我的目标是实现 Charles Moore 的 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 代码的作用,如有必要,在汇编程序中。

我觉得我距离取得这一突破还有一个障碍,如果有人可以提出一些建议或我可能会看到的地方,我将非常感激。

【问题讨论】:

  • 如果我是你,我会尝试将问题归结为最少的行数。也许只是回调、gtk_init、gtk_window_new 和对 g_signal_connect_data 的调用。此外,在 C 中执行相同的操作并分析反汇编。
  • 您没有找到g_signal_connect,因为它是C macro。真正的处理程序是g_signal_connect_data

标签: callback gtk signals forth


【解决方案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 文档。

虽然 import-library 单词有助于非 Forth 函数 在 Forth 环境中运行,反之,在 Forth 环境中运行的话 一个外来语境,是用回调词来完成的。他们允许 对于信号处理程序、完成处理程序、异常处理程序, POSIX 线程的启动例程,Objective-C 的方法实现 类等,等等。许多在操作系统下运行的 Forth 系统,如 SwiftForth、VFX、iForth、MacForth、iMops 和 Gforth 提供了方法 创建 Forth 回调。所以任何 Forth 声明都不能在这里使用 我猜被驳斥了。见this Forth + GTK example

顺便说一句,我在 SwiftForth OS X 中运行了修改后的代码。好的 ;-)

【讨论】:

  • 感谢您修改后的 cmets。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多