工控智汇

工控智汇

第11天,制作窗口《30天自制操作系统学习笔记》

admin 145 159


鼠标显示

windows中鼠标是可以在右侧和底部边缘隐藏的,而咱们的还无法做到

更新:

if(mxbinfo-scrnx-1){mx=binfo-scrnx-1;}if(mybinfo-scrny-1){my=binfo-scrny-1;}


BUG!移动到右侧后,鼠标在左侧显示

只有sheet_refreshsub函数在做把图层内容写入VRAM的工作,让它不刷新画面以外的部分

更新:

voidsheet_refreshsub(structSHTCTL*ctl,intvx0,intvy0,intvx1,intvy1){inth,bx,by,vx,vy,bx0,by0,bx1,by1;unsignedchar*buf,c,*vram=ctl-vram;structSHEET*sht;/*如果refresh的范围超出了画面则修正*/if(vx00){vx0=0;}if(vy00){vy0=0;}if(vx1ctl-xsize){vx1=ctl-xsize;}if(vy1ctl-ysize){vy1=ctl-ysize;}for(h=0;h=ctl-top;h++){(中略)}return;}


没有在左侧显示,修复bug

shtcrl的指定省略

sheet_updown函数仅是上下移动图层,就必须指定ctl,太麻烦

更新:

structSHEET{unsignedchar*buf;intbxsize,bysize,vx0,vy0,col_inv,height,flags;structSHTCTL*ctl;};

shtctl_init追加1行

更新:

structSHTCTL*shtctl_init(structMEMMAN*memman,unsignedchar*vram,intxsize,intysize){structSHTCTL*ctl;inti;ctl=(structSHTCTL*)memman_alloc_4k(memman,sizeof(structSHTCTL));if(ctl==0){gotoerr;}ctl-vram=vram;ctl-xsize=xsize;ctl-ysize=ysize;ctl-top=-1;/*没有一张SHEET*/for(i=0;iMAX_SHEETS;i++){ctl-sheets0[i].flags=0;/*未使用标记*/ctl-sheets0[i].ctl=ctl;/*记录所属*//*这里!*/}err:returnctl;}

更新:

voidsheet_updown(structSHEET*sht,intheight){structSHTCTL*ctl=sht-ctl;inth,old=sht-height;/*将设置前的高度记录下来*/(中略)}

这样sheet_updown函数里就可以不指定ctl了

接下来sheet_refresh、sheet_slide、sheet_free这让它们都不用指定ctl

更新:

voidsheet_refresh(structSHEET*sht,intbx0,intby0,intbx1,intby1){if(sht-height=0){/*如果正在显示,则按新图层的信息进行刷新*/sheet_refreshsub(sht-ctl,sht-vx0+bx0,sht-vy0+by0,sht-vx0+bx1,sht-vy0+by1);}return;}voidsheet_slide(structSHEET*sht,intvx0,intvy0){intold_vx0=sht-vx0,old_vy0=sht-vy0;sht-vx0=vx0;sht-vy0=vy0;if(sht-height=0){/*如果正在显示,则按新图层的信息进行刷新*/sheet_refreshsub(sht-ctl,old_vx0,old_vy0,old_vx0+sht-bxsize,old_vy0+sht-bysize);sheet_refreshsub(sht-ctl,vx0,vy0,vx0+sht-bxsize,vy0+sht-bysize);}return;}voidsheet_free(structSHEET*sht){if(sht-height=0){sheet_updown(sht,-1);/*如果正在显示,则先设置为隐藏*/}sht-flags=0;/*未使用标记*/return;}

更新后,也要更新

更新:

sheet_slide(shtctl,sht_back,0,0);→sheet_slide(sht_back,0,0);sheet_slide(shtctl,sht_mouse,mx,my);→sheet_slide(sht_mouse,mx,my);sheet_updown(shtctl,sht_back,0);→sheet_updown(sht_back,0);sheet_updown(shtctl,sht_mouse,1);→sheet_updown(sht_mouse,1);sheet_refresh(shtctl,sht_back,0,0,binfo-scrnx,48);→sheet_refresh(sht_back,0,0,binfo-scrnx,48);sheet_refresh(shtctl,sht_back,0,16,16,32);→sheet_refresh(sht_back,0,16,16,32);sheet_refresh(shtctl,sht_back,32,16,32+15*8,32);→sheet_refresh(sht_back,32,16,32+15*8,32);sheet_refresh(shtctl,sht_back,0,0,80,16);→sheet_refresh(sht_back,0,0,80,16);sheet_slide(shtctl,sht_mouse,mx,my);→sheet_slide(sht_mouse,mx,my);

