歡迎您光臨本站 登入註冊首頁

EGUI 嵌入式圖形系統文檔

admin @ 2014-03-25 , reply:0

概述

     EGui是一個基於LinuxFramebuffer的嵌入式圖形系統,採用完全開放源代碼方式發布代碼。並且EGui圖形代碼將會完全免費。&nb……

     EGui是一個基於Linux Framebuffer的嵌入式圖形系統,採用完全開放源代碼方式發布代碼。並且EGui圖形代碼將會完全免費。
     EGui目前基本完成圖形系統的完整的框架,有window管理,事件管理和事件分發,timer的實現,widget實現了一部分。

1. EGui 簡介
EGui是一個基於Linux Frame buffer的嵌入式圖形系統,希望它能為Linux提供嵌入式解決方案。關於他的其他的簡介我做了一個FAQ。

  1.  EGui 的網路資源有哪些?
      web: wwww.egui.org
           他其實連接到cnix.sf.net
      bbs: www.linuxfans.org 的 "EGui開源項目" 版塊.
           bbs上有文檔和下載.
           cnix.sf.net也都有文檔和下載的連接地址.
  2.  EGui適合什麼操作系統?
    Linux ,只支持2.6.xx版本.
  3. EGui和當前那個圖形最接近?
    GTK+FB.需要Framebuffer支持.或者QT/E。
  4. EGui採用C/S結構嗎?
    不需要,運行應用前,./bin/load_driver.sh即可.
    EGui本身帶有驅動模塊。窗口管理,事件管理都在驅動層實現。
  5. 怎麼編譯?
    如果在PC
    make
    make install
    如果在嵌入式平台:
    修改config.mk CROSSCOMPILER=arm(mipsel)-linux-
    修改src-gui/driver/Makefile KERNELSRC=/yourkernel
    make
    make install
  6. 怎麼運行?
    運行 make install命令后
    就會將編譯的程序複製到 ./bin目錄下了.
    ./load_driver.sh //安裝驅動模塊
    ./ewm *.bmp& //啟動背景桌面程序,bmp要24位色
    ./fifteen //遊戲程序
    ./testegui //jawbreaker 遊戲程序.
    ./monitor  //CPU使用狀態監視器.

1.1. 編譯環境
在Fedora core 4上一步步建立環境
1
update FC4 kernel 2.6.12-1.1447_FC4
1: download kernel-2.6.12-1.1447_FC4.src.rpm
2: rpm -ivh kernel-2.6.12-1.1447_FC4.src.rpm
3: cd /usr/src/redhat/SPECS/
4: uname -i
if your computer is i386,do so.
vi kernel-2.6.spec
modify
%define all_x86 i586 i686
as
%define all_x86 i586 i686 i386
5: rpmbuild -bb kernel-2.6.spec
6: cd /usr/src
7: ln -s /usr/src/redhat/BUILD/kernel-2.6.12/linux-2.6.12/ linux
8: cd linux
9: cp configs/kernel-2.6.12-i686.config .config //your computer CPU match config filename.
10: make menuconfig // save and exit
11: make all
12: make modules_install
13: make install
14: vi /boot/grub/grub.conf
add as follow:
title Fedora Core (2.6.12)
root (hd0,5)
kernel /boot/vmlinuz-2.6.12-1.1447_FC4.root ro root=LABEL=/ rhgb quiet
initrd /boot/initrd-2.6.12-1.1447_FC4.img

2修改啟動選項
config for Egui
1: compile kernel add framebuffer support and add your VGA card driver
2: modify /boot/grub/grub.conf
kernel /boot/vmlinuz-2.6.12-1.1447_FC4.root ro root=LABEL=/ rhgb quiet vga=0x316
add vga=0x316 //1024x768-16bbp mode
3: reboot your computer

1.2. 下載編譯EGui
下載地址:
http://www.linuxfans.org/nuke/modules.php?name=Site_Downloads&op=mydown&did=4269
此版本是這次文檔指定版本。
$ tar zxvf EGui-2006-04-16.tar.gz
$ cd EGui
$ make
$ make install //僅僅複製文件到./bin目錄。
1.2.1. 交叉編譯
$ tar zxvf EGui-2006-04-16.tar.gz
$ cd EGui
修改 config.mk
CROSSCOMPILER=mipsel-linux-
修改 src/driver/Makefile
KERNELSRC :=/usr/src/linux
$ make
$ make install //僅僅複製文件到./bin目錄。

1.3. 運行程序

  1. $ cd bin
    $ ./load_driver.sh #使用root用戶。
  2. $./ewm new.bmp >>/dev/null & ###啟動root窗口程序。顯示背景桌面。
    $./testegui >>/dev/null & #啟動jawbreaker遊戲程序

第2步可以修改 run-egui.sh實現
#!/bin/bash

./ewm EGui.bmp >>/dev/null &
sleep 3
./testegui >>/dev/null &

1.4. 截圖參考
 

2. EGui框架
這部分主要介紹EGui的整個框架部分,讓大家了解EGui的架構及其代碼的分佈情況,並不介紹其細節或者實現方法。
詳細的細節和實現方法將在以後的各部分詳細說明。
 

上圖是EGui的框架示意圖。
EGui本身應該是三個部分,加上應用的調用部分就是四個部分。
 Kernel驅動部分;
 Libegui部分;
 Libwidget部分;
 應用程序;
2.1. Kernel驅動部分
這部分主要作用:
 獲取framebuffer信息;
 創建/dev/egui設備文件號,默認是 c 240 0;
 分配窗口的ID號;
 獲取輸入事件,並且分發給窗口;
 儲存窗口的信息,包括位置;
代碼分佈:
Src-gui/driver/
2.2. Libegui部分
這部分主要作用:
 從/dev/egui 獲取和kernel通訊的設備的fd號;
 從/dev/fb? 獲取framebuffer地址;
 對顯卡的讀寫實現,包括:點,線,矩形,圖片;
 窗口的實現,繪製;
 游標的移動和繪製;
 事件傳給widget;
代碼分佈:
Src-gui/egui
2.3. Libwidget部分
這部分主要作用:
 創建不同類型的widget,例如:button,form,pixmap,edit等等;
 採用統一介面實現widget的顯示,事件,等等;
 事件的分發;
 父子widget機制的實現;
代碼分佈:
Src-gui/widget
2.4. 應用程序
EGui目前帶有部分測試程序,代碼都在demo/目錄;
 ewm,桌面管理;
 fifteen,十五個button排序遊戲;
 test , jawbreaker遊戲;
 bmp, 顯示和截圖程序;截圖程序將圖片存儲為 24位色BMP格式。
./capturebmp a.bmp
Chmod +r a.bmp
2.5. 其它說明
Include/common.h 和src-gui/driver/common.h是相同文件的複製,目的在於讓src-gui/driver能獨立編譯。
3. 窗口和事件的實現
3.1. 數據結構說明
先解釋幾個重要的數據結構大都來自common.h
3.1.1. struct _EGui_FBinfo {
  int             dev ;          // fb0,fb1,fb2
  int             screen_width;  // 1024
  int             screen_height; // 768
  int             bpp;           // 16
  unsigned char * Egui_phyaddress;
  unsigned char * smem_len;

  int             p_width;       // 1024 * 2,use by program
  int             p_height;      // 768 ,use by program
  int             p_bpp;         // 2 ,use by
  unsigned char * Egui_address;  //mmap address

  char            fbdevfile[8];

  int             red_length   ;
  int             green_length ;
  int             blue_length  ;
  int             red_offset  ;
  int             green_offset;
  int             blue_offset ;
  EGui_Window     *ewindow;
} ;
  int             dev ;          // fb0,fb1,fb2
  int             screen_width;  // 1024
  int             screen_height; // 768
  int             bpp;           // 16
  unsigned char * Egui_phyaddress;
  unsigned char * smem_len;
上面的部分來自framebuffer信息,
 
 int             p_width;       // 1024 * 2,use by program
  int             p_height;      // 768 ,use by program
  int             p_bpp;         // 2 ,use by
  unsigned char * Egui_address;  //mmap address
這部分是程序轉換后的結果,經常會拿來使用。

3.1.2. 
struct _EGui_Window {
  int pid;          /* program id */ 建立窗口進程的ID.
  Ecolor  *bgcolor;            /* background color */窗口的背景顏色
  short x, y;                   /* start postition */窗口在屏幕的開始坐標位置。
  short width, height;          /* windows w ,h  */窗口的寬和高
  short max_width;              /* visible w */
  short max_height;             /* visible h */
  short id;          /* windows id */
  char  name [NAMELEN];         /* windows name */
  char window_type;
  short   title_h;              /* title hieght */
  short   frame_w;  /* frame width */
  unsigned char  *savebuf; /* save buffer window size */
  unsigned char  *saveself; /* save oneself */
  EGui_Window *twindow; /* top window */
  EGui_Window *bwindow; /* bottom window */
  EGui_FBinfo *fbinfo;
  /* follow struct only can use in kernel
   * Don't use in use mode.NOTE::
   */
  window_list *window_list;

} ;
窗口的ID:窗口的ID號從1-0xFE,為普通的窗口號,最大支持255個窗口,
0xFF為特殊的ROOT窗口。
EGui目前設計彈出式菜單,和彈出窗口為普通窗口,其他的widget不算窗口。沒有窗口ID。
window_list *window_list;這個結構在kernel里使用,應用部分不可訪問。

