前言:

个人习惯学习源码先从编译结构了解代码模块,所以先从编译结构开始了解。
如果编译角度搞不定,就代码开始运行时,各个模块初始化的角度开始了解。

学习源码——编译角度

下载源码

    git clone https://github.com/VincentWei/minigui.gitminigui

编译

minigui使用autotools工具来生成Makefile文件,然后再执行make编译。

一般操作流程是:

autoconf
auto make
./configure
make

但是不起作用啊,autoconf执行失败。

于是直接运行autogen.sh,然后autoconf,automake,./configure都可运行了,但是make运行失败。

想了想,还是放弃从编译角度切入了吧

  1. 自动生成的Makefile太过复杂,难以解析
  2. autotools工具也不熟

学习源码——运行角度

初始化入口:

MiniGUIAppMain

MiniGUIAppMain是用例的入口函数,所以从这个函数开始顺腾摸瓜,了解代码的模块和结构
MiniGUIAppMain的定义:

                        #define MiniGUIMain \MiniGUIAppMain (int args, const char* argv[]); \int main_entry (int args, const char* argv[]) \{ \int iRet = 0; \if (InitGUI (args, argv) != 0) { \return 1; \} \iRet = MiniGUIAppMain (args, argv); \TerminateGUI (iRet); \return iRet; \} \int MiniGUIAppMain

从代码可知,MiniGUIMain 会先运行InitGUI(),然后再运行MiniGUIAppMain,界面完了以后,还会调用TerminateGUI回收界面资源

模块初始化

InitGUI()总共调用了下面20多个初始化函数,前置工作准备

初始化各个模块初始化的函数,以及模块的流程如下:

                1. _sysvipc_mutex_sem_init2. mg_InitSliceAllocator3. mg_InitFixStr4. mg_InitMisc5. mg_InitGAL6. InstallSEGVHandle7. mg_InitSystemRes8. mg_InitGDI9. mg_InitScreenDC10. license_create11. mg_InitCursor12. mg_InitLWEvent13. mg_InitLFManager14. mg_InitMenu15. mg_InitControlClass16. mg_InitAccel17. mg_InitDesktop18. mg_InitFreeQMSGList19. createThreadInfoKey20. SystemThreads21. SetKeyboardLayout22. SetCursor23. SetCursorPos24. mg_TerminateMgEtc

模块作用了解

一般来说,每个模块会有个小的说明文档,但是没有找到,所以算了。
看源码应该大致能了解其作用,如果不能了解其作用,则跟着用例的创建窗口的代码往下跑,看模块是怎么用的来学习他吧。

模块作用总结如下:

1. _sysvipc_mutex_sem_init信号量初始化,信号量是跨进程的,用于进程间共享内存锁。这个函数内部清空了许多sem锁,然后重新创建。功能:初始化锁2. mg_InitSliceAllocator作用尚未了结清楚,初步理解为窗口内存碎片整理3. mg_InitFixStr功能:字串补全,内存占用2^n~2^(n+1)时,空间大小补全为2^(n+1)4. mg_InitMisc功能:零零散散的杂项功能初始化,观其实现时是存取配置项功能。还有个clipboard剪辑版,暂时不了解5. mg_InitGAL功能:创建一个video设备,并创建一个surface对象与video设备互相指向。video设备初始化时,会从底层map一段内存出来,然后由surface对其进行管理。读写surface时会直接改变界面。6. InstallSEGVHandle功能:linux 系统信号监听及处理7. InitSystemRes功能:建一张存数据的hash表,用于存储资源。添加bmp内部资源,添加icon资源,添加样式资源    8. InitGDI全称:global graphic interface功能:包括了所有图形操作的接口9. InitScreenDC功能:1. 初始化InitBlockDataHeap(__mg_FreeClipRectList)2. dc_InitClipRgnInfo,初始化dc池,后续取hdc就从这里取3. 初始化全局dc,__mg_screen_dc4. 初始化全局dc,__mg_screen_sys_dc10. license_create功能:加载license相关资源,具体作用未明11. InitCursor功能:初始化鼠标资源12. mg_InitLWEvent功能:初始化IAL,事件输入模块13. mg_InitLFManager功能:初始化系统默认样式14. mg_InitMenu功能:菜单相关1. 初始化InitBlockDataHeap(MBHeap),作用未知2. 初始化InitBlockDataHeap(MIHeap),作用未知3. 初始化InitBlockDataHeap(TMIHeap),作用未知15. mg_InitControlClass功能:注册系统默认样式的控件16. mg_InitAccel功能:1. 初始化InitBlockDataHeap(ACHeap),作用未知2. 初始化InitBlockDataHeap(AIHeap),作用未知17. mg_InitDesktop功能:1. 初始化z序的数据结构2. 初始化InitBlockDataHeap(sg_FreeClipRectList)3. 初始化InitBlockDataHeap(sg_FreeInvRectList)4. 初始化__mg_hwnd_desktop,也就是DESKTOP_HWND5. 初始化桌面的消息队列,__mg_hwnd_desktop->pMessages =  __mg_dsk_msg_queue6. 设置系统默认的控件样式18. mg_InitFreeQMSGList功能:初始化InitBlockDataHeap(QMSGHeap),作用未知19. createThreadInfoKey功能:初始化主线程的pthread_key,使主线程也有对应的线程标志。后续创建主窗口时,也是根据该线程标志来获取消息队列的,也许还有很多和主线程pthread_key相关的模块20. SystemThreads功能:创建两个线程,一个是DesktopMain,另一个是EventLoopDesktopMain:不停的接收并处理消息,凡是发给桌面的消息,都在该线程处理EventLoop:运行IAL模块,不停地获取事件21. SetKeyboardLayout功能:初始化键盘布局相关,作用未知22. SetCursor&SetCursorPos功能:预测设置光标,作用未知23. mg_TerminateMgEtc功能:结束配置管理模块,作用未知

GAL模块解析

按照从上向下的顺序,第一我先详细说明GAL模块。

GAL模块的初始化,我就不按初始化的流程来说明,我先将模块拆解成一个个小模块,然后介绍完小模块以后,再说明整个初始化的流程。

video驱动管理模块——video-drivers

video会有各种不同厂商的设备,不同厂商的设备会有不同的驱动,所以video-drivers模块包含了很多video视频设备的驱动

所有的这些video驱动模块都保存在boot_strap(VideoBootStrap**)这个全局变量当中

src/newgal/video.c 中可以看到这个boot_strap这个全局变量包含了哪些驱动:

/* Available video drivers */
static VideoBootStrap *bootstrap[] = {#ifdef _MGGAL_DUMMY
&DUMMY_bootstrap,
#endif
#ifdef _MGGAL_FBCON
&FBCON_bootstrap,
#endif
#ifdef _MGGAL_QVFB
&QVFB_bootstrap,
#endif
...
NULL
};

然后我们只挑FBCON_bootstrap,稍微深入了解下。

fbcon驱动模块

fbcon模块的源码目录在:src\newgal\fbcon\

我们先看fbvideo.c文件,FBCON_bootstrap的定义:

                VideoBootStrap FBCON_bootstrap = {"fbcon", "Linux Framebuffer Console",FB_Available, FB_CreateDevice};

GAL模块初始化,选中FBCON_bootstrap驱动时,会调用FB_CreateDevice获取一个video设备对象,我们称之为’video’

以后我们看看FB_CreateDevice,对返回的video设备对象做了哪些初始化:

                this->VideoInit = FB_VideoInit;this->ListModes = FB_ListModes;this->SetVideoMode = FB_SetVideoMode;this->SetColors = FB_SetColors;this->VideoQuit = FB_VideoQuit;this->AllocHWSurface = FB_AllocHWSurface;this->CheckHWBlit = NULL;this->FillHWRect = NULL;this->SetHWColorKey = NULL;this->SetHWAlpha = NULL;this->UpdateRects = NULL;this->FreeHWSurface = FB_FreeHWSurface;this->GetFBInfo = FB_GetFBInfo;this->free = FB_DeleteDevice;

这些函数就是video设备对象可以执行的操作了
操作很多也很复杂,但是我只了解了FB_VideoInit和FB_SetVideoMode两个函数的实现
因为初始化就用到了这两个函数

FB_VideoInit

FB_VideoInit函数中,映射了一段内存到video->hidden->mapped_mem:

#define mapped_mem          (this->hidden->mapped_mem)
mapped_mem = mmap(NULL, mapped_memlen,PROT_READ|PROT_WRITE, MAP_SHARED, console_fd, 0);

以及计算了一个偏移地址:

ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo)
/* Memory map the device, compensating for buggy PPC mmap() */
mapped_offset = (((long)finfo.smem_start) -(((long)finfo.smem_start)&~(getpagesize () - 1)));
mapped_memlen = finfo.smem_len+mapped_offset;
FB_SetVideoMode

FB_SetVideoMode函数中,对传入的参数current(也就是surface)进行了初始化

/* Set up the new mode framebuffer */
current->flags = (GAL_FULLSCREEN|GAL_HWSURFACE);
current->w = vinfo.xres;
current->h = vinfo.yres;
current->pitch = finfo.line_length;
current->pixels = mapped_mem+mapped_offset;

其实SetVideoMode就有点像告诉video驱动,我要要显示的图像的大小,格式,你给我一张合适的画布放surface里,我自己绘图

总结:映射的这段buffer,会被video控制器以一定频率不停的读取显示到video设备上
而这段内存又保存在了surface中,所以操作surface->pixels,就有点像直接在设备界面上绘图

surface模块

源码位置:src/newgal/surface.c
surface模块的初始化入口是GAL_CreateRGBSurface函数,这个函数里面会new一个surface对象,
然后由GAL_VideoSurface这个全局指针接管。据我目前观察,之后大多数情况都是使用的GAL_VideoSurface

GAL初始化流程

文件入口:src\newgal\newgal.c

mg_InitGAL:GAL_VideoInit:GAL_GetVideo:FBCON_bootstrap->create:FB_CreateDevice:创建一个video设备对象,并返回video->VideoInit:映射一段buffer保存在video->hidden->mapped_mem中初始化全局变量:current_video = videocurrent_video->screen = NULLGAL_VideoSurface = GAL_CreateRGBSurface(...):创建一个surface初始化全局变量:GAL_VideoSurface->video = current_video;__gal_screen = GAL_SetVideoMode:video->SetVideoMode:根据mode设置surface内容,并返回初始化GDI模块的全局变量:SysPixelIndex

IAL模块解析

函数入口:mg_InitLWEvent->mg_InitIAL
文件入口:src/kernel/event.c->src/ial/ial.c

负责事件获取,并转成windows message上传到设备端

IAL引擎

同video有众多设备驱动一样,IAL也有众多引擎
根据配置里的IAL引擎名称,IAL模块会选择其中一个引擎赋值到全局变量__mg_cur_input中
然后使用__mg_cur_input来进行引擎操作,一下是IAL所有的引擎,我只取libinput说明一下

static INPUT inputs [] =
{/* General IAL engines ... */
#ifdef _MGIAL_QVFB
{"qvfb", InitQVFBInput, TermQVFBInput},
#endif
...
#ifdef _MGIAL_LIBINPUT
{"libinput", InitLibInput, TermLibInput},
#endif
/* ... end of general IAL engines */
};

libinput

libinput的入口函数是InitLibInput,IAL获取到libinput之后,便会调用该接口
这里我只说明两个函数,一个是初始化函数InitLibInput,以及wait_event_ex
因为初始化会用到InitLibInput,以及之后读取事件会调用wait_event_ex

InitLibInput

InitLibInput对于input引擎的初始化:

...
input->update_mouse = mouse_update;
input->get_mouse_xy = mouse_getxy;
input->set_mouse_xy = mouse_setxy;
input->get_mouse_button = mouse_getbutton;
input->set_mouse_range = mouse_setrange;
input->suspend_mouse= input_suspend;
input->resume_mouse = input_resume;input->update_keyboard = keyboard_update;
input->get_keyboard_state = keyboard_getstate;
input->suspend_keyboard = input_suspend;
input->resume_keyboard = input_resume;
input->set_leds = set_leds;input->wait_event_ex = wait_event_ex;
...
wait_event_ex
wait_event_ex可以获取事件,并返回事件的类型

IAL初始化流程

mg_InitIAL:
InitLibInput:
初始化__mg_cur_input,并给其接口赋初值,之后便是用这个全局对象获取事件