这样,全部更新完毕

显示窗口

像制作背景和鼠标那样,只要先准备一张图层,然后在图层缓冲区内描绘一个貌似窗口的图就可以了。

更新:

voidmake_window8(unsignedchar*buf,intxsize,intysize,char*title){staticcharclosebtn[14][16]={//这是关闭按钮x符号"OOOOOOOOOOOOOOO@","OQQQQQQQQQQQQQ$@","OQQQQQQQQQQQQQ$@","OQQQ@@QQQQ@@QQ$@","OQQQQ@@QQ@@QQQ$@","OQQQQQ@@@@QQQQ$@","OQQQQQQ@@QQQQQ$@","OQQQQQ@@@@QQQQ$@","OQQQQ@@QQ@@QQQ$@","OQQQ@@QQQQ@@QQ$@","OQQQQQQQQQQQQQ$@","OQQQQQQQQQQQQQ$@","O$$$$$$$$$$$$$$@","@@@@@@@@@@@@@@@@"};intx,y;charc;boxfill8(buf,xsize,COL8_C6C6C6,0,0,xsize-1,0);boxfill8(buf,xsize,COL8_FFFFFF,1,1,xsize-2,1);boxfill8(buf,xsize,COL8_C6C6C6,0,0,0,ysize-1);boxfill8(buf,xsize,COL8_FFFFFF,1,1,1,ysize-2);boxfill8(buf,xsize,COL8_848484,xsize-2,1,xsize-2,ysize-2);boxfill8(buf,xsize,COL8_000000,xsize-1,0,xsize-1,ysize-1);boxfill8(buf,xsize,COL8_C6C6C6,2,2,xsize-3,ysize-3);boxfill8(buf,xsize,COL8_000084,3,3,xsize-4,20);boxfill8(buf,xsize,COL8_848484,1,ysize-2,xsize-2,ysize-2);boxfill8(buf,xsize,COL8_000000,0,ysize-1,xsize-1,ysize-1);putfonts8_asc(buf,xsize,24,4,COL8_FFFFFF,title);//关闭按钮上色for(y=0;y14;y++){for(x=0;x16;x++){c=closebtn[y][x];if(c=='@'){c=COL8_000000;}elseif(c=='#39;){c=COL8_848484;}elseif(c=='Q'){c=COL8_C6C6C6;}else{c=COL8_FFFFFF;}buf[(5+y)*xsize+(xsize-21+x)]=c;}}return;}

对的init_screen8函数稍微进行了改造,

而×按钮的功能则是通过修改init_mouse_cursor8而得到的。

更新:

voidHariMain(void){.代码省略make_window8(buf_win,160,68,"window");/*这里!*/putfonts8_asc(buf_win,160,24,28,COL8_000000,"helloworld");/*这里!*/putfonts8_asc(buf_win,160,24,44,COL8_000000,"hellotoutiao");/*这里!*/}

测试:窗口成功显示


高速计数器

做一个能够计数,并将计数结果显示出来的窗口

更新:

voidHariMain(void){代码省略unsignedchar*buf_back,buf_mouse[256],*buf_win;buf_win=(unsignedchar*)memman_alloc_4k(memman,160*52);/*这里!*/make_window8(buf_win,160,52,"counter");/*这里!*/for(;;){count++;/*从这里开始*/sprintf(s,"%010d",count);boxfill8(buf_win,160,COL8_C6C6C6,40,28,119,43);putfonts8_asc(buf_win,160,40,28,COL8_000000,s);sheet_refresh(sht_win,40,28,120,44);/*到这里结束*/io_cli();if(fifo8_status(keyfifo)+fifo8_status(mousefifo)==0){io_sti();/*不做HLT*/}else{(中略)}}}

与其让CPU有空睡觉(HLT命令),还不如让它全力计数,所以被称为高速计数器

测试



画面bug:闪烁

这是由于先刷新refresh范围内的背景图层,后再刷新窗口图层造成的

消除闪烁

窗口图层刷新是因为窗口的内容有变化,所以要在画面上显示变化后的新内容。

如果只是窗口变了,那背景就不用刷新了。

假如上面有鼠标,但鼠标的图层没有变化,那我们应该刷新吗?必须要刷新。窗口的刷新,可能会覆盖鼠标的一部分显示区域。

所以仅对refresh对象及其以上的图层进行刷新就可以了

更新:

voidsheet_refreshsub(structSHTCTL*ctl,intvx0,intvy0,intvx1,intvy1,inth0){(中略)for(h=h0;h=ctl-top;h++){(中略)}return;}

追加了h0参数,只对在此参数以上的图层进行刷新

更新:

voidsheet_refresh(structSHEET*sht,intbx0,intby0,intbx1,intby1){if(sht-height=0){/*如果正在显示,则按新图层的信息进行刷新*/sheet_refreshsub(sht-ctl,sht-vx0+bx0,sht-vy0+by0,sht-vx0+bx1,sht-vy0+by1,sht-height);/*↑这里!*/}return;}voidsheet_slide(structSHEET*sht,intvx0,intvy0){intold_vx0=sht-vx0,old_vy0=sht-vy0;sht-vx0=vx0;sht-vy0=vy0;if(sht-height=0){/*如果正在显示,则按新图层的信息进行刷新*/sheet_refreshsub(sht-ctl,old_vx0,old_vy0,old_vx0+sht-bxsize,old_vy0+sht-bysize,0);sheet_refreshsub(sht-ctl,vx0,vy0,vx0+sht-bxsize,vy0+sht-bysize,sht-height);/*↑这里!*/}return;}voidsheet_updown(structSHEET*sht,intheight){(中略)/*以下主要是对sheets[]的重新排列*/if(oldheight){/*比以前低*/if(height=0){/*中间的提起*/for(h=old;hheight;h--){ctl-sheets[h]=ctl-sheets[h-1];ctl-sheets[h]-height=h;}ctl-sheets[height]=sht;/*这里*/sheet_refreshsub(ctl,sht-vx0,sht-vy0,sht-vx0+sht-bxsize,sht-vy0+sht-bysize,height+1);}else{/*隐藏*/if(ctl-topold){/*把上面的降下来*/for(h=old;hctl-top;h++){ctl-sheets[h]=ctl-sheets[h+1];ctl-sheets[h]-height=h;}}ctl-top--;/*正在显示的图层减少了一个,故最上面的高度也减少*//*这里*/sheet_refreshsub(ctl,sht-vx0,sht-vy0,sht-vx0+sht-bxsize,sht-vy0+sht-bysize,0);}}elseif(oldheight){/*比以前高*/if(old=0){/*中间的图层往下降一层*/for(h=old;hheight;h++){ctl-sheets[h]=ctl-sheets[h+1];ctl-sheets[h]-height=h;}ctl-sheets[height]=sht;}else{/*从隐藏状态变为显示状态*//*把在上面的图层往上提高一层*/for(h=ctl-top;h=height;h--){ctl-sheets[h+1]=ctl-sheets[h];ctl-sheets[h+1]-height=h+1;}ctl-sheets[height]=sht;ctl-top++;/*显示中的图层增加了一个,故最上面的高度也增加*/}sheet_refreshsub(ctl,sht-vx0,sht-vy0,sht-vx0+sht-bxsize,sht-vy0+sht-bysize,height);/*↑这里*/}return;}

sheet_refresh函数,让它只刷新指定的图层和它上面的图层

sheet_slide函数里,

图层的移动有时会导致下面的图层露出,所以要从最下面开始刷新。

在移动目标处,比新移来的图层位置还要低的图层没有什么变化,而且只是隐藏起来了

所以只要刷新移动的图层和它上面的图层就可以了。

sheet_updown函数里,针对个别不需要自下而上全部刷新的部分只进行局部刷新。这样修改以后,闪烁现象应该就会消失了。

测试:数字闪烁没问题


但是与鼠标叠加部分又有问题

闪烁现象是由于一会儿描绘一会儿消除造成的。所以说要想消除闪烁,就要在刷新窗口时避开鼠标所在的地方对VRAM进行写入处理。


这块内存用来表示画面上的点是哪个图层的像素,所以它就相当于是图层的地图。

当刷新图层1的时候,如果一边看着这个map一边刷新的话,就不必担心图层1和图层2重叠的部分被覆盖了。

写向map中写入1、2等图层号码的函数。

更新:

voidsheet_refreshmap(structSHTCTL*ctl,intvx0,intvy0,intvx1,intvy1,inth0){inth,bx,by,vx,vy,bx0,by0,bx1,by1;unsignedchar*buf,sid,*map=ctl-map;structSHEET*sht;if(vx00){vx0=0;}if(vy00){vy0=0;}if(vx1ctl-xsize){vx1=ctl-xsize;}if(vy1ctl-ysize){vy1=ctl-ysize;}for(h=h0;h=ctl-top;h++){sht=ctl-sheets[h];sid=sht-ctl-sheets0;buf=sht-buf;bx0=vx0-sht-vx0;by0=vy0-sht-vy0;bx1=vx1-sht-vx0;by1=vy1-sht-vy0;if(bx00){bx0=0;}if(by00){by0=0;}if(bx1sht-bxsize){bx1=sht-bxsize;}if(by1sht-bysize){by1=sht-bysize;}for(by=by0;byby1;by++){vy=sht-vy0+by;for(bx=bx0;bxbx1;bx++){vx=sht-vx0+bx;if(buf[by*sht-bxsize+bx]!=sht-col_inv){map[vy*ctl-xsize+vx]=sid;}}}}return;}

这个函数与以前的refreshsub函数基本一样,只是用色号代替了图层号码而已。代表图层号码的变量sid是“sheetlD今后程序会对照map内容来向VRAM中写入,所以有时没必要从下面开始一直刷新到最上面一层,因此不仅要能指定h0,也要可以指定h1。”的缩写。

更新:

voidsheet_refreshsub(structSHTCTL*ctl,intvx0,intvy0,intvx1,intvy1,inth0,inth1){inth,bx,by,vx,vy,bx0,by0,bx1,by1;unsignedchar*buf,*vram=ctl-vram,*map=ctl-map,sid;structSHEET*sht;if(vx00){vx0=0;}if(vy00){vy0=0;}if(vx1ctl-xsize){vx1=ctl-xsize;}if(vy1ctl-ysize){vy1=ctl-ysize;}for(h=h0;h=h1;h++){sht=ctl-sheets[h];buf=sht-buf;sid=sht-ctl-sheets0;bx0=vx0-sht-vx0;by0=vy0-sht-vy0;bx1=vx1-sht-vx0;by1=vy1-sht-vy0;if(bx00){bx0=0;}if(by00){by0=0;}if(bx1sht-bxsize){bx1=sht-bxsize;}if(by1sht-bysize){by1=sht-bysize;}for(by=by0;byby1;by++){vy=sht-vy0+by;for(bx=bx0;bxbx1;bx++){vx=sht-vx0+bx;if(map[vy*ctl-xsize+vx]==sid){vram[vy*ctl-xsize+vx]=buf[by*sht-bxsize+bx];}}}}return;}

今后程序会对照map内容来向VRAM中写入,所以有时没必要从下面开始一直刷新到最上面一层,因此不仅要能指定h0,也要可以指定h1。

更新:

voidsheet_refresh(structSHEET*sht,intbx0,intby0,intbx1,intby1){if(sht-height=0){/*如果正在显示,则按新图层的信息进行刷新*/sheet_refreshsub(sht-ctl,sht-vx0+bx0,sht-vy0+by0,sht-vx0+bx1,sht-vy0+by1,sht-height,sht-height);}return;}
voidsheet_slide(structSHEET*sht,intvx0,intvy0){structSHTCTL*ctl=sht-ctl;intold_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);}return;}

