您的位置:首页 > 产品设计 > UI/UE

minigui代码分析

2015-06-13 12:48 453 查看
一、minigui运行模式

1.线程模式:MiniGui-Threads

定义:_MGRM_THREADS

运行在MiniGui-Threads上的程序可以在不同的线程中建立多个窗口,但所有的窗口在一个进程或地址空间中运行,传统意义上的嵌入式操作系统。

2.进程模式:MiniGui-Processes

定义:_MGRM_Processes或者定义_LITE_VERSION

MiniGui-Processes上每个程序是单独的进程,每个进程也可以建立多个窗口,并且实现了多进程窗口系统。适用于具有完整UNIX特性的嵌入式式系统。

3.独立应用模式:MiniGui-Standalone

定义:_MGRM_STANDALONE 或者定义_LITE_VERSION和_STAND_ALONE

通过独立任务的方式运行,既不需要多进程支持也不需要多线程支持。

二、数据结构

1.CreateMainWindow函数参数:PMAINWINCREATE pCreateInfo

结构体MAINWINCREATE 定义了被创建的窗口的位置、标题、类型等基本参数。实际上包含了创建窗口的UI风格和窗口处理函数两方面的内容。

PMAINWINCREATE为指向该结构体的指针。

typedef struct _MAINWINCREATE
{
DWORD dwStyle;                                      //窗口风格
DWORD dwExStyle;                                    //窗口的附加风格
const char* spCaption;                              //窗口的标题
HMENU hMenu;                                        //附加在窗口上的菜单句柄
HCURSOR hCursor;                                    //在窗口中所使用的鼠标光标句柄
HICON hIcon;                                        //程序的图标句柄
HWND  hHosting;                                     //窗口消息队列的托管窗口
int (*MainWindowProc)(HWND, int, WPARAM, LPARAM);   //该窗口的消息处理函数指针,回调函数
int lx, ty, rx, by;                                 //窗口相对屏幕的绝对坐标,以象素点表示
int iBkColor;                                       //窗口背景颜色
DWORD dwAddData;                                    //附带给窗口的一个32 位值
DWORD dwReserved;                                   //预留,没有用到
}MAINWINCREATE;
typedef MAINWINCREATE* PMAINWINCREATE;


2.MAINWIN结构体:主窗口的详细信息由该结构体给出

typedef struct _MAINWIN
{
/* These fields are similiar with CONTROL struct. */
unsigned char DataType;     // 数据类型,表示是否是一个窗口(主窗口或者控件窗口),对于该结构和CONTROL结构,都必须是TYPE_HWND</span>
unsigned char WinType;      // 判断是否是主窗口,对于该结构,必须是TYPE_MAINWIN</span>
unsigned short Flags;       // special runtime flags, such EraseBkGnd flags

int left, top;      // the position and size of main window.
int right, bottom;
int cl, ct;         // the position and size of client area.
int cr, cb;

DWORD dwStyle;      // the styles of main window.
DWORD dwExStyle;    // the extended styles of main window.

int iBkColor;       // the background color.
HMENU hMenu;        // handle of menu.
HACCEL hAccel;      // handle of accelerator table.
HCURSOR hCursor;    // handle of cursor.
HICON hIcon;        // handle of icon.
HMENU hSysMenu;     // handle of system menu.
PLOGFONT pLogFont;  // pointer to logical font.

char* spCaption;    // the caption of main window.
int   id;           // the identifier of main window.

LFSCROLLBARINFO vscroll; // the vertical scroll bar information.
LFSCROLLBARINFO hscroll; // the horizital scroll bar information.

/** the window renderer */
WINDOW_ELEMENT_RENDERER* we_rdr;

HDC   privCDC;      // the private client DC.
INVRGN InvRgn;      // 这个主窗口的无效区域,在处理MSG_PAINT消息时很重要
PGCRINFO pGCRInfo;  // pointer to global clip region info struct.

// the Z order node.
int idx_znode;

PCARETINFO pCaretInfo; // pointer to system caret info struct.

DWORD dwAddData;    // the additional data.
DWORD dwAddData2;   // the second addtional data.

int (*MainWindowProc)(HWND, int, WPARAM, LPARAM); // the address of main window procedure.

struct _MAINWIN* pMainWin; // the main window that contains this window. for main window, always be itself.

HWND hParent;       // the parent of this window.   for main window, always be HWND_DESKTOP.

/* Child windows.*/
HWND hFirstChild;    // the handle of first child window.
HWND hActiveChild;  // the currently active child window.
HWND hOldUnderPointer;  // the old child window under pointer.
HWND hPrimitive;    // the premitive child of mouse event.

NOTIFPROC NotifProc;    // the notification callback procedure.

/* window element data. */
struct _wnd_element_data* wed;

/* Main Window hosting. The following members are only implemented for main window.*/
struct _MAINWIN* pHosting; // the hosting main window.
struct _MAINWIN* pFirstHosted; // the first hosted main window.
struct _MAINWIN* pNextHosted;  // the next hosted main window.

PMSGQUEUE pMessages;  // the message queue.

GCRINFO GCRInfo; // the global clip region info struct. put here to avoid invoking malloc function.

#ifdef _MGRM_THREADS
pthread_t th;        // the thread which creates this main window.
#endif
//the controls as main
HWND hFirstChildAsMainWin;

HDC   secondaryDC;                // the secondary window dc.
ON_UPDATE_SECONDARYDC update_secdc; // the callback of secondary window dc
RECT  update_rc;
} MAINWIN;
3.MSGQUEUE消息队列

