2009年1月27日 星期二

_NET_WM_ICON 資料在64bit OS上之輸出

0 意見

日前由於手上有一個64bit的Linux,便幫忙PCMan前輩測試了一段程式碼,茲將心得貼於下方。

此bug由來是因為Lxpanel中的工作列上,工作圖示無法正確顯示。




先來看看來自xmisc.c的原始碼:

data=alloca((pib.width*pib.height+2)*sizeof(long));
data[0]=pib.width;
data[1]=pib.height;
for(j=0;j
a=&(pib.pixelPtr[j*pib.pitch]);
r=&(a[pib.offset[0]]);
g=&(a[pib.offset[1]]);
b=&(a[pib.offset[2]]);
a=&(a[pib.offset[3]]);
p=&(data[2+j*pib.width]);
for(i=0;i
*p=(*a<<24)|(*r<<16)|(*g<<8)|*b;
p++;
a+=pib.pixelSize;
r+=pib.pixelSize;
g+=pib.pixelSize;
b+=pib.pixelSize;
}
}


這邊將這些顏色資料宣告為long並儲存

根據 freedesktop.org 規範視窗管理程式的 EWMH spec,視窗的圖示 (顯示在視窗左上角那個),是用 property 的方式儲存,其他程式可以透過讀取視窗的 _NET_WM_ICON 這個 property,來取得視窗的圖示。

EWMH spec 原文:

_NET_WM_ICON CARDINAL[][2+n]/32

This is an array of possible icons for the client. This specification does not stipulate what size these icons should be, but individual desktop environments or toolkits may do so. The Window Manager MAY scale any of these icons to an appropriate size.

This is an array of 32bit packed CARDINAL ARGB with high byte being A, low byte being B. The first two cardinals are width, height. Data is in rows, left to right and top to bottom.

照這段說明所寫,我們呼叫 Xlib 的函數 XGetWindowProperty 來取得視窗的 _NET_WM_ICON 這個 property 時,他會以一個陣列的形式傳回視窗的圖示,而陣列中的每個元素儲存的,是圖示上每個畫素的 32 位元 ARGB 值。在陣列的開頭兩個元素儲存的,分別是圖示的寬度和高度。

所以我們預期,XGetWindowProperty(); 會傳回給我們的是一個 32 位元整數的陣列,開頭兩個元素是圖示的寬度和高度,而後面的其他元素則是點陣圖的 pixels 資料。

LXPanel的taskbar.c中的原始碼則為:

if(result == Success)
{
guint32* pdata = data;
guint32* pdata_end = data + nitems;
guint32* max_icon = NULL;
guint32 max_w = 0, max_h = 0;

/* get the largest icon available. */
/* FIXME: should we try to find an icon whose size is closest to
* iw and ih to reduce unnecessary resizing? */
while(pdata + 2 < w =" pdata[0];" h =" pdata[1];" size =" (w" w="%d," h="%d," size="%d">


這邊是使用guint32來撈出資料。在32bit OS上,這段程式碼很正常;但在64bit OS上,我們卻發現回傳的值是64bit的array

底下這段測試程式碼來自好友rick68
int main(void)
{
printf("sizeof(int) = [%d]\n", sizeof(int));
printf("sizeof(long) = [%d]\n", sizeof(long));
printf("sizeof(long long) = [%d]\n", sizeof(long long));

return 0;
}


將這個程式在32bit OS下編譯執行,產生結果為:
sizeof(int) = [4]
sizeof(long) = [4]
sizeof(long long) = [8]

在64bit OS下編譯執行,結果則為:
sizeof(int) = [4]
sizeof(long) = [8]
sizeof(long long) = [8]


這邊可以發現,long的長度在32bit OS下是32bit,而在64bit OS下則為64bit。

查詢 XgetWindowPropert 的文件,找到如下的敘述:

If the returned format is 8, the returned data is represented as a char array. If the returned format is 16, the returned data is represented as a array of short int type and should be cast to that type to obtain the elements. If the returned format is 32, the property data will be stored as an array of longs (which in a 64-bit application will be 64-bit values that are padded in the upper 4 bytes).


如果傳回的 format 是 32,代表資料是 long integer 陣列 (在 64 位元程式內就會是 64 位元)。也就是實際上資料只有 32 bit,但是他傳回的會是加上 4 bytes 作 padding 的 64 bit 整數,所以程式的處理必須用 long int 的 array,而不是 32bit int。

因此若使用guint32儲存,在64bit OS上就會發生錯誤。將guint32改用gulong來撈取資料後此問題就正常了,也可正常顯示icon



參考資料
http://code.google.com/p/gatos2/source/browse/trunk/avview/xmisc.
http://mlblog.osdir.com/video.gatos.devel/2005-10/msg00031.shtml
http://www.mail-archive.com/rxvt-unicode@lists.schmorp.de/msg00321.html
http://standards.freedesktop.org/wm-spec/wm-spec-latest.html#id2552223
http://linux.die.net/man/3/xchangeproperty

特別感謝PCMan大哥檢視並修改此篇文章!
深入閱讀......

2009年1月14日 星期三

讓OpenSUSE 11.0 每個虛擬主控台都有背景

0 意見

日前使用openSUSE 11.0,驚訝於他的tty1有背景。但其他tty就沒有相對應的背景,因此上網找資料想達成這個目的。
以下即為我找到的方法

openSUSE的文字背景,是bootsplash這個程式提供的功能。
這個程式主要提供開機畫面(silent),以及tty背景畫面。

該程式主要設定檔在/etc/splashy/config.xml
主題放在/etc/bootsplash/themes/資料夾中
預設主題為openSUSE,在其中的config資料夾中,存有不同解析度的config檔案。
但這些config檔案載入以後會秀出silent的畫面,也就是會出現開機畫面。
因此我們要對這個檔案作修改,讓它只含有background的設定。


深入閱讀......

2009年1月2日 星期五

Python特色簡述-變數與記憶體管理

0 意見

Python是一個專注於易讀性與一致性的程式語言。
小弟將最近學習Python所感受到的一些Python的特色紀錄於下。

Python的主要變數型態有:number string list tuple dictionary
其中number list tuple是不可變更的,dictionary的key也是不可變更的(但可新增)。
雖說這些變數不可變更,我們仍可透過指定新值的方式去變更。
而tuple是list不可變更的版本,若是希望程式的list不要在執行過程中變更,一開始可宣告為tuple
list tuple dictory都可任意巢狀化。

為何list內可以不限定資料型態,且可自由巢狀化?
這是因為Python的變數事實上不是存放物件本身,而只是Reference,類似C語言的指標,指向物件所在之記憶體位置。當指定新值給變數時,就是改變Reference指向新的物件。
因此當list中某一欄的指標指向新的list,就成為巢狀結構了。


深入閱讀......