尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

ReactOS 图形系统分析(15):窗口对象 — EWNDOBJ(engwindow.c)

ReactOS 图形系统分析(15):窗口对象 — EWNDOBJ(engwindow.c) ReactOS 图形系统分析15窗口对象 — EWNDOBJengwindow.c1. 概述engwindow.c位于win32ss/gdi/eng/engwindow.c是 GDI 引擎的窗口对象WNDOBJ/EWNDOBJ管理模块。它让显示驱动能够跟踪窗口的位置与可见区域变化从而优化窗口表面的绘制如硬件加速、合成器。ntuser (WND 窗口对象位置/尺寸/可见区域) ↓ VIS_ComputeVisibleRegion 计算可见区域 engwindow.c (EWNDOBJ 管理 ← 本分析对象) ├── EngCreateWnd / EngDeleteWnd 生命周期 ├── IntEngWndUpdateClipObj 从 WND 更新裁剪对象 ├── IntEngWindowChanged 窗口变化通知回调驱动 └── WNDOBJ_bEnum / cEnumStart 可见区域矩形枚举 ↓ 显示驱动 (通过 WNDOBJCHANGEPROC 接收变化通知)核心思想驱动创建窗口表面时调用EngCreateWnd获得 WNDOBJ之后窗口移动/改变大小时引擎通过WNDOBJCHANGEPROC回调通知驱动驱动可据此高效更新例如只重绘露出部分或跟踪精灵位置。2. 核心数据结构2.1 EWNDOBJ扩展窗口对象[engobjects.h](file:///d:/reactos/win32ss/gdi/eng/engobjects.h#L92-L105)typedefstruct_EWNDOBJ:_XCLIPOBJ// 继承CLIPOBJ RWNDOBJ 裁剪私有字段{/* 扩展窗口对象部分 */HWND Hwnd;// 关联的窗口句柄WNDOBJCHANGEPROC ChangeProc;// 变化回调驱动注册FLONG Flags;// 关心的变化标志intPixelFormat;// 像素格式OpenGL 用}EWNDOBJ,*PEWNDOBJ;2.2 WNDOBJDDI 公开部分 CLIPOBJ RWNDOBJtypedefstruct_RWNDOBJ{PVOID pvConsumer;// 驱动私有数据RECTL rclClient;// 客户区矩形SURFOBJ*psoOwner;// 所有者表面}RWNDOBJ;/* WNDOBJ CLIPOBJ RWNDOBJ通过 _WNDOBJ 别名引用 */WNDOBJ 本质是一个特殊的 CLIPOBJ它的裁剪区域 窗口的可见客户区。驱动通过WNDOBJ_bEnum/WNDOBJ_cEnumStart枚举可见矩形复用 CLIPOBJ 机制见《ReactOS 图形系统分析_8.md》。2.3 变化标志驱动请求的标志WO_*EngCreateWnd 的 fl 参数标志含义WO_RGN_CLIENT客户区变化通知WO_RGN_CLIENT_DELTA客户区增量变化WO_RGN_SURFACE表面区域变化WO_RGN_SURFACE_DELTA表面区域增量变化WO_DRAW_NOTIFY绘制通知WO_SPRITE_NOTIFY精灵重叠通知WO_RGN_WINDOW / WO_RGN_DESKTOP_COORD / WO_RGN_UPDATE_ALL未实现FIXME引擎触发的回调标志WOC_*标志含义WOC_RGN_CLIENT客户区可见区域已更新WOC_CHANGED窗口已变化WOC_DELETE窗口对象将被删除WOC_DRAWN已绘制WOC_SPRITE_OVERLAP / WOC_SPRITE_NO_OVERLAP精灵重叠/不重叠3. 核心函数分析3.1 创建 — EngCreateWnd是否失败失败EngCreateWnd(pso, hWnd, pfn, fl, iPixelFormat)UserEnterExclusive(用户子系统独占锁)fl 含未支持标志?(WO_RGN_WINDOW 等)FIXME 警告继续UserGetWindowObject(hWnd)获取窗口对象退出返回 NULL分配 EWNDOBJEngAllocMemIntEngInitClipObj(Rects 指向内嵌 rclBounds)IntEngWndUpdateClipObj用窗口可见区域填充裁剪对象释放内存填充 DDI 公开部分psoOwner pso, pvConsumer NULL填充内部字段Hwnd/ChangeProc/Flags/PixelFormatUserSetProp 关联到窗口(AtomWndObj 属性)gcountPWOUserLeave 返回 WNDOBJ关键代码WNDOBJ*APIENTRYEngCreateWnd(SURFOBJ*pso,HWND hWnd,WNDOBJCHANGEPROC pfn,FLONG fl,intiPixelFormat){WindowUserGetWindowObject(hWnd);// 1. 取窗口对象if(WindowNULL)gotoExit;ClipEngAllocMem(FL_ZERO_MEMORY,sizeof(EWNDOBJ),GDITAG_WNDOBJ);IntEngInitClipObj((XCLIPOBJ*)Clip);// 2. 初始化裁剪对象/* 3. 用窗口可见区域填充裁剪对象 */if(!IntEngWndUpdateClipObj(Clip,Window)){EngFreeMem(Clip);gotoExit;}/* 4. 填充 DDI 公开部分 */WndObjUser(WNDOBJ*)Clip;WndObjUser-psoOwnerpso;WndObjUser-pvConsumerNULL;/* 5. 填充内部字段 */Clip-HwndhWnd;Clip-ChangeProcpfn;Clip-Flagsfl(WO_RGN_CLIENT_DELTA|WO_RGN_CLIENT|WO_RGN_SURFACE_DELTA|WO_RGN_SURFACE|WO_DRAW_NOTIFY);if(flWO_SPRITE_NOTIFY)Clip-Flags|WOC_SPRITE_OVERLAP|WOC_SPRITE_NO_OVERLAP;Clip-Flags|WOC_CHANGED|WOC_DELETE;// 始终发送Clip-PixelFormatiPixelFormat;/* 6. 通过窗口属性关联到窗口 */UserSetProp(Window,AtomWndObj,Clip,TRUE);gcountPWO;returnWndObjUser;}要点只保存驱动请求的标志fl WO_*回调时按此过滤WOC_CHANGED/WOC_DELETE始终加入 Flags这些通知必须发送通过AtomWndObj窗口属性把 EWNDOBJ 挂到窗口上窗口变化时能找回3.2 从窗口更新裁剪对象 — IntEngWndUpdateClipObjBOOLEAN FASTCALLIntEngWndUpdateClipObj(EWNDOBJ*Clip,PWND Window){/* 计算窗口的可见区域考虑兄弟窗口遮挡 */visRgnVIS_ComputeVisibleRegion(Window,TRUE,TRUE,TRUE);if(visRgn!NULLvisRgn-rdh.nCount0){/* 可见区域 → 裁剪对象多矩形 → DC_COMPLEX */IntEngUpdateClipRegion((XCLIPOBJ*)Clip,visRgn-rdh.nCount,visRgn-Buffer,visRgn-rdh.rcBound);REGION_Delete(visRgn);}else{/* 退化为客户区矩形 */IntEngUpdateClipRegion((XCLIPOBJ*)Clip,1,Window-rcClient,Window-rcClient);}/* 更新客户区矩形和唯一性标志 */Clip-rclClientWindow-rcClient;Clip-iUniq;returnTRUE;}要点VIS_ComputeVisibleRegion计算窗口的真实可见区域扣除被覆盖部分——多矩形时裁剪对象变为DC_COMPLEX驱动用WNDOBJ_bEnum枚举可见矩形只绘制可见部分。3.3 窗口变化通知 — IntEngWindowChanged窗口移动/改变尺寸/删除时由 ntuser 调用VOID FASTCALLIntEngWindowChanged(PWND Window,FLONG flChanged){ClipUserGetProp(Window,AtomWndObj,TRUE);// 找回 WNDOBJif(!Clip)return;switch(flChanged){caseWOC_RGN_CLIENT:/* 更新裁剪对象和客户区 */IntEngWndUpdateClipObj(Clip,Window);break;caseWOC_DELETE:/* FIXME: WNDOBJ 由 win32k 还是驱动删除 */break;}/* 调用驱动回调 */IntEngWndCallChangeProc(Clip,flChanged);/* HACK: WOC_RGN_CLIENT 后再发 WOC_CHANGED */if(flChangedWOC_RGN_CLIENT)IntEngWndCallChangeProc(Clip,WOC_CHANGED);}3.4 回调调度 — IntEngWndCallChangeProcVOID FASTCALLIntEngWndCallChangeProc(EWNDOBJ*Clip,FLONG flChanged){if(Clip-ChangeProcNULL)return;/* 按驱动请求的标志过滤 */flChangedClip-Flags;if(flChanged0)return;/* WOC_CHANGED 无矩形数据传 NULL其余传 WNDOBJ 指针 */if(flChangedWOC_CHANGED)Clip-ChangeProc(NULL,flChanged);elseClip-ChangeProc((WNDOBJ*)Clip,flChanged);}3.5 删除 — EngDeleteWndVOID APIENTRYEngDeleteWnd(WNDOBJ*pwo){Clip(EWNDOBJ*)pwo;/* 从窗口移除属性 */WindowUserGetWindowObject(Clip-Hwnd);if(Window)UserRemoveProp(Window,AtomWndObj,TRUE);--gcountPWO;/* 释放资源Rects 堆数组 对象本身 */IntEngFreeClipResources((XCLIPOBJ*)Clip);EngFreeMem(Clip);}3.6 DDI 枚举函数驱动侧/* 枚举可见矩形转给 CLIPOBJ_bEnum */BOOL APIENTRYWNDOBJ_bEnum(WNDOBJ*pwo,ULONG cj,ULONG*pul){returnCLIPOBJ_bEnum(pwo-coClient,cj,pul);}/* 枚举初始化转给 CLIPOBJ_cEnumStart */ULONG APIENTRYWNDOBJ_cEnumStart(WNDOBJ*pwo,ULONG iType,ULONG iDirection,ULONG cLimit){returnCLIPOBJ_cEnumStart(pwo-coClient,FALSE,iType,iDirection,cLimit);}要点WNDOBJ 的枚举完全复用 CLIPOBJ 机制——WNDOBJ 本质就是带窗口语义的 CLIPOBJ。3.7 设置消费者 — WNDOBJ_vSetConsumerVOID APIENTRYWNDOBJ_vSetConsumer(WNDOBJ*pwo,PVOID pvConsumer){Hack(pwo-pvConsumerNULL);pwo-pvConsumerpvConsumer;// 保存驱动私有数据/* HACK: 首次设置时补发初始状态MSDN 要求创建后回调最近状态 */if(Hack){IntEngWndCallChangeProc(Clip,WOC_RGN_CLIENT);IntEngWndCallChangeProc(Clip,WOC_CHANGED);IntEngWndCallChangeProc(Clip,WOC_DRAWN);}}4. 数据流窗口变化 → 驱动收到通知显示驱动engwindow.cntuser (WND 窗口)显示驱动engwindow.cntuser (WND 窗口)驱动创建窗口表面窗口移动/改变尺寸驱动处理销毁EngCreateWnd (pso, hWnd, ChangeProc, fl)UserGetWindowObject VIS_ComputeVisibleRegionWNDOBJ (含可见区域 CLIPOBJ)IntEngWindowChanged (WOC_RGN_CLIENT)VIS_ComputeVisibleRegion (重新计算)IntEngWndUpdateClipObj (更新裁剪对象 iUniq)ChangeProc(WNDOBJ, WOC_RGN_CLIENT)ChangeProc(NULL, WOC_CHANGED)WNDOBJ_cEnumStart / WNDOBJ_bEnum (枚举可见矩形)可见矩形列表只重绘可见区域 (硬件加速)EngDeleteWndUserRemoveProp (解除关联)5. 设计特点总结WNDOBJ 即特殊 CLIPOBJ窗口对象继承 CLIPOBJ裁剪区域 窗口可见区域枚举完全复用 CLIPOBJ 机制。可见区域计算VIS_ComputeVisibleRegion计算扣除遮挡后的真实可见区域多矩形 → DC_COMPLEX。回调过滤只发送驱动请求的标志flChanged Clip-Flags减少无关通知。窗口属性关联通过AtomWndObj属性把 WNDOBJ 挂到窗口窗口变化可快速找回。iUniq 失效标记裁剪区域每次更新iUniq驱动可据此判断缓存是否失效。HACK 兼容创建/设置消费者时补发初始状态通知符合 MSDN 对 WNDOBJCHANGEPROC 的约定。精灵通知预留WO_SPRITE_NOTIFY支持精灵重叠跟踪未完整实现。6. 源码索引位置关键内容[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L18-L44)IntEngWndCallChangeProc回调过滤调度[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L49-L92)IntEngWndUpdateClipObj可见区域 → 裁剪对象[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L97-L138)IntEngWindowChanged窗口变化通知[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L143-L214)EngCreateWnd创建[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L220-L250)EngDeleteWnd删除[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L256-L317)WNDOBJ_bEnum / cEnumStart / vSetConsumer[engobjects.h](file:///d:/reactos/win32ss/gdi/eng/engobjects.h#L42-L46)RWNDOBJ 结构[engobjects.h](file:///d:/reactos/win32ss/gdi/eng/engobjects.h#L92-L105)EWNDOBJ 结构关联模块[eng/clip.c](file:///d:/reactos/win32ss/gdi/eng/clip.c) — CLIPOBJ 机制WNDOBJ 的继承基础[ntuser/window.c](file:///d:/reactos/win32ss/user/ntuser/window.c) — WND 窗口对象上游[ntuser/vis.c](file:///d:/reactos/win32ss/user/ntuser/vis.c) — VIS_ComputeVisibleRegion 可见区域计算关联文档《ReactOS 图形系统分析_4.md》— GDI 引擎整体架构本文件是窗口对象子模块《ReactOS 图形系统分析_8.md》— 裁剪管理WNDOBJ 复用的 CLIPOBJ 机制本文档基于 ReactOS 源代码win32ss/gdi/eng/engwindow.c分析2026 年 8 月
返回列表