struct _MSGQUEUE
{
DWORD dwState;              // message queue states

#ifdef _MGRM_THREADS
pthread_mutex_t lock;       // lock
sem_t wait;                 // the semaphore for wait message
sem_t sync_msg;             // the semaphore for sync message
#endif

PQMSG  pFirstNotifyMsg;     // head of the notify message queue
PQMSG  pLastNotifyMsg;      // tail of the notify message queue

#ifdef _MGRM_THREADS
PSYNCMSG pFirstSyncMsg;     // head of the sync message queue
PSYNCMSG pLastSyncMsg;      // tail of the sync message queue
#else
IDLEHANDLER OnIdle;         // Idle handler
#endif

#ifdef _MGRM_THREADS
PMAINWIN pRootMainWin;      // The root main window of this message queue.
#endif

MSG* msg;                   /* post message buffer */
int len;                    /* buffer len */
int readpos, writepos;      /* positions for reading and writing */

int FirstTimerSlot;         /* the first timer slot to be checked */
DWORD TimerMask;            /* timer slots mask */

int loop_depth;             /* message loop depth, for dialog boxes. */
};


三、CreateMainWindow函数流程

1.init_desktop_win

<pre name="code" class="objc">static void init_desktop_win (void)
{
static MAINWIN sg_desktop_win;
PMAINWIN pDesktopWin;

LICENSE_SET_MESSAGE_OFFSET();

pDesktopWin = &sg_desktop_win; //作为默认的Desktop

pDesktopWin->pMessages         = __mg_dsk_msg_queue;  // 自己的消息队列,其他窗口发送的SendMessage将消息压入该队列[luther.gliethttp]
pDesktopWin->MainWindowProc    = DesktopWinProc;      // 桌面默认回调处理函数

pDesktopWin->DataType          = TYPE_HWND;
pDesktopWin->WinType           = TYPE_ROOTWIN;
#ifdef _MGRM_THREADS
pDesktopWin->th                = __mg_desktop;
#endif

pDesktopWin->pLogFont          = GetSystemFont (SYSLOGFONT_WCHAR_DEF);
pDesktopWin->spCaption         = "THE DESKTOP WINDOW";

pDesktopWin->pGCRInfo          = &sg_ScrGCRInfo;
pDesktopWin->idx_znode         = 0;

pDesktopWin->pMainWin          = pDesktopWin;
pDesktopWin->we_rdr            = __mg_def_renderer;

__mg_hwnd_desktop = (HWND)pDesktopWin;  // 登记到desktop的全局量中
__mg_dsk_win  = pDesktopWin;
}


