具體的代碼講解和調試請參看視訊:
Linux kernel Hacker, 從零建構自己的核心
我還記得,早年學習win32 GUI程式設計,通過調用一個API 叫MessageBox, 使得程式能快速彈出一個小視窗,當看到這個小視窗出現在螢幕上時,開心得不得了,覺得非常不可思議,它生動形象,跟原來在控制台上運作的,隻能給出黑底白色結果的dos程式完全不同,從此,我從黑色單調的世界進入了稱之為“圖形界面“的色彩斑斓的絕妙空間。
一直以來,我心中困惑着,這些形象生動而又具有立體感的小視窗到底是怎麼實作的,知道現在,有能力,有條件,開發一個系統核心時,我才能從底層原理上,了解這些動人小視窗的前世今生,這裡,我想和大家分享一下,他們是怎麼來到這個世界的。
前面幾節,我們花了不少精力去實作圖層的技術效果,現在,我們可以基于圖層的基礎上,看看那些花哨的界面是如何制作出來的,這節,我們看看,小小的MessageBox是怎麼創造出來的,先讓大家看看本節代碼運作後的效果:
一個小巧可愛的MessageBox躍然于桌面上,下面我們看看它的實作代碼:
void make_window8(struct SHTCTL *shtctl, struct SHEET *sht, char *title) {
static char closebtn[][] = {
"[email protected]",
"OQQQQQQQQQQQQQ[email protected]",
"OQQQQQQQQQQQQQ[email protected]",
"[email protected]@[email protected]@QQ[email protected]",
"[email protected]@[email protected]@QQQ[email protected]",
"[email protected]@@@QQQQ[email protected]",
"[email protected]@QQQQQ[email protected]",
"[email protected]@@@QQQQ[email protected]",
"[email protected]@[email protected]@QQQ[email protected]",
"[email protected]@[email protected]@QQ[email protected]",
"OQQQQQQQQQQQQQ[email protected]",
"OQQQQQQQQQQQQQ[email protected]",
"O$$$$$$$$$$$$$[email protected]",
"@@@@@@@@@@@@@@@@"
};
int x, y;
char c;
int bxsize = sht->bxsize;
int bysize = sht->bysize;
boxfill8(sht->buf, bxsize, COL8_C6C6C6, , , bxsize - , );
boxfill8(sht->buf, bxsize, COL8_FFFFFF, , , bxsize - , );
boxfill8(sht->buf, bxsize, COL8_C6C6C6, , , , bysize - );
boxfill8(sht->buf, bxsize, COL8_FFFFFF, , , , bysize - );
boxfill8(sht->buf, bxsize, COL8_848484, bxsize - , , bxsize - , bysize - );
boxfill8(sht->buf, bxsize, COL8_000000, bxsize - , , bxsize - , bysize - );
boxfill8(sht->buf, bxsize, COL8_C6C6C6, , , bxsize - , bysize - );
boxfill8(sht->buf, bxsize, COL8_000084, , , bxsize - , );
boxfill8(sht->buf, bxsize, COL8_848484, , bysize - , bxsize - , bysize - );
boxfill8(sht->buf, bxsize, COL8_000000, , bysize - , bxsize - , bysize - );
showString(shtctl, sht, , , COL8_FFFFFF, title);
for (y = ; y < ; y++) {
for (x = ; x < ; x++) {
c = closebtn[y][x];
if (c == '@') {
c = COL8_000000;
} else if (c == '$') {
c = COL8_848484;
} else if (c == 'Q') {
c = COL8_C6C6C6;
}
else {
c = COL8_FFFFFF;
}
sht->buf[(+y) * sht->bxsize + (sht->bxsize - + x)] = c;
}
}
return;
}
make_window8 函數是專門用來繪制這個小視窗的,大家可以猜到,closebtn這個數組,對應的是小視窗右上角的X按鈕,這個數組中,@元素所對應的就是圖像中關閉按鈕的小叉叉。該調用函數中,參數sht對應的就是該小視窗的圖層,代碼中,boxfill8這幾個函數的調用,作用是繪制視窗的主窗體,showString調用用來顯示小視窗上方的小标題,下面的兩個for循環這是用來繪制小窗台右上角的關閉按鈕。
接下來,我們再看看這個函數是如何被調用的:
void message_box(struct SHTCTL *shtctl, char *title) {
struct SHEET *sht_win;
unsigned char *buf_win;
sht_win = sheet_alloc(shtctl);
buf_win = (unsigned char *)memman_alloc_4k(memman, * );
sheet_setbuf(sht_win, buf_win, , , -);
make_window8(shtctl, sht_win, title);
showString(shtctl, sht_win, , , COL8_000000, "Welcome to");
showString(shtctl, sht_win, , , COL8_000000, "MyOS");
sheet_slide(shtctl, sht_win, , );
sheet_updown(shtctl, sht_win, );
}
message_box函數中,首先為我們的小窗台配置設定一個圖層對象sht_win, 并通過記憶體配置設定接口,配置設定一塊4k可用記憶體,這塊記憶體将用于存儲小窗台的像素資訊,同時把這塊記憶體跟圖層對象關聯起來,兩個showString的調用用來顯示窗體中間的字元串内容,sheet_slide使得窗體的左上角坐标為(80, 72),并且設定該窗體的高度為1,我們還記得,前一節我們将桌面的高度設定為0,把窗體高度設定為1,這樣它才能顯示在桌面之上。
我們看看主入口函數的改變:
void CMain(void) {
....
message_box(shtctl, "windown");
sheet_updown(shtctl, sht_back, );
sheet_updown(shtctl, sht_mouse, );
io_sti();
....
}
在入口函數中,我們調研message_box,這樣,一旦系統啟動之後,小視窗就會出現,注意到 sheet_updown(shtctl, sht_mouse, 100); 這一句,我們把滑鼠的高度設定成100,這樣滑鼠就可以出現在目前所有窗體的上方,我們可以做個有趣的小實驗,把滑鼠的高度改成1,把小窗台的高度改成2,我們可以得到下面的效果:
我們看到,滑鼠移動到小窗台區域時,它跑到了窗體的底部而不是上頭,這個效果也充分顯示了圖層高度的相應效果。
經過一系列的努力,我們已經成功進入到了色彩斑斓的GUI世界,這個世界還有很多奇妙秘密等待我們開發和挖掘,讓我們繼續努力吧^_^!