用 XRandR Extension 監控螢幕設定變化
最近一直感覺到系統有時莫名緩慢,CPU 負載也相當高,初期沒去注意,也一味的相信應該都是瀏覽器開太多網頁和 Flash 檔案所造成的,但種種情況令人不解,總覺得不完全是瀏覽器所造成的。將所有瀏覽器關閉後追蹤發現,自己之前寫的『JuShelf』(Dock 程式)竟吃掉近 50% 的 CPU 資源。原兇是之前寫的一段程式,用來偵測目前螢幕設定是否有改變,並依據螢幕設定而調整顯示位置,以讓 Dock 永遠顯示在螢幕的中央。
原本的做法相當笨,利用 g_idle_add_full() 讓程式空閒時就去偵測螢幕設定,但由於 Dock 通常是晾在一旁沒有工作的,所以程式經常有空閒時間,這讓程式以每秒百計的次數不停檢查。這還不打緊,由於每次檢查都要與 X Server 做一次至數次溝通,付出的代價更為高昂。
抓到臭蟲以後,便開始著手改進,使用了 XRandR Extension 來取代原有的解決方案。過去筆者曾撰文『寫支 C 程式用 XRandr Extension 設定你的螢幕解析度』說明 XRandR 的使用方式,不過當時只著重於取得 X Server 的顯示設定,這次將利用 XRandR Extension 以等待 RRScreenChangeNotify event 來得知螢幕設定何時改變。
由於完整程式太長,這邊只摘錄重點片斷,主要是檢查 XRandR 版本和註冊事件:
之後在等待 X Event 時,可以利用 ev->type - xrandr_event_base 去取得 XRandR 的事件:
後記
無論是舊的 GNOME 2.0 還是新的 GNOME 3.0,通常都在 gnome-settings-daemon 實作 XRandR 的事件監聽,所以才能實現自動切換螢幕設定,當 External Monitor 接上電腦時。
原本的做法相當笨,利用 g_idle_add_full() 讓程式空閒時就去偵測螢幕設定,但由於 Dock 通常是晾在一旁沒有工作的,所以程式經常有空閒時間,這讓程式以每秒百計的次數不停檢查。這還不打緊,由於每次檢查都要與 X Server 做一次至數次溝通,付出的代價更為高昂。
抓到臭蟲以後,便開始著手改進,使用了 XRandR Extension 來取代原有的解決方案。過去筆者曾撰文『寫支 C 程式用 XRandr Extension 設定你的螢幕解析度』說明 XRandR 的使用方式,不過當時只著重於取得 X Server 的顯示設定,這次將利用 XRandR Extension 以等待 RRScreenChangeNotify event 來得知螢幕設定何時改變。
由於完整程式太長,這邊只摘錄重點片斷,主要是檢查 XRandR 版本和註冊事件:
int rr_major_version, rr_minor_version; int rr_minor_version, xrandr_error_base; /* Initializing X Stuffs... */ /* XRandr extension */ XRRQueryVersion(disp, &rr_major_version, &rr_minor_version); if (rr_major_version < 1 || (rr_major_version == 1 && rr_minor_version < 2)) { printf("RANDR extension is too old (must be at least 1.2)\n"); return 1; } /* Allow XRandR Extension Event */ XRRSelectInput(disp, DefaultRootWindow(disp), RRScreenChangeNotifyMask); XRRQueryExtension(disp, &rr_minor_version, &xrandr_error_base);
之後在等待 X Event 時,可以利用 ev->type - xrandr_event_base 去取得 XRandR 的事件:
/* XRandr Extension Event */ switch(ev->type - xrandr_event_base) { case RRScreenChangeNotify: printf("Got RRScreenChangeNotify\n"); break; }
後記
無論是舊的 GNOME 2.0 還是新的 GNOME 3.0,通常都在 gnome-settings-daemon 實作 XRandR 的事件監聽,所以才能實現自動切換螢幕設定,當 External Monitor 接上電腦時。
留言
張貼留言