3.1.3. struct _EGui_Event {
  short x;   /* cursor x */當前游標的位置
  short y;   /* cursor y */
  int type;                     /* event type */
  int code;   /* key code */
  int pid;
} ;
Type:有以下幾類。新的代碼已經有些改變了。
/* EGui Event type */
#define PRESS_KEY              1
#define CLICK_LEFT             2
#define CLICK_RIGHT            3
#define CLICK_MIDDLE           4
#define REL_LEFT               5
#define REL_RIGHT              6
#define REL_MIDDLE             7

#define RELEASE_KEY            8
/* These are events about window,
 * they aren't input device events.
 */
#define FOCUS_CHANGED          9 /* window's focus change */
#define W_MOVE                 10 /* window's move event */
#define W_SIZE_CHANGED         11 /* window's size change */
#define CURSOR_MOVE            12 /* only cursor move */
#define HIDE_CURSOR            13 /* cursor hide */
#define REDRAW_RECTANGLE       14
3.1.4. struct _window_list {
  struct list_head *next, *prev;
  /* save data for window */
  EGui_Window *window;                    /* window */
  unsigned char *width_in;
  unsigned char *height_in;
  int pid;          /* program id */
  short  id;   /* window id */
  wait_queue_head_t  event_wait;   /* Zzzzz ... */
  int done;
};
這是個列表,用來將window連接在一起,排在鏈頭的是焦點窗口,依次往後排列。
這樣ROOT窗口應該排在鏈尾。
 
unsigned char *width_in;
  unsigned char *height_in;
用來記錄窗口的位置,width_in,height_in字元長度為屏幕長度,窗口所佔用部分為1,其他為用:
例如屏幕位1024x768,窗口開始點位 20,32.寬為100,高為50那麼,
Width_in 長度為1024,從width_in[20]-----width_in[120],為1,其他部分為0。
Height_in 長度為768,從height_in[32]-----height_in[82]為1,其他部分為0。

event_wait:每個窗口都有此數據結構,當沒有事件產生時,窗口處於等待狀態。
為了配合timer使用,此等待達到10毫秒就會返回。

3.2. 窗口的實現
目前窗口有create,draw,close,move功能。
3.2.1. 窗口的create
首要函數在src-gui/egui/window.c
Egui_CreateWindow ( EGui_FBinfo *fbinfo,short x,short y,
    short width,short height, Ecolor * bgcolor,char window_type)
此函數主要做以下幾件事情:
 申請EGui_Window數據空間,設置pid,位置,背景色,類型等。
 通過ioctl 通知kernel建立window_list.

Kernel部分需要工作:
代碼在src-gui/driver/kegui.c
new_window ( void __user * argp)
通過map表申請id,添加新的window_list,
主要為了在kernel里管理窗口。
3.2.2. 窗口的draw
首要函數在src-gui/egui/window.c
Egui_drawwindow ( EGui_Window *ewindow)
主要繪畫窗口的標題欄,標題,和邊框。

3.2.3. 窗口的close
在kernel里從map表裡釋放ID,釋放window_list表。

3.2.4. 窗口的查找
窗口的查找主要是游標對應的窗口,從而分發游標事件。
所以src-gui/driver提供了窗口查找函數。
為了方便,可以通過pid,id查找窗口。

3.3. 事件的實現
圖形窗口主要為了方便人機交互,所以事件的管理是圖形系統的一個關鍵部分。
鍵盤輸入的管理很簡單,一般都是將按鍵交給焦點窗口,但是滑鼠事件就非常複雜。
需要查找游標所對應的窗口。

3.3.1. EGui事件的獲取
Kernel部分:
EGui事件在kernel部分獲取鍵盤,滑鼠等input事件。
利用kernel的input機制,註冊event_handler函數,這樣就可以獲取所有通過input註冊的輸入事件。這一點不需要像其他的圖形系統一樣繁瑣的去猜測到底系統是什麼滑鼠,或者什麼鍵盤。
在src-gui/driver/event.c里有下面的函數。
egui_event (unsigned int type,unsigned int code,
     int value)
當系統有任何輸入就會調用這個函數,我將這個事件通過游標所在窗口和焦點所在窗口方式將事件打包存放到事件對列里,當前列表裡存放了30個循環覆蓋事件。(當前版本代碼有點bug,新版本已經修改。)

Libegui部分:
   這部分代碼是給應用程序使用的,當應用程序所有的初始化工作完成以後,就會進入一個loop程序里。
 
代碼如下: 
while (1)
    {    /* loop get event */
      get_egui_event ();
      Egui_timer_handler();
    }
