DirectFB编程指南


DirectFB 编程指南 ________________________________________________________________________________ 目录 第一章 DirectFB 简介........................................................................................................................2 第二章 基础架构................................................................................................................................3 第一节 Fusion.................................................................................................................................3 第二节 DFB 进程线性地址空间...................................................................................................6 第四节 DFB Core...........................................................................................................................7 第五节 Core Part 简介...................................................................................................................8 第三章 DFB 核心..............................................................................................................................11 第一节 DFB 主要对象及其关系.................................................................................................11 第二节 图像内存池.....................................................................................................................18 第三节 绘图机制.........................................................................................................................20 第四节 事件机制.........................................................................................................................22 第五节 窗口更新的一般算法.....................................................................................................23 第四章 窗口管理器..........................................................................................................................25 第一节 简介.................................................................................................................................25 第二节 unique 简介......................................................................................................................29 第三节 hacking unique..................................................................................................................33 第 n 章 代码示例...............................................................................................................................34 后记....................................................................................................................................................57 1 DirectFB 编程指南 ________________________________________________________________________________ 第一章 DirectFB 简介 DirectFB 是基于 Linux Framebuffer 设备的一个图形处理库.这个项目于 2000 年开始,历 经 7 年的发展,目前最新的版本为 1.1.0.由于这个库定位于嵌入式设备,因此代码非常的小巧, 高效.整个库的风格,特别是在用户接口方面,像 DirectDraw 的风格,估计开发者原来也是 DD 的开发人员或者用户.作为对 Framebuffer 的一个简单的封装.这个库提供了如下功能(接口). ✔ 输入设备管理,实现对各类输入设备的扩展. ✔ 窗口管理器接口,实现对窗口管理器的扩展. ✔ 显示系统管理器,实现 DFB 在不同的显示系统上运行. ✔ 硬件驱动管理,为 DFB 提供硬件加速驱动. ✔ 扩展接口:字体管理,静态图像管理,视频数据管理. ✔ 事件队列,用于向用户派发各类窗口消息. ✔ 绘图,包括绘制直线,距形,三角形填冲等等. 应用情况,目前,多个开源的图形库已经有 DFB 的支持了,例如,GTK+,Cairo,Pango 等. 2 DirectFB 编程指南 ________________________________________________________________________________ 第二章 基础架构 DFB 有一个层次划分非常明确的架构,每一层都实现了一个简单而有效的接口,作为更高 层抽象的基础. 第一节 Fusion _DFB________________________________________ user space | Fusion lib ____________|________________________________ Fusion Device | Fusionee(s) -> Message Queue | Reactor(s) SHMPool(s) Call(s) ____________|__Property(s) Skirmish(s) Ref(s)______ Fusion 是 DFB 用于进程间通信的一个组件,包括内核部份和用户空间库两个部份.内核实 现为一个字符设备,用户空间库通过 ioctl 与之交互,并向 DFB 提供较高层的接口. 内核部份提供了如下实体对象和功能: ✔ Fusion world.一个 Fusion world 对应一个 Fusion 设备,可以看作多个进程交互的场所. 进程在能够使用 Fusion world 之前,必须 fusion_enter 一下,称之为”进入”. ✔ World 数据共享.用来表示一个 Fusion world 的数据结构分为两部份:本地部分和共享 部份,每个 DFB 线程拥有自己的本地部份.共享部份则由所有的进程共享.实际上,这是 DFB 一个核心的概念,在后面我们会看到许多数据结构都具有这样的特征. ✔ Fusionee.一个 Fusionee 可以看作用户线程在 Fusion world 中的存根.每个 Fusionee 都有一个消息队列.进程间的通信就是通过消息队列来进行的. ✔ 主/从或者 MASTER/SLAVE 进程.主 DFB 进程是指第一个进入某个 Fusion world 的进 程,主进程负责初始化某个结构的 Share 部份.从 DFB 进程则是指那些第二个及以后进 入的进程,从进程会共享主进程创建的 Share 结构.另外,主进程对应的 Fusionee 的 ID 号一定是 FUSIONEE_ID_MASTER. 3 DirectFB 编程指南 ________________________________________________________________________________ ✔ 消息,消息是进程间通信的基础.当需要通信时,需要向指定的 Fusionee 发送消息.目前 提供的消息类型包括:FMT_SEND,FMT_CALL,FMT_REACTOR,FMT_SHMPOOL. 消息由一个 Message 格式的消息头和消息数据组成.消息头中包括了消息类型,数据指 针,回调函数等信息.其中回调函数由接收者在接收到消息后调用,实现了一个消息签收 的功能. ✔ Reactor.Reactor 可以看作为一个消息源,对该消息源感兴趣的进程可以注册到该消息 源,以便在有消息发生时接收到通知. ✔ 函数共享,或者说进程间函数调用.内核提供这样的机制,使得进程可以注册自己的函数 到 Fusion world 中供其它进程调用. ✔ 共享内存池.共享内存的支持主要是在用户空间部分,内核部份只是提供全局线性空间 的维护,避免出现地址冲突.例如,两个内存池映射到同一个线性空间等.和 Reactor 一样, 内存池也可以发送消息.可以参见后面 DFB 进程地址空间的划分小节. ✔ 其它如 Property,Shirmish.是 Fusion 设备用于支持进程间同步的一些设施. 用户空间部份提供了如下对象和功能: ✔ 消息泵.负责从内核部分读取消息,并根据消息类型的不同进行相应的处理.每个 DFB 进程都有一个消息泵. ✔ 监听机制.用户空间实现了一个 FusionReactor 结构,这个结构和内核中的 Reactor 一 一对应.实现了对消息的响应.每个 FusionReactor 有两个监听函数的列表,一个叫全局 列表或者本地响应列表,这个表中注册的是一个(索引,参数)对.其中索引用于在某个函 数数组中定位需要调用的函数.全局列表用于注册进程内或者说本地的监听函数.另一 个列表为远程响应列表,这是个(函数指针,参数)对的列表.这个列表用于监听其它进程. 进程使用 fusion_reactor_dispatch 函数来派发消息.这个函数会先把消息派发给本地 监听函数.然后再通过 Fusion 设备派发给其它进程.当有其它进程的消息到达时,进程 会调用远程响应列表中的函数进行处理. ✔ FusionObject,这是对 FusionReactor 的进一步封装.所有 DFB 的核心数据结构都是从 这个结构继承过来,因此也自动具备了消息源的功能.例如,CoreWindow 结构.DFB 规 定,FusionObject 必须是结构的第一个成员. ✔ 共享内存.用户空间用 mmap 磁盘文件的方式实现了虚拟内存.主要的结构为 FusionSHMPool 和 FusionSHMPoolShared.每对这样的结构代表一个内存池,系统能 够创建的内存池个数为 16 个.重要的成员为:addr_base,代表内存池的开始线性地址, 和 heap,代表实际的支持文件.这个文件按如下方式命名: fusion..,一 般这个文件会在 dev 目录下创建. 4 DirectFB 编程指南 ________________________________________________________________________________ 用 SHMALLOC 宏分配共享内存. 5 DirectFB 编程指南 ________________________________________________________________________________ 第二节 DFB 进程线性地址空间 DFB 是通过地址空间的映射实现进程间数据共享的,因此有必要讲讲 DFB 地址空间的划 分方式. ✔ World 数据共享,每个 DFB 进程都持有一个类型为 FusionWorld 的数组,这个数组目前 的大小为 8,也就是说,一个 DFB 进程最多可以进入 8 个 Fusion world.每个 World 的共 享部份被依次映射到从 0x20000000 开始到 0x20010000 之间的空间.每个数据区的大 小为 0x2000,8 个数据区刚好占满这段空间. ✔ 共享内存,从 0x20010000 开始是 DFB 的共享内存区.总共可用的共享内存区大小为 0x1FFEF000 字节. -------------- | ... | 0x20000000 -> -------------- | World0 Share | <- kernel page 0x20002000 -> -------------- | ... | ... 0x2000E000 -> -------------- | World7 Share | <- kernel page 0x20010000 -> -------------- | shm pool 1 | <- fusion.0.1 | shm pool 2 | <- fusion.0.2 | shm pool 3 | <- fusion.7.1 | ... | ... somewhere -> | ... | <- framebuffer 这是某个 DFB 进程的一个可能的内存映像 6 DirectFB 编程指南 ________________________________________________________________________________ 第四节 DFB Core DFB Core 由多个 Core Part 组成,正是这些 Part 实现了 DFB 的核心功能,示意图如下: Core ________________________|____________________________ | | | | | | | | | clipboard colorhash system input graphics surface screen layer wm | | | | systems inputdrivers gfxdrivers wm DFB 用 CoreDFB 和 CoreDFBShared 这样一对结构来表示 Core.这对结构是连接 Fusion world 和 Core 的桥梁.Share 部分由主进程初始化: ✔ 创建共享内存池 shmpool,这是个很重要的内存池,所有 Core Part 的共享结构,如 DFBWMCoreShared 等都是从这里分配的. ✔ 从这个内存池中分配 CoreDFBShared 结构,这个结构会持有到 shmpool 的指针. ✔ 创建 shmpool_data 内存池. ✔ 启动各个 Part 的初始化过程. Core Part 和 Core 之间是通过一个 CorePart 的结构来连接的.这个结构定义了: ✔ 特定于 Part 的本地结构和共享结构的大小. ✔ Part 和 Core 初始化过程之间的接口 所有 Part 必须用宏 CORE_PART 来申明.DFB 预定义了一个 CorePart 的数组,通过该数组 DFB 才能找到各个 Part 并进行初始化,所以如果要新增一个 Part,除了要用前面宏来申明外, 还要在这个数组中添加对应的条目. 另外,在 Core Part 之下还可以有一个模块层,模块提供了 DFB 运行时扩展的能力,所有的 模块放在特定的目录下,Core Part 在初始化时会加载这些模块.例如,Part wm 下的 wm 模块用 于实现不同的窗口管理器,目前,DFB 中有两个窗口管理器:default 和 unique.再如 gfxdrivers 模块下则实现了特定显卡的驱动,这些驱动可以提供优于 DFB 的硬件加速的绘图函数.模块使 用 DEFINE_MODULE_DIRECTORY 宏来申明. 7 DirectFB 编程指南 ________________________________________________________________________________ 第五节 Core Part 简介 一,system system 负责向 Core 注册显示系统,所有可能的系统实现为 systems 中的一个模块,目前 ,DFB 实现了下列模块 ✔ fbdev,Linux Framebuffer 设备.默认. ✔ osx ✔ sdl,SDL 渲染面. ✔ vnc ✔ x11,X Window 渲染面. Core 在初始化的过程中,在 Part 的初始化过程启动之前,会调用函数 dfb_system_lookup,这 个函数枚举所有可用的硬件,找到和 dfb_config->system 匹配的模块,得到一个 CoreSystemFuncs 类型的接口.该接口包含了显示系统的初始化入口.system 在初始化时会 调用这个入口.后者一般会调用 dfb_screens_register 和 dfb_layers_register 向 Screen 和 Layer Part 注册 screen 和 layer. 注:layer 是 Core 对显示硬件的抽象 二,surface 这个部份主要负责初始化 surface 的内存分配池.这些分配池用于分配存放图像数据所需 内存.包括如下几类分配池 ✔ Shared Memory ✔ System Memory ✔ Preallocated Memory 关于图像分配池的运行机制参见后面说明 三,layer 这个部份负责初始化已经向系统注册了的 layer. 四,screen 这个部份负责初始化已经向系统注册了的 screen. 五,graphics 8 DirectFB 编程指南 ________________________________________________________________________________ 这个部份主要检查显示系统是否支持硬件加速,如果支持装入相应的驱动.例如,fbdev 就 提供了硬件加速的可能,当然,合适的驱动模块必须存在. 六,wm 这个部份根据 dfb_config->wm 装入对应的窗口管理器模块. 七,input 这个部份枚举所有的输入模块,进行相关的初始化,构建一个 CoreInputDevice 类型的设 备列表. 八,clipboard 这个部份比较简单,没有什么初始化处理.DFB 的 clipboard 就是一块内存,调用 dfb_clipboard_set 来保存数据,调用 dfb_clipboard_get 来获取数据. 九,colorhash 顾名思义,这个部份提供 RGBA 的 Hash 处理.核心函数为 dfb_colorhash_lookup. 十,各 part 核心结构列表 Part 名称 核心结构 主要接口/结构 System DFBSystemCore DFBSystemCoreShared CoreSystemFuncs Surface pool DFBSurfaceCore DFBSurfaceCoreShared SurfacePoolFuncs Layer DFBLayerCore DFBLayerCoreShared DisplayLayerFuncs CoreLayer CoreLayerShared Screen DFBScreenCore DFBScreenCoreShared ScreenFuncs CoreScreen CoreScreenShared Graphics DFBGraphicsCore DFBGraphicsCoreShared GraphicsDriverFuncs Wm DFBWMCore DFBWMCoreShared CoreWMFuncs Input DFBInputCore DFBInputCoreShared CoreInputDevice InputDeviceShared Clipboard DFBClipboardCore DFBClipboardCoreShared Colorhash DFBColorHashCore DFBColorHashCoreShared 9 DirectFB 编程指南 ________________________________________________________________________________ 10 DirectFB 编程指南 ________________________________________________________________________________ 第三章 DFB 核心 核心的主要功能,简单的说就是将适当的数据传送到适当的地方.本章主要介绍这个功能 是如何实现的. 第一节 DFB 主要对象及其关系 CoreLayer -> CoreLayerContext(s) -> CoreLayerRegion(s) -> CoreSurface(s) | / | \ | \ | / | \ | / CoreWindowStack(s) | CoreSurfaceBuffer(s) | | \ | / | CoreWindow(s) --------------| ✔ Layer,对应显示系统提供的接口.例如,framebuffer 设备,x11 提供的渲染面等,总之能够 直接或间接存取硬件设备的接口.Layer 描述了显示系统的硬件能力,包括:分辨率,色彩 格式,缓冲方式等等.DFB 用 CoreLayer 及 CoreLayerShared 来代表一个 Layer. DFB 在 CoreLayer 之上封装一个 IDirectFBDisplayer 接口,这个接口中重要的函数为 SetCooperativeLevel,用这个函数可以在一个 Layer 中创建多个 Context.新创建的 Context 会记录在 CoreLayerShared 中,同时接口也会持有最后创建的 Context 的指针. 另一个重要的函数是 SwitchContext,这个函数激活 Layer 中的某个 Context.当然并不 是任意一个 Context,要么是 Layer 的 Primary Context 要么是接口当前持有的 Context.详细情况请参考 IDirectFBDisplayLayer_SwitchContext 函数. Primary Context,顾名思义,这是一个默认的 Context,即,当用户没有显式的创建一个 Context 时,DFB 将使用这个 Context. 活动 Context,每个 Layer 可以有 0 个或 1 个活动的 Context.Context 需要通过 IDirectFBDisplayer 的 SwitchContext 来激活.当激活一个 Context 时,也会激活所属的 Region.后者在激活时重要的一步就是 realize 的过程,详细情况可参见 Region 部份. CoreLayerShared 的一些成员影响着 Context 的初始化,列示如下: 成员类型 成员名 说明 DFBDisplayLayerConfig default_config 这个值将成为 CoreLayerContext.config 11 DirectFB 编程指南 ________________________________________________________________________________ 成员类型 成员名 说明 的值,而且后者会用于初始化 CoreLayerContext.primary.config,这是个 CoreLayerRegionConfig 类型的变量,将用 于配置 Context 的 Primary region default_config 的值则是由特定的显示系统提供的.例如,fbdev 系统就把 buffermode 初 始化为 DLBM_FRONTONLY,表明 fbdev 不支持双缓冲.详细情况可以参考各个显示模 块的 InitLayer 函数. 其它的从 CoreLayerShared 继承过来的值可以参考 dfb_layer_context_init 函数. ✔ Context,是对显示系统可见区域的一个划分.实际上 Context 是整个系统的开始点,随着 Context 对象的创建,Window Stack,Region,Surface 等对象都会跟着创建起来.DFB 用 CoreLayerContext 来表示一个 Context. 和 region 关系,一个 Context 中可以存在一个或多个 Region.其中有一个为 Primary region.这个 Region 在非 DLBM_WINDOWS 模式(单区域配置)下使用.在 DLBM_WINDOWS 模式(多区域配置)下,Context 中存在多个 Region. CoreLayerContext 用 primary 成员描述 Primary region 的相关信息,用 regions 数组记 录多区域配置.参见下表: 成员 类型 说明 primary.region CoreLayerRegion * Primary region 指针 primary.config CoreLayerRegionConfig Primary region 配置信息 regions FusionVector 多区域配置下的区域集 ✔ Screen,上图中没有画出 Screen 对象,是因为这个对象和其它对象之间没有明确的关 联.但是 Screen 却有着很重要的作用.它代表的就是整个可见的显示区域 .CoreLayerContext 用 screen 成员来描述对这个区域的分割,参见下表: 成员 类型 说明 location DFBLocation 比例分割量.location.x 和 y 代表分割区域的左 上角坐标在 screen 中的相对位置,location.w 和 h 代表分割区域占整个 screen 大小的百分比. rectangle DFBRectangle 绝对分割量,直接代表分割区在 screen 上的位 12 DirectFB 编程指南 ________________________________________________________________________________ 成员 类型 说明 置和大小. mode CoreLayerLayoutMode CLLM_LOCATION CLLM_CENTER CLLM_POSITION CLLM_RECTANGLE 默认情况下,Context 会占据整个的 Screen.用户可以调用 IDirectFBDisplayer 接口的 下面函数来改变上述参数: 函数 需要的能力 说明 SetScreenLocation DLCAPS_SCREEN_LOCATION SetScreenPosition DLCAPS_SCREEN_POSITION SetScreenRectangle DLCAPS_SCREEN_LOCATION 例如,SetScreenLocation( disp , 0.2 , 0.2 , 0.5 , 0.5)将调整对应的 Context 分割区域 到相对位置(0.2,0.2)处,大小为 Screen 大小的一半. 在单区域配置的情况下,上述参数的调整也会调整 Primary region 的目标区域. ✔ Region,代表的是 Context 中的一块区域,单区域配置下,Primary region 占据整个的 Context 区域,多区域配置下,一个 Region 占据一个子区域. 同时 Region 也有配置信息,例如,大小,色彩格式,surface 配置,视口,透明,剪裁区等等. 这里面有些信息是从 Context 继承过来,反映的是显示硬件的一些参数,例如,分辨率,色 彩格式等,另一些是 Region 自身的参数,如大小,视口等.DFB 用 CoreLayerRegion 代表 一个 Region. Region 的状态,Region 可处于启用/禁用,激活/非激活,实现/未实现状态. 和 surface 关系,每个 Region 可以有 0 个或 1 个 Surface,前者在多区域配置时出现,这 个配置下显示硬件会提供显示所需的 Surface.后者在单区域配置时出现,硬件不提供 Surface 支持,因此需要 DFB 都会为其创建一个.可参见下表: 缓冲区模式 Surface Surface buffer 个数 DLBM_WINDOWS 0 0 DLBM_FRONTONLY 1 1 DLBM_BACKVIDEO 1 2 DLBM_BACKSYSTEM 1 2,个数和 BACKVIDEO 模式下一样,但是分配的 13 DirectFB 编程指南 ________________________________________________________________________________ 缓冲区模式 Surface Surface buffer 个数 内存区不一样,前者从显存中分配,后者从系统内 存中分配 DLBM_TRIPLE 1 3 Region 的 realize(实现)过程.简单的说,这个过程就是在视频分配池中锁定一块和 Region 的 Surface 大小对应的内存,这块内存从具备 CSAF_CPU_READ 和 CSAF_GPU_READ 能力的池中分配.详细情况请参见 set_region 函数和 fbdevAllocateBuffer 函数. ✔ Surface 用于保存图像/形数据.每个 Surface 至少会分配一个 Surface buffer 对象,这个 对象代表了各种类型的内存.可以是共享内存,系统内存,显存之一.DFB 的绘图引擎在 绘制图形时,必须被告之一个目标 Surface,生成的图形就保存在其中.另外,一些窗口管 理器会使用 Surface 来装入一些窗口装饰的图片.再如,字体接口会使用缓冲区来装入 字体数据. 为了防止屏幕显示的闪烁,用于显示的 Surface 一般会分配两个或以上的 buffer(DFB 最多支持 3 个),一个用于显示,另一个用于数据更新.影响缓冲区个数的配置参数参见下 表: DFBSurfaceCapabilities 缓冲区个数 DSCAPS_TRIPLE 3 DSCAPS_DOUBLE 2 --- 1 14 DirectFB 编程指南 ________________________________________________________________________________ ✔ WindowStack,这个对象实现了如下功能:1 光标管理,包括装入默认的光标数据,光标数 据的切换,光标的更新等等.2 背景管理,如设置背景色或者设置背景图片等等. ✔ Window,和 Region 一样,也是代表屏幕上的一个区域.区别在于 Window 更多是一个用 户层的概念.是一个用户可以操作的对象.可以改变大小,可以移动,可以关闭,不同 Window 可以相互覆盖等等.两者的关系如下: 单区域配置下,所有的 Window(s)共享一个 Primary Region.Window 有自己的 Surface,Primary Region 也有自己的 Surface.只不过后者分配的是显示系统内存,屏幕 更新时,需要从 Window 向 Primary Region 传送窗口的图像数据.根据 Primary Region 缓冲区模式的不同,有可能先传送到后端,然后再交换到前端缓存进行显示.也有可能直 接传送到前端缓存直接显示.参见下图: 15 DirectFB 编程指南 ________________________________________________________________________________ Surface1 <- Window1 ->| Surface2 <- Window2 ->| -> Primary Region -> Surface ... Surfacen <- Windown ->| 多区域配置下,每个 Window-Region 对共享一个 Surface.Region 没有到 Surface 的引 用,Surface 分配的是显示系统内存.与上面模式相比,窗口图像不需要再从 Window 传 送到 Region.这种模式只有那些内建了窗口支持的显示系统才提供.参见下图: Region1 <- Window1 -> Surface1 Region2 <- Window2 -> Surface2 ... Regionn <- Windown -> Surfacen ✔ 通过前面的描述我们可以知道 DFB 中主要对象存在下面所示的视觉关系: ______Screen____________________________ | | | ______Context_Primary region_____ | | | __Window1__ | | | | | | __Window2_ | | | | |___________| | | | | | | |__________| | | | |_____________________________| | |_______________________________________| 或者 ______Screen____________________________ | | | ______Context__________________ | | | ___Region1__ | | | | | | ___Region2_ | | | | |___________| | | | | | | |__________| | | | |_____________________________| | 16 DirectFB 编程指南 ________________________________________________________________________________ |_______________________________________| 17 DirectFB 编程指南 ________________________________________________________________________________ 第二节 图像内存池 图像内存池用于分配存储图像数据所需内存.不同的池具有不同的存取特性.例如 ,CSAF_GPU_READ 特性表示显示系统的显示内存,这类内存池只有显示系统才能提供.各类 池的详细情况参见下表: 名称 特性 surface 类型 系统池,这些分配池在 surface part 初始化的时候创建 Shared Memory 这个分配池将会从共享内 存区分配 CSAF_CPU_READ, CSAF_CPU_WRITE, CSAF_SHARED CSTF_LAYER, CSTF_WINDOW, CSTF_CURSOR, CSTF_FONT, CSTF_SHARED, CSTF_INTERNAL System Memory 从系统内存中分配 CSAF_CPU_READ, CSAF_CPU_WRITE CSTF_FONT, CSTF_INTERNAL Preallocated Memory 从系统内存中分配 CSAF_CPU_READ, CSAF_CPU_WRITE CSTF_PREALLOCATED 显示系统提供的分配池 Frame Buffer Memory 从 framebuffer 中分配 CSAF_CPU_READ, CSAF_CPU_WRITE, CSAF_GPU_READ, CSAF_GPU_WRITE, CSAF_SHARED CSTF_LAYER, CSTF_WINDOW, CSTF_CURSOR, CSTF_FONT, CSTF_SHARED, CSTF_EXTERNAL X11 Shm Images CSAF_CPU_READ, CSAF_CPU_WRITE, CSAF_GPU_READ, CSAF_GPU_WRITE, CSAF_SHARED CSTF_LAYER, CSTF_WINDOW, CSTF_CURSOR, CSTF_FONT, CSTF_SHARED, CSTF_EXTERNAL SDL CSAF_CPU_READ, CSAF_CPU_WRITE, CSAF_GPU_READ, CSAF_GPU_WRITE CSTF_LAYER, CSTF_WINDOW, CSTF_CURSOR, CSTF_FONT, CSTF_EXTERNAL 18 DirectFB 编程指南 ________________________________________________________________________________ 图像内存池主要对象及关系图 CoreSurface < - > CoreSurfaceBuffer /|\ /|\ | |---------------------| \ | / | CoreSurfacePool -> CoreSurfaceAllocation <- CoreSurfaceBufferLock 图像池系统的入口函数原型如下: DFBResult dfb_surface_pools_negotiate( CoreSurfaceBuffer *buffer, CoreSurfaceAccessFlags access, CoreSurfacePool **ret_pool ) 这个函数用 access 和 buffer->surface->type 匹配分配池的 access 和 types 字段,并返回匹配 成功的分配池.调用者进一步在返回的池中分配内存. DFBResult dfb_surface_pool_allocate( CoreSurfacePool *pool, CoreSurfaceBuffer *buffer, CoreSurfaceAllocation **ret_allocation ) 每一次成功的分配用一个 CoreSurfaceAllocation 结构来表示.这个结构并不提供实际的内存 指针,后者的获得必须再经过一个锁定的过程. DFBResult dfb_surface_pool_lock( CoreSurfacePool *pool, CoreSurfaceAllocation *allocation, CoreSurfaceBufferLock *lock ) 这个函数返回一个 CoreSurfaceBufferLock 结构,这个结构的 addr 成员才代表可存取的内存 地址.实际上,对于某些类型的分配池,例如,Shared Memory 分配和锁定没有区别,而对于另一 些分配池,例如,framebuffer,分配和锁定是不同的.前者仅仅确定了内存在分配池中的偏移,后 者则将这个偏移加上 framebuffer 的基地址上,形成可以存取的地址. 19 DirectFB 编程指南 ________________________________________________________________________________ 第三节 绘图机制 一,总体结构 绘图引擎 | \ | / CardState ------------------- | | GenefxState | \ | / \ | / Buffer1 Buffer2 ... Buffern 直接硬件加速 CardState 是 DFB 绘图功能的核心,这个结构定义了如下重要成员: ✔ CoreSurface *destination,将要在其上绘制图形的 Surface ✔ CoreSurface *source,源 Surface,当需要进行 bitblt 操作时才会使用 ✔ CoreSurfaceBufferRole to,目标 Surface 的缓冲区类型,可能的值包括 CSBR_FRONT CSBR_BACK CSBR_IDLE ✔ CoreSurfaceBufferRole from,源 Surface 的缓冲区类型 ✔ CoreSurfaceBufferLock dst,目标缓冲区内存地址 ✔ CoreSurfaceBufferLock src,源缓冲区内存地址 ✔ GenefxState *gfxs,软驱动状态,当某个绘图功能不能硬件加速时,DFB 将使 用一个软驱动来实现图形绘制.gfxs 用于向其传递初始状态 二,绘图函数的基本流程 ✔ 调用 dfb_state_lock,这个函数锁定 CardState ✔ 调用 dfb_state_start_drawing 通知硬件层 ✔ 调用 dfb_gfxcard_state_check,进行状态检查,例如,检查 clip 的值是否合法,以及保证 clip 区落入目标区域,再如,如过是进行 bitblt 操作,检查源 Surface 是否已经设置等等. 还有最重要的一点就是检查硬件是否支持指定的绘图功能.详细情况请参考函数定义. ✔ 调用 dfb_gfxcard_state_acquire,这个函数会为目标 Surface 锁定一块 CSAF_GPU_WRITE 能力的(还有可能加上 CSAF_GPU_READ)内存,如果是 bitblt 操 作,还要为源 Surface 锁定一块 CSAF_GPU_READ 能力内存.(不过似乎没有看到 DFB 将这些地址传递给硬件) ✔ 如果 dfb_gfxcard_state_check 和 dfb_gfxcard_state_acquire 都返回真值,表明特定的 绘图功能是可以硬件加速的.DFB 会调用 Layer 层提供的加速接口.否则,进入下面步骤 20 DirectFB 编程指南 ________________________________________________________________________________ ✔ 调用 gAcquire,这个函数初始化软引擎.同前面类似,这个函数会为目标 Surface 锁定一 块内存,只不过类型变为 CSAF_CPU_WRITE(或者加上 CSAF_CPU_READ),如果是 bitblt 操作,再为源锁定一块 CSAF_CPU_READ 内存. ✔ 调用软引擎函数进行图形绘制,这些函数都是以 g 打头.例如,gFillRectangle ✔ 调用 dfb_state_unlock 三,使用 从上面绘图函数的基本流程我们可以看出通过为 CardState 设置恰当的值就可以实现绘 图和 bitblt 的功能,下面是各种用法的一个示意图 surface1 surface2 / \ | CSBR_FRONT CSBR_BACK CSBR_FRONT /|\ /|\ | /|\ | | |------1-------| | | |--------------------------|------2-------| 情形 1,是指 Region 的缓冲模式为 DLBM_BACKSYSTEM 的情况,在更新 Region 时,DFB 将 图像数据从后端缓存拷贝前端缓存. 情形 2,这种情况一般是指向屏幕拷贝一些预先装入的图形数据,例如,光标的更新.再如,字体数 据等.视目标 Surface 缓冲区模式的不同,拷贝到前端或者后端 DFBResult dfb_layer_region_flip_update( CoreLayerRegion *region, const DFBRegion *update, DFBSurfaceFlipFlags flags ) { ✔ 检查 region 是否关联 Surface,如果没有无需更新. ✔ 根据 region buffermode 的不同进行相应出理,最简单的一种情况是,缓冲模式为 DLBM_BACKSYSTEM 的情形,这时,DFB 会调用 dfb_back_to_front_copy 将 update 区域内的图像数据从后端缓存拷贝到前端缓存.其它情况也是类似处理.详细情况可参 考函数定义. } 这个函数将更新 region 的指定部份,是对前面缓冲区基本操作的一个具体应用.窗口管理器会 大量使用这个函数. 21 DirectFB 编程指南 ________________________________________________________________________________ 第四节 事件机制 一,总体结构图 CoreInputDevice | | DFBInputEvent \ | / |__CoreWindowStack ... -> | DFBWindowEvent |__UniqueDevice ... -> | ----------> CoreWindow /|\ /|\ |__EventBuffer etc. 省略号表示中间可能还有更多的转换 但一般最后会给 CoreWindow 派发消息 DFB 使用 CoreInpurDevice 结构来代表 DFB 检测到的输入设备.当 Input part 初始化完毕后, 系统中就存在这样的一个列表了.设备最重要的属性包括: ✔ DFBInputDeviceTypeFlags,设备类型.可能的值为:DIDTF_KEYBOARD,键盘 ,DIDTF_MOUSE,鼠标,DIDTF_JOYSTICK,游戏棒,DIDTF_REMOTE,遥控器 ,DIDTF_VIRTUAL,虚拟设备. ✔ DFBInputDeviceCapabilities,设备能力,DICAPS_KEYS, 设备支持按键 ,DICAPS_AXES,设备支持滚轮,DICAPS_BUTTONS,设备支持鼠标按钮. CoreInputDevice 从 FusionObject 继承过来,因此具备发送消息的能力.需要监听输入事件的 对象,只要向 CoreInputDevice 设备注册就可以了,为此,Input part 提供了下面函数: void dfb_input_enumerate_devices( InputDeviceCallback callback, void *ctx, DFBInputDeviceCapabilities caps ) 这个函数会枚举系统中所有可用的 CoreInputDevice,如果设备能力和 caps 匹配,则调用 callback,一般会在这个回调函数中注册对象到设备.目前注册到 CoreInputDevice 的对象可以 参见上图. 二,事件类型 CoreInputDevice 产生的事件用 DFBInputEvent 结构来表示,重要的成员类型如下: ✔ DFBEventClass,可能的值为 DFEC_INPUT,DFEC_WINDOW,DFEC_USER, DFEC_UNIVERSAL,DFEC_VIDEOPROVIDER ✔ DFBInputEventType,可能的值为 DIET_KEYPRESS,DIET_KEYRELEASE, DIET_BUTTONPRESS,DIET_BUTTONRELEASE,DIET_AXISMOTION 22 DirectFB 编程指南 ________________________________________________________________________________ ✔ DFBInputEventFlags,可能的值为... 设备监听者在收到这些事件后,作一些转化,再继续派发到更下一级的监听者.例如 ,CoreWindowStack 会把事件派发给窗口管理器,后者一般会把事件转化为 DFBWindowEvent 类型事件并派发给 CoreWindow 对象.DFB 用户会注册到这个对象上,从 而监听到消息.(注意,这个过程是特定于窗口管理器的.) static DFBResult wm_process_input( CoreWindowStack *stack, void *wm_data, void *stack_data, const DFBInputEvent *event ) 这个函数是窗口管理器处理输入事件的接口.不同的窗口管理器可以实现不同的逻辑.详细情 况参见第四章 窗口管理器. 第五节 窗口更新的一般算法 窗口更新是指如何在显示区域显示窗口图像.DFB 采用的算法可以称为”更新区域分治 法”,这个算法基于这样的一个假设,窗口是分层的,高层的窗口可以遮挡低层的窗口.算法从最 高层窗口开始,依次确定窗口在更新区域中占据的面积.并将高层窗口未占据的区域传递给低 层窗口划分.参见下图: ____u1_u3_________________ | | | .....l1.........___u2____________ |_______ | | | | |......l3........|.......l2.....__________ |____ | | | | | | | |__region_ |___i___ |_____o____| | | 23 DirectFB 编程指南 ________________________________________________________________________________ | | | | | |__opaque______ | | |__window_________________| region 代表需要更新的区域,window 为某个窗口占据的区域,opaque 为窗口的不透明区域,i 为 region 和 window 的交叉区域,o 为窗口不透明区和 region 的交叉区域.u1 和 l1 分别是 i 区 域在 region 区域中的上面空间和左面空间.u2 和 l2 是 o 区域在 i 区域中的对应空间,u3 和 l3 是 o 区域在 region 区域中的对应空间. 当 region 开始更新时,找到窗口栈中最顶层的窗口,计算 i 区和 o 区,如果整个窗口都是不 透明的,则 i 区和 o 区是一样的,那么整个 i 区将完全被当前窗口占据.u1 区和 l1 区将被别的窗 口占据.用这两个区继续裁剪下一层的窗口.并重复这个过程,直到所有的窗口都被处理.如果窗 口的不透明区小于窗口区,如上图所示,只有 o 区被窗口占据,u2 和 l2 区将不属于窗口.DFB 将 用这两个区来裁剪下一层的窗口.上述裁剪过程完毕后,窗口栈里每个窗口在 region 中占据的 区域也确定了,剩下的事情就是把窗口图像传递到对应区域就行了. 24 DirectFB 编程指南 ________________________________________________________________________________ 第四章 窗口管理器 第一节 简介 窗口管理器并不是 DFB 核心功能.DFB 只提供了必要的 API 接口,用户可以在这个基础上 实现自己的窗口管理器.支持架构的总体层次如下: 管理层 glue 函数,这一层的函数和下面窗口管理器接口函数是 一一对应的,都具有 dfb_ + 窗口管理器接口函数名的命 名方式.其作用是实现 DFB 核心到窗口管理器的转接,另 外也可以在这一层实现所有窗口管理器都适用的逻辑. 接口 struct CoreWMFuncs 窗口管理器 default unique ... 对于窗口管理器的实现者来说,主要通过接口层和 DFB 打交道.DFB 用 CoreWMFuncs 结构 来表示这个接口层,定义如下: ✔ wm_get_info,窗口管理器通过这个函数向 wm part 提供一个 CoreWMInfo 结构,这个 结构包含了窗口管理器的一些重要信息.参见下表: 成员名 类型 说明 version CoreWMVersion 版本信息 name,vendor,url,lic ense char * 名称,开发者,主页,适用的许可协议 wm_data_size int 窗口管理器本地结构大小 wm_shared_size int 窗口管理器共享结构大小 stack_data_size int 在 CoreWindowStack 中的私有数据大小 window_data_size int 在 CoreWindow 中的私有数据大小 25 DirectFB 编程指南 ________________________________________________________________________________ ✔ Fusion 相关的接口函数,如 wm_initialize,wm_join 等 ✔ wm_init_stack,DFB 会在创建 CoreWindowStack 对象时调用这个函数.窗口管理器可 以在这个时候创建自己的和 CoreWindowStack 对应的结构.例如,unique 就在这个函 数中创建了 UniqueContext. ✔ wm_close_stack,在析构 CoreWindowStack 对象时调用. ✔ dfb_wm_set_active,这个函数在 DFB 启用/禁用 CoreWindowStack 时调用.当 CoreLayerContext 被启用/禁用时,也会对 CoreWindowStack 进行相应的操作. ✔ wm_resize_stack,当 CoreWindowStack 的大小调整时调用. ✔ wm_process_input,有输入事件发生时 CoreWindowStack 会调用这个函数来派发消 息. ✔ wm_flush_keys ✔ wm_window_at,返回指定位置上的窗口.目前 DFB 内部似乎还没有地方使用这个函数. 而且也没有连接到用户接口,看来是一个还在变动中的接口函数. ✔ wm_window_lookup,按照 WindowID 查找窗口.用户可以通过 IDirectFBDisplayer 的 GetWindow 来调用这个函数. ✔ wm_enum_windows,枚举窗口管理器中的窗口.这个函数为每个窗口调用指定的回调 函数. ✔ wm_get_insets,返回窗口边框大小.DFB 认为边框区域不属于用户可以存取的区域.因 此在返会用户可用区域时,需要调用这个函数来计算边框区域,以便扣除. ✔ wm_preconfigure_window,窗口预配置,DFB 在创建窗口的时候,会给窗口管理器一个 修改窗口配置信息的机会. ✔ wm_set_window_property/wm_get_window_property/wm_remove_window_propert y,用于设置/获取窗口属性.类似于 Cookie 的东西.用户可以通过 IDirectFBWindow 的 SetProperty/GetProperty/RemoveProperty 来使用这些功能. ✔ wm_add_window,DFB 在创建新的窗口时会调用这个函数,窗口管理器可以在这个函 数中创建和 CoreWindow 对应的结构.例如,unique 在这个函数中创建了 UniqueWindow. ✔ wm_remove_window,DFB 在移除一个窗口时会调用这个函数. ✔ wm_set_window_config,DFB 在修改窗口配置时会调用这个函数. 26 DirectFB 编程指南 ________________________________________________________________________________ ✔ wm_restack_window,DFB 在调整了窗口的 z-order 后,会掉用这个函数.用户可以通过 IDirectFBWindow 的相关函数来调整窗口的 z-order,这些函数是:Raise/Lower/ RaiseToTop/LowerToBottom/PutAtop/PutBelow. ✔ wm_grab/wm_ungrab ✔ wm_request_focus ✔ wm_update_stack/wm_update_window/wm_update_cursor,这些都是和窗口更新相 关的函数. 另外,DFB 还提供了两个简单的窗口管理器供参考,一个是 default 窗口管理器,演示了基本的 窗口管理功能: ✔ 支持窗口的移动,关闭 z-order 调整等操作 ✔ 支持 Meta 键 ✔ 事件处理 ✔ 不支持窗口修饰 unique 则实现了更多的特性,具体参见后面介绍. 27 DirectFB 编程指南 ________________________________________________________________________________ 28 DirectFB 编程指南 ________________________________________________________________________________ 第二节 unique 简介 unique 窗口管理器实现了较多的特性 一,总体关系图 | -> CoreWindow -> CoreWindowStack < - > CoreLayerContext | | / | \ / | \ | | | |--------------------| | \ | / \ | / | | WindowData StackData -> UniqueContext | | | / | \ / | \ | | |-----------------------------------------------| | | \ | / | | ---- UniqueWindow <----------------------------------------------| UniqueWindow.surface 指向 CoreWindow 的 surface UniqueContext.region 指向 CoreLayerContext 的 Primary region , UniqueContext.surface 指向 Primary region 的 surface 可以看出,unique 是 DFB 核心部份的自然扩展.每个对象都是核心对象的继承. 二,StReT Stack Region Tree 的简称.unique 把显示区域分为多个层.上一层的图像会覆盖下一层的 图像.所有层的叠加结果组成显示区域的图像.区域还可以划分出子区域.unique 用 StretRegion 来代表这样的区域.这个结构的主要成员如下: ✔ StretRegion *parent 父 ✔ int level 在父中的层级 ✔ int levels 这个 StretRegion 支持的层数 29 DirectFB 编程指南 ________________________________________________________________________________ ✔ FusionVector *children 这是一个向量数组,每个层对应一个向量.用这个来记录对应层 中的 StretRegion. ✔ DFBRegion bounds 相对于父区域的坐标,不同层间的子区域可以相互交叉,同一层中 的子区域一般不允许交叉. ✔ StretRegionClassID clazz 所属类,不同的类别实现不同的输入频道切换和区域更新 方式. root __________________|____________________ | | | | | DESKTOP USER SYSTEM CURSOR SCREEN | frame _______|__________________ | | | BACKGROUND CONTENT FOREGROUND | | window foo 上图中,大写字符代表某个 StretRegion 提供的层.靠右边的层具有更高的优先级,即,这个层中 的区域更后更新.例如,如果 CURSOR 层中有区域的话,一定会覆盖 USER 层中的交叉区域.同 时,子区域比父区域具有更高的优先级,即,子区域比父区域更后更新.小写字符代表属于某个层 的具体的 StretRegion. root 覆盖整个可视区域,frame,window,foo 区域组成 unique 下的窗口,foo 为环绕 frame 的 8 个区域,它们是 4 个边和 4 个角,这些区域一般用于装饰窗口之用,window 为 frame 的中心区, 这个部分才是提供给客户使用的区域. unique 提供一个 StReT 历遍器来实现上述更新策略: void stret_iteration_init( StretIteration *iteration, StretRegion *region, StretRegion *abort_at ) 用这个函数进行初始化,region 指明需要历遍的开始区域,例如上图中的 root 区域.abort_at 为 终止目标区域,如果设置了该参数,历遍时如果遇到了这个区域,历遍将会终止. StretRegion * stret_iteration_next( StretIteration *iteration,const DFBRegion *clip ) 30 DirectFB 编程指南 ________________________________________________________________________________ 开始历遍,如过历遍的过程中某个区域和 clip 有交叉,函数会返回这个区域. unique 中有一个测试 StReT 的例子,下面是这个例子的示意图 (裁剪区域稍作了修改)图中白色区域为裁剪区域,落入这个区域的区域包括:红(2),黄(4),蓝(1), 绿(0),黑(5),和 Root 区(浅蓝),棕色(3)区域没有落入. stret_iteration_next 历遍时,将依次返回:4 2 1 0 5 Root 三,unique 的窗口更新 讲到 unique 的窗口更新,就必须弄清楚 StReT 和 unique 其它对象间的关系,下面是一个示意 图: UniqueContext <-> StretRegion(root) /|\ \|/ UniqueWindow <-> StretRegion(frame) /|\ /|\ /|\ /|\_________________ | | \|/ | | |------------> StretRegion(region) StretRegion(foos[]) |______________________________________/|\ root 代表整个 UniqueContext 的可见区域.可以理解为 unique 的桌面.UniqueWindow 是桌面 的一个子区域.在 UniqueWindow 内部,frame 又被分为内容区和装饰区.两者不在同一个层中. unique 窗口的更新其实就是从 root 区开始的历遍过程.规则是:子区域先历遍后更新, 高层次 区域先历遍后更新.例如,上面 frame 要比 root 后更新, foos 要比 region 后更新. 下面这个函数是 unique 窗口更新的入口.DFB 在更新整个窗口栈的时候会调用它(通过 wm_update_stack) 31 DirectFB 编程指南 ________________________________________________________________________________ DFBResult unique_context_update( UniqueContext *context, const DFBRegion *updates, int num, DFBSurfaceFlipFlags flags ) { ✔ 计算 root 和 updates 数组的交叉区域列表,如果无任何交叉,无需更新,返回. ✔ 设置 CardState 的目标 Surface ✔ 对 root 调用 stret_region_update,这个函数按照前面所述的更新次序更新相关的区域. } 四 ,事件处理 从前面我们已经看到 unique 在 CoreInputDevice 上挂接了自己的事件处理器,下面主要 讲讲从 UniqueDevice 开始以后的处理机制. UniqueDevice |__UniqueContext -> 光标的更新等 |__UniqueInputSwitch => UniqueInputChannel |__UniqueWindow |__foo... 要点如下 ✔ unique 把设备分为 3 类,键盘,指针,滚轮.每一类都用一个 UniqueDeviceClass 实例代 表. ✔ UniqueDevice 把事件派发给对应设备类.后者将 DFBInputEvent 类型的事件转化为 UniqueInputEvent 类型事件后再传递给 UniqueContext 和 UniqueInputSwitch. 设备类 事件 转化 指针 DIET_AXISMOTION UIET_MOTION DIET_BUTTONPRESS DIET_BUTTONRELEASE UIET_BUTTON 键盘 DIET_KEYPRESS DIET_KEYRELEASE UIET_KEY 滚轮 DIET_AXISMOTION UIET_WHEEL 32 DirectFB 编程指南 ________________________________________________________________________________ ✔ UniqueInputSwitch unique 用这个对象实现事件到各个区域的派发.即如果事件的发生 地点落入某个区域,则该事件将会发送到该区域的接收频道,这是一个 UniqueInputChannel 类型的实例. 第三节 hacking unique unique 窗口管理器虽然提供了窗口装饰,但是还是缺少一些基本的元素,例如,最小最大以 及关闭按钮.本小节讲解如何利用 unique 提供的基本设施添加上述功能.基本原理就是在现有 的装饰区中添加新的装饰区.并且实现装饰区的消息处理,要点如下: ✔ 新装饰区布局如下:1 2 3 为新加入的装饰区.分别代表最小最大以及关闭按钮 ___frame_________________________ | _________________|_1_|_2_|_3_| | | | | | | | content | | | |___________________________| | |________________________________ | ✔ 修改 StretRegion 结构添加下列成员 名称 类型 说明 foo_channel UniqueInputChannel 区域的事件处理函数 foo_channel_reaction GlobalReaction startx , starty int 窗口拖动时的起始位置 dragged bool 拖动标志 lighted int 按钮是否点亮 origin_bounds DFBRectangle ✔ 制作按钮图片,每个按钮两张,分别对应正常状态和点亮装态.修改 wm/unique/data/Makefile.in 使其能够处理新加入的图片. ✔ 修改 UniqueFooIndex 添加 UFI_MIN,UFI_MAX,UFI_CLOSE ✔ 添加_unique_region_input_channel_listener 函数,这个函数实现装饰区域事件的响应 ✔ 其它,比较多,说不完.详细情况看看后面的 diff 文件吧. 33 DirectFB 编程指南 ________________________________________________________________________________ 第 n 章 代码示例 一,共享内存空间地址分配 #include #include #include #include int main(int argc , char * args[]) { int fd[2]; int i; FusionSHMPoolNew pool; pool.max_size = 0x10000; pool.addr_base =0; if ( (fd[0] = open("/dev/fusion/0" , O_RDWR | O_NONBLOCK ) ) <=0 ) err(1 , "open 0"); if ( (fd[1] = open("/dev/fusion/1" , O_RDWR | O_NONBLOCK ) ) <=0 ) err(1 , "open 1"); if( ioctl( fd[0] , FUSION_SHMPOOL_NEW , &pool) ) err(1 , "pool new"); printf("pool %d addr 0x%x\n",pool.pool_id , pool.addr_base ); pool.addr_base =0; pool.pool_id = 0; for( i = 0 ; i < 3 ; i++) { if( ioctl( fd[1] , FUSION_SHMPOOL_NEW , &pool) ) err(1 , "pool new"); printf("pool %d addr 0x%x\n",pool.pool_id , pool.addr_base ); } } 这个例子说明无论是同一个 World 中的共享池,还是不同 World 中的.都会在进程的地址空间 中统一分配. 二,Reactor #include #include #include #include #define BUF sizeof(FusionReadMessage)+8 int main( int argc , char * args[]) 34 DirectFB 编程指南 ________________________________________________________________________________ { int i , j , k = 0, l , fd[2] , reactor[2]; char buf[BUF]; FusionEnter e; FusionReactorAttach a; FusionReactorDispatch d; char *msg = "ABCD"; //open 2 worlds if( (fd[0] = open("/dev/fusion/0")) <=0) err( 1 , "open"); if( (fd[1] = open("/dev/fusion/1")) <=0) err( 1 , "open"); //enter and create reactor in the 2 worlds e.api.major = FUSION_API_MAJOR; e.api.minor = FUSION_API_MINOR; for( i = 0 ; i < 2 ; i++ ) { e.fusion_id = 0; if( ioctl( fd[i] , FUSION_ENTER , &e) ) err( 1 , "enter"); printf(" entered as %d\n" , e.fusion_id); if( ioctl( fd[i] , FUSION_REACTOR_NEW , &reactor[i]) ) err( 1 , "reactor"); printf(" reactor %d\n" , reactor[i]); } //attach to reactor for( i = 0 ; i < 2 ; i++ ) for( j = 0 ; j < 2 ; j++) { a.reactor_id = reactor[j]; a.channel = 0; if( ioctl( fd[i] , FUSION_REACTOR_ATTCH , &a)) err( 1 , "attach"); } //say hello for( i = 0 ; i < 2 ; i++ ) for( j = 0 ; j < 2 ; j++) { d.reactor_id = reactor[i]; d.channel = 0; d.self = 0; d.msg_size = 1; d.msg_data = msg[k++]; if( ioctl( fd[i] , FUSION_REACTOR_DISPATCH , &d) ) err( 1 , "dispatch"); } //read message for( i = 0 ; i < 2 ; i++ ) for( j = 0 ; j < 2 ; j++) { FusionReadMessage *rd; r = read( fd[i] , buf , BUF ); 35 DirectFB 编程指南 ________________________________________________________________________________ printf("read %d bytes\n" , r); rd = ( FusionReadMessage*)buf; printf("fusionee %d message type %d id %d size %d channel %d\n" , i, rd->msg_type,rd->msg_id , rd->msg_size , rd->msg_channel); printf("msg "); for( l = 0 ; l < rd->msg_size ; l++) printf("%c" , (rd+1)[l]); printf("\n"); } } 三,DFB 的 tests 目录中提供了很多使用 fusion lib 的例子可以参考. 四,hacking unique 的 diff 文件 Index: wm/unique/stret.c =================================================================== --- wm/unique/stret.c (revision 1) +++ wm/unique/stret.c (revision 2) @@ -35,6 +35,11 @@ #include #include +#include +#include +#include +#include + #include #include @@ -835,3 +840,32 @@ return region->data; } +void +stret_region_set_lighted( StretRegion *region , int light) +{ + CardState *state; + D_DEBUG_AT(UniQuE_StReT,"stret_region_set_lighted %p %d\n",region,light); + + UniqueWindow *win = region->data; + DFBRegion update = DFB_REGION_INIT_TRANSLATED( ®ion->bounds , win- >full.x , win->full.y ); 36 DirectFB 编程指南 ________________________________________________________________________________ + D_MAGIC_ASSERT( win, UniqueWindow ); + + UniqueContext *context = win->context; + D_MAGIC_ASSERT( context, UniqueContext ); + + state = dfb_layer_state( dfb_layer_at(context->layer_id)); + D_MAGIC_ASSERT( state, CardState ); + + if(light) + region->lighted = 1; + else + region->lighted = 0; + //make a update + D_DEBUG_AT(UniQuE_StReT,"stret_region_set_lighted updateregion %d %d %d %d\n", + update.x1 , update.y1 , update.x2 , update.y2); + unique_context_update( context , +//&DFB_REGION_INIT_TRANSLATED(®ion->bounds,win->full.x,win->full.y) +&update, + 1 , DSFLIP_BLIT); +} + Index: wm/unique/stret.h =================================================================== --- wm/unique/stret.h (revision 1) +++ wm/unique/stret.h (revision 2) @@ -151,5 +151,6 @@ void *stret_region_data ( const StretRegion *region ); +void stret_region_set_lighted( StretRegion *region , int light); #endif Index: wm/unique/unique.c =================================================================== --- wm/unique/unique.c (revision 1) +++ wm/unique/unique.c (revision 2) @@ -925,12 +925,15 @@ if (flags & CCUF_ENABLE) { CoreSurface *cursor_bs; + DFBSurfaceCapabilities surface_caps = DSCAPS_NONE; D_ASSERT( context->cursor_bs == NULL ); 37 DirectFB 编程指南 ________________________________________________________________________________ /* Create the cursor backing store surface. */ - ret = dfb_surface_create( wmdata->core, stack->cursor.size.w, stack- >cursor.size.h, - DSPF_RGB16, stack->cursor.policy, DSCAPS_NONE, NULL, &cursor_bs ); + dfb_surface_caps_apply_policy( stack->cursor.policy, &surface_caps ); + ret = dfb_surface_create_simple( wmdata->core, stack->cursor.size.w, stack- >cursor.size.h, + DSPF_ARGB, surface_caps, CSTF_SHARED | CSTF_CURSOR, 0,NULL, + &cursor_bs ); if (ret) { D_ERROR( "WM/Default: Failed creating backing store for cursor!\n" ); return ret; @@ -976,9 +979,9 @@ } if (flags & CCUF_SIZE) { - ret = dfb_surface_reformat( wmdata->core, context->cursor_bs, - stack->cursor.size.w, stack->cursor.size.h, - context->cursor_bs->format ); + ret = dfb_surface_reformat( stack->cursor.surface, + stack->cursor.size.w, stack->cursor.size.h, + context->cursor_bs->config.format ); if (ret) { D_ERROR( "WM/Default: Failed resizing backing store for cursor!\n" ); return ret; Index: wm/unique/window.c =================================================================== --- wm/unique/window.c (revision 1) +++ wm/unique/window.c (revision 2) @@ -51,8 +51,8 @@ #include #include #include +#include - D_DEBUG_DOMAIN( UniQuE_Window, "UniQuE/Window", "UniQuE's Window" ); 38 DirectFB 编程指南 ________________________________________________________________________________ @@ -155,7 +155,7 @@ remove_window( window ); - for (i=0; i<8; i++) { + for (i=0; i<_UFI_NUM; i++) { if (window->foos[i]) stret_region_destroy( window->foos[i] ); } @@ -289,6 +289,11 @@ goto error; } + ret = attach_foos( core , uniwin , context , shared); + if (ret) { + D_MAGIC_CLEAR( uniwin ); + goto error; + } /* Change global reaction lock. */ fusion_object_set_lock( &uniwin->object, &context->stack->context->lock ); @@ -1049,7 +1054,7 @@ return DFB_LIMITEXCEEDED; if (window->surface) { - ret = dfb_surface_reformat( NULL, window->surface, + ret = dfb_surface_reformat( window->surface, width, height, window->surface->config.format ) ; if (ret) return ret; @@ -1327,8 +1332,8 @@ sizes = shared->foo_rects; - if (width <= sizes[UFI_NW].w + sizes[UFI_NE].w) - width = sizes[UFI_NW].w + sizes[UFI_NE].w + 1; 39 DirectFB 编程指南 ________________________________________________________________________________ + if (width <= sizes[UFI_NW].w + sizes[UFI_NE].w + sizes[UFI_MIN].w + sizes[UFI_MAX].w + sizes[UFI_CLOSE].w) + width = sizes[UFI_NW].w + sizes[UFI_NE].w + sizes[UFI_MIN].w + sizes[UFI_MAX].w + sizes[UFI_CLOSE].w + 1; if (width <= sizes[UFI_SW].w + sizes[UFI_SE].w) width = sizes[UFI_SW].w + sizes[UFI_SE].w + 1; @@ -1341,7 +1346,8 @@ ret_rects[UFI_N].x = sizes[UFI_NW].w; ret_rects[UFI_N].y = 0; - ret_rects[UFI_N].w = width - sizes[UFI_NW].w - sizes[UFI_NE].w; + ret_rects[UFI_N].w = width - sizes[UFI_NW].w - sizes[UFI_NE].w + - sizes[UFI_MIN].w - sizes[UFI_MAX].w - sizes[UFI_CLOSE].w; ret_rects[UFI_N].h = sizes[UFI_N].h; ret_rects[UFI_NE].x = width - sizes[UFI_NE].w; @@ -1378,6 +1384,22 @@ ret_rects[UFI_NW].y = 0; ret_rects[UFI_NW].w = sizes[UFI_NW].w; ret_rects[UFI_NW].h = sizes[UFI_NW].h; + + ret_rects[UFI_CLOSE].x = width - sizes[UFI_NE].w - sizes[UFI_CLOSE].w; + ret_rects[UFI_CLOSE].y = 0; + ret_rects[UFI_CLOSE].w = sizes[UFI_CLOSE].w; + ret_rects[UFI_CLOSE].h = sizes[UFI_CLOSE].h; + + ret_rects[UFI_MAX].x = width - sizes[UFI_NE].w - sizes[UFI_CLOSE].w -sizes [UFI_MAX].w; + ret_rects[UFI_MAX].y = 0; + ret_rects[UFI_MAX].w = sizes[UFI_MAX].w; + ret_rects[UFI_MAX].h = sizes[UFI_MAX].h; + + ret_rects[UFI_MIN].x = width - sizes[UFI_NE].w - sizes[UFI_CLOSE].w -sizes [UFI_MAX].w + - sizes[UFI_MIN].w; + ret_rects[UFI_MIN].y = 0; + ret_rects[UFI_MIN].w = sizes[UFI_MIN].w; + ret_rects[UFI_MIN].h = sizes[UFI_MIN].h; } static void 40 DirectFB 编程指南 ________________________________________________________________________________ @@ -1386,7 +1408,7 @@ WMShared *shared ) { int i; - DFBRectangle rects[8]; + DFBRectangle rects[_UFI_NUM]; D_MAGIC_ASSERT( window, UniqueWindow ); D_MAGIC_ASSERT( context, UniqueContext ); @@ -1397,7 +1419,7 @@ foo_rects( window, context, shared, rects ); - for (i=0; i<8; i++) + for (i=0; i<_UFI_NUM; i++) window->foos[i]->bounds = DFB_REGION_INIT_FROM_RECTANGLE( &rects[i] ); } @@ -1410,7 +1432,7 @@ if (! (window->options & DWOP_GHOST)) { if (window->foos[0]) { - for (i=0; i<8; i++) + for (i=0; i<_UFI_NUM; i++) window->foos[i]->flags |= SRF_INPUT; } @@ -1418,7 +1440,7 @@ } else { if (window->foos[0]) { - for (i=0; i<8; i++) + for (i=0; i<_UFI_NUM; i++) window->foos[i]->flags &= ~SRF_INPUT; } @@ -1433,7 +1455,7 @@ 41 DirectFB 编程指南 ________________________________________________________________________________ { int i; DFBResult ret; - DFBRectangle rects[8]; + DFBRectangle rects[_UFI_NUM]; StretRegionFlags flags = SRF_ACTIVE | SRF_OUTPUT; D_MAGIC_ASSERT( window, UniqueWindow ); @@ -1446,21 +1468,23 @@ if (! (window->options & DWOP_GHOST)) flags |= SRF_INPUT; - for (i=0; i<8; i++) { + for (i=0; i<_UFI_NUM; i++) { ret = stret_region_create( shared->region_classes[URCI_FOO], window, i, flags, 1, DFB_RECTANGLE_VALS( &rects[i] ), window->frame, UNFL_FOREGROUND, context->shmpool, &window->foos[i] ); if (ret) - goto error; + goto error; + } return DFB_OK; error: for (--i; i>0; --i) + { stret_region_destroy( window->foos[i] ); - + } return ret; } @@ -1521,3 +1545,147 @@ return DFB_OK; 42 DirectFB 编程指南 ________________________________________________________________________________ } +ReactionResult +_unique_region_input_channel_listener( const void *msg_data, + void *ctx ) +{ + const UniqueInputEvent *event = msg_data; + StretRegion *foo = ctx; + UniqueWindow *window = foo->data; + + D_MAGIC_ASSERT( foo, StretRegion ); + D_MAGIC_ASSERT( window, UniqueWindow ); + + D_ASSERT( event != NULL ); + + D_DEBUG_AT( UniQuE_Window, "_unique_region_input_channel_listener( %p, %p )\n", + event, window ); + + switch(event->type) { + case UIET_MOTION: + if(foo->arg == UFI_N ||foo->arg == UFI_NW ||foo->arg == UFI_NE) + { + if(foo->dragged) { + move_window( window , event->pointer.x - foo->startx , + event->pointer.y - foo->starty); + foo->startx = event->pointer.x; + foo->starty = event->pointer.y; + } + } + break; + case UIET_BUTTON: + if(foo->arg == UFI_N ||foo->arg == UFI_NW ||foo->arg == UFI_NE) + { + if( event->pointer.press) { + foo->dragged = true; + foo->startx = event->pointer.x; + foo->starty = event->pointer.y; + }else{ + foo->dragged = false; + } + } + if(foo->arg == UFI_MIN ||foo->arg == UFI_MAX ||foo->arg == UFI_CLOSE) + { + DFBWindowEvent evt; + if(event->pointer.press) 43 DirectFB 编程指南 ________________________________________________________________________________ + { + stret_region_set_lighted( foo , 0); + } + if(!event->pointer.press) + { + stret_region_set_lighted( foo , 1); + if( foo->arg == UFI_MIN || foo->arg == UFI_MAX) + { + foo->origin_bounds.x = window->bounds.x; + foo->origin_bounds.x = window->bounds.y; + foo->origin_bounds.x = window->bounds.w; + foo->origin_bounds.x = window->bounds.h; + } + if(foo->arg == UFI_MIN) + { + } + else if (foo->arg == UFI_MAX) + { + /* if( foo->state != 2) //not maxmized + { + move_window( window , 0 , 0 ); + resize_window( window , window->context->stack->width, + window->context->stack->height); + foo->state = 2; + }else + { + move_window( window , foo->origin_bounds.x , foo->origin_bounds.y ); + resize_window( window , foo->origin_bounds.w, + foo->origin_bounds.h); + foo->state = 0; + }*/ + } + else if (foo->arg == UFI_CLOSE) + { + evt.type = DWET_CLOSE; + dfb_window_post_event( window->window , &evt); + //quick hack just destroy it + dfb_window_destroy( window->window ); + } + } + } + break; + default: + D_ONCE( "unknown event type" ); + break; + } + return RS_OK; 44 DirectFB 编程指南 ________________________________________________________________________________ +} + +void +unique_window_clear_lighted( UniqueWindow *win) +{ + int i; + + for( i = 0 ; i < _UFI_NUM ; i++) + if(win->foos[i]->lighted) + { + stret_region_set_lighted( win->foos[i] , 0 ); + } +} + +static DFBResult +attach_foos( CoreDFB *core, + UniqueWindow *window, + UniqueContext *context, + WMShared *shared ) +{ + int i; + DFBResult ret; + + if(window->foos[0] == NULL ) + return DFB_OK; + + for( i =0 ; i < _UFI_NUM ; i++) + { + ret = unique_input_channel_create( core, context, &window->foos[i]- >foo_channel ); + if (ret) { + D_MAGIC_CLEAR( window ); + goto error; + } + + ret = unique_input_channel_attach_global(window->foos[i]->foo_channel, + UNIQUE_REGION_INPUT_CHANNEL_LISTENER, + window->foos[i],&window->foos[i]->foo_channel_reaction); + if( ret ) { + D_MAGIC_CLEAR( window ); + goto error; + } + } + return DFB_OK; +error: + for(--i;i > 0 ; --i) 45 DirectFB 编程指南 ________________________________________________________________________________ + { + if(window->foos[i]->foo_channel_reaction.attached) + unique_input_channel_detach_global( window->foos[i]->foo_channel, + &window->foos[i]->foo_channel_reaction ); + if (window->foos[i]->foo_channel) + unique_input_channel_destroy( window->foos[i]->foo_channel ); + } + return ret; +} Index: wm/unique/uniquewm.c =================================================================== --- wm/unique/uniquewm.c(revision 1) +++ wm/unique/uniquewm.c (revision 2) @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -89,34 +90,27 @@ DFBResult ret; void *data; int pitch; + CoreSurfaceConfig config; D_ASSERT( core != NULL ); D_MAGIC_ASSERT( shared, WMShared ); - ret = dfb_surface_create( core, foo_desc.width, foo_desc.height, foo_desc.pixelformat, - CSP_VIDEOHIGH, DSCAPS_NONE, NULL, &shared->foo_surface ); + config.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_CAPS | CSCONF_PREALLOCATED; + config.size.w = foo_desc.width; + config.size.h = foo_desc.height; + config.format = foo_desc.pixelformat; + config.caps = DSCAPS_NONE; + config.preallocated[0].addr = foo_desc.preallocated[0].data; + config.preallocated[0].pitch = foo_desc.preallocated[0].pitch; + 46 DirectFB 编程指南 ________________________________________________________________________________ + ret = dfb_surface_create( core , &config , CSTF_NONE , 0 , NULL , &shared- >foo_surface); if (ret) { D_DERROR( ret, "UniQuE/WM: Could not create %dx%d surface for border tiles!\n", foo_desc.width, foo_desc.height ); return ret; } - ret = dfb_surface_soft_lock( core, shared->foo_surface, DSLF_WRITE, &data, &pitch, false ); - if (ret) { - D_DERROR( ret, "UniQuE/WM: Could not lock surface for border tiles!\n" ); - dfb_surface_unref( shared->foo_surface ); - return ret; - } - - for (i=0; ifoo_surface, data, pitch, 0, i ), - foo_data + i * foo_desc.preallocated[0].pitch, - DFB_BYTES_PER_LINE( foo_desc.pixelformat, foo_desc.width ) ); - } - - dfb_surface_unlock( shared->foo_surface, false ); - dfb_surface_globalize( shared->foo_surface ); return DFB_OK; @@ -185,8 +179,10 @@ shared->insets.r = foo[UFI_E].rect.w; shared->insets.b = foo[UFI_S].rect.h; - for (i=0; i<8; i++) + for (i=0; i<_UFI_NUM; i++) shared->foo_rects[i] = foo[i].rect; + for(i=0 ; i< 5 ; i++) + shared->foo_rects[_UFI_NUM - 1 + i] = foo[_UFI_NUM-1+i].rect; } else dfb_input_set_global( _unique_device_listener, shared->device_listener ); Index: wm/unique/classes/foo.c =================================================================== 47 DirectFB 编程指南 ________________________________________________________________________________ --- wm/unique/classes/foo.c (revision 1) +++ wm/unique/classes/foo.c (revision 2) @@ -36,6 +36,7 @@ #include #include +#include #include @@ -58,10 +59,10 @@ { UniqueContext *context; UniqueWindow *window = region_data; - + D_MAGIC_ASSERT( region, StretRegion ); D_MAGIC_ASSERT( window, UniqueWindow ); - + context = window->context; D_MAGIC_ASSERT( context, UniqueContext ); @@ -77,8 +78,19 @@ *ret_channel = window->channel; break; - case UDCI_POINTER: - *ret_channel = window->channel; + case UDCI_POINTER: + unique_window_clear_lighted( window ); + if( arg == UFI_N || arg == UFI_NE || arg == UFI_NW || + arg == UFI_MIN || arg == UFI_MAX || arg ==UFI_CLOSE) + { + *ret_channel = region->foo_channel; + if(arg == UFI_MIN || arg == UFI_MAX || arg ==UFI_CLOSE) + { + stret_region_set_lighted( region , 1); + } + } + else 48 DirectFB 编程指南 ________________________________________________________________________________ + *ret_channel = window->channel; // *ret_channel = context->foo_channel; break; @@ -118,6 +130,8 @@ D_MAGIC_ASSERT( window, UniqueWindow ); D_MAGIC_ASSERT( state, CardState ); + if(!D_FLAGS_IS_SET( window->flags, UWF_DECORATED ) ) return; + shared = window->shared; D_MAGIC_ASSERT( shared, WMShared ); @@ -203,10 +217,15 @@ dfb_state_set_clip( state, &clip ); break; + case UFI_CLOSE: + case UFI_MIN: + case UFI_MAX: + if( region->lighted) + arg += 4; case UFI_NE: case UFI_SE: case UFI_SW: - case UFI_NW: + case UFI_NW: for (i=0; ichannel; return DFB_OK; Index: wm/unique/window.h =================================================================== --- wm/unique/window.h (revision 1) +++ wm/unique/window.h (revision 2) @@ -130,6 +130,13 @@ UNIQUE_WM_MODULE_WINDOW_LISTENER } UNIQUE_WINDOW_GLOBALS; +void +unique_window_clear_lighted( UniqueWindow *win); +static DFBResult +attach_foos( CoreDFB *core, + UniqueWindow *window, + UniqueContext *context, + WMShared *shared ); #endif Index: wm/unique/internal.h =================================================================== --- wm/unique/internal.h (revision 1) +++ wm/unique/internal.h (revision 2) @@ -77,7 +77,12 @@ UFI_S, UFI_SW, UFI_W, - UFI_NW + UFI_NW, + UFI_MIN, + UFI_MAX, + UFI_CLOSE, + + _UFI_NUM } UniqueFooIndex; typedef ReactionResult (*UniqueWMContextNotify)( WMData *data, @@ -115,7 +120,7 @@ 50 DirectFB 编程指南 ________________________________________________________________________________ DFBInsets insets; - DFBRectangle foo_rects[8]; + DFBRectangle foo_rects[_UFI_NUM + 5 ]; CoreSurface *foo_surface; }; @@ -212,7 +217,7 @@ StretRegion *frame; StretRegion *region; - StretRegion *foos[8]; + StretRegion *foos[_UFI_NUM]; DFBInsets insets; @@ -270,6 +275,14 @@ unsigned long arg; /* Optional argument for region class instance. */ FusionSHMPoolShared *shmpool; + + UniqueInputChannel *foo_channel; + GlobalReaction foo_channel_reaction; + int startx , starty; + bool dragged; + int lighted; + DFBRectangle origin_bounds; + int state; }; struct __UniQuE_UniqueDevice { @@ -373,5 +386,8 @@ ReactionResult _unique_window_input_channel_listener( const void *msg_data, void *ctx ); +ReactionResult _unique_region_input_channel_listener( const void *msg_data, + void *ctx ); + #endif 51 DirectFB 编程指南 ________________________________________________________________________________ Index: wm/unique/context.c =================================================================== --- wm/unique/context.c (revision 1) +++ wm/unique/context.c (revision 2) @@ -394,7 +394,7 @@ /* Different compositing methods depending on destination format. */ if (flags & DSBLIT_BLEND_ALPHACHANNEL) { - if (DFB_PIXELFORMAT_HAS_ALPHA( state->destination->format )) { + if (DFB_PIXELFORMAT_HAS_ALPHA( state->destination->config.format )) { /* * Always use compliant Porter/Duff SRC_OVER, * if the destination has an alpha channel. @@ -418,7 +418,7 @@ dfb_state_set_src_blend( state, DSBF_ONE ); /* Need to premultiply source with As*Ac or only with Ac? */ - if (! (stack->cursor.surface->caps & DSCAPS_PREMULTIPLIED)) + if (! (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED)) flags |= DSBLIT_SRC_PREMULTIPLY; else if (flags & DSBLIT_BLEND_COLORALPHA) flags |= DSBLIT_SRC_PREMULTCOLOR; @@ -443,7 +443,7 @@ * cx = Cd * (1-As*Ac) + Cs*As * Ac (still same effect as above) * ax = Ad * (1-As*Ac) + As*As * Ac (wrong, but discarded anyways) */ - if (stack->cursor.surface->caps & DSCAPS_PREMULTIPLIED) { + if (stack->cursor.surface->config.caps & DSCAPS_PREMULTIPLIED) { /* Need to premultiply source with Ac? */ if (flags & DSBLIT_BLEND_COLORALPHA) flags |= DSBLIT_SRC_PREMULTCOLOR; Index: wm/unique/input_channel.c =================================================================== --- wm/unique/input_channel.c (revision 1) +++ wm/unique/input_channel.c (revision 2) @@ -50,6 +50,7 @@ static const ReactionFunc unique_input_channel_globals[] = { _unique_window_input_channel_listener, 52 DirectFB 编程指南 ________________________________________________________________________________ + _unique_region_input_channel_listener, NULL }; Index: wm/unique/data/foo_sw.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: wm/unique/data/foo_min_h.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wm/unique/data/foo_min_h.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: wm/unique/data/foo_max_h.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wm/unique/data/foo_max_h.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: wm/unique/data/Makefile.in =================================================================== --- wm/unique/data/Makefile.in (revision 1) +++ wm/unique/data/Makefile.in (revision 2) @@ -231,7 +231,9 @@ foo_s.png \ foo_sw.png \ foo_w.png \ - foo_nw.png + foo_nw.png \ + foo_min_n.png foo_max_n.png foo_close_n.png foo_restr_n.png \ + foo_min_h.png foo_max_h.png foo_close_h.png foo_restr_h.png @BUILD_TOOLS_FALSE@@CROSS_COMPILING_FALSE@directfb_csource = $(DIRECTFB_CSOURCE) 53 DirectFB 编程指南 ________________________________________________________________________________ @BUILD_TOOLS_TRUE@@CROSS_COMPILING_FALSE@directfb_csource = $(top_builddir)/tools/directfb-csource Index: wm/unique/data/foo_n.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: wm/unique/data/foo_min_n.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wm/unique/data/foo_min_n.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: wm/unique/data/foo_s.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: wm/unique/data/foo_ne.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: wm/unique/data/foo_max_n.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wm/unique/data/foo_max_n.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: wm/unique/data/foo_restr_h.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wm/unique/data/foo_restr_h.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: wm/unique/data/foo_w.png =================================================================== 54 DirectFB 编程指南 ________________________________________________________________________________ Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: wm/unique/data/foo_se.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: wm/unique/data/foo_restr_n.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wm/unique/data/foo_restr_n.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: wm/unique/data/foo_close_h.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wm/unique/data/foo_close_h.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: wm/unique/data/foo_close_n.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: wm/unique/data/foo_close_n.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Index: wm/unique/data/foo_nw.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: wm/unique/data/foo_e.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: wm/unique/input_channel.h =================================================================== 55 DirectFB 编程指南 ________________________________________________________________________________ --- wm/unique/input_channel.h (revision 1) +++ wm/unique/input_channel.h (revision 2) @@ -67,7 +67,8 @@ /* global reactions */ typedef enum { - UNIQUE_WINDOW_INPUT_CHANNEL_LISTENER + UNIQUE_WINDOW_INPUT_CHANNEL_LISTENER, + UNIQUE_REGION_INPUT_CHANNEL_LISTENER } UNIQUE_INPUT_CHANNEL_GLOBALS; #endif Index: inputdrivers/linux_input/linux_input.c =================================================================== --- inputdrivers/linux_input/linux_input.c (revision 1) +++ inputdrivers/linux_input/linux_input.c (revision 2) @@ -933,7 +933,7 @@ ioctl( fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit ); /** count typical keyboard keys only */ - for (i=KEY_Q; i
还剩56页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 7 人已下载

下载pdf

pdf贡献者

yushang

贡献于2015-07-02

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf