A Technical Introduction to MiniGUI

by Zhong Shuyi (Oct. 16, 2003)

Foreword: MiniGUI is a four-year-old open source GUI framework for Linux devices -- especially those running real-time applications -- that is now a stable, viable alternative to QT/Embedded and Microwindows, according to founder and maintainer Wei Yongming. MiniGUI supports uClinux, among other kinds of embedded Linux, and can be built with POSIX thread library support. We asked Mr. Wei for a technical introduction to MiniGUI, and he and his development team put together the following overview and mini-tutorial. Enjoy . . . !

--------------------------------------------------------------------------------

Building MiniGUI for Embedded Linux Systems

The use of Linux in embedded systems is overwhelming today. Many traditional industry giants and new embedded devices vendors base their embedded software solutions on Linux.

Most embedded Linux development involves three aspects: the embedded OS system (bootloader, Linux kernel, etc.), the graphical user interface (GUI), and the applications. Qt/Embedded and MicroWindows are popular in the embedded Linux GUI world. In this article, we introduce MiniGUI, a desirable alternative to those two graphics libraries, and describe the basic concepts about how to use MiniGUI in an embedded Linux system.

What's MiniGUI

MiniGUI is a lightweight GUI library for Linux-based embedded systems and a GPL-licensed free software project. After over four years of development since the end of 1998 as an open source project, MiniGUI has become a stable and reliable one for widespread application in a variety of products and programs. Not long ago, Beijing Feynman Software Technology, the maintainer and vendor of MiniGUI, released MiniGUI V1.3.0, which is the latest stable version and adds support for uClinux.

MiniGUI is a complete GUI system tailored to the embedded systems, with the following main technical features:

  • Complete multi-window support and messaging mechanism
  • Plentiful controls in common use, including static textbox, button, single-line and multi-line compilation box, list box, combo box, progress bar, property page, toolbar, track bar, treeview, listview, month calendar, and so on
  • Dialog box, message box and other GUI elements like menu, acceleration key, insertion character and timer, etc.
  • Windows' resources file support, such as bitmap, icon, and cursor
  • Support for all popular image files including JPEG, GIF, PNG, TGA, and BMP, etc.
  • Multi-character-set and multi-font support, such as ISO8859-1 -- ISO8859-15, GB2312, Big5, EUCKR, UJIS, lattice font and vector fonts such as TrueType, as well as Adobe Type1, and so on
  • Special support to embedded systems, including the common I/O operations, byte-order related functions, etc.
  • Support for a variety of display equipment from monochromatic LCDs to 32-bit color monitors, offering powerful graphical functions

Many technical innovations have been made in the course of MiniGUI development, which enable MiniGUI to become more suitable for embedded systems and exhibit agreeable flexibility, applicable to various high-end or low-end embedded systems including hand-held devices, set-top boxes, game terminals, and so forth. The advantages of MiniGUI include:

  • Light-weighted, little resources consumption
  • High performance
  • High reliability and stability
  • Highly configurable

MiniGUI offers embedded Linux developers a good alternative to Qt/Embedded or MicroWindows. For real-time embedded systems, MiniGUI is more suitable because of the advantages mentioned above.

Porting MiniGUI to your Linux device

You will need to do little extra coding work to port MiniGUI to your embedded device running Linux. Let's learn about MiniGUI's system architecture first.

MiniGUI is a tiered GUI system, with a "Graphics Abstraction Layer" (GAL) and an "Input Abstraction Layer" (IAL) to deal with low level output and input. The concept of an abstraction layer is somewhat similar to the concept of driver in the operating system. An abstraction layer defines a set of abstract interfaces independent of any particular hardware or low-level systems, and all the top-level graphics operations and input process are based on these interfaces. We can call the implementation code for the abstraction layer a graphics engine or an input engine. With the GAL and the IAL architecture, we can easily port MiniGUI to a new devices or operating systems.

Most embedded Linux systems provide the frame buffer driver to the applications for display output. If this is the case, you do not need to do any porting work on the graphics engine, because MiniGUI's fbcon graphics engine supports the Linux frame buffer already. If not, a bit of coding work is necessary, but you will not have to write an entirely new graphics engine from the start.

On a Linux device, there are no standard interfaces to process inputs from input devices such as touch screens and keypads. So, in most cases, you will need to write a new MiniGUI input engine (driver) for your input device. To write an input driver for MiniGUI is fairly easy, because the input interface in MiniGUI is well defined. You can use the iPaq input driver (MiniGUI source directory/src/ial/ipaq.c) as a reference and model. Normally what you should do is as such: open and initialize your input devices first, when MiniGUI is inquiring about input; achieve input data from input devices, if there is any; transfer it to MiniGUI input events; and, return to the system.

A "Hello world" example

Let's have a look at a "Hello world" example of a MiniGUI application.

/* 
** helloworld.c: Sample program for MiniGUI Programming Guide
**     The first MiniGUI Application
*/

#include <stdio.h>
#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>

static int HelloWinProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    switch (message) {
        case MSG_PAINT:
            hdc = BeginPaint (hWnd);
            TextOut (hdc, 100, 100, "Hello world!");
            EndPaint (hWnd, hdc);
            return 0;
        case MSG_CLOSE:
            DestroyMainWindow (hWnd);
            PostQuitMessage (hWnd);
            return 0;
    }

    return DefaultMainWinProc(hWnd, message, wParam, lParam);
}

int MiniGUIMain (int argc, const char* argv[])
{
    MSG Msg;
    HWND hMainWnd;
    MAINWINCREATE CreateInfo;

#ifdef _LITE_VERSION
    SetDesktopRect(0, 0, 800, 600);
#endif

    CreateInfo.dwStyle = WS_VISIBLE | WS_BORDER | WS_CAPTION;
    CreateInfo.dwExStyle = WS_EX_NONE;
    CreateInfo.spCaption = "HelloWorld";
    CreateInfo.hMenu = 0;
    CreateInfo.hCursor = GetSystemCursor(0);
    CreateInfo.hIcon = 0;
    CreateInfo.MainWindowProc = HelloWinProc;
    CreateInfo.lx = 0;
    CreateInfo.ty = 0;
    CreateInfo.rx = 320;
    CreateInfo.by = 240;
    CreateInfo.iBkColor = COLOR_lightwhite;
    CreateInfo.dwAddData = 0;
    CreateInfo.hHosting = HWND_DESKTOP;

    hMainWnd = CreateMainWindow (&CreateInfo);
    if (hMainWnd == HWND_INVALID)
        return -1;
    ShowWindow(hMainWnd, SW_SHOWNORMAL);
    while (GetMessage(&Msg, hMainWnd)) {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    MainWindowThreadCleanup (hMainWnd);
    return 0;
}

#ifndef _LITE_VERSION
#include <minigui/dti.c>
#endif

Running this program will create a 320x240 size window on the screen, with the "HelloWorld" window caption and a "Hello world!" text drawed in the middle of this application window.

As you can see, MiniGUI is a typical message-driven GUI system. The "MiniGUIMain" function is the entry point of every MiniGUI application. This application creates a main window with CreateMainWindow function first, shows this window, and then begins message loop using while (GetMessage (&Msg, hMainWnd)) statements.

MiniGUI consists of two versions, MiniGUI-Threads and MiniGUI-Lite, differing in system architecture. MiniGUI-Threads, also the initial MiniGUI version, is based on the POSIX thread mechanism. MiniGUI-Threads applications run at the same address space, significantly improving the inter-program communications efficiency. This kind of system architecture is cut out for time-critical systems such as real-time control systems.

MiniGUI-Lite

MiniGUI-Lite has simplified client/server architecture and the following features:

Maintains over 99% compatibility with the former MiniGUI-Threads version at the source code level. Capable of simultaneously running multiple MiniGUI-Lite-based applications, i.e., multiple processes, and providing process switchover at front-desk and back office. MiniGUI-Lite is suitable for more complicated embedded system with many applications, such as handheld information devices. There is little difference between programming for MiniGUI-Threads and programming for MiniGUI-Lite. Actually, the "Hello world" example above will run on either version. Running MiniGUI

Now, you may want to have a try with MiniGUI on your device.

Getting MiniGUI

Download the latest MiniGUI library libminigui-1.3.0.tar.gz and the support resource package minigui-res-1.3.0.tar.gz from http://www.minigui.com/eproduct.shtml.

libminigui-1.3.0.tar.gz is the MiniGUI library source package, and minigui-res-1.3.0.tar.gz contains the basic runtime resource for MiniGUI, such as icons, cursors, and fonts, etc. Release the source package with the following command:

tar zxvf libminigui-1.3.0.tar.gz

A directory named libminigui-1.3.0 containing MiniGUI library source will be generated in your current working directory.

Cross compiling

Next you should cross compile MiniGUI and the application. The selection of cross compiler depends on your target platform. MiniGUI supports a variety of processors, including ARM (StrongARM, Xscale, ARM7, ARM9), MIPS, M68K, COLDFIRE, PowerPC, etc. Here we use arm Linux and arm-toolchain-2.1.3 tool chain as an example.

If you have not installed your tool chain, installed it using the following commands (as root):

# rpm -ivh arm-linux-binutils-2.10-1.i386.rpm
# rpm -ivh arm-linux-gcc-2.95.2-1.i386.rpm
# rpm -ivh arm-linux-glibc-2.1.3-1.i386.rpm

These commands will install an arm-linux toolchain in the /usr/local/arm-linux directory.

Fix PATH environment variable to make system able to find the arm linux compiler arm-linux-gcc. You can add the following line into the .bash_profile file in your user home directory:

export PATH=/usr/local/arm-linux/bin:$PATH

MiniGUI will be configured as MiniGUI-Threads version by default. Configure and compile MiniGUI as thread version for the arm linux target with the following commands:

cd libminigui-1.3.0
CC=arm-linux-gcc ./configure --target=arm-linux --prefix=/usr/local/arm-linux/arm-linux
make
make install

Compile the "Hello world" MiniGUI example application:

arm-linux-gcc -o helloworld helloworld.c -lminigui -lpthread

MiniGUI-Threads needs pthread library, so add -lpthread flag when compiling MiniGUI-Threads applications.

Installing to your device

We assume you have a root file system in the /opt/targetfs/ directory prepared for your target platform. Install MiniGUI libraries, runtime resources, configuration file, and MiniGUI applications into this file system first, and burn the Linux image to the target board later via serial line or whatever.

Install MiniGUI shared libraries:

cp /usr/local/arm-linux/arm-linux/lib/libminigui.so* /opt/targetfs/usr/local/lib/ -af

Install MiniGUI runtime resources:

tar zxvf minigui-res-1.3.0.tar.gz
cd minigui-res-1.3.0

Edit the config.linux file in the minigui-res-1.3.0 directory, change prefix to:

prefix = /opt/targetfs/usr/local

Type "make install" on the command line, and the resources will be installed into the /opt/targetfs/usr/local/lib/minigui directory:

make install

You can also change prefix to the same directory as the MiniGUI install directory, here /usr/local/arm-linux/arm-linux:

prefix = /usr/local/arm-linux/arm-linux

Later you can copy the resources in /usr/local/arm-linux/arm-linux/lib/minigui to the /opt/targetfs/usr/local/lib/minigui directory:

cp /usr/local/arm-linux/arm-linux/lib/minigui/* /opt/targetfs/usr/local/lib/minigui/ -rf

MiniGUI needs a configuration file named MiniGUI.cfg in runtime. This configuration file will be installed into the /usr/local/arm-linux/arm-linux/etc/ directory when you compile and install the MiniGUI library. MiniGUI searches for MiniGUI.cfg on startup in the /usr/local/etc/ and /etc/ directory, so copy this file into the etc directory in the target root file system:

cp /usr/local/arm-linux/arm-linux/etc/MiniGUI.cfg /opt/targetfs/etc/

Now, copy your MiniGUI application "helloworld" into the target root file system:

cp helloworld /opt/targetfs/usr/local/bin/

If there is a startup script file like /etc/init.d/rc.local in your target system, edit this file and add such a line:

/usr/local/bin/helloworld

This will make the system execute the helloworld program after startup, and you can see a "Hello world!" MiniGUI window at that time!