18.8.10

Unofficial QtWRT tutorial 1: Hello, view modes!

Almost one month ago, we announced Qt Web Runtime, and released some snapshot for N900. Basically, QtWRT is a framework, using which you can write "native" application with standard web technology, e.g. HTML, CSS, and JavaScript. As a good starting point, you should take a look at this article.

Note that we're still working on it, and it's now just in the technology preview state ;)

1 install QtWRT
You should enable the extras-devel repository on your Rover and install the qtwrt-experimental package from there. Then, you can find in your Application Manager that Qt Web Runtime Technology Preview for N900 installed.


2 config.xml
To write your own web applications, besides the normal HTML pages, you also need a config.xml file to define e.g. the starting file, icon, features you need (i.e. access to Device APIs), as well as author's information, etc. More details and default values are defined here.

The following piece shows a minimum sample:
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns = "http://www.w3.org/ns/widgets">
</widget>


You can also define the name and icon (only PNG files supported) of the web app in config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns = "http://www.w3.org/ns/widgets">
  <name>A sample web app</name>
  <icon src="app_icon.png" />
</widget>

The name and icon will be appeared in the Application Grid or the Desktop menu --> Add widget based on the view mode the web app supports (see below).

3 view modes
View modes define the visual presentation of web applications. The W3C spec has defined five different view modes, but we only support three of them in this snapshot:
windowed - The default view mode. You can find / launch web apps in this mode from the Application Grid. It also supports the native chromes and user-defined menus.
fullscreen - It can also be found / launched from the Application Grid. No need to say what is full screen, right ;)
minimized - It equals to the native widgets on the Home Screen.

The following piece defines the view modes in config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns = "http://www.w3.org/ns/widgets"
    viewmodes = "someviewmode fullscreen minimized" >
</widget>

The unknown view mode "someviewmode" is ignored. It supports both "fullscreen" and "minimized" mode in this case. If no supported view mode is defined, "windowed" mode is used.

You can get the current view mode through the widget.viewMode interface in JavaScript.

Also, the transfer among different view modes is supported, with the exception from windowed / fullscreen to minimized, e.g.:
<a href="javascript:widget.viewMode='windowed'">Go to windowed mode</a>

With the following code, you can handle the view mode change event in the viewModeChanged function:
widget.onviewmodechange = viewModeChanged;
function viewModeChanged(mode)
{
  if (mode == "windowed") {
    // going to windowed mode
  } else if (mode == "minimized") {
    // going to minimized mode
  } else if (mode == "fullscreen") {
    // going to full screen mode
  }
}


4 package your application and install it
Well, I just assume you have enough knowledge to write whatever HTML page you like, and have renamed it to index.htm (the default starting file name).

Now just zip all your HTML files together with the config.xml file. Note that the config.xml file should be at the top level of the zip, and the name is case sensitive.

Then please rename it to *.wgt and copy it to your Rover. To make it like a native application, you can install it from the File Manager, and you can find your installed web applications in Application Manager!

Eh, I'm talking about some details during the installation here. You can skip this if not interested.

When you tap on the wgt file in File Manager, widgetinstaller is launched. It does some sanity checking of it, e.g. whether it's a valid zip file, if the config.xml is valid, etc., then convert it to a Debian file, and use the Application Manager to install the generated Debian file.

If you are interested in the generated Debian file, you can use the "--no-install" option of the widgetinstaller to have it copied to the current directory.

5 a sample
First, let's write the config.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns="http://www.w3.org/ns/widgets"
    id="http://xizhizhu.blogspot.com/qtwrt/view-modes-sample"
    viewmodes="minimized fullscreen windowed">
  <name>View Modes Sample</name>
  <description>
    Well, it shows how the view modes work.
  </description>
  <author href="http://xizhizhu.blogspot.com/" email="xizhi.zhu@gmail.com">Xizhi Zhu</author>
  <license>In the public domain without any warranty.</license>
</widget>