這裡有2個函數,分別是獲取事件和timer輪訓事件。

get_egui_event ();
在event.c里實現,通過ioctl獲取kernel事件,如果超過10毫秒沒有得到事件就返回。

Egui_timer_handler();
如果有timer事件就調用timer事件,如果沒有timer事件直接返回。
具體關於timer事件回調我們將專門的timer論題詳述。

細說get_egui_event();
當它通過ioctl獲取的事件應該是kernel已經計算好的為該進程的窗口事件,此文檔對應的版本,還沒有在一個進程實現多窗口,原因就是libegui里沒有再將事件對應的窗口查找出來。因為應用沒有作多窗口鏈表。這個以後肯定會實現。
目前實現的是將event給唯一的窗口,libegui里的event.c負責事件處理,將滑鼠和window事件操作傳給window.c,其他的傳給widget。

Libwidget的事件處理,他同kernel機制一樣,要分發事件給具體的widget.

3.3.2. 事件處理類型
Libegui部分:
CLICK_LEFT:這個部分是判斷一個單擊左鍵產生后是否在window的標題欄內,如果是則可以移動窗口。
W_MOVE:(後來版本已經改變)
移動窗口
HIDE_CURSOR:
這是Egui的一個特殊實現,當游標從A窗口,移動到B窗口時,先是進程(A窗口所在的進程)A1移動滑鼠,后是進程B1移動滑鼠,但是進程A1並不知道游標已經在進程B1了。所以這時同時出現2個滑鼠。這時kernel發送一個通知進程A1關閉滑鼠的事件。這個實現以後會改掉。
Libwidget事件:
PRESS_KEY:鍵盤輸入事件,目前傳給edit控制項。
其他事件,單擊,釋放,移動滑鼠等,都對應不同的控制項的不同操作,這部分在widget章節詳細描述。 

4. Widget的實現
Egui本身內置了widget實現,實現widget更多的是為了驗證窗口管理,拖動,事件管理的可行性。
主要是widget框架的搭建和實例的應用。
4.1. widget框架
widget_main.c
主要將申請的新控制項放入鏈表,採用樹狀結構
  
圖中A為window下連接的第一個widget,
A1,A2,A3為他的子widget,A1,A2,A3之間的關係為兄弟關係。
A11,A12位A1的子widget。A11,A12位兄弟關係。
這個框架應該不同多解釋。

那麼父與子是什麼關係呢?子widget要在父widget的區域內。
目前EGui的實現兄弟之間不交接。

除了鏈表外,widget_main.c還要查找event所屬與的widget。

Widget.c的作用:抽象層,大部分widget的操作,例如:
Draw,show,事件處理等都通過抽象層完成。

Widget目前支持click_left, press_key, rel_left, draw_in, draw_out等事件和事件的回調。
控制項的事件回調,應用最多的是button,一般我們都要處理滑鼠點擊button后的動作。
這時候會調用用戶自己寫的事件處理。
 
4.2. 控制項實例
目前實現的控制項不多,button,edit,pixmap,window,form.
這裡面其他的我不再細說,主要講window。為了不混淆概念,我用“w_win”,代表window的widget。“window”代表EGui_Window,就是真正的帶有ID的window。
為什麼再製作一個和window一樣的名字的widget呢?
主要是為了在全部的window大小範圍內實現widget可以控制的區域。
大家知道,EGui的widget裡子widget只能在父widget範圍內,所以關閉按鈕,window圖標就不好用widget去實現,所以我就做了一個w_win這個控制項,他就是widget鏈表圖中的A控制項。

5. Timer和其他實現
5.1. timer
這部分是我同事幫我做的,這部分實現和gtk非常像,因為我們不想用pthread去實現,所以要和event一起去通過loop來實現。因為event需要等待至少10毫秒才返回,並且,如果出現需要用很多時間來處理的event,就會造成timer被延時。所以一般來說這個timer的實現不要用來做精確定時。
雖然他的參數種,最小的單位是1毫秒,在實際應用中可能會是10毫秒,所以我建議大家使用這個timer時,用10毫秒的整數倍數去實現。

5.2. 其他實現
這是給這個文檔留的一個後門吧,原本的意思是寫一些我認為EGui里實現的比較好的閃光點拿出來給大家講講。
這部分文檔以後再陸續的去補充吧。

6. 總結
在5.1期間我將這個文檔趕製了出來,沒有時間去檢查,沒有時間去細化。加上我的文筆不好大家先看著,有什麼問題大家提出來,我再修改。
謝謝大家收看,休息時間馬上回來,祝大家節日快樂。


[admin via 研發互助社區 ] EGUI 嵌入式圖形系統文檔已經有7161次圍觀

http://cocdig.com/docs/show-post-42518.html