The Microwindows Project
Enabling graphical applications on embedded Linux systems
By Gregory Haerr
Chief Maintainer, The
Microwindows Project
Why use Linux?
In the fast-changing world of embedded, handheld and wireless devices, there are many hardware and software design changes taking place. Many devices now feature 32-bit microprocessors from Intel, MIPS and Motorola, as well as larger LCD graphical displays. In order to leverage the significant results gained in the desktop arena the last ten years, many developers are turning to using desktop-like operating systems with these new embedded designs. One of the most promising emerging areas seems to be running Linux in these environments, for a couple of good reasons: Linux on embedded systems brings with it the entire power of desktop computing, along with many solutions already running. Linux, being open source, allows any aspect of the solution to be fully understood and then customized for a particular application. Linux also alreadys supports all the new microprocessors typically included in embedded designs, including StrongARM, MIPS and PowerPC. Finally, Linux is free, with no royalty payments required for it’s use.
Problems with the X Window System
Having a freely-usable, open source, high-quality operating system with a TCP/IP stack sets the stage for interesting, innovative applications using wireless devices. However, the resource requirements of these new applications comes under scrutiny, since most embedded devices lack hard drives and large amounts of RAM. The desktop windowing system used on all desktop Linux systems is the X Window System, originally developed by MIT, DEC and others in the early 1980’s. The X Window system features a client/server architecture that allows applications running on any UNIX host (clients) to display on an X-based terminal (server). Quite a bit of code is devoted to making sure that the client/server paradigm works well across different host and server environments. These days, typically the X clients and server run on the same machine, the user’s desktop. The X Window Server is typically compiled to support differing hardware chipsets with auto-detection, as well as having multiple copies of all drawing functions both above and below the clipping layer for high speed. As a result, the X Window System is large and complex, typically requiring at least 8MB of memory for execution.
Why Microwindows?
In most embedded designs, the X Window System is overkill, especially when running a dedicated graphics application. For this reason, the Microwindows Project was developed. Microwindows is an open source project aimed at producing desktop-quality graphics functionality for small devices. The architecture allows for ease in adding different display, mouse, touchscreen and keyboard devices, as I will explain below. Starting with Linux version 2.2.0, the kernel contains code to allow user applications to access graphical display memory as a framebuffer, which ends up being a memory-mapped region in a user process space that, when written to, controls the display appearance. This allows graphics applications to be written without having to have knowledge of the underlying graphics hardware, or use the X Window System. This is the way that Microwindows typically runs on embedded systems.
Microwindows was designed to attempt to bring applications to market quickly, with a minimum of effort. In order to accomplish this, I felt that designing yet another graphics applications programming interface (API) would steepen the learning curve, thus discouraging interest and increasing time-to-market. Microwindows implements two popular graphics programming interfaces: the Microsoft Windows Win32/WinCE graphics display interface (GDI), used by all Windows CE and Win32 applications, and an Xlib-like interface, known as Nano-X, used at the lowest level by all Linux X11 widget sets. This allows the extremely large group of Windows programmer talent to be used in developing the graphical side of the application, as well as being familiar to the core group of Linux graphics programmers used to working with X11.
Microwindows runs in 50-250k of memory, an order of magnitude smaller than the X Window System. This is primarily the result of using a single routine for each of the drawing functions in the engine layer. The engine layer checks for clipping and calls a driver-level routine for drawing a pixel or line if unclipped. The X Window System duplicates the entire drawing routine for each pixel depth and has clipped and unclipped versions for speed.
Microwindows fully supports the new Linux kernel framebuffer architecture, and currently has support for 1, 2, 4, 8, 16, 24, and 32 bits per pixel displays, with support for palettized and truecolor display color implementations, as well as grayscale. With both APIs, all colors are specified in the portable RGB format, and the system has routines to convert to the nearest available color, or shade of gray for monochromatic systems. Although Microwindows fully supports Linux, it’s internal, portable architecture is based on a relatively simple screen device interface, and can run on many different RTOS’s as well as bare hardware. This brings a big benefit: graphics programming by the customer can be shared between projects, and even run on different targets with different RTOS’s, without having to rewrite the graphics side of the application.
Microwindows supports host platform emulation of the target platform graphically. That is, Microwindows applications for Linux can be developed and prototyped on the desktop, run and tested without having to cross-compile and run on the target platform. This is accomplished using Microwindows’ X11 screen driver, where the target application is run on the desktop host and displayed within an X window. The driver can be told to emulate exactly the target platform’s display in terms of bits per pixel and color depth. Thus, even though the desktop system is 24 bit color, it can display a 2bpp grayscale for previewing the target application. Since both the host and target are running Linux, most all operating systems services are available on the desktop host.
There are significant differences in the way that programmers familiar using Microsoft Windows or the Linux X Window System implement graphical applications. Microsoft Windows programmers typically use Microsoft’s Foundation Classes (MFC) C++ applications framework, or the newer Active Template Library (ATL) framework. Source code is provided for both of these interfaces, and both must use the Win32 GDI for all graphics drawing. Windows also includes quite a few user interface controls that are useable from the Win32 GDI, including buttons, listboxes, and the like. The X Window System, on the other hand, provides a low level interface known as Xlib, which implements low level drawing primitives only, and packages them up for execution on the display server. Most user interface solutions rely on "widget sets" implemented on top of Xlib, for modern functionality. We are working at porting some of the more popular widget sets to Microwindows, including GTK+/GDK, the basis of the GNOME project’s desktop, and FLTK, a small C++ toolkit which implements quite a few user controls.
Microwindows Architecture
A key component in the design of Microwindows is to keep things small. Although this can sometimes preclude implementation of more complex applications, the Microwindows design has distinct separation of driver level, engine level, and API level functionality so that, if desired, complex functionality can be added on an as-needed basis without complicating the entire design. I’ll discuss each of these implementation levels in more detail.
At the lowest level, Microwindows abstracts a data structure for a display screen, a mouse or touchpad input device, and a keyboard device. This structure appears identical on the top side, for use by the drawing engine, and includes code to interface with the specific device the driver is written for. Microwindows includes drivers for quite a few different devices and operating systems, with more being included with each release. Screen drivers for the Linux framebuffer include support for displays running 1, 2, 4, 8, 16, 24 and 32 bits per pixel, supporting palettized, grayscale, and truecolor display. The screen driver definition includes entry points for reading and writing a pixel, drawing a horizontal or vertical line, and optionally, blitting memory from the screen to memory or vice versa. By implementing only these basic entry points, all of the upper level Microwindows functionality, including TrueType or Adobe Type 1 font support, RGB colors, jpeg and bmp image handling, will run. If your screen device has hardware acceleration, or a peculiar method of implementation in one of these areas, a modication to the driver is all that is required. In the same manner, touchscreen and keyboard/button input is brought into the system.
At the middle level of Microwindows is the drawing engine. This code is device-independent, since all drawing is implemented by calling a screen driver. The drawing engine presents a set of standard entry points for the API level above to call for drawing functionality. The Microwindows engine abstracts an RGB color model for all colors, regardless of the physical display device. Routines are provided that determine the hardware pixel value from an RGB triple, using the same interface regardless of whether the physical display is running pallettized grayscale or truecolor. In addition, Microwindows implements all clipping at the engine layer, using a fast, multiple-rectangle approach that allows for arbitrarily complex regions to be specified for drawing. All font display is handled at the engine layer, including our new support for unicode-based TrueType fonts using FreeType, and Adobe Type 1 fonts using T1Lib. Compiled in proportional fonts are also supported. The engine implements anti-aliasing using alpha blending for smoother looking fonts on higher resolution displays. Currently, support for Ascii, Unicode-16, Unicode-32, and UTF-8 encoding are supported.
The uppermost level of Microwindows implements one of the two supported APIs. At this level, the window abstraction is implemented, which allow applications programmers to contain their display data in a full screen or overlapped window. This layer is also responsible for event handling, and passing received hardware events such as touch screen or button presses to the application.
Compile time options
The Nano-X API allows applications to be built using a client/server protocol over a network socket, or local UNIX domain sockets. This allows several applications, running on the embedded device or a remote host to connect to the Microwindows server to for display. In addition, the client/server protocol can use shared memory for passing data between the client and server. A compile time option allows all applications to be linked with the server for smaller environments, or environments without a filesystem. Microwindows also supports linking directly with a real time operating system for extremely compact environments. Compilation for various features is turned on or off in a configuration file, which allows Microwindows to be built in modules, and include only the items that will be used.
Summary
The Microwindows Project provides a much-needed solution for smaller systems and embedded devices by providing a graphical runtime with minimal ram and disk requirements. By implementing the two most popular graphics APIs, users already familiar with graphics programming can start producing applications quickly. Because Microwindows is open source and free, it is being evaluated and used in an increasing number of systems designs today.
Microwindows is a work in progress, and new features are being added regularly. I invite you to check out our web site at http://microwindows.org for more information and screenshots of demo applications. The Microwindows project is licensed under the MPL (Netscape license), which means that it can be used with designs under non-disclosure, without having to release proprietary source code.
Bio
Greg Haerr is an expert UNIX and Windows programmer, specializing in operating systems, interpreter, and graphics windowing system designs. He is CEO and founder of Century Software, a leader in UNIX connectivity solutions, as well as the Chief Maintainer of the Microwindows Project.