Then the HTML file.
<html>
<header>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>View Modes</title>
  <script type="text/javascript">
    function init()
    {
      output = document.getElementById("viewmode");
      output.innerHTML = widget.viewMode;

      widget.onviewmodechange = changeViewMode;
    }

    function changeViewMode(mode)
    {
      output.innerHTML = widget.viewMode;
    }
  </script>
</header>

<body onload="init()">
  <div id="viewmode"></div><br />
  <a href="javascript:widget.viewMode='minimized'">minimized</a><br />
  <a href="javascript:widget.viewMode='windowed'">windowed</a><br />
  <a href="javascript:widget.viewMode='fullscreen'">fullscreen</a>
</body>
</html>


Now let's zip the file, send it to N900 and install it from the File Manager. You can find it installed in the Application Manager and already launched in the home screen.


You may ask, why the last line of "fullscreen" is not shown there? Well, that's due to the fixed size in the minimized mode, 312x82. Also, in the minimized mode, you can't actually interact with it, but only tap on it and open the windowed or fullscreen mode if supported. In the minimized mode, it's the same as native widgets that you can move it around, close it and add it back, as well as the transparent background by default.

Then you can tap the links to toggle between windowed and fullscreen mode. And for sure you'll find another "limitation" that you can't go back to minimized mode from the link. The only way is to close the window. Well, that's exactly what is expected.



Another thing is, in the fullscreen mode, it automatically shows the "go back to windowed" button if windowed mode is supported, otherwise the "close" button. Emm, the same as the browser, right?


Updated on 19.8.2010
Screenshots added into the posts ;)

16.8.10

Basic samples for SSL communication over Qt

1) client
class SSLClient: public QObject
{
Q_OBJECT

public:
SSLClient(QObject* parent = NULL)
: QObject(parent)
{
connect(&client, SIGNAL(encrypted()),
this, SLOT(connectionEstablished()));
connect(&client, SIGNAL(sslErrors(const QList<QSslError> &)),
this, SLOT(errorOccured(const QList<QSslError> &)));
}

void start(QString hostName, quint16 port)
{
client.setProtocol(QSsl::TlsV1);
client.connectToHostEncrypted(hostName, port);
}

public slots:
// handle the signal of QSslSocket.encrypted()
void connectionEstablished()
{
// get the peer's certificate
QSslCertificate cert = client.peerCertificate();

// write on the SSL connection
client.write("hello, world", 13);
}

// handle the signal of QSslSocket.sslErrors()
void errorOccured(const QList<QSslError> &error)
{
// simply ignore the errors
// it should be very careful when ignoring errors
client.ignoreSslErrors();
}

private:
QSslSocket client;
};


int main(int argc, char** argv)
{
QApplication app(argc, argv);

SSLClient client;
client.start("127.0.0.1", 8888);

return app.exec();
}



2) server
class SSLServer: public QTcpServer
{
Q_OBJECT

public:
SSLServer(QObject* parent = NULL)
: QTcpServer(parent)
{
}

void start(QString certPath, QString keyPath, quint16 port)
{
listen(QHostAddress::Any, port);
this->certPath = certPath;
this->keyPath = keyPath;
}

public slots:
void readyToRead()
{
qDebug() << serverSocket->readAll();
}

void errorOccured(const QList &)
{
serverSocket->ignoreSslErrors();
}

protected:
void incomingConnection(int socketDescriptor)
{
serverSocket = new QSslSocket;
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyToRead()));
connect(serverSocket, SIGNAL(sslErrors(const QList &)),
this, SLOT(errorOccured(const QList &)));
serverSocket->setProtocol(QSsl::TlsV1);
serverSocket->setPrivateKey(keyPath);
serverSocket->setLocalCertificate(certPath);
serverSocket->startServerEncryption();
} else {
delete serverSocket;
}
}

private:
QSslSocket *serverSocket;
QString certPath;
QString keyPath;
};

int main(int argc, char** argv)
{
QApplication app(argc, argv);

SSLServer server;
server.start("ca.cer", "ca.key", 8888);

return app.exec();
}