2.main函数
#define main_entry main

#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

3.CreateMainWindow函数流程

HWND GUIAPI CreateMainWindowEx (PMAINWINCREATE pCreateInfo,
const char* werdr_name, const WINDOW_ELEMENT_ATTR* we_attrs,
const char* window_name, const char* layer_name)
{
// 指针
PMAINWIN pWin;

if (pCreateInfo == NULL) {
return HWND_INVALID;
}

if (!(pWin = calloc(1, sizeof(MAINWIN)))) { //分配结构体内存
return HWND_INVALID;
}

#ifdef _MGRM_THREADS //这是重要部分,用于找到消息队列
if (pCreateInfo->hHosting == HWND_DESKTOP || pCreateInfo->hHosting == 0) {
/*如果托管窗口为桌面窗口或者没有托管窗口,为新建的主窗口创建线程信息和消息队列,获取本线程关联的消息队列结构体。
*若获取失败说明该窗口是最顶层的主窗口,目前还有对应的消息队列,则为其创建一个消息队列结构体*/
if ((pWin->pMessages = GetMsgQueueThisThread ()) == NULL) { //试图获取本线程关联的消息队列结构体
if (!(pWin->pMessages = mg_InitMsgQueueThisThread ()) ) { //试图去创建一个消息队列结构体
free (pWin);

return HWND_INVALID;
}
pWin->pMessages->pRootMainWin = pWin;//如果创建消息队列结构体成功,则设置当前窗口为根窗口
}
else {
/* Already have a top level main window, in case of user have set
a wrong hosting window */
pWin->pHosting = pWin->pMessages->pRootMainWin;//设置托管口
}
}
else {
pWin->pMessages = GetMsgQueueThisThread (); //直接获取,这种情况下,是可以肯定消息队列已经存在
if (pWin->pMessages != kernel_GetMsgQueue (pCreateInfo->hHosting) || //该函数的调用者必须和hosting的消息队列所在线程一致。这很重要
pWin->pMessages == NULL) {
free (pWin);

return HWND_INVALID;
}
}

if (pWin->pHosting == NULL) //如果当前窗口的托管主窗口为空,利用传递的函数参数获得托管主窗口信息
pWin->pHosting = gui_GetMainWindowPtrOfControl (pCreateInfo->hHosting);
/* leave the pHosting is NULL for the first window of this thread. */
#else
pWin->pHosting = gui_GetMainWindowPtrOfControl (pCreateInfo->hHosting); //运行模式为非MiniGui-Threads,获得托管窗口的句柄
if (pWin->pHosting == NULL)
pWin->pHosting = __mg_dsk_win; //托管窗口句柄为空,设置托管窗口为默认桌面窗口

pWin->pMessages = __mg_dsk_msg_queue; //将消息队列设置为默认桌面消息队列
#endif

pWin->pMainWin      = pWin; //以下部分在初始化结构体成员,可以忽略
pWin->hParent       = 0;    //当前窗口的父窗口不存在
pWin->pFirstHosted  = NULL; //第一个托管主窗口
pWin->pNextHosted   = NULL; //下一个托管主窗口
pWin->DataType      = TYPE_HWND;      //数据类型
pWin->WinType       = TYPE_MAINWIN;   //窗口类型

#ifdef _MGRM_THREADS
pWin->th            = pthread_self(); //创建主窗口的线程
#endif

pWin->hFirstChild   = 0;    //第一个子窗口的句柄为0,即不存在
pWin->hActiveChild  = 0;    //当前活动的子窗口的句柄为0,即不存在
pWin->hOldUnderPointer = 0; //旧的子窗口
pWin->hPrimitive    = 0;

pWin->NotifProc     = NULL;

pWin->dwStyle       = pCreateInfo->dwStyle;
pWin->dwExStyle     = pCreateInfo->dwExStyle;

#ifdef _MGHAVE_MENU
pWin->hMenu         = pCreateInfo->hMenu;
#else
pWin->hMenu         = 0;
#endif
pWin->hCursor       = pCreateInfo->hCursor;
pWin->hIcon         = pCreateInfo->hIcon;

#ifdef _MGHAVE_MENU
if ((pWin->dwStyle & WS_CAPTION) && (pWin->dwStyle & WS_SYSMENU)) //如果当前窗口包含标题且包含系统菜单,则创建系统菜单
pWin->hSysMenu= CreateSystemMenu ((HWND)pWin, pWin->dwStyle);
else
#endif
pWin->hSysMenu = 0; //否则系统菜单项为0

pWin->spCaption    = FixStrAlloc (strlen (pCreateInfo->spCaption));//分配空间存放标题
if (pCreateInfo->spCaption [0]) //如果函数参数结构体的标题字符串的第一个字符非空
strcpy (pWin->spCaption, pCreateInfo->spCaption); //复制标题到结构体的标题项

pWin->MainWindowProc = pCreateInfo->MainWindowProc; //消息处理函数
pWin->iBkColor    = pCreateInfo->iBkColor;

pWin->pCaretInfo = NULL; //指向系统插入字符信息结构体

pWin->dwAddData   = pCreateInfo->dwAddData;
pWin->dwAddData2  = 0;
pWin->secondaryDC = 0;

/* Scroll bar */ //下面是初始化滚动条相关的内容
if (pWin->dwStyle & WS_VSCROLL) { //垂直方向的滚动条
pWin->vscroll.minPos = 0;
pWin->vscroll.maxPos = 100;
pWin->vscroll.curPos = 0;
pWin->vscroll.pageStep = 101;
pWin->vscroll.barStart = 0;
pWin->vscroll.barLen = 10;
pWin->vscroll.status = SBS_NORMAL;
}
else
pWin->vscroll.status = SBS_HIDE | SBS_DISABLED;

if (pWin->dwStyle & WS_HSCROLL) { //水平方向的滚动条
pWin->hscroll.minPos = 0;
pWin->hscroll.maxPos = 100;
pWin->hscroll.curPos = 0;
pWin->hscroll.pageStep = 101;
pWin->hscroll.barStart = 0;
pWin->hscroll.barLen = 10;
pWin->hscroll.status = SBS_NORMAL;
}
else
pWin->hscroll.status = SBS_HIDE | SBS_DISABLED;

/** perfer to use parent renderer */ //初始化渲染器相关的内容,这时可以忽略这一部分
if (pWin->dwExStyle & WS_EX_USEPARENTRDR) {
if (((PMAINWIN)pCreateInfo->hHosting)->we_rdr) {
pWin->we_rdr = ((PMAINWIN)pCreateInfo->hHosting)->we_rdr;
++pWin->we_rdr->refcount;
}
else {
return HWND_INVALID;
}
}
else {
/** set window renderer */
set_window_renderer (pWin, werdr_name);
}

/** set window element data */
while (we_attrs && we_attrs->we_attr_id != -1) {
// append_window_element_data (pWin,
//       we_attrs->we_attr_id, we_attrs->we_attr);
DWORD _old;
set_window_element_data ((HWND)pWin,
we_attrs->we_attr_id, we_attrs->we_attr, &_old);
++we_attrs;
}

/** prefer to parent font */
if (pWin->dwExStyle & WS_EX_USEPARENTFONT)
pWin->pLogFont = __mg_dsk_win->pLogFont;
else {
pWin->pLogFont = GetSystemFont (SYSLOGFONT_WCHAR_DEF);
}

if (SendMessage ((HWND)pWin, MSG_NCCREATE, 0, (LPARAM)pCreateInfo)) // MSG_NCCREATE表示窗口已经创建但是还没有向系统注册
goto err;

/** reset menu size */
ResetMenuSize ((HWND)pWin);

#ifdef __TARGET_FMSOFT__
pCreateInfo->lx += __mg_mainwin_offset_x;
pCreateInfo->rx += __mg_mainwin_offset_x;
pCreateInfo->ty += __mg_mainwin_offset_y;
pCreateInfo->by += __mg_mainwin_offset_y;
#endif

SendMessage ((HWND)pWin, MSG_SIZECHANGING, //开始发生一些消息,让窗口进行一些工作
(WPARAM)&pCreateInfo->lx, (LPARAM)&pWin->left);
SendMessage ((HWND)pWin, MSG_CHANGESIZE, (WPARAM)&pWin->left, 0);

pWin->pGCRInfo = &pWin->GCRInfo;

if (SendMessage (HWND_DESKTOP, MSG_ADDNEWMAINWIN, (WPARAM) pWin, 0) < 0)//这个很重要:把主窗口发送给Desktop窗口托管,进行管理。
goto err;

/*
* We should add the new main window in system and then
* SendMessage MSG_CREATE for application to create
* child windows.
*/
if (SendMessage ((HWND)pWin, MSG_CREATE, 0, (LPARAM)pCreateInfo)) { //发送一个MSG_CREATE消息,告知应用程序窗口已经创建成功
SendMessage(HWND_DESKTOP, MSG_REMOVEMAINWIN, (WPARAM)pWin, 0);
goto err;
}
<pre name="code" class="objc">
#ifndef _MGRM_PROCESSES
    screensaver_create();
#endif
return (HWND)pWin;

err:
#ifdef _MGRM_THREADS
if (pWin->pMessages && pWin->pHosting == NULL) {
mg_FreeMsgQueueThisThread ();
}
#endif

if (pWin->secondaryDC) DeleteSecondaryDC ((HWND)pWin);
free (pWin);

return HWND_INVALID;
}



