消除圖層刷新而導(dǎo)致的嚴(yán)重閃爍-2

請參看視頻,已獲得更詳細(xì)的講解和展示
Linux kernel Hacker, 從零構(gòu)建自己的內(nèi)核

上一節(jié)院尔,我們消除了因刷新而導(dǎo)致的嚴(yán)重閃爍旧烧,但問題并沒有從根子上解決茁肠,因?yàn)楫?dāng)我們把鼠標(biāo)挪動(dòng)不斷刷新自己的Message Box上面時(shí)泽腮,發(fā)現(xiàn)鼠標(biāo)居然變得閃動(dòng)起來御蒲,這是因?yàn)椋?dāng)窗體自身刷新時(shí)诊赊,它會把處于它上方的窗體也進(jìn)行刷新厚满,而這種操作其實(shí)是沒有必要的。我們看下面這種情況:

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

所以數(shù)字1代表的是標(biāo)號為1的窗口所對應(yīng)的像素點(diǎn)碧磅,數(shù)字2所代表的是編號為2的窗口所對應(yīng)的像素點(diǎn)碘箍,顯然,窗口1的右下邊部分被窗口2所覆蓋鲸郊,并且窗口2比窗口1的高度還要高丰榴,當(dāng)窗口1的像素進(jìn)行刷新時(shí),如果窗口2的內(nèi)容沒有變化的話严望,那么窗口2 完全不需要進(jìn)行刷新多艇,這就要求窗口1只能更新那些沒有被窗口2覆蓋的點(diǎn),也就是說像吻,窗口1只能更新一下部分像素點(diǎn):

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1

也就是右下角那部分,他是不能去更新的复隆,這就要求拨匆,當(dāng)我們?nèi)ニ⑿嘛@存時(shí),必須知道哪一個(gè)像素點(diǎn)屬于窗口1挽拂,哪一個(gè)像素點(diǎn)屬于窗口2惭每,刷新時(shí),屬于窗口1的像素點(diǎn)亏栈,我就更新台腥,屬于窗口2的像素點(diǎn),我就忽略绒北,這樣才能解決上節(jié)看到的鼠標(biāo)閃爍的問題黎侈。這樣我們就需要在圖層的數(shù)據(jù)結(jié)構(gòu)中引入新的變量,用來記錄該圖層像素點(diǎn)所對應(yīng)的窗體編號闷游,代碼如下峻汉,win_sheet.h:

struct SHTCTL {
    unsigned char *vram, *map;
    int xsize, ysize, top;
    struct SHEET *sheets[MAX_SHEETS];
    struct SHEET sheets0[MAX_SHEETS];
};

上面的結(jié)構(gòu)體定義中贴汪,多增加了一個(gè)變量map, 它的作用就是用來記錄圖層每一個(gè)像素點(diǎn)所對應(yīng)的窗體編號的。在win_sheet.c中做如下更改:

struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram,
  int xsize, int ysize) {
  ....
   //為圖層像素編號數(shù)值分配內(nèi)存
    ctl->map = (unsigned char*)memman_alloc_4k(memman, xsize * ysize);
    if (ctl->map == 0) {
        memman_free_4k(memman, (int)ctl, SIZE_OF_SHTCTL);
        return 0;
    }
  .....
}

在初始化圖層信息時(shí)休吠,為map變量分配內(nèi)存扳埂,以便用來記錄圖層像素點(diǎn)的窗口編號。如何確定每個(gè)窗體圖層所對應(yīng)的編號呢瘤礁,很簡單阳懂,所有的圖層都是從圖層控制器SHTCTL 的圖層數(shù)組sheets0中分配的,我們把圖層對象在這個(gè)數(shù)值中的下標(biāo)作為它的窗體編號柜思,我們在win_sheet.c里面添加一個(gè)函數(shù)叫refresh_map希太,用來記錄當(dāng)前需要刷新的窗口的像素所對應(yīng)的編號。

void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) {
    int h, bx, by, vx, vy, bx0, by0, bx1, by1;
    unsigned char *buf, sid, *map = ctl->map;
    struct SHEET *sht;
    
    if (vx0 < 0) {vx0 = 0;}
    if (vy0 < 0) {vy0 = 0;}

    if (vx1 > ctl->xsize) {vx1 = ctl->xsize;}
    if (vy1 > ctl->ysize) {vy1 = ctl->ysize;}

    for (h = h0; h <= ctl->top; h++) {
        sht = ctl->sheets[h];
        //獲取圖層編號酝蜒,也就是圖層對象在圖層數(shù)組中的下標(biāo)
        sid = sht - ctl->sheets0;
        buf = sht->buf;
        bx0 = vx0 - sht->vx0;
        by0 = vy0 - sht->vy0;
        bx1 = vx1 - sht->vx0;
        by1 = vy1 - sht->vy0;

        if (bx0 < 0) { bx0 = 0;}
        if (by0 < 0) { by0 = 0;}
        if (bx1 > sht->bxsize) {bx1 = sht->bxsize;}
        if (by1 > sht->bysize) {by1 = sht->bysize;}

        for (by = by0; by < by1; by++) {
            vy = sht->vy0 + by;
            for (bx = bx0; bx < bx1; bx++) {
                vx = sht->vx0 + bx;
                if (buf[by * sht->bxsize + bx] != sht->col_inv) {
                    //將圖層標(biāo)號設(shè)置到map變量里
                    map[vy * ctl->xsize + vx] = sid;
                }
            }
        }
        
    }

    return;
}

這個(gè)函數(shù)跟以前的刷新函數(shù)refresh_sub幾乎一模一樣誊辉,是用來設(shè)置像素對應(yīng)的圖層編號的,假如窗口1的某個(gè)像素位于坐標(biāo)(20亡脑, 30)堕澄,那么我就在map[30xsize + 20] 處設(shè)置為1, xsize 是桌面的寬度霉咨,如果窗口2移動(dòng)后蛙紫,有像素點(diǎn)也移動(dòng)到了坐標(biāo)(20,30), 那么上面的代碼就會把map[30xsize + 20] 處設(shè)置為2,也就是窗口1的像素被窗口2所覆蓋了途戒。

有了像素所在位置對應(yīng)的窗口號后坑傅,我們就可以只刷新對應(yīng)窗口的像素點(diǎn),于是我們對窗口刷新函數(shù)做下列修改:

void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) {
    int h, bx, by, vx, vy;
    unsigned char *buf, c, *vram = ctl->vram, *map = ctl->map, sid;
    struct SHEET *sht;
    if (vx0 < 0) {vx0 = 0;}
    if (vy0 < 9) {vy0 = 0;}
    if (vx1 > ctl->xsize) {vx1 = ctl->xsize;}
    if (vy1 > ctl->ysize) {vy1 = ctl->ysize;}

    for (h = h0; h <= h1; h++) {
        sht = ctl->sheets[h];
        buf = sht->buf;
        
        //獲得當(dāng)前圖層對應(yīng)的窗口號
        sid = sht - ctl->sheets0;

        for (by = 0; by < sht->bysize; by++) {
            vy = sht->vy0 + by;
            for (bx = 0; bx < sht->bxsize; bx++) {
                vx = sht->vx0 + bx;
                if (vx0 <= vx && vx < vx1 && vy0 <= vy && vy < vy1) {
                    c = buf[by * sht->bxsize + bx];
                    //確定當(dāng)前坐標(biāo)對應(yīng)的素點(diǎn)是否屬于要刷新的窗口
                    if (map[vy * ctl->xsize + vx] == sid && c != sht->col_inv) {
                        vram[vy * ctl->xsize + vx] = c;
                    }
                }
            }
        }
    }
}

