目前Qt for S60 已经可以在很多S60 设备上运行了,比如我的5530和 N97都是可以里,另外我见过N95也可以。
但是QT是怎样在 S60 上跑起来的呢,尤其是GUI部分,其实目前Qt的UI程序本质上还是一个基于Avkon UI Framework的程序.
有几点可以证明:
1. 可以支持程序切换,就是长按那个功能键弹出的任务列表,这只有基于avkon的程序才可以。
2. 可以有Softkey和status pane,甚至可以和这个控件交互。
3. 按 红键 可以退出程序,实际上这个红键的处理其实是avkon framework做的,其实有些qt自带的示例程序是没办法退出的,只能靠按 红键。
我们可以来看看几段源代码:
qt\src\s60main\qts60main.cpp :
GLDEF_C TInt E32Main()
{
CTrapCleanup *cleanupStack = q_check_ptr(CTrapCleanup::New());
TInt err = 0;
TRAP(err, QtMainWrapper());
delete cleanupStack;
return err;
}
从这里可以看出,qt的程序也是有 Cleanup stack的,所以可以调用一些原来的需要 Cleanupstack的Symbian API。
然后通过调用 main()函数就进入了我们的程序的代码了。
一般QT的GUI程序总是 从 QApplication 开始的,那么让我们进入QApplication的构造函数去看看。
QApplication 的构造调用了 QApplicationPrivate::construct,在这个函数里调用了很重要的 qt_init(...)
这个 qt_init是 每个不同平台有不同的实现的,看看s60的实现吧。
void qt_init(QApplicationPrivate * /* priv */, int)
{
if (!CCoeEnv::Static()) {
// The S60 framework has not been initalized. We need to do it.
TApaApplicationFactory factory(S60->s60ApplicationFactory ?
S60->s60ApplicationFactory : newS60Application);
CApaCommandLine* commandLine = 0;
TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
// After this construction, CEikonEnv will be available from CEikonEnv::Static().
// (much like our qApp).
CEikonEnv* coe = new CEikonEnv;
QT_TRAP_THROWING(coe->ConstructAppFromCommandLineL(factory,*commandLine));
delete commandLine;
S60->qtOwnsS60Environment = true;
} else {
S60->qtOwnsS60Environment = false;
}
这个 newS60Application 函数是重点,我们可以看到此时 CoeEnv EikonEnv都已经存在了,越来越像Symbian程序了 :)
qt\src\gui\s60framework\qs60mainapplication.cpp : newS60Application 定义在这里,好了剩下的就是一般Avkon程序的启动过程了,app->doc->appui
最后 程序会来到 qs60mainappui 的ConstructL
iEikonEnv->DisableExitChecks(ETrue);
BaseConstructL(CAknAppUi::EAknEnableSkin);
CEikButtonGroupContainer* nativeContainer = Cba();
nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
这里我们可以看出来 QT程序是支持 Avkon的skin的,默认的 softkey,也就是 cba(control button area)是存在的。
好了到此为止一个 完成的 Avkon程序初始化完成了,下面就可以初始化qt自己的窗口了,调用栈会原路返回到 main(),继续qt widget的创建,最后进入 app.exec()
进入exec后经过若干次函数调用,最后进入 QEventDispatcher,当然在s60上会进入 QEventDispatcherS60::processEvents(...)
虽然QT最终也是 ActiveScheduler的调度,但是和一般的 Symbian的程序不同的是,它不是直接调用CActiveScheduler::Start(),这个函数一旦进去就出不来了,直到程序结束。
所以Qt没有调用Start(),而是自己WaitForAnyReqeust,等到请求后,调用RunIfReady,这样就不会被困死在ActiveScheduler里面了,而是可以有机会运行自己的eventloop。
QT这样的做法还是很巧妙的,在Symbian这样的烂架构下能做到这样实在不容易。也因此,以前的symbian API都是可以在 qt里面调用的,因为Symbian API所需要的运行环境 Cleaupstack CCoeEnv ActiveScheduler,都是具备的。
综上看来,QT GUI还是构建在Symbian Avkon等架构之上的,但是我相信这不会是永远的结构,只是为了目前能在现有的设备上运行而采取的方式。
Avkon 长期看来是一定会被抛弃的,那么以后Qt到底是构建在 cone 还 直接基于Window Server还不可知,这一切要等到Nokia的第一款QT手机发布才会揭晓。