SystemThreads模块解析

函数入口:SystemThreads
文件入口:src/kernel/init.c

该模块主要是运行起桌面模块和IAL模块,将这两者关联到一块

创建线程DesktopMain

初始化桌面

调用init_desktop_win函数,初始化桌面参数,如下:

...
static MAINWIN desktop_win;
pDesktopWin = &desktop_win;
pDesktopWin->pMessages         = __mg_dsk_msg_queue;
pDesktopWin->MainWindowProc    = DesktopWinProc;
...
pDesktopWin->pMainWin          = pDesktopWin;
pDesktopWin->we_rdr            = __mg_def_renderer;__mg_hwnd_desktop = (HWND)pDesktopWin;
__mg_dsk_win  = pDesktopWin;
...

注意:

#define HWND_DESKTOP        __mg_hwnd_desktop

也就是说HWND_DESKTOP就是桌面本身,类型是MAINWIN

消息处理

获取并处理消息的步骤如下:

while (GetMessage(&Msg, HWND_DESKTOP)) {...
DesktopWinProc (HWND_DESKTOP,
Msg.message, Msg.wParam, Msg.lParam);
...
}

创建线程EventLoop

循环读消息

IAL_WaitEvent

发消息

发送消息到HWND_DESKTOP桌面的毁掉函数中

control模块解析

函数入口:mg_InitControlClass
文件入口:src\gui\ctrlclass.c

button控件

文件入口:src\control\button.c
函数入口:RegisterButtonControl

控件有很多自定义模块,我这里就专门挑button说下
控件的绘制是在WinProc中的WM_PAINT中进行的,RegisterButtonControl函数中会
将WNDCLASS类型的对象填上一些参数,然后调用AddNewControlClass。具体代码如下:

BOOL RegisterButtonControl (void)
{WNDCLASS WndClass;WndClass.spClassName = CTRL_BUTTON;
WndClass.dwStyle     = WS_NONE;
WndClass.dwExStyle   = WS_EX_NONE;
WndClass.hCursor     = GetSystemCursor (IDC_ARROW);
WndClass.iBkColor    =
GetWindowElementPixel (HWND_NULL, WE_MAINC_THREED_BODY);
WndClass.WinProc     = ButtonCtrlProc;return AddNewControlClass (&WndClass) == ERR_OK;
}AddNewControlClass函数会根据WndClass的内容创建一个CTRLCLASSINFO结构的对象,然后将其保存到ccitable链表中

初始化流程

BOOL mg_InitControlClass ()
{int i;for (i=0; i<LEN_CCITABLE; i++)
ccitable[i] = NULL;// Register system controls here.
#ifdef _MGCTRL_STATIC
if (!RegisterStaticControl ())
return FALSE;
#endif#ifdef _MGCTRL_BUTTON
if (!RegisterButtonControl())
return FALSE;
#endif
...
}

GDI模块初始化

入口函数有两个:mg_InitScreenDC,mg_InitGDI
入口文件:src/newgdi/gdi.c

前面模块了解部分已经初步学习,所以就不写了

mg_InitScreenDC

dc_InitClipRgnInfo

初始化DC池,将每一个DC和surface挂钩,具体初始化如下:

for (i=0; i<DCSLOTNUMBER; i++) {/* Local clip region */
InitClipRgn (&DCSlot[i].lcrgn, &__mg_FreeClipRectList);
MAKE_REGION_INFINITE(&DCSlot[i].lcrgn);/* Global clip region info */
DCSlot[i].pGCRInfo = NULL;
DCSlot[i].oldage = 0;/* Effective clip region-- 有效剪辑区,暂时不了解 */
InitClipRgn (&DCSlot[i].ecrgn, &__mg_FreeClipRectList);
}

dc_InitScreenDC

调用两次,初始化__mg_screen_dc和__mg_screen_sys_dc
具体初始化的内容,我提炼了一下,如下:

1. pdc->DataType = TYPE_HDC;
2. 初始化bkcolor
3. 初始化画笔颜色,和样式
4. 初始化画刷颜色
5. 初始化DevRC,设备可显示屏幕大小
6. pdc->surface = surface;
7. pdc->cur_dst = pdc->surface->pixels;
...

minigui源码学习相关推荐

  1. Shiro源码学习之二

    接上一篇 Shiro源码学习之一 3.subject.login 进入login public void login(AuthenticationToken token) throws Authent ...

  2. Shiro源码学习之一

    一.最基本的使用 1.Maven依赖 <dependency><groupId>org.apache.shiro</groupId><artifactId&g ...

  3. mutations vuex 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

    前言 Vuex源码系列不知不觉已经到了第六篇.前置的五篇分别如下: 长篇连载:Vuex源码学习(一)功能梳理 长篇连载:Vuex源码学习(二)脉络梳理 作为一个Web前端,你知道Vuex的instal ...

  4. vue实例没有挂载到html上,vue 源码学习 - 实例挂载

    前言 在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法. src ├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能. ├── ...

  5. 2021-03-19Tomcat源码学习--WebAppClassLoader类加载机制

    Tomcat源码学习--WebAppClassLoader类加载机制 在WebappClassLoaderBase中重写了ClassLoader的loadClass方法,在这个实现方法中我们可以一窥t ...

  6. jQuery源码学习之Callbacks

    jQuery源码学习之Callbacks jQuery的ajax.deferred通过回调实现异步,其实现核心是Callbacks. 使用方法 使用首先要先新建一个实例对象.创建时可以传入参数flag ...

  7. JDK源码学习笔记——Integer

    一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...

  8. DotText源码学习——ASP.NET的工作机制

    --本文是<项目驱动学习--DotText源码学习>系列的第一篇文章,在这之后会持续发表相关的文章. 概论 在阅读DotText源码之前,让我们首先了解一下ASP.NET的工作机制,可以使 ...

  9. Vuex源码学习(五)加工后的module

    没有看过moduleCollection那可不行!Vuex源码学习(四)module与moduleCollection 感谢提出代码块和截图建议的小伙伴 代码块和截图的区别: 代码块部分希望大家按照我 ...

最新文章

  1. nodejs源码—初始化
  2. ad中电容用什么封装_图文并茂用最通俗易懂的对话为你讲解电子技术知识- C什么是电容?...
  3. 两个“敢”,是销售员必须懂的心法
  4. 15年程序员老兵的40条编程技巧,句句都是血泪史!
  5. C++中在使用自定义类型(结构体类型)的stl数据结构时,operate的用法
  6. Android 反编译修改源码
  7. css设置html背景颜色代码,CSS背景颜色
  8. 04 用户权限管理 实验报告
  9. 我的一百个2019(四):2019,我被坑惨了
  10. 基于Spring Boot的宠物猫店管理系统的设计与实现毕业设计源码140909
  11. 腾讯互娱AMS | 我的打包我做主——浅析前端构建
  12. 元数据管理平台技术白皮书
  13. 超级好用的编辑器UltraEdit
  14. win10命令行模式无法切换输入法
  15. Ubuntu 14.04安装Nvidia显卡驱动以及查看显卡驱动
  16. unity之万代南梦宫高管:传统开发商如何做好手游
  17. Vegas使用技巧—— 如何实现三维立体调整?
  18. 宝塔面板能打开, 但wordpress 网站不能打开,提示建立数据库连接时出错--解决办法
  19. PointNet代码分析
  20. 《零基础学机器学习》笔记-第1课-新手快速上路路径

热门文章

  1. appium怎么测试ios_使用Appium,Cucumber和Serenity测试iOS应用程序—质量秘诀
  2. 七年之痒,从小米6看小米公司的善与罪
  3. video标签 或 微软云 azure-media-player 禁止在iphone safari中默认全屏播放
  4. linux tar zcxf,tar/gzip/zip文件打包、压缩命令
  5. 通用ESP8266连接阿里云物联网平台
  6. android n进入分屏代码分析_Android分屏多窗口的实践代码
  7. MYSQL登录错误:mysqladmin: connect to server at 'localhost' failed acess denied for user 'root'@'localhos
  8. 喜羊羊与灰太狼java_喜羊羊与灰太狼之懒洋洋风波
  9. windows 下搭建邮件服务器
  10. 腾讯云短信服务(SMS)申请流程