GTK+ 馬戲團:邪惡的 g_signal_connect 出場

GTK+ 馬戲團有五花八門的精彩表演,而今天壓軸好戲就是『邪惡的野獸 - g_signal_connect 』。g_signal_connect 可以戰勝所有的 widget 和 window,有強而有力的爪子,能劃破層層阻礙;有尖銳嚇人的牙齒,只須咬一口便深可見骨。雖然它已被馴服,但隨時還是有機會獸性大發反撲過來。:P

GTK+ Program 本身並不難,就算是第一次接觸的人,也能輕易上手並寫出什麼東西來。但對於較常接觸 GTK+ programing 的人,卻常會抱怨 GTK+ 的設計,層層的 window 和 widget 常搞到什麼事都要兜個大圈才能解決。而對 GTK+ 設計架構和細節了解不夠透徹的人,更是常常寫 5 分鐘 code ,卻要花 5 個小時 debug ,小弟我就是最好的例子 :(

所以,探討 GTK+ 的一些細節,有助於我們在撰寫 GTK+ 程式時避免問題的發生,減少 debug 的時間。

接觸過的人都曉得, GTK+ 的優點就是將各種東西都寫成一個個直接的 function call,任何人都可以很容易的去呼叫使用。但那些 function call 的背後常常各自為政互相打架,卡來卡去的結果不是『無限迴圈』就是『程式流程大亂』,我們如果不深入了解 GTK+ 的運作,這些問題將都會無解。

在 GTK+ 之中很多問題的發生,都是從邪惡的 g_signal_connect 開始。它是 GTK+ 各種物件的共通管道,programer 們可以利用它設定各種狀況的 handler,像是 widget 的 button-press-event, toggled ...etc。不過 g_signal_connect 所決定好的事,卻是有各種不同的觸發時機,有些會馬上就觸發如: toggled 事件,有些會在所有 event 處理完後,idle 時才觸發。若是沒有掌握好觸發的時機,一切的流程設計將會毀滅,而且找不到問題所在。

但是這些不同的時機,要深入了解 GTK+ Source 之後才會發現。對於一般 programer 來說,可沒這麼多時間一一深入了解每一個元件的運作,最好的解決辦法就是養成習慣,所有 widget 和 window 都設定好 Ready 之後,再呼叫 g_signal_connect 設定 event handler,這樣可以避免掉很多問題發生。

當然還有其他 g_signal_connect 衍生的問題,不過不再多提,有機會再整理成文好了。 :P

留言

  1. 其實重點就是....
    你 call 的每個 API 內部,都可能觸動該物件定義的事件
    如果在那個 API 操作了物件後,引發了一個事件,
    在你的 function call 還沒返回之前,
    這個事件,就會先沿著整個訊息的傳遞鍊,
    一個個傳遞到所有連接到這個 signal 的
    handler,直到所有 handler 都呼叫完,
    或是中途有人要求停止,打斷了這個傳遞
    你的 function call 才會返回。

    所以...當你在一個 signal handler 內,
    對自身物件呼叫其他 API 時,你要小心
    這個操作,可能會引起某些你沒想到的事件
    而這個事件,很可能會呼叫到你現在所在的handler。
    於是,在你的 function call 返回之前,
    你自己這個 handler 本身,又被呼叫了一次,
    就形成了遞迴,而被呼叫的 handler 裡面,
    又不小心觸動了同一個事件,導致自己本身
    的 handler 又被呼叫一次,變成無窮遞迴,
    最後的下場,當然就是 stack overflow。

    這只是眾多 gtk+ 陷阱之一而已 XD

    回覆刪除

張貼留言

這個網誌中的熱門文章

有趣的邏輯問題:是誰在說謊

Web 技術中的 Session 是什麼?

淺談 USB 通訊架構之定義(一)

淺談 USB 通訊架構之定義(二)

Reverse SSH Tunnel 反向打洞實錄