refresh_sub在刷新時(shí)喷斋,會遍歷給定高度(h0)以上的所有圖層唁毒,如果某個(gè)高度比當(dāng)前要刷新的窗口高度高,并且它覆蓋了當(dāng)前窗體的某部分星爪,那么兩個(gè)窗體的對應(yīng)像素就會重合浆西,高度高的窗體會把對應(yīng)坐標(biāo)處的像素標(biāo)號設(shè)置成自己的窗體標(biāo)號,也就是在上面的循環(huán)中顽腾,map[vy * ctl->xsize + vx] 所對應(yīng)的窗體標(biāo)號與當(dāng)前窗體的標(biāo)號就會不一樣近零,于是vram[vy * ctl->xsize + vx] = c;這一句就不會執(zhí)行,于是與當(dāng)前刷新窗體重合的抄肖,但高度更高的窗體就不用做沒必要的刷新久信。

其他對應(yīng)的圖層刷新函數(shù)也做相應(yīng)改動(dòng):


void sheet_slide(struct SHTCTL *ctl, struct SHEET *sht, int vx0, int vy0) {
    int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
    sht->vx0 = vx0;
    sht->vy0 = vy0;
    if (sht->height >= 0) {
         sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0);
         sheet_refreshmap(ctl, vx0, vy0, vx0+sht->bxsize, vy0+sht->bysize, sht->height);
         sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, 
                          old_vy0 + sht->bysize, 0, sht->height - 1);
         sheet_refreshsub(ctl, vx0, vy0, vx0+sht->bxsize, vy0+sht->bysize, sht->height, 
                          sht->height);
    }
}

void sheet_updown(struct SHTCTL *ctl, struct SHEET *sht, int height) {
 ....
 if (old > height) {
    ....
     if (height >= 0) {
     ....
    //窗體高度更新后,要更改像素點(diǎn)所在位置的窗體標(biāo)號
            sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0+sht->bxsize, sht->vy0+sht->bysize,
        height+1);
            sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0+sht->bxsize, sht->vy0+sht->bysize,
        height+1, old);
        } else {
          ....
              //窗體高度更新后漓摩,要更改像素點(diǎn)所在位置的窗體標(biāo)號
            sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0+sht->bxsize, sht->vy0+sht->bysize,
        0);
            sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0+sht->bxsize, sht->vy0+sht->bysize,
        0, old - 1);
        }
 } else {
    ....
    //窗體高度更新后裙士,要更改像素點(diǎn)所在位置的窗體標(biāo)號
        sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0+sht->bxsize, sht->vy0+sht->bysize,
        height);       

        sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0+sht->bxsize, sht->vy0+sht->bysize,
        height, height);
   }
 

}

做完上面的修改后,鼠標(biāo)閃爍的問題就可以消失了幌甘。

這里寫圖片描述
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末潮售,一起剝皮案震驚了整個(gè)濱河市痊项,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酥诽,老刑警劉巖鞍泉,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肮帐,居然都是意外死亡咖驮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門训枢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來托修,“玉大人,你說我怎么就攤上這事恒界∧廊校” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵十酣,是天一觀的道長涩拙。 經(jīng)常有香客問我,道長耸采,這世上最難降的妖魔是什么兴泥? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮虾宇,結(jié)果婚禮上搓彻,老公的妹妹穿的比我還像新娘。我一直安慰自己嘱朽,他們只是感情好旭贬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著燥翅,像睡著了一般骑篙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上森书,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機(jī)與錄音谎势,去河邊找鬼凛膏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛脏榆,可吹牛的內(nèi)容都是我干的猖毫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼须喂,長吁一口氣:“原來是場噩夢啊……” “哼吁断!你這毒婦竟也來了趁蕊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤仔役,失蹤者是張志新(化名)和其女友劉穎掷伙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體又兵,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡任柜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沛厨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宙地。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖逆皮,靈堂內(nèi)的尸體忽然破棺而出宅粥,到底是詐尸還是另有隱情,我是刑警寧澤电谣,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布秽梅,位于F島的核電站,受9級特大地震影響辰企,放射性物質(zhì)發(fā)生泄漏风纠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一牢贸、第九天 我趴在偏房一處隱蔽的房頂上張望竹观。 院中可真熱鬧,春花似錦潜索、人聲如沸臭增。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽誊抛。三九已至,卻和暖如春整陌,著一層夾襖步出監(jiān)牢的瞬間拗窃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工泌辫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留随夸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓震放,卻偏偏與公主長得像宾毒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子殿遂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容