Sunday, January 27, 2008

Gtk Embedded MPlayer


Recently, I want to embed a mplayer into my gtk program. I use the -wid option of mplayer to assign the parent X Window ID and draw the mplayer on a GtkDrawingArea. However, It still need some control widgets to control the mplayer. MPlayer provide the -input option to read input command from a file. The file could be a UNIX FIFO, so others can send command to mplayer through fifo. The command list is here. ( you can see it by type "mplayer -input cmdlist").

seek Float [Integer]
pause
loop Integer [Integer]
volume Float [Integer]
mute [Integer]
get_percent_pos
get_time_pos
get_time_length

I write a simple widget to embed mplayer and provide some require api to specified command. The project is named GtkEmbMPlayer. Here is the code for version 0.1.0
There is also a sample program to demo the widget.
PS: the sample and the widget still buggy.

Monday, January 21, 2008

x window panel from scratch


最近正在看怎麼寫一個x window上的panel, 也就順便看了一下Window Manager的架構, 在網路上找了一下, 覺的最好的範例是fbpanel (http://fbpanel.sourceforge.net/) , 有興趣的人可以自己下載source code回來看看.
接下來就來說說如何自己寫一個panel, 其實panel也是一個window, 只是他多了一些不一樣屬性, 在這裡我就用程式碼來說明 (以下的程式碼大部分都使用GTK+, 如果不喜歡GTK, 可以直接使用XLib, 或是任何Toolkit找到相對應的api就可以了, 觀念都一樣, 甚至連api名字都差不多)
首先建立一個window

GtkWidget* panel = gtk_window_new(GTK_WINDOW_TOPLEVEL);

如同一般window一樣, panel也是一個TOPLEVEL的window,
將panel的decoration(視窗旁邊的裝飾)關掉,
gtk_window_set_decorated( GTK_WINDOW( panel), FALSE );

接下來是一些比較簡單的屬性, resizable, position
gtk_window_set_resizable( GTK_WINDOW( panel), FALSE);
gtk_window_set_position( GTK_WINDOW( panel), GTK_WIN_POS_NONE);


之後的屬性就需要window被realized以後才能夠更改, 所以我們這裡要先realized
gtk_widget_realize(panel);

skip task bar hint就是讓window manager在taskbar上不顯示這個視窗(panel不會出現在taskbar是很正常的一件事)
gtk_window_set_skip_taskbar_hint( GTK_WINDOW( panel) , TRUE );

skip pager hint有個很好的例子, 當按下Alt-Tab出現window list, 他不會出現在裡面(panel不會出現在pager也是很正常的一件事)
gtk_window_set_skip_pager_hint( GTK_WINDOW( panel) , TRUE );

然後讓panel永遠比別人大...阿...是在別的視窗上面啦
gtk_window_set_keep_above( GTK_WINDOW( panel), TRUE);

每個desktop都要看得到panel
gtk_window_stick( GTK_WINDOW(panel));

跟window manager講說這是個dock type的window
gtk_window_set_type_hint ( GTK_WINDOW(panel), GDK_WINDOW_TYPE_HINT_DOCK);


設定panel的大小跟位置
gtk_widget_set_size_request(panel, gdk_screen_width(), 64);
gtk_window_move( GTK_WINDOW(panel), 0, gdk_screen_height() - 64);


你以為這樣就結束了嘛?
並沒有, 最後設定_NET_WM_STRUT這個HINT讓Window Manager知道panel已經用掉視窗邊邊的某個區域了, 格式為
_NET_WM_STRUT, left, right, top, bottom, CARDINAL[4]/32
你塞進去的資料假設為一個unsign long[4],第0個代表螢幕左邊保留的寬度,下面以此類推
另一個HINT是_NET_WM_STRUT_PARTIAL可以用來通知windowmanager你只要預留邊邊域的一部分就好
_NET_WM_STRUT_PARTIAL, left, right, top, bottom, left_start_y, left_end_y,
right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x,
bottom_end_x,CARDINAL[12]/32
詳細請參照EWMH
gulong data[12] = { 0 };
data[3] = 64;//_panel->allocation.height;
data[4 + 3*2] = _panel->allocation.x;
data[5 + 3*2] = _panel->allocation.x + _panel->allocation.width;
gdk_property_change( _panel->window,
gdk_atom_intern("_NET_WM_STRUT_PARTIAL",FALSE),
gdk_atom_intern ("CARDINAL", FALSE),
32, GDK_PROP_MODE_REPLACE, (unsigned char *)data, 12);
gdk_property_change( _panel->window,
gdk_atom_intern("_NET_WM_STRUT",FALSE),
gdk_atom_intern ("CARDINAL", FALSE),
32, GDK_PROP_MODE_REPLACE, (unsigned char *)data, 4);

這樣就可以產生一個位在螢幕底部的panel, 裡面的東西就隨便你放啦