X Window研究笔记(11)
转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>
11.X Window扩展机制--对象装饰
Decorator模式是一个非常重要的模式,它在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。X Server是用C开发的,不方便使用正统的装饰模式,但大量使用了类似装饰模式的扩展方式。可以被装饰的对象有:
- 屏幕: ScreenRec
- 窗口:WindowRec
- 图片: PixmapRec
- 绘图上下文: GC
- 颜色映射: Colormap
- 客户端:ClientRec
其实现过程可以这样理解:
- 初始化时,把原始对象的部分函数指针保存下来,并用自己的函数去替代它。
- 调用时,装饰之后的函数被调用,在该函数中,完成一些装饰性功能,并适当的位置调用原始的函数。
其中,用得最多的是对ScreenRec的装饰,下面我们以sprite模块中对ScreenRec的装饰为例,分析一下它的实现原理:
sprite指像鼠标指针一类的屏幕精灵,它的特点是,形状可能不规则,可以在屏幕上移动,会覆盖当前位置的图像,当它移动到新的位置时,自动恢复先前位置的图像。
sprite的初始化是在miSpriteInitialize中完成的:
Bool
miSpriteInitialize(pScreen,cursorFuncs,screenFuncs)
ScreenPtrpScreen;
miSpriteCursorFuncPtrcursorFuncs;
miPointerScreenFuncPtrscreenFuncs;
...{
miSpriteScreenPtrpPriv;
VisualPtrpVisual;
#ifdefRENDER
PictureScreenPtrps=GetPictureScreenIfSet(pScreen);
#endif
if(miSpriteGeneration!=serverGeneration)
...{
miSpriteScreenIndex=AllocateScreenPrivateIndex();
if(miSpriteScreenIndex<0)
returnFALSE;
miSpriteGeneration=serverGeneration;
miSpriteGCIndex=AllocateGCPrivateIndex();
}
if(!AllocateGCPrivate(pScreen,miSpriteGCIndex,sizeof(miSpriteGCRec)))
returnFALSE;
pPriv=(miSpriteScreenPtr)xalloc(sizeof(miSpriteScreenRec));
if(!pPriv)
returnFALSE;
if(!miPointerInitialize(pScreen,&miSpritePointerFuncs,screenFuncs,TRUE))
...{
xfree((pointer)pPriv);
returnFALSE;
}
for(pVisual=pScreen->visuals;
pVisual->vid!=pScreen->rootVisual;
pVisual++)
;
pPriv->pVisual=pVisual;
pPriv->CloseScreen=pScreen->CloseScreen;
pPriv->GetImage=pScreen->GetImage;
pPriv->GetSpans=pScreen->GetSpans;
pPriv->SourceValidate=pScreen->SourceValidate;
pPriv->CreateGC=pScreen->CreateGC;
pPriv->BlockHandler=pScreen->BlockHandler;
pPriv->InstallColormap=pScreen->InstallColormap;
pPriv->StoreColors=pScreen->StoreColors;
pPriv->PaintWindowBackground=pScreen->PaintWindowBackground;
pPriv->PaintWindowBorder=pScreen->PaintWindowBorder;
pPriv->CopyWindow=pScreen->CopyWindow;
pPriv->ClearToBackground=pScreen->ClearToBackground;
pPriv->SaveDoomedAreas=pScreen->SaveDoomedAreas;
pPriv->RestoreAreas=pScreen->RestoreAreas;
#ifdefRENDER
if(ps)
...{
pPriv->Composite=ps->Composite;
pPriv->Glyphs=ps->Glyphs;
}
#endif
pPriv->pCursor=NULL;
pPriv->x=0;
pPriv->y=0;
pPriv->isUp=FALSE;
pPriv->shouldBeUp=FALSE;
pPriv->pCacheWin=NullWindow;
pPriv->isInCacheWin=FALSE;
pPriv->checkPixels=TRUE;
pPriv->pInstalledMap=NULL;
pPriv->pColormap=NULL;
pPriv->funcs=cursorFuncs;
pPriv->colors[SOURCE_COLOR].red=0;
pPriv->colors[SOURCE_COLOR].green=0;
pPriv->colors[SOURCE_COLOR].blue=0;
pPriv->colors[MASK_COLOR].red=0;
pPriv->colors[MASK_COLOR].green=0;
pPriv->colors[MASK_COLOR].blue=0;
pScreen->devPrivates[miSpriteScreenIndex].ptr=(pointer)pPriv;
pScreen->CloseScreen=miSpriteCloseScreen;
pScreen->GetImage=miSpriteGetImage;
pScreen->GetSpans=miSpriteGetSpans;
pScreen->SourceValidate=miSpriteSourceValidate;
pScreen->CreateGC=miSpriteCreateGC;
pScreen->BlockHandler=miSpriteBlockHandler;
pScreen->InstallColormap=miSpriteInstallColormap;
pScreen->StoreColors=miSpriteStoreColors;
pScreen->PaintWindowBackground=miSpritePaintWindowBackground;
pScreen->PaintWindowBorder=miSpritePaintWindowBorder;
pScreen->CopyWindow=miSpriteCopyWindow;
pScreen->ClearToBackground=miSpriteClearToBackground;
pScreen->SaveDoomedAreas=miSpriteSaveDoomedAreas;
pScreen->RestoreAreas=miSpriteRestoreAreas;
#ifdefRENDER
if(ps)
...{
ps->Composite=miSpriteComposite;
ps->Glyphs=miSpriteGlyphs;
}
#endif
returnTRUE;
}
这个函数有点长,但我们只需要理解关键几点:
- AllocateScreenPrivateIndex分配私有数据空间,用于保存原始函数指针等信息。
- pPriv->PaintWindowBackground = pScreen->PaintWindowBackground; 之类的语句用于保存原始的函数指针。
- pScreen->PaintWindowBackground = miSpritePaintWindowBackground; 之类的语句用于把原始的函数指针替换为装饰之后的函数。
这里要特别说明的是,所谓的原始函数指针,并非一定是原装正品,可能已经是被别的模块装饰之后的函数。
下面我们继续看函数调用的实现:
staticvoid
miSpritePaintWindowBackground(pWin,pRegion,what)
WindowPtrpWin;
RegionPtrpRegion;
intwhat;
...{
ScreenPtrpScreen;
miSpriteScreenPtrpScreenPriv;
pScreen=pWin->drawable.pScreen;
SCREEN_PROLOGUE(pScreen,PaintWindowBackground);
pScreenPriv=(miSpriteScreenPtr)pScreen->devPrivates[miSpriteScreenIndex].ptr;
if(pScreenPriv->isUp)
...{
/**//*
*Ifthecursorisonthesamescreenasthewindow,checkthe
*regiontopaintforthecursorandremoveitasnecessary
*/
if(RECT_IN_REGION(pScreen,pRegion,&pScreenPriv->saved)!=rgnOUT)
miSpriteRemoveCursor(pScreen);
}
(*pScreen->PaintWindowBackground)(pWin,pRegion,what);
SCREEN_EPILOGUE(pScreen,PaintWindowBackground,miSpritePaintWindowBackground);
}
为了看明白这段程序,先得弄清楚两个宏:
SCREEN_PROLOGUE: 用于取出原始的函数指针,后面可以调用原始函数。
#define SCREEN_PROLOGUE(pScreen, field)/
((pScreen)->field = /
((miSpriteScreenPtr) (pScreen)->devPrivates[miSpriteScreenIndex].ptr)->field)
SCREEN_EPILOGUE:重新把装饰过的放回去,以便于下次再调。
#define SCREEN_EPILOGUE(pScreen, field, wrapper)/
((pScreen)->field = wrapper)
弄清楚了这两个宏,上面的程序不难理解了。这种扩展方式的好处在于,运行时动态为对象添加功能,同时又避免了扩展功能与框架的耦合,这是通过子类继承父类,然后重载部分虚函数无法实现的。
(待续)
分享到:
相关推荐
X Window研究笔记 虽然X Window是一个非常复杂的系统,但只要静下心来分析,通常遇到的问题也是很容易解决的,前年我花了一段时间去研究X Window的实现,我发现了解它的实现后,很多问题都迎刃而解了
X-window简略笔记
X Window 程式设计入门--第一章 什么是 X Window X Window 程式设计入门--第二章 X Programming 的第一步 X Window 程式设计入门--第三章 绘图(Graphic) X Window 程式设计入门--第三章 绘图(Graphic) X Window 程...
Xwindow程序设计入门,网上收藏,很好的资料,对了解xwindow编程很有帮助
X Window System 是一套在各种位元映像显示器 (bitmapped dispalys) 上具有极大可携性 (portable) 的视窗系统 (window system), 它是由麻省理工学院 (MIT)所发展出来. X Windows System ( 本书以後部 份简称为...
This practical guide shows X programmers how to construct working 3D applications using OpenGL and how to tightly integrate OpenGL applications with the X Window System. Written by a Silicon Graphics...
描述X window 直接渲染架构的概念,实现
对Linux操作系统的桌面环境软件X window的介绍及启动流程
X Window System 是一套在各种位元映像显示器 (bitmapped dispalys) 上具有极大可携性 (portable) 的视窗系统 (window system), 它是由麻省理工学院 (MIT)所发展出来. X Windows System ( 本书以後部 份简称为...
Linux与X Window系统基础 Linux与X Window系统基础
Linux下X-Window系统程序设计简介.pdf
这个文档为Linux用户提供了一些基本的关于理解和配置X-Window系统的信息。 这只是一个入门级别的文档。假设已经有了一个安装好的并且正在工作的 X-Window系统。
window manager for x window manager for x window manager for x
关于X window的介绍。让你了解并熟悉X window。
Xwindow 是一个非常出色的图形系统,你应该抱怨的是那些不稳定的包装,而不是 Xwindow 本身。
Xming, windows操作系统连接Linux, Unix的x window 工具。
Window批处理命令学习笔记,批处理实用简小工具
一份课程报告,介绍了X-Window的架构体系,并对启动代码做了分析