發表文章

目前顯示的是有「GTK」標籤的文章

GTK+ 全面進化

圖片
Moblin 帶來的震憾莫過於 3D 樣貌的 UI,其底層 Clutter Toolkits 提供方便易用的 API,確實讓開發者能輕易撰寫炫麗的界面。不過,Clutter 的角色一直被視為一套新的 3D Engine,只是讓人重新打造操作介面而已。這未免小覷了 Clutter 的威力,其真正的好戲,在結合了 GTK+ 之後才正要開始。 這是一段結合 GTK+ Notebook Widget 的展示,隨著觸發而產生的換頁特效: 借由 Offscreen 的實作,可將各種 GTK+ Widget 畫在 Clutter Actor 之上,以此做各種動畫效果,其架構如下所示: 我們可以視為 GTK+ Widget 被轉換成一個個 Clutter Actor,當然這些 Widget 仍然還保留著原本各種 GTK+ 的性質,包括 Signal 等機制,只不過在顯示上,Widget 並非直接被畫在螢幕上,而是畫在 Clutter 的 Buffer 上,讓最後的繪圖動作都交由 OpenGL 做處理。此外,Clutter-GTK 實作了一個假的 GtkWindow 以騙過 GTK+ Toolkits,達成結合兩者的目的。 雖然現在許多 UI 設計都是一窩蜂照抄 iPhone,但不可否認,舊有的使用者習慣還是存在,畢竟遵循舊有習慣的軟體數量太多,還是不太可能一時間淘汰掉。但是, Clutter 給了一個新的機會,讓被人稱為極落伍的 GTK+ UI 有再進化的空間,至於能做到什麼程度,就看各開發者的創意了。

心得分享簡報上線:桌面開發、快速開機、快速開發

本次分享活動應熱烈,差點沒把敝人搾乾。而簡報以『作中學』為主要訴求,對像以對程式開發有興趣的普通人為主,應要求,『領進門』是本次分享的重點,所以不談論太高深的進階內容,並附上些簡單上手之實例。 本次三個簡報和相關範例檔案可在此取得: 桌面開發 desktop_dev.pdf easy-ui-design.tgz 快速開機 fastboot.pdf 快速開發 fastdev.pdf fastdev.tgz Autotool 懶人包: project_example.tgz 若有更多疑問,可直接與本人連繫和交流,能力所及,將不吝答覆。

改變 GtkWidget 的 parent

GTK程式通常是由一個個 Object 所堆積起來,所以 GtkWidget 和 container 都記錄著 parent/child (父/子)的關係。又因為一個 GtkWidget 不能同時擁有兩個 parent,通常,所有的父子關係都是在程式初始化時就被決定好。然而在某些情況,為節省功夫或記憶體,我們會想重覆利用一個 GtkWidget 或是某 container 之下整個體系的成員,而不是重覆描繪類似或一模一樣的介面內容。 遇上這種需求,GTK 提供了一個 function call 可去改變 Widget 的 parent: void gtk_widget_reparent(GtkWidget *widget, GtkWidget *new_parent) 當然,重新被賦予 parent 的 Widget 會被當成最後一個 child widget,換句話說,若是在 Box 中,會被排列顯示在最後,這時我們可以用此 function 去調整其 widget 在 box 中的位置: void gtk_box_reorder_child(GtkBox *box, GtkWidget *child, gint position) 後記 一個簡單的小技巧,在此筆記之。

GLib 就是懶.為一些 G stuffs 加上多國語言支援

一般來說,實作一個多國語言的應用程式,會在需要被翻譯的字串上做特殊標注或處理。為了減少標注所浪費的字元數,在 『gi18n.h』中更近一步定義了 _(String) 和 N_(String) ,用以取代原本的 gettext(String)。 事實上,多國語言支援的內部實作,就是呼叫 gettext() 去處理並依情況而填入不同語言的字串,當找不到符合系統語言的翻譯檔時,便會使用開發時所標注的原始語言。使用 #define 去定義成 _(String) 這種形式,也只是圖個方便使用罷了。 然而,N_(String) 又是什麼?和 _(String) 使用的時機不一樣,是用來針對一些 static variable 所提供的多國語言支援方法。之前說到,其實 _(String) 是使用 gettext() 這 function 做字串處理,這在多數狀況下都是可行的,但是在某種情況下,直接使用 gettext() 去對字串做翻譯替換確是有很大的問題。 用一些例子會更為清楚,宣告一個靜態的陣列,裡面事先填好一些字串〔這裡使用 GtkItemFactoryEntry 的資料結構當範例〕: static GtkItemFactoryEntry menu_items[] = { { N_("/_File"), NULL, NULL, 0, "<branch>" }, { N_("/_File/_New Window"), NEW_WINDOW_ACCEL, newwindow, 1, "<stockitem>", GTK_STOCK_ADD } }; 其中,『/_File』和『/_File/_New Window』分別使用 N_(String) 被標示成需要被翻譯。為什麼在這不使用 _(String) 而是使用 N_(String) ?因為這是一個靜態的變數陣列,無法要求這陣列被存取時,使用 function 去動態取得字串資料然後再填入陣列,這本身並不符合陣列的行為和定義。可是,不能使用 _(String) 就意味著靜態陣列裡的字串,沒辦法支援多國語言。因此,N_(String) 就是在這樣的問題發生之下,被創造出來的方法,在這特殊的情況中被用來代替 _(St...