1)判断传入的参数pCreateInfo是否为空

Case NULL:若参数为空,返回HWND_INVALID

Case NOT NULL:若参数不为空,继续执行2

2)为PMAINWIN类型的pWin分配内存空间,并判断pWin是否为空

Case NULL:分配空间失败,返回HWND_INVALID

Case NOT NULL:分配空间成功,继续执行3

3)是否定义_MGRM_THREADS:

3.a定义了_MGRM_THREADS,代表minigui的运行模式为MiniGui-Threads

设置pWin的成员pWin->pMessages和pWin->pHosting

3.b没有定义_MGRM_THREADS,代表minigui的运行模式为非MiniGui-Threads

设置pWin的成员pWin->pMessages和pWin->pHosting

4)设置pWin的成员。
5)初始化渲染器相关的内容。

6)SendMessage ((HWND)pWin,MSG_NCCREATE, 0, (LPARAM)pCreateInfo)

表示该窗口已经创建但是还没有向系统进行注册,当收到这种类型的消息时可以对自己创建的对象进行初始化,但不能创建子窗口,也不能进行绘图。如果函数返回值为非零值,创建的窗口将被销毁。

7)SendMessage ((HWND)pWin,
MSG_SIZECHANGING,(WPARAM)&pCreateInfo->lx, (LPARAM)&pWin->left);

指示了将要被更改的窗口的大小,当窗口大小将要发生改变时,该消息会发送给窗口。如果你想要控制窗口改变后的实际位置和大小(窗口改变可能是MoveWindow或者其他函数引起的),你需要使用MSG_SIZECHANGING作为SendMessage函数的第二个参数,并且通过第二个参数返回位置和大小信息。

9)SendMessage ((HWND)pWin,MSG_CHANGESIZE, (WPARAM)&pWin->left, 0);

确定改变后的窗口大小。

9)SendMessage (HWND_DESKTOP,MSG_ADDNEWMAINWIN, (WPARAM) pWin, 0);

把主窗口发送给Desktop窗口托管,进行管理,并绘制窗口。

10)SendMessage ((HWND)pWin,MSG_CREATE, 0, (LPARAM)pCreateInfo);

发送一个MSG_CREATE消息,告知应用程序窗口已经创建成功。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: