为了方便窗口的移动 ,及相交窗口关闭之后被遮挡窗口的重绘,因此给每个窗口建立一个内存BUF,等到不涉及内容变更的重绘,只需要将该BUF复制到显存之中。
然而,重绘时存在一个被遮挡时如何操作的问题。比如下图中依次为从外到内1、2、3、4号窗口、桌面,现关闭1号窗口,那么将需要重绘桌面,4号、3号2、号窗口,还有空出的桌面。
具体过程如下:
1、取一块1号窗口大小的内存。
2、将1号区域分别与桌面、4号窗口、3号、2号窗口相交,所得区域用相应窗口内容重绘,
3、将内存的内容复制到显存中。
这种方法将计算过程与刷新屏内容分开,避免闪烁。移动1号窗口只需先做上述过程再重绘就可以。但是会存在多次重复绘制重叠区域,但复杂程度不高,比较实用。
另外则需要窗口是顺序保存。鼠标也可以用此方法刷新,
具体代码如下:
DWORD windows_draw_rect(LPWNDINFO wnd, LPRECT rect, BYTE* drawbuff) {
void * wndvram;
RECT newrect;
//计算窗口被rect截取的区域
if ((wnd->y0 > rect->bottom) || ((wnd->y0 + wnd->height) <= rect->top)
|| ((wnd->x0 + wnd->width) <= rect->left)
|| (rect->right < wnd->x0)) {
//矩形不重合
return 0;
}
//左、顶取两者最大,右、底取两都最小
newrect.left = (wnd->x0 < rect->left) ? rect->left : wnd->x0;
newrect.top = (wnd->y0 < rect->top) ? rect->top : wnd->y0;
newrect.right =
((wnd->x0 + wnd->width-1) < rect->right) ?
(wnd->x0 + wnd->width-1) : rect->right;
newrect.bottom =
((wnd->y0 + wnd->height-1) < rect->bottom) ?
(wnd->y0 + wnd->height-1) : rect->bottom;
//print_farmat_msg("重合区域%d,%d,%d,%d\n", newrect.left, newrect.top, newrect.right, newrect.bottom);
DWORD rectw = (rect->right - rect->left + 1);
DWORD newrectw =(newrect.right - newrect.left + 1), newrecth = (newrect.bottom
- newrect.top + 1);
wndvram = wnd->vram
+ ((newrect.left - wnd->x0) + (newrect.top - wnd->y0) * wnd->width)
* VBE_BPP;
drawbuff=(char *)drawbuff+((newrect.left-rect->left)+(newrect.top-rect->top)*(rect->right-rect->left+1))* VBE_BPP;
for (int y = 0; y < newrecth; y++) {
memcpy((char *) drawbuff + (y * rectw) * VBE_BPP,
(char*) wndvram + (y * wnd->width) * VBE_BPP, newrectw * VBE_BPP);
}
return 1;
}
//从窗口列表中恢复区域
void restore_rect(LPRECT rect) {
//申请一块临时区域,从最底层画面开始在临时区域画,
void *vbeVarm;
DWORD rectw = (rect->right - rect->left + 1);
DWORD recth = (rect->bottom - rect->top + 1);
// print_farmat_msg("恢复区域%d,%d,%d,%d\n", rect->left, rect->top, rect->right,
// rect->bottom);
//每个象素点占VBE_BPP
void* temp = kr_malloc(rectw * recth * VBE_BPP);
//窗口列表循环
LPWNDINFO elem = (LPWNDINFO) (lpWndInfoLists.tail.prev);
while (elem != (LPWNDINFO) (&lpWndInfoLists.head)) {
//子窗口没有单独的vram
if (elem->dwStyle != WS_CHILD) {
windows_draw_rect(elem, rect, temp);
}
elem = elem->prev;
}
vbeVarm = lpSysShareData->vbePhPtr
+ (rect->left + rect->top * lpSysShareData->ScreenWidth) * VBE_BPP;
//临时区域绘画完成,将临时区域写到屏上
for (int y = 0; y < recth; y++) {
memcpy((char *) vbeVarm + (y * lpSysShareData->ScreenWidth) * VBE_BPP,
(char *) temp + (y * rectw) * VBE_BPP, rectw * VBE_BPP
);
//vbeVarm[x + y * lpSysShareData->ScreenWidth] = temp[x
// + y * (rect->bottom - rect->top + 1)];
}