活用 g_object_weak_ref 避免 memory leak

這是一個常見又惱人的問題 - Memory Leak 記憶體洩漏。常見的情況是軟體用一段時間後,記憶體使用量肥大,在許多功能複雜的軟體之中,不免會看到這類的情形。不過我們不能完全怪罪軟體設計者〔雖然他們還是佔很重要的因素〕,對程式開發者來說,要達成完全 Leak-free ,幾乎是不可能的事,因為除了自己寫的程式之外,各種 system call 都有可能造成 memory leak 的發生〔如 pango〕。 不過話說回來,system 裡各種 library 所造成的 memory leak 畢竟還是少量,軟體開發者所造成的問題佔著大多數,一個真實的例子:從 Firefox 每次 release 就一直在修正 memory leak 就可以發現修也修不完。 來探討 memory leak 的形成原因,顧名思義就是漏水,記憶體外漏產生了無法控制的記憶體區塊。舉個簡單的例子: void func() { char *p; p = (char *)malloc(12); p = (char *)malloc(10); free(p); } 此例的程式碼會出現 12 bytes 的 memory leak,因為第一次 malloc 取得的記憶體區塊未被釋放。換句話說,在第二次 malloc 之後,我們已經失去前一次記憶體區塊的位址了,該區塊對我們來說,已經是再也無法控制的記憶體區塊〔因為不知道位址〕,但他仍然會在程式結束前活在那。如此一來,要是我們重複呼叫此 function ,每次都會造成 12 bytes 的浪費。 當然,這是明顯可以看出 memory leak 存在的例子,有很多情況是很難發現問題的,尤其是在結構複雜的程式中。 有一個情況是這樣,在 Gtk+ 程式的設計中,常會臨時建立一個 structure 傳給 Widget event 的 callback function,程式碼大致如下: s = malloc(struct cb_s); g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(cb_func), s); 和傳統的程式不同,我們不能在 g_signal_connect 之後就用 g_free() 去釋放 s,因為在 menu_item 這 ...

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,這樣可以避...

使用 GtkStatusIcon 實作 System Tray

圖片
孤陋寡聞的我,一直都還在用 libegg EggTrayIcon 去撰寫 System Tray。由於過去寫的程式通常只是顯示一個 Icon 在 System Tray Bar 上,所以長久以來也沒有碰到什麼問題。直到這兩天在設計 Network Status 的 Display on System Tray時,才發現 EggTrayIcon 缺少一些重要的功能。查明後,才知道必須使用 libegg 的 EggStatusIcon 等其他 Functions 去實作那些功能。 得到答案本該是很開心的,但非常不幸的,同時也在 libegg 的 CVS 裡,得知了 libegg 已停止開發的消息﹝消息還是 2006 年的!﹞。文中說到了因為 Gtk-2.10 以後,規範了一個標準的 GtkStatusIcon Widget 去實作 System Tray,導致 libegg 便不再有存在的必要性,因此不再繼續維護下去。 關於 GtkStatusIcon 的詳細說明文件,可以在【 GNOME Documentation Libaray -- GTK+ Reference Manual 】找到,有興趣的人可以去參考參考。 就單純的 Hello World Program 來說,用 GtkStatusIcon Widget 去實作 System Tray 非常容易,下面是一個簡單的範例: #include <gtk/gtk.h> int main(int argc, char **argv) { GtkStatusIcon *tray_icon; gtk_init(&argc, &argv); tray_icon = gtk_status_icon_new(); gtk_status_icon_set_from_file(tray_icon, "/tmp/trayicon.png"); gtk_status_icon_set_tooltip(tray_icon, "Hello Tray Icon!!"); gtk_status_icon_set_visible(tray_icon, TRUE); gtk_main(); return 0; } 另外順便也展示一...