sheet_slide函数里,首先重写map,分别对应移动前后的图层,然后调用sheet_refreshsub函数。在移动前的地方,只针对上层图层移走之后而露出的下层图层进行重绘就可以了。在移动目的地处仅重绘了一张移动过去的图层。

更新:

voidsheet_updown(structSHEET*sht,intheight){structSHTCTL*ctl=sht-ctl;inth,old=sht-height;if(heightctl-top+1){height=ctl-top+1;}if(height-1){height=-1;}sht-height=height;if(oldheight){if(height=0){for(h=old;hheight;h--){ctl-sheets[h]=ctl-sheets[h-1];ctl-sheets[h]-height=h;}ctl-sheets[height]=sht;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{if(ctl-topold){for(h=old;hctl-top;h++){ctl-sheets[h]=ctl-sheets[h+1];ctl-sheets[h]-height=h;}}ctl-top--;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);}}elseif(oldheight){if(old=0){for(h=old;hheight;h++){ctl-sheets[h]=ctl-sheets[h+1];ctl-sheets[h]-height=h;}ctl-sheets[height]=sht;}else{for(h=ctl-top;h=height;h--){ctl-sheets[h+1]=ctl-sheets[h];ctl-sheets[h+1]-height=h+1;}ctl-sheets[height]=sht;ctl-top++;}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);}return;}

在调用sheet_refreshsub函数之前,先执行sheet_refreshmap来重做map。

测试(11_day\harib08h):bug消失了


好多代码都看不懂,


先跟着继续往下看看。

今天就到这里,拜拜。