7.12.10

The Beauty of Qt 3: Implicit Sharing

To maximize resource usage and minimize copying, Qt uses implicit data sharing in many classes, so that the data is copied only when a function writes to it. This trick is also referred to as flyweight pattern sometimes.

Now let's take QByteArray as an example to see how it's implemented. It uses a private struct of Data to track the shared data:
struct Data {
  QBasicAtomicInt ref; // reference count, the operation on it is atomic
  int alloc; // allocated space for the data
  int size; // actual size of the data, not counting the ending '\0' added by QByteArray
  char *data; // point to the data
  char array[1]; // where the data is stored, and the data always end with '\0'
};


Here, we use both the pointer of data and array just because the data might actually be stored in another object. When an object is copied, e.g. through the assignment operator, it only copies the pointer to the shared data:
QByteArray &QByteArray::operator=(const QByteArray & other)
{
  // increase the reference count of the shared data it's supposed to be used
  other.d->ref.ref();

  // decrease the reference count of the share data currently used, and free it if no one else is using
  if (!d->ref.deref())
    qFree(d);

  // point to the shared data
  d = other.d;

  return *this;
}


On the other hand, if it's to be changed by e.g. the resize() function, it copies the data if any other object also shares it:
void QByteArray::resize(int size)
{
  if (size <= 0) {
    // if the target is no bigger than 0, points to an empty data block
    Data *x = &shared_empty;
    x->ref.ref();
    if (!d->ref.deref())
      qFree(d);
    d = x;
  } else if (d == &shared_null) {
    // if currently a null array, just create a new data block
    Data *x = static_cast<data *>(qMalloc(sizeof(Data)+size));
    Q_CHECK_PTR(x);
    x->ref = 1;
    x->alloc = x->size = size;
    x->data = x->array;
    x->array[size] = '\0';
    (void) d->ref.deref();
    d = x;
  } else {
    // if any other object uses this data block, or the current memory is too small or too big
    // reallocate space, and copy the data for it
    // note that this operation might consume some time if the data is huge
    if (d->ref != 1 || size > d->alloc || (size < d->size && size < d->alloc >> 1))
      realloc(qAllocMore(size, sizeof(Data)));
    if (d->alloc >= size) {
      d->size = size;
      if (d->data == d->array) {
        d->array[size] = '\0';
      }
    }
  }
}


With this in mind, let's see how to use QSharedData and QSharedDataPointer to implement our own implicit shared data objects.
// first implement your data object inheriting from QSharedData, which provides the reference count
class SharedData: public QSharedData
{
public:
  SharedData()
    : QSharedData()
    , var(0)
  {}

  SharedData(const SharedData &other)
    : QSharedData(other)
    , var(other.var)
  {}

  int var;
};

// then the data owner
class DataOwner
{
public:
  DataOwner()
  : d(new SharedData)
  {}

  DataOwner(int var)
  : d(new SharedData)
  {
    // for write access, the -> operator will automatically copy the shared data if needed
    d->var = var;
  }

private:
  // this template class hides all the details for implicit sharing
  // therefore, no need to provide copy constructor or assignment operator
  QSharedDataPointer<SharedData> d;
};


Quite simple, right ;) Then just proceed to implement explicit shared data objects using QExplicitlySharedDataPointer yourself.

1.12.10

The Beauty of Qt 2: Meta Object

Besides the D-pointers, another interesting thing in Qt is the Q_OBJECT macro. It provides the access to meta objects, which enables you to enjoy more features of a QObject, e.g. signals and slots. The meta object provides information about class name, properties and methods of a QObject, which is also known as reflection.

Using QMetaObject, you can print the information of the class name, etc.:
QObject obj;
const QMetaObject *metaObj = obj.metaObject();
qDebug() << "class name: " << metaObj->className();
qDebug() << "class info count: " << metaObj->classInfoCount();
qDebug() << "methods: ";
// starting from QMetaObject::methodOffset() so it won't display the methods inherited
for (int i = metaObj->methodOffset(); i < metaObj->methodCount(); ++i)
  qDebug() << metaObj->method(i).methodType() << " " << metaObj->method(i).signature();


As none of these information is supported in pure C++, Qt uses the Meta Object Compiler (moc) to do all the tricks. It reads each header file, and generates a C++ source file (moc_*.cpp) containing the code for meta-object, if it finds a Q_OBJECT macro used in any class declaration. With the code generation approach, Qt not only gains the flexibility as in e.g. Java, but also keeps the performance and scalability as in C++.

Suppose we have the following simple class:
class MyObject : public QObject
{
  Q_OBJECT
public:
  explicit MyObject(QObject *parent = 0);

  void myFunc();

public slots:
  void mySlot(int myParam);

signals:
  void mySignal(int myParam);
};


The following code / information will be generated by moc, and can be retrieved through pointers defined in the anonymous struct of QMetaObject::d:
// pointed by QMetaObject::d.data, the beginning stored "as" a QMetaObjectPrivate struct
static const uint qt_meta_data_MyObject[] = {
  5, // revision, the internals have been changed several times
  0, // classname, offset of qt_meta_stringdata_MyObject

  // the following are defined as (number, index) pair
  0, 0, // classinfo
  2, 14, // we have two methods, starting at index 14 (i.e. the signal)
  0, 0, // properties
  0, 0, // enums/sets
  0, 0, // constructors

  0, // flags
  1, // signal counts

  // for signals slots, and properties, the signatures and parameters are offset of qt_meta_stringdata_MyObject
  // signals: signature, parameters, type, tag, flags
  18, 10, 9, 9, 0x05,

  // slots: signature, parameters, type, tag, flags
  32, 10, 9, 9, 0x0a,

  0 // eod
};

// pointed by QMetaObject::d.stringdata
static const char qt_meta_stringdata_MyObject[] = {
  "MyObject\0\0myParam\0mySignal(int)\0"
  "mySlot(int)\0"
};


The above information, as well as the information for its base class, is stored as the static meta object for this class:
const QMetaObject MyObject::staticMetaObject = {
  { &QObject::staticMetaObject, // pointer to its base class, stored at QMetaObject::d.superdata
    qt_meta_stringdata_MyObject, qt_meta_data_MyObject, 0 }
};


In this way, if you want to do type cast for QObject, instead of using the somewhat expensive operator of dynamic_cast, we can use qobject_cast. It exploits the benefits of the meta object system, thus avoiding the runtime type cast:
template <class T> inline T qobject_cast(QObject *object)
{
#if !defined(QT_NO_QOBJECT_CHECK)
  reinterpret_cast(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(object));
#endif
  return static_cast(reinterpret_cast(0)->staticMetaObject.cast(object));
}


Here, the trick is that the QMetaObject of the target type checks if the object inherits from it:
const QObject *QMetaObject::cast(const QObject *obj) const
{
  if (obj) {
    const QMetaObject *m = obj->metaObject();
    do {
      if (m == this)
        return obj;
    } while ((m = m->d.superdata));
  }
  return 0;
}


Also, moc will generate some code for each signal. Whenever a signal is emitted, this function will be called internally:
void MyObject::mySignal(int _t1)
{
  void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
  // it checks all the connected slots, and call each of them based on the connection type
  QMetaObject::activate(this, &staticMetaObject, 0, _a);
}


In the end, the slots are invoked by the generated qt_metacall function:
int MyObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
  // if this function is called by the super class, just return
  _id = QObject::qt_metacall(_c, _id, _a);
  if (_id < 0)
    return _id;

  // call the function based on its ID
  if (_c == QMetaObject::InvokeMetaMethod) {
    switch (_id) {
    case 0: mySignal((*reinterpret_cast< int(*)>(_a[1]))); break;
    case 1: mySlot((*reinterpret_cast< int(*)>(_a[1]))); break;
    default: ;
    }

    // remove the IDs "consumed" by this class so that in its subclass the ID always starts with 0, and the return value of -1 means already consumed
    _id -= 2;
  }

  return _id;
}


25.11.10

The Beauty of Qt 1: D-Pointer / Private Implementation

I believe many of you who just start reading the source code of Qt will have the question: why Qt uses those private classes? What's the benefit of such a design pattern? Well, the most significant reason is to keep the binary compatibility.

Then what is binary compatibility? The article from KDE TechBase defines it like this:
A library is binary compatible, if a program linked dynamically to a former version of the library continues running with newer versions of the library without the need to recompile.
With this definition in mind, the benefit is easy to see: without it, whenever a library is updated, all the applications rely on it should be recompiled to work. Definitely, it's totally unacceptable for any widely used libraries like Qt. More information on binary compatibility itself can be found on that article from KDE TechBase, and here I only want to share with you how it's used.

Without the usage of D-pointers, we may have a class defined as below:
class MyClass
{
public:
MyClass();
~MyClass();
private:
int myVar;
};


Obviously, the private member of myVar here is a big enemy of binary compatibility. There fore, we refactor the code into the following:
class MyClassPrivate;
class MyClass
{
public:
MyClass();
~MyClass();
private:
MyClassPrivate * const d_ptr;
Q_DECLARE_PRIVATE(MyClass);
};


Here, we use a pointer d_ptr to refer to the private implementation, and the macro of Q_DECLARE_PRIVATE is employed to define some helper functions and friend class:
#define Q_DECLARE_PRIVATE(Class) \
inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \
inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } \
friend class Class##Private;


Then we define the private class as below:
class MyClassPrivate
{
public:
MyClassPrivate(MyClass *parent);
private:
MyClass * const q_ptr;
Q_DECLARE_PUBLIC(MyClass);
int myVar;
};


Here, the q_ptr pointer points the public interface, and the Q_DECLARE_PUBLIC macro is used to define some helper functions:
#define Q_DECLARE_PUBLIC(Class) \
inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
friend class Class;


And we can further use the following two macros to ease the access:
#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()


That's all about the usage of D-pointers and private implementations in Qt. Let me use a simple sample to end this post ;)
// myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H

#include <QtCore/QObject>

class MyClassPrivate;
class MyClass: public QObject
{
Q_OBJECT
public:
MyClass(QObject *parent = 0);
virtual ~MyClass();
void dummyFunc();

signal:
void dummySignal();

private:
MyClassPrivate * const d_ptr;
Q_DECLARE_PRIVATE(MyClass);
Q_DISABLE_COPY(MyClass);
};

#endif // MYCLASS_H

// myclass.cpp
#include "myclass.h"

class MyClassPrivate
{
public:
MyClassPrivate(MyClass *parent)
: q_ptr(parent)
{
}

void foobar()
{
Q_Q(MyClass);
emit q->dummySignal();
}

private:
MyClass * const q_ptr;
Q_DECLARE_PUBLIC(MyClass);
};

MyClass::MyClass(QObject *parent)
: QObject(parent)
, d_ptr(new MyClassPrivate(this))
{
}

MyClass::~MyClass()
{
Q_D(MyClass);
delete d;
}

void MyClass::dummyFunc()
{
Q_D(MyClass);
d->foobar();
}


The Chinese translation is available at: http://blog.csdn.net/zhu_xz/archive/2010/11/25/6035861.aspx

1.11.10

New release of Web Runtime for N900

Finally, I'm happy to push the latest Web Runtime (v1.1.0) for N900 to the extras-devel repository. Please note that this release is only tested against PR 1.3. There's no new features implemented compared to the previous release back in July, but only bug fixes. Personally, this is one of the last duties for me in the WRT project, and let's see what I would play with in the future ;)
What is Web Runtime?
It's a development framework with which you can write applications in standard Web technologies, like HTML, CSS, and JavaScript. Also, a bunch of Device APIs are provided to grant you the access to native resources, e.g. file system, sensors, etc., using JavaScript.
To install WRT on N900, you should first enable the extras-devel repository.

If you have the previous release installed, you should first uninstall:
sudo gainroot
apt-get purge libwrt-experimental1

Then install the new release:
sudo gainroot
apt-get install qtwrt

Have fun and feel free to go to the public forum for more questions ;)

28.10.10

Hybrid application using QML and Qt C++

Moved to http://www.zionsoft.net/2010/10/hybrid-application-qml-qt/

Though QML provides a nice way to design user interfaces, and JavaScript is employed there to implement the application logic and works pretty nice in many cases, we might still need Qt C++ in some situations (well, at least JavaScript has limited access outside its sandbox).

1) integrate QML into Qt C++
Suppose we have a QML file, named "myqml.qml", like this:
// this line should be "import QtQuick 1.0" since Qt 4.7.1
import Qt 4.7

Rectangle {
  id: myRectangle
  width: 800
  height: 480
  color: "lightgray"

  Text {
    id: myText
    text: "I love hybrid application!"
    anchors.centerIn: parent
    font.pointSize: 28
    font.bold: true
  }
}


One easy way to integrate is to use the QDeclarativeView class, which provides a widget to display QML files. You just need the following three lines:
QDeclarativeView view;
view.setSource(QUrl::fromLocalFile("myqml.qml"));
view.show();


However, QDeclarativeView consumes more resources than normal widgets. Fortunately, we can integrate QML into a graphics scene. The following lines shows the basic usage:
// provides an environment for instantiating QML components
QDeclarativeEngine engine;

// encapsulates a QML component definition
QDeclarativeComponent component(&engine, QUrl::fromLocalFile("myqml.qml"));

// creates the graphics item for QML at the engine's root context
QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(component.create());

scene.addItem(item);


Then with the help of the QDeclarativeItem class, you can easily access the properties of the QML element, e.g.:
qDebug() << item->property("color").typeName();
item->setProperty("color", QColor(255, 255, 255));


2) exposing Qt C++ objects to QML
You can also expose native Qt C++ objects to QML through QDeclarativeContext:
QDeclarativeContext *context = engine->rootContext();
context->setContextProperty("textFromQt", QString("I love hybrid application!"));


Then in QML, you can have e.g. the following line to access them:
text: textFromQt

You can also use QDeclarativePropertyMap to manage the exposed properties:
QDeclarativePropertyMap map;
map.insert("key1", "value1");
map.insert("key2", "value2");
context->setContextProperty("map", &map);


In a QML engine, there could be a couple of contexts, forming a tree structure. The child contexts inherit properties in the parent context. By default, there is only one root context, but you can always add more to give finer control of the exposed data, i.e. different QDeclarativeComponent inside the same context have the same exposed data set.

To expose a self-defined object, we can use the following code:
// define a class with properties
class MyObject: public QObject
{
  Q_OBJECT

  // the NOTIFY signal is needed to inform about changes
  // all properties will be exposed to QML
  Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
  MyObject(QObject *parent = 0) : QObject(parent), m_text("I love hybrid application!") {}

  QString text() const { return m_text; }
  void setText(QString &text)
  {
    m_text = text;
    emit textChanged();
  }

signals:
  void textChanged();

private:
  QString m_text;
};

// then just expose it so QML can access it through name "myObject"
engine->rootContext()->setContextProperty("myObject", new MyObject());


Moreover, we can create new QML types:
// define the new type
class MyType : public QDeclarativeItem
{
  Q_OBJECT

public:
  MyType(QDeclarativeItem *parent = 0) : QDeclarativeItem(parent)
  {
    setFlag(QGraphicsItem::ItemHasNoContents, false);
  }

  void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
  {
    QPen pen(QColor(100, 100, 100), 2);
    painter->setPen(pen);
    painter->drawLine(0, 100, 100, 100);
  }
};

// then register to expose it
qmlRegisterType<mychart>("com.blogspot.xizhizhu.mytype", 1, 0, "MyType");


In QML, you can use it like this:
import com.blogspot.xizhizhu.mytype 1.0

MyChart {
 id: myChart
 width: 100
 height: 200
}


Now let's jump to invoke a Qt C++ function from QML. Basically, QML can invoke slots and functions declared with Q_INVOKABLE. Suppose we have the following function in MyObject:
Q_INVOKABLE void showMessage()
{
  QMessageBox::information(NULL, "My Test", "Invoking a native function ;)");
}


Then you can invoke it in QML:
myObject.showMessage();

3) write plugins as QML extension
The benefits for using plugins as QML extensions are similar to using shared libraries, and it can be easily achieved with the help of QDeclarativeExtensionPlugin. Let's reuse the MyType class defined in the previous section. First, we need to create a plugin:
class MyPlugin : public QDeclarativeExtensionPlugin
{
  Q_OBJECT
public:
  void registerTypes(const char *uri)
  {
    qmlRegisterType<MyType>(uri, 1, 0, "MyType");
  }
};

Q_EXPORT_PLUGIN2(myPlugin, MyPlugin);


Then create a file named "qmldir" to define which plugin to load from where (suppose the plugin is called "myplugin):
plugin myplugin /path/to/plugin

Now we can use qmlviewer to launch the QML file:
// no need to import now
MyChart {
 id: myChart
 width: 100
 height: 200
}


4) summary
  • Use QDeclarativeView or QDeclarativeComponent to integrate a QML file into native Qt C++.
  • Qt C++ can access the properties of QML elements through QDeclarativeItem.
  • Expose native objects to QML through QDeclarativeContext.
  • New QML types can be exported through qmlRegisterType.
  • The properties of native objects are exported as properties, and the slots or functions declared with Q_INVOKABLE can be invoked in QML.
  • Create plugins for extension using QDeclarativeExtensionPlugin.


  • 10.9.10

    Unofficial Qt Web Runtime tutorial 2: Menu API

    If there is no API, Qt WRT is merely nothing but a naive web browser. Then what APIs are supported other than standard HTML and JavaScript now? You can first get a list of features already supported, or to be supported in the near future here.

    As a summary, we have already supported the APIs of menus, widget object, URI schemes, web inspector, console log, some Device APIs, as well as some HTML 5 features and standard JavaScript from Qt WebKit. Let's start with the menu API.

    1 view menu
    You can create the menu items to the chrome's menu bar (we call it view menu) with the following JavaScript code:
    var menuItem = new nokia.device.MenuItem("Menu item", changeTitle);
    nokia.device.menu.addMenuItem(menuItem);
    function changeTitle()
    {
      nokia.device.menu.title = "New title";
    }


    Here, you have created a menu item named "Menu item" and added it to the menu bar. When it's triggered, the function changeTitle() will be called to set the menu's title to "New title".

    Note that since on the device the menu's title is also the same as the window's title, it actually changes the window's title too.

    2 context menu
    The context menu can be created with the following piece of code:
    var contextMenu = new nokia.device.ContextMenu("contextMenuArea");
    var changeTitleItem = new nokia.device.MenuItem("Change Title");
    changeTitleItem.onselect = changeTitle;
    contextMenu.addMenuItem(changeTitleItem);


    Here, a context menu is created and an item named "Change Title" is added to the menu. When you long tap on the HTML element with id "contextMenuArea", this context menu will pop up. Then if you select the "Change Title" item, the changeTitle() function will be called.

    Of course, only the widgets in the windowed or fullscreen mode could have context menus; and only the widgets in the windowed mode can have view menus.

    Note that there's a known bug (already fixed for the next release) that if you long tap on the area where no context menu is defined, an empty context menu is popped-up.

    3 sample
    Only the HTML file this time ;)
    <html>
    <header>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      <title>Menu sample</title>
      <script type="text/javascript">
        function changeTitle()
        {
          if (nokia.device.menu.title == "Title 1")
            nokia.device.menu.title = "Title 2";
          else
            nokia.device.menu.title = "Title 1";
        }

        function init()
        {
          var menuItem = new nokia.device.MenuItem("item", changeTitle);
          nokia.device.menu.addMenuItem(menuItem);

          var contextMenu = new nokia.device.ContextMenu("contextMenuArea");
          contextMenu.addMenuItem(menuItem);
        }
      </script>
    </header>
    <body onload="init()">
      <div id="contextMenuArea">There is a context menu.</div>
    </body>
    </html>


    As you can see, one menu item can be added to multiple menus, exactly the same as native Qt apps. Here goes some screenshots:
     
     

    The first one shows the simple sample when launched. The second and third one show the view menu and the context menu, respectively, while the last one shows that the title has been updated after you tap on the menu. More screenshots can be found here, while the sample code is available here.

    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();
    }


    30.5.10

    JavaScript benchmarking on N900 PR1.2

    Two months earlier, I did my JavaScript benchmarking on N900 PR1.1, and compare it with other platforms. Now, as N900 PR1.2 got released, Opera has released a preview for Maemo, and Chrome is ported to N900 by Jacekowski, I did another round of benchmarking.

    V8SunSpiderPeacekeeper
    MicroB (default browser)21.235.12128
    FireFox21.415.84141
    Opera49.524.41119
    Qt 4.6.210512.04238
    QtWebKit 2.01049.36286
    Chrome1138.84344
    For V8 and Peacemaker, the higher the score, the better performance it has. For Sunspider, it's the lower the better.

    Chrome is really fast as a result of its excellent V8 JavaScript engine and frequent release cycle.

    Qt 4.6.2 is still quite good, especially considering the fact that the WebKit integrated is quite old. Note that QtWebKit will be released separately from Qt, meaning we could enjoy more about the latest WebKit technology then.

    However, both Opera and FireFox (MicroB uses FireFox's Gecko JavaScript engine) have quite a long way to go. Moreover, when running V8 and Peacekeeper, both MicroB and FireFox complained about unresponsive JavaScript.

    15.5.10

    这位评论真的用过N900吗?!

    刚看了一篇谈论手机杯具的文章,说的是N900。不过很怀疑这位老兄是否真的用过N900......

    文章说:N900最大的尴尬在于它那被消极淡化的通话功能。
    话说Nokia对Maemo/MeeGo系列的定义是“移动电脑”(mobile computer)吧!打开N900的官方首页,上面就写得非常清楚:Nokia N900 mobile computer。本来定位就不是智能手机,所以通话功能被“淡化”不正常吗?或者说你见过哪部PDA会“强化”电话功能的?好吧,你会说我这样强词夺理了,那我们接着看......

    然后文章对N900的“消极淡化通话功能”列出了几个“铁证”:
    1,机身正面没有任何拨号快捷键,哪怕是触控按键都没有。
    2,默认桌面菜单也没有任何与通话相关的快捷方式。
    3,QWERTY全键盘采用了三排式的布局,因此并没有单独的数字键。也就是说,打开侧滑盖还是没法直接拨号。
    4,没有竖屏模式,也就是说诺基亚设计它的初衷就是让你始终横着拿它。横着打电话?有难度吧。。。

    好吧,我们看图说话:
    这是我N900上四个桌面之一,上面可以任意摆设各种Widget、快捷方式和联系人,也可以自行调整其放置的位置。标号为1的红圈就是联系人的快捷方式,标号为2的红圈是最近通话和拨号功能的快捷方式,标号为3的红圈则是放在单个联系人的快捷方式。当然单个联系人也是可以自定义头像的,只不过考虑到隐私我暂时删除罢了。

    当然了,默认情况下,桌面也是有联系人和最近通话的快捷方式的,好像也有邮件或者短信息的快捷方式......我就不刷机证明了啊;)

    当然了,既然有如此方便的软键盘拨号,为何还要打开侧滑盖呢?

    然后我们再看看“没有竖屏模式”的笑话!你点开最近通话和拨号功能,然后看下图:
    我觉得这个应该叫做“竖屏模式”了吧?!而且通话功能的竖屏模式是默认开启的......

    我想,我只能说这位搞评论的朋友没有用过N900吧!

    PS 这三张照片都是用另一部N900的相机在晚上10点左右拍摄的,外界光线不好,室内也没开灯:)

    20.3.10

    JavaScript benchmarking on N900 and my laptop

    I just ran some JavaScript benchmark tests of V8 version 5, SunSpider v0.9.1 and Peacekeeper on my laptop. My laptop is HP EliteBook 6930p, which has Intel Core 2 Duo CPU P8600 @ 2.40GHz, 4 GB RAM, running KUbuntu 9.10 with kernel 2.6.31-20-generic. Also, I ran it on my N900 PR1.1 with Qt 4.6.2, and collected some results for iPhone 3GS, Droid and Nexus One, and HTC Desire.

    The following scores are from V8, the higher the better.
    FireFox for Ubuntu 3.5.8 - 248
    Qt 4.6.2 – 910
    Chrome 5.0.307.11 Beta – 4155
    QtWebKit 2.0 – 2816
    N900 - 105
    iPhone 3GS - no results
    Droid - 39.5
    Nexus One - 63.5
    HTC Desire - 66.1

    Then I found some results of iPhone 3GS for V8 version 3:
    N900 - 103
    iPhone 3GS - 53

    The following scores are from SunSpider, the lower the better.
    FireFox for Ubuntu 3.5.8 – 2484.7
    Qt 4.6.2 – 1136.0
    Chrome 5.0.307.11 Beta – 462.1
    QtWebKit 2.0 – 635.6
    N900 - 12.5
    iPhone 3GS - 16.7
    Droid - 34.2
    Nexus One - 14.7
    HTC Desire - 12.02

    The following scores are from Peacekeeper, the higher the better.
    FireFox for Ubuntu 3.5.8 – 1510
    Qt 4.6.2 – 3261
    Chrome 5.0.307.11 Beta – 4324
    QtWebKit 2.0 – 4288
    N900 - 244

    Chrome’s V8 engine is really fast, and WebKit still has a long way to go!

    Also, N900 performs much better than iPhone 3GS, Droid and Nexus. Considering HTC Desire, N900 wins easily on V8, but lost a little on SunSpider. However, if you consider MicroB, the default browser on N900, it’s a disaster due to the slow engine of Gecko and N900 even used a pretty old version.

    Then the ACID3 test.
    FireFox for Ubuntu 3.5.8 – 93
    Qt 4.6.2 – 100
    Chrome 5.0.307.11 Beta – 100
    QtWebKit 2.0 – 100


    * The test for QtWebKit 2.0 is done with the revision number of 56441.

    21.2.10

    IC cards are vulnerable to MITM attacks

    Researchers from Cambridge found a vulnerability in IC cards using EMV, which is used worldwide (with over 730 million cards in circulation) in chip and pin credit/debit cards. Note that the authors claimed that “the protocol is broken”. The details will be published at IEEE Security and Privacy Symposium in May this year, and a working draft is available now.

    With this vulnerability, criminals are able to launch Man-In-The-Middle (MITM) attacks easily and use stolen cards without knowing the correct PIN. The attack works for both online and offline transactions on terminals. Fortunately, it can’t work for ATM transactions.

    Let’s see how it works. The EMV protocol can be split into three steps:
    1 Card authentication – assure which bank issued the card and the data hasn’t been tampered.
    1.1 The terminal requests the list of available applications (e.g. card use at shops, ATM functionality, etc.), and selects one of them.
    1.2 The terminal reads the information of the card-holder, including card details (e.g. primary account number, start and expiry date), backwards compatibility data, and control parameters for the protocol. Some information is signed by RSA, and the certificate chain is also included in the information.

    2 Card-holder verification – assure the PIN entered matches the one stored on the card.
    2.1 The terminal sends the inputed PIN to the card for verification.
    2.2 If the inputed PIN matches the one stored on the card, 0×9000 is returned to the terminal. Otherwise, 0×63Cx is returned, where ‘x’ is the number of further PIN verification attempts the card allows. Note that the response is NOT directly authenticated.

    3 Transaction authorization – assure the bank authorizes the transaction.
    3.1 The terminal asks the card to generate a cryptographic MAC over the transaction details, including e.g. the transaction amount, currency, type, a random nonce generated by the terminal, and the terminal verification result. Note that the terminal verification result merely enumerates possible failure conditions, and doesn’t indicate which particular method is used in case of success.
    3.2 The card sends back also a sequence counter identifying the transaction, a variable length field containing data generated by the card, and the MAC. The MAC is usually generated using 3DES with a symmetric key shared between the card and the issuer.
    3.3 The terminal sends the response to the bank for transaction authorization.
    3.4 If the check passes, the bank sends back a two byte long response code, and a MAC over the message sent from the card and the response code.
    3.5 The response is forwarded by the terminal to the card. If the card verifies the response from the bank, it updates some internal states to note that the bank authorizes the transaction.
    3.6 The terminal asks the card to generate a transaction certification, signifying that it’s authorizing the transaction to proceed. It will be sent to the bank and stored locally for further use.

    Due to the above two flaws, the bad boy is able to launch the MITM attack like this:
    1) It hijacks the communication in step 2, sending 0×9000 to the terminal to fool it into believing the PIN verification succeeds.
    2) As the PIN is never sent to the card, it will be fooled into believing the terminal doesn’t support PIN verification, and the PIN retry counter is not modified.
    3) As the terminal verification result doesn’t tell the particular method used, the terminal believes the PIN verification succeeds and the card believes the PIN verification is not attempted.
    4) The variable length field containing data generated by the card generated in step 3.2 is issuer-specific, and not specified in EMV. Therefore, the terminal can’t decode it, and the issuing bank doesn’t know which card-holder verification scheme is used.

    Also, the researchers found that EMV failed to provide adequate evidence to produce in dispute resolution and litigation, among other issues. And we should be aware that this vulnerability is not implementation-specific, but the fundamental protocol is broken!