- 1、本文档共6页,可阅读全部内容。
- 2、有哪些信誉好的足球投注网站(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
Gtk main 原理
们知道GUI应用程序都是事件驱动的。这些事件大部分都来自于用户,比如键盘事件、鼠标事件或笔点事件。还有一些事件来自于系统内部,比如定时事件、socket事件和其它文件事件等等。在没有任何事件的情况下,应用程序处于睡眠状态。 因为这种事件驱动机制,GUI应用程序都毫无例外的需要一个主循环(main loop)。主循环(main loop)控制应用程序什么时候进入睡眠状态,什么时候被唤醒。主循环实现得好,应用程序才能工作正常又省电。 Win32 GUI应用程序的主循环是我们比较熟悉的,其大致如下: // Main message loop: while (GetMessage(msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg)) { TranslateMessage(msg); DispatchMessage(msg); } } 在这个主循环中,它不断的从消息队列中提取消息,然后分发给消息的目标(通常是窗口),直到GetMessage返回FALSE(收到WM_QUIT消息,一般调用PostQuitMessage)为止,如果队列中没有消息,应用程序就进入睡眠状态。这种方法简单明了,缺陷也是明显的,它只能挂在消息队列上,而不能同时挂在多个事件源上(如管道和socket等)。要挂在多个事件源上,需要使用其它方式,比如用WaitForMultipleObjects,那就比较麻烦了。 而在GTK+应用程序中,其主循环(main loop)更加简单,但是非常的不明了:gtk_main (); 不少人用GTK+写了很长时间的程序,还是觉得这行代码很神秘,不知道里面到底干了什么。本文试图分析一下gtk_main的工作原理: gtk_main主要是对glib的main loop的包装,基本上分为三步:1.调用初始化函数。2.进入glib main loop3.调用~初始化函数。 所以弄清楚glib main loop之后,gtk_main的实现也就尽收眼底了,本文重点分析glib的main loop的实现。main loop使用模式大致如下:loop = g_main_loop_new (NULL, TRUE);g_main_loop_run (loop); g_main_loop_new创建一个main loop对象,一个main loop对象只能被一个线程使用,但一个线程可以有多个main loop对象。在GTK+应用中,一个线程使用多个main loop的主要用途是实现模态对话框,它在gtk_dialog_run函数里创建一个新的main loop,通过该main loop分发消息,直到对话框关闭为止。 g_main_loop_run则是进入主循环,它会一直阻塞在这里,直到让它退出为止。有事件时,它就处理事件,没事件时就睡眠。 g_main_loop_quit则是用于退出主循环,相当于Win32下的PostQuitMessage函数。 Glib main loop的最大特点就是支持多事件源,使用非常方便。来自用户的键盘和鼠标事件、来自系统的定时事件和socket事件等等,还支持一个称为idle的事件源,其主要用途是实现异步事件。Main loop的基本组成如下图所示: GMainLoop的主要部件是GMainContext,GMainContext可以在多个GMainLoop间共享,但要求这些GMainLoop都在同一个线程中运行,前面提到的模态对话框就属于这一类。GMainContext通常由多个GSource组成,GSource是事件源的抽象,任何事件源,只要实现GSource规定的接口,都可以挂到GMainContext中来。 GSource的接口函数有:1. gboolean (*prepare) (GSource *source, gint *timeout_);进入睡眠之前,在g_main_context_prepare里,mainloop调用所有Source的prepare函数,计算最小的timeout时间,该时间决定下一次睡眠的时间。2. gboolean (*check) (GSource *source); poll被唤醒后,在g_main_context_check里,mainloop调用所有Source的check函数,检查是否有Source已经准备好了。如果poll是由于错误或者超时等原因唤醒的,就不必进行dispatch了。3. gboolean (*dispatch) (GSource*source, GSourceFunc ca
文档评论(0)