Windows
(Win32)
Macintosh OS X
Linux
“Knowledge is power.”
It could go without saying that in order to build a cross-platform development framework, we must know (in good depth) the platforms we wish to target. Towards that end, this document details how these platforms work, and what must be done in order to make Abstract applications run on them.
The initial targets are Windows, Macintosh OS X, and Linux. There is no reason why Mac OS 9 can't be supported, but by the time Abstract gets rolling, OS 9 support may be moot. Unless otherwise specified, the word “Macintosh” or “Mac” means OS X. As for Linux, since it has many distributions, likely verifiable/supported targets are Red Hat/Fedora.
All three platforms support modern GUI systems. Each has their particular strengths and weaknesses. Since Abstract shields applications from environmental particulars, each platform gets to dictate its appearance with its native look and feel. Linux ports may run successfully on other UNIX and UNIX-derived platforms, so the term “Linux” will be used to refer to all of them.
All the platforms feature 32-bit memory addressing, protected memory, preemptive multitasking, multithreading, virtual memory, Unicode support, OpenGL, 32-bit graphical interfaces and related desktop/workstation support. It's almost a cross-platform framework developer's dream come true. This is actually no coincidence, since all three have heavily borrowed ideas from UNIX.
Microsoft Windows is actually a fairly wide family of operating systems ranging from Windows CE for handheld and other small devices to Windows XP. There is even a customized version of Windows 2000 used in the XBox gaming console. However, the APIs are largely the same, and most developers have enjoyed few issues deploying applications from Windows 95 to XP. For our purposes, since we want to support Unicode, we'll initially stick to Windows XP and Windows 2000.
Longhorn (the next version of Windows) apparently has a different set of native APIs but will support the current ones. Therefore, the Win32 version of Abstract will run on Longhorn but will not be optimized for it and applications may not adhere fully to the Longhorn interface guidelines.
User interface consistency is quite good, although variations occur from the wide assortment of developers writing programs. There is a canonical OEM reference available, however. Keyboard focusing support in particular is well done.
Although Microsoft is promoting its C# language as the preferred compiler in its .NET framework, C++ support is readily available using the existing Win32 APIs. These APIs will continue to be supported in the next version of Windows (codenamed “Longhorn”) as well. For widest compatiblity, we'll aim for support of the DevStudio 6.0 Standard Edition build environment.
Win32 applications use an OS-specific version of main() called WinMain. This entrypoint not only takes a command-line argument string but details about application instances and launch behavior. Since the command line is treated as one big string, we have to do some extra work to parse it. Windows requires apps to have 32 x 32 pixel-sized icons but is moving towards larger sizes.
Programs need to set up an event loop that acquires and dispatches messages. The latter is easy because Windows has a standard function called, appropriately enough, DispatchMessage, which simply forwards the message to the indicated window. Prior to that, however, the application is expected to translate any keyboard messages to their menu command equivalents. An OS X developer can picture Windows as having preinstalled event handlers into every window an app creates. Command events are easy to identify since they use the WM_COMMAND identifier.
Menubars are normally created by passing a resource ID or handle to a menu creation parameter in the main window's class definition. In Abstract, we need to create our menus dynamically. Fortunately, menus can be made this way also. Some apps even dispense with normal window APIs and implement their own menus as buttons and specialized popup toolbars (which in fact, is pretty much what menus are). Menubars cannot (or at least should not) be made outside of windows -- normally, an application creates a main window that contains not only the menubar but all subwindows as well. Where exceptions exist (such as Visual Basic 3.x) the menu bar still creates a small narrow window so that it has something to reside in. Unlike the Mac, there is no fixed screen location for the menubar.
Buttons and other widgets are treated as window subclasses, which simplifies creation, event handling, and manipulation. Scrollbars for subcontent windows are an exception -- they can be widgets but also mere attributes of a window that enables its WS_HSCROLL / WS_VSCROLL window style flags. Scrollbar events are simply events, fortunately, making them easy to manage. Although scrollbars provide 16-bit precision, this is not a problem since the user can only position a scrollbar with pixel accuracy anyway. We probably prefer the scrollbar-as-widget paradigm.
File handling is often accomplished using stdio interfaces although some use Win32 calls. File IDs are character strings and folder IDs also, with absolute references treated as longer strings known as path specifications. In Windows, volumes have single-letter IDs (“drive letters”) followed by a colon, and backslash (“\”) characters indicate folder distinctions. Since volume names must be unique in the filesystem, folder IDs are easily implemented. File types are handled by appending a period (“.”) character and then a short abbreviated form of the type descriptor.
Text files normally use CRLF (ASCII codepoint sequence 0x0D, 0x0A) line endings.
Endianness is Intel (little-endian). This is not strictly a Windows feature but has more to do with Windows running pretty much exclusively on Intel CPUs.
2D graphics are done by obtaining a temporary device context handle and issuing GDI calls. Off-screen bitmaps are implemented with DIBSECTION structures, which use BGR channel ordering in 24/32 bit mode. Through DirectDraw, one can also make offscreen bitmaps precisely matching the display hardware pixel layout for top performance, although most GDI operations are already accelerated.
OpenGL support is native since Windows 95 OSR 2 with at least a fairly adequate OEM software renderer. Accelerated OpenGL is also very commonplace, although some driver differences crop up here and there. Performance is superlative given the wide adoption of nVidia hardware. Windows also offers Direct3D, which would be interesting to support if we could do so portably.
Viewpanes are easy to implement because most visible entities are window objects. Tab order, however, is defined by the order of subpane creation, so it is not easy to modify.
OS X is the highly regarded Macintosh user interface running on a UNIX-derived services core. The consistency of its GUI is about as perfect as it gets, largely in part to users' high expectations and Apple's strong communication of standards. Keyboard focusing of widgets, however, appears limited to text fields. Our reference platform will be OS X 10.2 (“Jaguar”).
Since Abstract uses C++, the port will make use of the Carbon APIs. These interfaces basically expose the OS 9 services and their traditional function calls so that legacy applications and programs using C, Pascal, and C++ can easily continue to be developed for OS X.
On OS X, applications use a standard main() entrypoint. They need to provide (preferably) 128 x 128 pixel-sized icons. Our reference build environment will be Project Builder 2.0.1 using gcc 3.0. It is also possible to use makefiles in a terminal window.
Applications normally use the Carbon Event Manager to install event handlers and process event loops (and each thread in a program can have an event loop). Usually, a program defines handlers and simply calls RunApplicationEventLoop to let OS X manage the main event loop. When that function ends, one can simply release any allocated resources and exit main() with a requisite result code.
For Abstract, we need the base application class to install a command event handler so that Abstract can process all commands and dispatch them according to its rules. OS X actually mimics Abstract in terms of dispatching, but to be safe we'll want most events routed through Abstract.
OS X applications can have event queues on a per-window and per-viewpane basis through the use of the HIToolbox, so our job is simplified. Subclasses of abstract's CViewpane simply implement methods, much like MFC CWnd objects do on Windows.
Menubars are normally created by passing a resource ID or handle to a menu creation API. In Abstract, we need to create our menus dynamically. Fortunately, Carbon's Menu Manager offers a wealth of routines to do so. The menubar occupies a fixed location at the top of the screen completely separate from any windows.
Buttons (for toolbars) could be custom-drawn widgets or use button objects from the Control Manager. On OS X, the Aqua interface dominates and should be adhered to for consistency, so command imagery may need to be “coated” with translucent “glass” to appear as respectable button objects. This has to be done at runtime, of course -- developers should not do such decorating themselves. The HIView system (which replaces the older Control Manager) offers an adequate set of other widgets to handle dialog visualization of core types. Some buttons (like “Burn CD”) are even animated, which means we might want to extend button imagery to include animated formats.
Subcontent windows should create and attach scrollbars. On the Mac, scrollbars are governed by the Control Manager and treated as controls, which are their own entity class instead of also being specialized window attributes like they are on Windows. Because scrollbars are positioned within a window's client area, care must be taken not to draw over them. This is usually accomplished by shrinking in the window's Grafport clipping rectangle. When the mouse goes down in a scrollbar, HandleControlClick is called and given a pointer to a tracking function that deals with scrollbar manipulations. Here, Abstract would generate and post the necessary subcontent protocol messages to the viewpane.
File handling on the Mac was historically a botched job in terms of APIs. They're so numerous and complex that Apple provided a MoreFiles package to simplify using them. Somehow, the idea that the stdio interfaces might be adequate didn't occur to anyone. This is a case where Abstract can shine, by just reducing the problem to its essence. Here, we shield the use of FSSpec records with CFolderID and CFileID. Although Mac files can have resource forks, in Abstract we ignore them since other platforms don't use them. This is not a problem because most developers don't bother with them either. Resources make sense inside executable images, but extending the idea to files of all types was unnecessary. Folder IDs can be specified as path strings with colons as separators, although this is discouraged since volumes on the Macintosh can have duplicate names. In Abstract, we cannot let the absolute file ID specifier widget address volumes by name, or if we do, we have a rule that the name indicates the first such volume found. Either way, once defined, the folder ID class must store the volume's integer ID to avoid having the volume reference drift through the filesystem namespace. Another solution, when detecting duplicate volume labels, is to simply prompt the user to choose which one he means. In other folder ID acquisitions, such as the Open and Save dialogs, the problem doesn't exist since there is no string specification ability. File types are best handled by applying the “type” code in the file's metadata entry and applying a more traditional dot-and-string suffix to the filename.
Text files normally use CR (ASCII codepoint sequence 0x0D) line endings, although with the use of a UNIX core, LF (0x0A) line endings should be expected.
The Mac, of course, uses Motorola (big endian) byte ordering for numeric scalars, so the base CFile class automatically preps itself to read/write these types with that endianness.
Viewpanes are automatically buffered for flicker-free display. Applications are pretty much unaware and/or unable to circumvent this behavior. OS X also has considerable multiple-monitor support. Window objects are limited to top-level entities, since dialog elements are treated separately as controls. Therefore, viewpanes need to be implemented explicitly in a manner similar to the Pane system in Metrowerks PowerPlant.
2D graphics are drawn by obtaining references to Grafports from a window and then making QuickDraw calls. Off-screen bitmaps are treated as GWorld entities and their contents copied using CopyBits calls. The color channel ordering is RGB.
OpenGL is intrinsic (especially since OS X actually renders with OpenGL quite a bit) and accelerated on newer hardware. Performance is superlative. In fact, unaccelerated OpenGL may not exist on OS X since Apple's use of OpenGL postdates its incorporation of accelerated 3D graphics hardware.
Apple ships a traditional one-button mouse but OS X supports two-button mice as well. Ideally, Abstract's runtime configuration should allow users to map “button #2” events to a combination button + keyboard press event.
Linux started off as a “better Minix”, which Linus Torvalds wrote to have his own UNIX-style system running on Intel 386 hardware. Although the spirit and style of UNIX was preserved, Linux is not a pure UNIX, at least in the sense that it does not use the canonical AT&T UNIX source codes. The GNU toolset and XFree86 (an X Windows implementation) were added shortly after to form what one considers a normal Linux distribution. For our purposes, we will use the Red Hat 8.0 distribution and gcc 3.2. For a true introduction to Linux, we would also have to introduce UNIX, but to keep this short suffice to say that UNIX began as a robust timesharing command-line environment with GUI services added later. Although Linus began Linux after the advent of GUIs, his resources at the time were insufficient to bother competing with the established X Windows and Motif libraries. Even today, the effort to establish a more modern common windowing system remains Herculean.
Linux is perhaps the easiest and most difficult platform to support. Easy, because the de facto X Windows libraries were designed with near limitless flexibility in mind. Hard, because... well, if you've ever coded a pure X Windows program, you know what we mean. Most people use higher-level libraries such as Motif, GTK, KDE, Qt, etc. A lightweight and customizable widget library might be the best approach for Abstract, although a pure framebuffer approach is not without its appeal.
GUI consistency is below par. A chief problem is the lack of a standard window manager and/or desktop environment, or at least a standard protocol for them to agree upon. Clipboard implementations in particular can be horrid -- cut/copy/paste is simply not guaranteed to work across all applications, even if the source and destination are both graphical. On a postive note, however, there are basically two main desktops: KDE and Gnome, and they both attempt to imitate (and do so pretty well) the GUIs of Mac and Windows. Within an application, behavior is tolerable. Recent efforts by industry leaders indicate a growing trend to downplay or even eliminate the difference between these environments. Abstract may in fact be quite good on this platform in terms of simplifying GUI development under Linux.
C++ support is easy because UNIX and C were developed in tandem, and C/C++ are the most popular low-level languages for UNIX-style systems. Otherwise, scripting languages dominate, such as Perl, Python, Tk, and the various shell languages (Bourne, C-shell, Korn, etc.).
File I/O is almost entirely stdio based, although directory manipulation uses services that differ from how people do it on Windows. Text files normally use LF (ASCII codepoint 0x0A) line endings. Filetypes are similar to Windows and pathspecs are also strings except that volume names are multicharacter and the separator symbol is a forward slash (“/”). Filenames are case sensitive.
Endianness can be either little- or big-endian), because Linux runs on different CPU families (although the Intel version is by far the most popular).
2D performance can be tricky because the concept of a framebuffer is actually a recent idea in UNIX, because X Windows works using a client/server display architecture. However, libraries have been developed to let applications easily get at the host framebuffer. For most purposes, however, it's not all that necessary. Quality font availabilty is another weakness, although the situation is improving.
OpenGL is normally available in software form via Mesa, but it's slow. Accelerated OpenGL is pretty much the only way to go for an app to use 3D, but driver support remains spotty.
Copyright
2003-2004 Daylon Graphics Ltd.
Abstract is a trademark of Daylon
Graphics Ltd.
Author(s): Ray Gardener
(rayg@daylongraphics.com)
Location:
http://www.daylongraphics.com/other/abstract/platforms.htm
Last
updated: