Click here to Skip to main content
12,999,837 members (54,095 online)
Click here to Skip to main content
Add your own
alternative version

Stats

44K views
1.6K downloads
51 bookmarked
Posted 20 Jan 2014

Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework - Introduction

, 9 Mar 2015
Rate this:
Please Sign up or sign in to vote.
How to get out the maximum from the Roma widget in C# efficiently without dependencies to GUI frameworks like GTK or KDE. Basics and description of concepts.

Download complete project, older version 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90 32 bit (zip).

Download complete project, older version 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90 64 bit (zip).

Download complete project current version 1.00 32 bit (zip)

Download complete project current version 1.00 64 bit (zip)

Download Xrw API Documentation (in HTML) version V1.00 (zip)

Introduction

This article introduces the Roma Widget Set (Xrw), a C# GUI application framework, that is directly based on X11 library calls. The idea of the Roma Widget Set has been developed as consequence of the first article from an article series dealing with Xlib/X11/Xt/Xm, Programming Xlib with Mono Develop - Part 1: Low-level (proof of concept) and influenced by the experience made through writing the subsequent articles Programming Xlib with Mono Develop - Part 2: Athena widgets (proof of concept), Programming Xlib with Mono Develop - Part 3: Motif widgets (proof of concept) and Programming Xlib with Mono Develop - Part 4: FWF Xt widgets.

The zero dependency promise means, it requires only assemblies of the free Mono standard installation and libraries of the free X11 distribution; it doesn't particularly require GNOME, KDE or any commercial library.

Because the whole Topic grew beyond 50 print pages, i decided to split it into three parts with and into four parts with . With i moved the complete API description to a separate HTML documentation (that is part of the Xrw project) and restructured all four articles to make reading more entertaining and exciting:

  • This article: Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework - Introduction. It contains a short explanation of the widget set's features. (Before it was: ~ Basics. It contained general descriptions.) This atricle should always be the preferred starting point.
  • The first split-off article: Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework - Widget set. Due to the constantly growing of 'boring' API documentation, the API documentation has been moved with to a separate HTML documentation (that is part of the Xrw project) and this article has been focused on a briefly introduction of all widgets. (Before it was: ~ Intrinsic widgets. It contained the full featured API reference description of intrinsic widgets only.)
  • The second split-off article: Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework - Programming techniques. Due to the constantly growing of 'boring' API documentation, the API documentation has been moved with to a separate HTML documentation (that is part of the Xrw project) and this article has been focused on programming techniques. (Before it was: ~ Simple widgets. It contained the full featured API reference description of simple widgets only.)
  • The third split-off article: Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework - MVVM/XAML support. Due to the constantly growing of 'boring' API documentation, the API documentation has been moved with to a separate HTML documentation (that is part of the Xrw project) and this article has been focused on introducing the MVVM/XAML support of the Xrw. (Before it was: ~ Composite widgets. It contains the full featured API reference description of composite widgets only.)

This article provides a sample application's complete solution for 32 bit and 64 bit. All features, described later on, can be marked as:

  • available from version 0.1,
  • available from version 0.2,
  • available from version 0.3,
  • available from version 0.4,
  • available from version 0.5,
  • available from version 0.6,
  • available from version 0.7,
  • available from version 0.8,
  • available from version 0.9,
  • available from version 1.0.
  • disabled with version 0.2,
  • disabled with version 0.3,
  • disabled with version 0.4,
  • disabled with version 0.5,
  • disabled with version 0.6,
  • disabled with version 0.7,
  • disabled with version 0.8,
  • disabled with version 0.9 and

First - the main disadvantages:

  • The complete GUI application framework is crafted - there is no big developer comunity in the background.
  • The framework uses the capabilities of C# and X11 (via P/Invoke) only - currently no additional libraries like Xt, Xpm, Xft, Cairo, Pango, ... or X11 extensions like XRENDER (for alpha blending and color gradient support), DOUBLE_BUFFER (for flicker-free drawing of expensive content), DAMAGE (for a better expose handling), XInputExtension (for gesture support), ... are involved. That's why drawing capabilities are limited (no native support for color gradients, no font antialiasing) and user interaction capabilities are limited (not flicker-free, no gestures).
  • It is platform dependend - it runs on X11 only.
  • There is no GUI designer.
  • Only 24 bit color model (16 777 216 colors, 32 bits per pixel) is fully supported right from . The 16 bit color model (65536 colors, 16 bits per pixel) is supported since , but no color optimization or smoothing is provided for the reduced color space.

Second - the main advantages:

  • The framework is small, very well inline-documented and can be adopted/extended to a specific need easyly. In addition a full featured API reference HTML documentation is part of the Xrw project.
  • The framework comes with complete source code and is wirtten entirely in C# - all parts of the framework can be maintained from a single C# solution or project.
  • The framework has no dependencies except X11 and it has zero overhead. It is very lightweight and fast.
  • The framework starts to provide widgets, that are not available for Athena widget set, and some of them even not for Motif or GTK. The first of them is a basic ribbon, followed by a property grid.
  • The framework core got a XAML wrapper (introduced with ) and has been optimized to support the MVVM pattern. This enables platform independend development (Windows and UNIX/LINUX), even if the framework is limited to X11 only, and is currently unique among the GUI frameworks for UNIX/LINUX.

This enumeration provokes questions:

  • Why not utilize GTK#? GTK#'s current stable implementation is still based on GTK's version 2.12. There is an unstable GTK# implementation based on GTK's version 2.24 and a GTK# implementation based on GTK's version 3.xx is in development (GTK# version 2.99) for more than two years without substantial progress now. All in all - GTK# is very stable (several huge applications rely in it, e.g. MonoDevelop), integrated into GTK's home page and well documented (via Mono's API documentation) but it is more or less outdated, the procedural roots of GTK's 'C' API shine through the C# wrapper and -very important- it is not a smooth .NET integration (e. g. Data Binding for models is not available). IMO it is the very best alternative to the Xrw project.
  • Why not utilize Qt#/Qyoto/QtSharp? The history and the current state of Qt's C# binding libraries are very confusing. None of the them has an own home page or is integrated into Qt's home page. The new Qt version 5.x API is not supported and they provide no smooth .NET integration (e. g. signal/slot mechanism is separate from .NET events).
  • Why not utilize Mono's implementation of System.Windows.Forms? Even if there are tons of documentation and samples, the development is announced to be complete, full compatibility with .NET is neither achieved nor possible and the technology is outdated.
  • Why not use Moonlight? It is abandoned and it's archetyp Silverlight is discontinued as well.
  • Why another GUI application framework (and not wxWidgets, FLTK, FOX or something like that)? None of the so far mentioned GUI frameworks is MVVM/XAML ready. It is fun to deal with the callenges such a complex initiative contains. The individuality that applications can reach and the flexibility to design an uncommon GUI for a specific application is unbeatable. The only, currently very promising alternative seems to be the the very young MonoGame. I'll watch it's progress and capabilities.

There are no plans to run the framework on other platforms than X11 - a MVVM/XAML support with desired syntax and functionality as near to the Microsoft® original as reasonable is the better way to achieve platform independence. It might be that any future version is based on a more modern API than X11, e.g. CLUTTER.

Currently i plan to close this project with version 1.0 and to evolve an "Next Level" Roma Widget Set, that introduces some new aspects: 1: Drawing shall enable gradient colors and antialiasing text (either via the Cairo library or via the X11 extension like XRENDER), if necessary in cooperation with Pango or Xft library. 2: XAML/MVVM support for GUI definition shall reach a level that enables a developer to develop for X11 and Windows in parallel, using as much portable code (XAML and C#) as possible.

Background

(1) The Roma Widget Set has been designed to support programming of simple GUIs for small tools. It's focus is the efficiency in application, not the completeness of rarely used features.

What are the alternatives?

All other native X11 or platform independent widget sets or GUI application frameworks - the Athena widget set and its descendants (e. g. neXtaw, XawM, Xaw-Xpm, XawPlus or Xaw3d), the Motif widget set (Open Motif or LessTif), GTK (GTK+ already has the C# wrapper GTK#), KDE (Qt already has C# wrappers Qt# (outdated), Qyoto (outdated) and QtSharp), wxWidgets, FLTK and FOX - are developed in C/C++ and are very hard to adopt/extend to a specific purpose within a C# project.

The Roma Widget Set GUI application framework shall support all adoptions/extentions through native C# code, integrate the .NET framework components and feel native .NET.

This is not a new idea/requirement. The DotGNU Portable.NET project - gone with the shutdown of it's parent project DotGNU in December 2012 - contains the pnetlib, which was under active development until March 2007 by Rhys Weatherley, at that time director of Southern Storm Software, Pty Ltd, and others. The last version (0.8.0) of the pnetlib project contains Xsharp and System.Windows.Forms among other things. While Xsharp implements a basic framework to program X11 from C# (and might be worth to take a look at it), System.Windows.Forms is a re-implementation of Microsoft's not ECMA standardized namespace and has always been subject of discussions and warnings about whether Microsoft is probably planning to destroy such C# implementations through patent suits.

(2) The Roma Widget Set framework is not intended to re-implement (be API compatible to) any known GUI framework. But, starting with , the Roma Widget Set framework got a XAML wrapper providing a WPF/MVVM pattern compatible XAML layer and can now (as an alternative to it's native C# API) be accessed via XAML with desired syntax and functionality as near to the Microsoft® original as reasonable.

This introduced a new design goal: To support programming of cross-platform GUIs. It's focus is the virtually complete Microsoft® compatibility, not the completeness of rarely used features.

Are there alternatives?

All other widget sets or GUI application frameworks - Athena widget, Motif, GTK (GTK#), KDE ( Qt#/Qyoto/QtSharp), wxWidgets (wx.NET) FOX, FLTK, and V- stick to their traditional API and do not support the MVVM pattern and XAML.

Using the code

The sample application was written with Mono Develop 2.4.1 for Mono 2.8.1 (built 2010-11-17) on OPEN SUSE 11.3 Linux 32 bit EN and GNOME desktop. Neither the port to any older nor to any newer version should be a problem. The sample application's solution consists of three projects (the complete sources are provided for download):

  • X11Wrapper defines the function prototypes, structures and types for Xlib/X11 calls to the libX11.so
  • Xrw contains the Roma Witget Set (Xrw) and (introduced with ) the HTML documentation of the API
  • X11 contains the sample application

The sample application is also tested with Mono Develop 3.0.6 for Mono 3.0.4 (built 2013-02-02) on OPEN SUSE 12.3 Linux 64 bit DE and GNOME desktop, IceWM, TWM und Xfce.

The only difference between the 32 bit and the 64 bit solution is the definition of some X11 specific data types, as already described in the first article of this series.

Advice: To use the class library documentation shortcut (F1) from MonoDevelop, the "mono-tools" package have to be installed.

Main application window

The image shows the sample application with XrwTheme.GeneralStyle.WinClassic.

The image shows the sample application with XrwTheme.GeneralStyle.Gtk2Clearlooks.

The sample application demonstates

  • a ribbon widget in sector A with three ribbons, that demonstrate
    • a ribbon application menu,
    • three ribbon tabs (Dialog test, Radio & toggle test, Split test),
    • several ribbon panels (Large buttons, Medium buttons, ...),
    • several ribbon buttons (File dialog, ...),
    • several ribbon split buttons (Font, Color, ...),
    • several ribbon control groups on the second ribbon tab (horizontal text align, vertical text align, weight and slant, superscript and subscript),
    • several ribbon control group radio nodes and ribbon control group toggle nodes on the second ribbon tab (left, center, justify, right, ...),
  • a top tabbed notebook widget in sector B with two tabs,
    • the first tab contains a horizontally paned widget with a tree widget to the left and a property grid to the right,
    • the second tab contains a horizontally paned widget with a list widget to the left and a property grid to the right,
  • a bottom tabbed notebook widget in sector C with four tabs,
    • the first tab contains a menu widget and a command widget,
    • the second tab contains three toggle button widgets,
    • the third tab contains three radio button widgets,
    • the fourth tab contains a horizontal spin button, a combo box and a link button,
    • the fifth tab contains a text widget,
  • a label widget in sector D,
  • the call of all available standard dialogs like
    • X11 font specification based bitmap and vector font dialog introduced with ,
    • GTK/Windows like font dialog introduced with ,
    • file dialog introduved with ,
    • color selector dialogs with 8x2 and 2x8 selectable colors introduced with ,
    • color chooser dialog introduced with ,
    • message box introduced with (including markup, introduced with ),
  • the call of individual dialogs to demonstrate
    • several dock panel based layouts introduced with ,
    • a simple drawing on canvas introduced with ,
    • a simple drawing on image introduced with and
    • a uniform grid based layout introduced with .

Widget set standard dialogs

The sample application provides the ribbon application menu items "Open" and "Save as" within the ribbon's application menu to test the "File selection" dialog XrwFileSelectionDialog.

The sample application provides the ribbon split buttons "Font | X11 dialog" and "Font | GTK/Windows dialog" to test the "Font selection" dialogs XrwBitmapAndVectorFontSelectionDialog and XrwFontSelectionDialog.

The sample application provides the ribbon split buttons "Color | Selector 2x8 dialog", "Color | Selector 8x2 dialog" and "Color | Chooser dialog" to test the "Color selection" dialogs XrwColorSelectionDialog and XrwColorChooseDialog.

The sample application provides the ribbon split buttons "Info | About dialog" and "Info | Help dialog" to test the "Message box" dialog XrwMessageBox.

Sample application individual dialogs

The sample application provides the ribbon split buttons "Layout | Dock top first bottom second", "Layout | Dock top first left secondHelp dialog",  "Layout | Dock left first right second" and "Layout | Dock left first top second" to show dialogs, that demonstrate the capabilities of the XrwDockPanel.

The sample application provides the ribbon split button "Layout | Simple drawing on canvas" to show a dialog, that demonstrate the capabilities of the XrwCanvas in combination with XrwArcFigure, XrwEllipseFigure, XrwLineFigure, XrwPathFigureCollection and XrwRectangleFigure.

The sample application provides the ribbon split button "Layout | Simple drawing on image" to show a dialog, that demonstrate the capabilities of the XrwImage.

The sample application provides the ribbon split button "Layout | Uniform grid" to show a dialog, that demonstrate the capabilities of the XrwUniformGrid.

Idea backlog

IdeaAppearedSolved
Add ComboBox widget with SpinMenu.version 0.1version 0.2
Add SpinButton widget.version 0.1version 0.2
Add support for 16 bit color model.version 0.1version 0.2
Add a font selection dialog similar to GTK/Windows (suitable to use with I18N text output, using font set instead font)version 0.1, refreshed version 0.5version 0.7
Add missing static Xrw<align>Notebook factory method NewBottomTabedNotebook.version 0.1version 0.3
Change from 8 bit string to 16 bit string drawing to enable more than only ASCII characters (I18N text output)version 0.2version 0.6
Add a simple initial color dialog.version 0.2version 0.5
Add a basic ribbon widget.version 0.2version 0.3
Add missing static Xrw<align>Notebook factory methods NewLeftTabedNotebook and NewRightTabedNotebook.version 0.3 
Add a paned widget.version 0.3version 0.4
Add a grid form widget.version 0.3version 0.4
Add a basic property grid widget.version 0.3version 0.4
Add tooltip to widgets.version 0.3version 0.9
Add enhanced tooltip to ribbon.version 0.3 
Add a labeled frame widget.version 0.3 
Add an input dialog.version 0.4 
Add alternative list views (Small icons, Large icons, List and Details).version 0.4version 0.5
Add a more advanced color dialog.version 0.5version 0.6
Add convenient wrapper XrwOpenFileDialog and XrwSaveFileDialog around XrwFileSelectionDialog.version 0.5 
Add cut/copy/paste to XrwText.version 0.5version 0.6
Support simple GUI definition via XAML to proof the concept.version 0.6version 0.7
Add multiline editor.version 0.7 
Support sub-menus on menu-items.version 0.8 
Add basic printing capability.version 0.8 
Change widget/gadget coordinates from Int32 based to Double based valuesversion 0.9 
Align drawing closer to Cairo.Contextversion 0.9 

Fixed errors

Fixed with :

  1. Double painting of XrwShell's children fixed.
  2. Missing background color initialization for widgets derived from XrwCore added.
  3. Fixed X11Graphic constructor arguments individualColormap and graphicDepth from application.IndividualColormap and application.ColorDepth to IntPtr.Zero and defaultColordepth (to use the root window's color map and depth, not the application's color map and depth), and fixed X11Graphic.CreateIndependentGraphicPixmap() / X11Graphic.CreateIndependentMaskPixmap() method argument window from application.Window to defaultRootWindow in XrwApplicationFramework.SetWmShellIcon(). Both was necessary to support 16 bit color model.
  4. Fixed X11lib.XCreateGC() method argument x11drawable from window to pixmap in <code>X11Graphic.CreateIndependentGraphicPixmap(). It was necessary to support 16 bit color model.

Fixed with :

  1. Fixed exception during application closing, if any XrwOverrideShell is currently poped up, now the collection handling for parent's child list is correct. (Disposal of an XrwOverrideShell implies removal from it's parent child list - this alters the child list collection.)
  2. Fixed X11Graphic.StockIcon.Information16 size from 18x18 to 16x16.
  3. Fixed XrwVisibleRectObj.ExpandToAvailableHeight, XrwVisibleRectObj.ExpandToAvailableWidth, XrwVisibleRectObj.ExpandToMaxSiblingHeight and XrwVisibleRectObj.ExpandToMaxSiblingWidth on any fixed dimension, now setting true is suppressed, if a fixed height/width is assigned.
  4. Fixed XrwVisibleRectObj.SetFixedHeight and XrwVisibleRectObj.SetFixedWidth on any dimension expansion is set, now XrwVisibleRectObj.ExpandToAvailableHeight and XrwVisibleRectObj.ExpandToAvailableWidth or XrwVisibleRectObj.ExpandToMaxSiblingHeight and XrwVisibleRectObj.ExpandToMaxSiblingWidth are reset to false if formerly true.
  5. Fixed XrwRectObj.GeometryManagerAccess.SetAssignedGeometry() for a fixed height assignment, now XrwVisibleRectObj.FixedSize.Height is applied correctly - only if XrwVisibleRectObj.IsFixedHeight is true.

Fixed with :

  1. Fixed XrwTree's calculation of PreferredSize().
  2. Fixed drawing error in XrwVisibleRectObj.DrawFrame(). One pixel frames now don't overrun right/bottom coordinate.
  3. Fixed X11Graphic.StockIcon.Question16 and X11Graphic.StockIcon.Error16 size from 18x18 to 16x16.
  4. Fixed XrwFileSelectionDialog height adaption. Width adaption has already been correct. Now a height change of the dialog leads to height change of the places and files viewports.
  5. Fixed XrwBitmapAndVectorFontSelectionDialog height adaption. Width adaption has already been correct. Now a height change of the dialog leads to height change of the font style, font resolution and font size viewports.
  6. Fixed scroll bar update for a XrwViewport containing a XrwTree on tree node collapse or expand. Now the XrwTree calls the registered SizePreferenceChanged delegates.
  7. Fixed positioning of a manager widget inside a manager gadget. E. g. a XrwPaned (horizontal) widged inside a XrwBox gadget (vertical) is positioned correct. Now the GeometryManagerAccess.SetAssignedGeometry() method resets not only a widget's assigned position to 0,0, but also the position offset of it's children. This is because a widget has it's own X11 window and all positions must be measured relativle to the window.
  8. Fixed crash if application has a working folder different to the installation folder. Now the X11Graphic loader also looks up the installation folder for a graphic file not found in the working folder.

Fixed with :

  1. Fixed XrwViewport's calculation of CalculateChildLayout(). For children, whose size needs one scroll bar only, and the display of this scroll bar decreases the available size in a manner that requires a second scroll bar, now the second scroll bar will be displayed.
  2. Fixed redrawing problem of GUI parts, obscured (covered) by XrwSimpleMenu (or it's derivatives XrwSpinMenu and XrwDropDownCellEditorShell) and uncovered after menu popdown, if any selected XrwSme invokes a dialog. (This is because a dialog (XrwDialogShell/XrwTransientShell/XrwWmShell) implements an internal event processing loop.) Now the sme's OnButtonReleased delegate will not be called directly by the sme's ButtonRelease event Instead a CustomMessage event will be generated, that goes to the end of the message queue. The CustomMessage event only calls the sme's OnButtonReleased delegate, if it is his turn (in the message queue). This procedure guarantees the processing of any menu's Unmap event before the sme's ButtonRelease event.

Fixed with:

  1. Fixed XrwComboBox's wrong display of selected value. After a selection change, the old value is displayed instead of the new one. This problem is caused by the fix no. 2. The CustomMessage, generated by a sme's ButtonRelease event, has not been processed correctly because the XrwSpinMenu has been registered twice to the XrwApplicationShell - as child and as associated shell. Now the XrwSpinMenu is registered as associated shell only.
  2. Fixed calculation errors in XrwGridForm's MinimumSize() and PreferredSize(). Now the left/right/top/bottom margins and the child sizes (for columns of dynamic width/rows of dynamic height) are considered.
  3. Fixed pointer motion behavior of XrwScrollBar. Now MotionNotify events outside the thumb (inside up/down buttons or slide area) do not confuse the thumb position calculation.
  4. Fixed undo ([Ctrl] + [z])/redo ([Ctrl] + [y]) begaviour for XrwText. Now an undo command for a multi-character insert removes all inserted characters (not only the first one) and now all redo comands (no matter whether remove or insert of single-character or multi-character) work at the original selection and caret position (not at the current selection and caret position, if they have moved) and restore the correct selection and caret position after operation as well.
  5. Fixed XrwBox and XrwSpinBox's wrong PreferredSize calculation. Now the ExpandToMaxSiblingWidth and ExpandToMaxSiblingHeight flags of children are considered.
  6. Fixed XrwGridFrame's wrong CalculateGridGeometry calculation. Now the BorderWidth is considered.
  7. Fixed XrwGridFrame's wrong CalculateMinimumSize and CalculatePreferredSize calculation. Now the Margin is no longer considered for FixedDimension columns/rows.
  8. Fixed the sub-classes of XrwLabelBase (affected are XrwComboBox, XrwLabel, XrwLabelAndColor, XrwTextSpinButton, XrwToggle), and the XrwText's wrong PreferredSize calculation. Now the FixedSize is considered.
  9. Fixed XrwMenuButton's wrong menu registration. Now the registration of the built-in menu works for XrwMenuButtons that are child of a XrwDialogShell as well.
  10. Fixed XrwOverrideShell's wrong registration/deregistration to/from the parent XrwWmShell during Realize and Unrealize. Now the registration/deregistration works for XrwOverrideShells that are child of a XrwDialogShell as well.
  11. Fixed calculation error for XrwViewport's HScrol.ThumbPageWidth and VScroll.ThumbPageWidth property during CalculateChildLayout. Now the ThumbPageWidth is calculated as part, not as multiple, of the viewport's clip size.
  12. Fixed redrawing problem of GUI parts, obscured (covered) by XrwRibbonAppMenu and uncovered after menu popdown, if any selected XrwSme invokes a dialog. (see "Fixed with " No. 2).

Fixed with :

  1. Fixed XrwList's and XrwTree's wrong display after editing an enumerable value with the default editor based on XrwDropDownCellEditorShell. After the selection of a new value, the old value has been still displayed instead of the new one. Now redrawing is invoked explicitly.
  2. Fixed error in XrwComboBox's XrwSpinMenu spin fore/spin back functionality. The menu pops down after any spin button click. This error has been undetected since , when XrwSimpleMenu introduced HandleParentRoutedClientMessage() (see "Fixed with " No. 2).

Fixed with :

  1. Fixed infinite loop in XrwVisibleRectObj's DrawTextLineAutoLineBreak() method, if widget/gadget width is smaller than the width of one single character.
  2. Fixed redrawing problem in XrwWmShell and derivatives. In case of ALL children of the shell are gadgets, configure events with new size < old size the configure events aren't followed by an expose event generated by the X11 server. In this case an expose event must be generated manually.
  3. Fixed drawing of insensitive widget's/gadget's text for XrwLabel and derivatives. Since introduced StyleText, every text style sets the foreground color. Now insensitive widget's/gadget's text keeps the foreground color unchanged for all text styles.
  4. Fixed incomplete application termination, if application window is closed while any dialog is open. Dialogs (transient shells) take over the (infinite) message loop processing from the application shell. Closing the application window calls DefaultClose() for every associated transient shell now. A transient shell must override the DefaultClose() method to stop it's (infinite) message loop processing.
  5. Fixed structure layout for X11lib.XColor. The color values for red, green and blue are of type X11.TUshort (0-65535), not X11.TUchar (0-255).
  6. Fixed the high CPU load on idle message queue (about 50% for two cores). The evaluation of suspended ConfigureEvent did return immediately from XrwApplicationShell.DoEvent() message queue evaluation instead to return only after any suspended ConfigureEvent has been found and processed. CPU load is below 1% now (for two cores).
  7. Fixed the display errors for XrwSpinBox navigation. For any XrwSpinBox, that is part of a transient shell, the navigation has caused display errors on the application shell's top left corner, if the appearance of any spin button is switched off (even temporary). All spin buttons, that are removed from XrwSpinBox, have been re-parented to ApplicationShell and produced the display errors on the application shell after their Unrealize() call. Now spin buttons, that are removed, are re-parented to WmShell and avoid display errors on the application shell after their Unrealize() call.
  8. Override shell based popups (XrwSimpleMenu, XrwRibbonAppMenu, XrwToolTipShell, XrwBaseCellEditorShell) and derivatives (XrwSpinMenu, XrwDropDownCellEditorShell, XrwGenericCellEditorShell) do not acquire the focus after popup via  RequestInputFocus() anymore. As a result override shell based popups do not trigger FocusOut (for application or dialog shell, they belong to) and FocusIn (for themselfs) events any longer. Therefore the application or dialog shell, the popups belong to, do not loose the active window frame - and do not confuse anymore by appearing inactive. Instead the key event processing in XrwApplicationShell preferres registered override shells.
  9. Removal of the INotifyPropertyChange implementation from (almost) all controls, since the Microsoft® original doesn't implement INotifyPropertyChange for controls.

Fixed with :

  1. Fixed calculation of MinimumSize() and PreferredSize() for XrwDockPanel. Fallback for children without DockStyle patched and height impact for children with DockStyle.Fill noticed.
  2. Fixed wrong calls to X11lib.XSync(). Many callts to X11lib.XSync() have been performed with parameter discard set to (X11.TBoolean)1. This is wrong because it discards all events already synchronized to the event queue. The parameter discard set to (X11.TBoolean)1 should be the absolute exception. This may also have an positive impact on ony types of popups, XrwOverrideShell derivatives as well as XrwTransientShell derivatives.
  3. The X11.TBoolean has been defined to map sbyte, but X11/Xlib.h defines Bool to be int. This has been fixed and X11.TBoolean is defined to map int now.
  4. Fixed crash on close a modal dialog box and immediate open another modal dialog box. Sometimes the input focus can't be set to the newly opened modal dialog box, because the XrwDialogShell is not yet maped by the X server while the X client requests the input focus for the shell.
  5. The XrwPathFigureCollectionGeometry.Bounds property did take into account only the boundings of the last X11.IPathFigure of multiple figures, this is fixed now.
  6. The System.Windows.Media.PathGeometry.TryParsePathData() method did not correctly parse successive path segments of the same type (move to, line to, curve, ...), that do not repeat the segment code (M, L, C, ...). Not repeating the segment code is permitted by definition and will be treated correct now.
  7. The XrwGridForm.CalculateChildLayout() method didn't catch rows/columns, that are out of range. This is fixed now and rows/columns, that are out of range, fall back to meanigful values.
  8. The XrwRectObj.KeyPress and XrwRectObj.KeyRelease events have been sent twice for XrwApplicationShell because XrwApplicationShells have peen processed once during the widget hierarchy traversing and once as a fallback, if no event delegate has flagged the event to stop further processing. The fallback is suppressed now, if the event has already been sent to the XrwApplicationShell during the widget hierarchy traversing.
  9. Since removed the INotifyPropertyChange implementation from (almost) all controls, an alternative implementation is provided and DependencyProperty bindings work again.
  10. Some minor bugs are fixed in X11.Text.TextStyle class constructor's markup parser. Now <s> (strikeout) and <u> (underline) work correctly and unnecessary (no change to previous style) X11.Text.Style creations do not appen anymore.
  11. The XrwFileSelectionDialog did show "Default" as column names for places list and files list. This is fixed to "Folder names" and "File names" now.

Interim result : Verion 1.00 of Xrw widget/gadget interface is very reliable. All known bugs are fixed.

But: Some capabilities are still missing. Especially printing support is not realized and drawing capabilities have reached the limit of the X11 API. The XAML/MVVM approach is much more efficient to use for GUI creation and much more fun.

This is why i decided to focus on XrwXAML for the next view versions and to provide Cairo drawing besides X11 drawing. The alternative to Cairo would be OpenGL/Mesa, but Cairo provides PDF (--> printing) and SVG support off the cuff.

Improvements

Improved with :

  1. Generic drawing method to draw arrows for scroll bars, forth and back buttons XrwVisibleRectObj.DrawArrow().
  2. New method signature for X11lib.XAllocWMHints(), now returning the unmanaged memory handle of WMHints and the marshaled strurture as reference argument. This enables to call X11lib.Free() with the unmanaged memory handle of WMHints.

Improvements with :

  1. Removal of needles X11 events from the event queue (events for an X11 window, that just has been unrealized) on XrwApplicationShell.RemoveCild() and XrwCore.DisposeByParent().
  2. Additional themes XrwTheme.GeneralStyle.WinLuna, XrwTheme.GeneralStyle.WinRoyale and XrwTheme.GeneralStyle.WinMidori.
  3. Extensions to the XrwNotebook to support bottom tabs.
  4. A ribbon widget, that supports application menu button/application menu, tabs, panels, buttons, split buttons and control groups as well as theming.

Improvements with :

  1. New optional column header display for XrwViewport, if Child implements XrwIGridView interface (like XrwList and XrwTree do).
  2. Ability to display multiple columns for XrwList and, if embedded in a XrwViewport, optional column header.
  3. Ability to display multiple columns for XrwTree and, if embedded in a XrwViewport, optional column header.
  4. Reduced needles redrawing of XrwComposite's children by calling InvokeRedraw() for gadgets (children without own window) only (widgets receive the expose event from the WM anyway).
  5. Reduced flickering during the application window's resizing process (see "Specific aspects of event processing" for details).
  6. Multiple root nodes for XrwTree.
  7. Added a paned manager widget XrwPaned, that supports child resizing without any parent size change, and a grid form manager gadget XrwGridForm, that supports column/row based child layout (including column/row span capabilities and fixed or dynamic column/row dimensions).
  8. Convenience functions to set user defined font specification and explicit assignment of the current DefaultFontName to every newly created widget's GC (graphics context).
  9. XrwList and XrwTree show boolean values as toggle images now, instead of as text.
  10. Added editability for XrwTree (required for a simple property grid widget).
  11. Added a simple property grid widget XrwPropertyGrid, using reflection to determine the properties to display and edit. Properties of type string, bool, ThreeState and enum are editable (utilize the provided standard editors).

Improvements with :

  1. Replacement of the proprietrary data types TSize, TPoint and TRectangle by System.Drawing.Size, System.Drawing.Point, System.Drawing.Rectangle and some extension methods.
  2. XrwList now supports the view types ViewType.List, ViewType.SmallIcon and ViewType.LargeIcon in addition to ViewType.Details.
  3. XrwList now supports multi selection.
  4. Reduced flickering on mouse move inside XrwList and XrwTree. Mouse move handler calls RedrawContent() directly now (instead of calling InvokeRedraw(), that is always deleting the background first - the reason for flickering - and calling RedrawContent() afterwards).
  5. Added column resizig for XrwList and XrwTree.
  6. Added clipping to text output, important for XrwList and XrwTree column resizing below column's preferred size.
  7. Added in-place editing for XrwList and XrwTree, build-in editors provided for single line text, boolean values, three-state values and enumerations.
  8. Introduction of the X11Surface class to centralize all rendering associated properties for XrwVisibleRect and derived widgets and to prepare for easy switch to "Cairo" rendering in later versions of the widget set (see Programming Cairo text output beyond the 'toy' text API (C#/X11) - a prrof of concept meanwhile).
  9. Added column reordering for XrwList and XrwTree.
  10. Introduction and exclusive usage of new static log class SimpleLog, implemented through X11wrapper solution, instead of heterogeneous Console.WriteLine() calls.
  11. The XrwGridForm now overrides the MinimumSize now PreferredSize methods of  XrwComposite with more suitable size calculations.

Improvements with :

  1. Now international text output (I18N) is supported on X servers, where the C runtime provides locale setting (libc.setlocale) and is configured to a locale other than "C" and "POSIX" as well as the X server supports internationalization (X11ibc.XSupportsLocale). (This is realized using XCreateFontSet and XwcDrawString instead XLoadFont and XDrawString.) Otherwise text output is improved from 256 character set (ASCII) to 65535 character set (ISO) using XDrawString16 instead XDrawString.
  2. Now XrwScrollBar supports auto-repeat not only for up/down buttons, but for slide area too. Auto-repeat on up/down buttons invoke a step move. Auto-repeat on slide area invoke a page move.
  3. Now XrwScrollBar's factory methods support a custom ThumbMaxValue in the range of 100 ... INITIAL_THUMB_MAX_VALUE (1.000.000). This provides adopted value ranges - e.g. for red/green/blue color components with a value range of 0 ... 255 each.
  4. Now XrwText supports (optional) RegEx validation and invokes ValueChanged event on valid value changes. It also supports cut ([Ctrl] + [x]), copy ([Ctrl] + [c]) and paste ([Ctrl] + [v]) operations of simple STRING data via clipboard.
  5. The XrwApplicationShell now supports the clipboard events SelectionNotify (to determine whether the data provider supports STRING data and to incorporate STRING data into a XrwText widget) and SelectionRequest (to provide the data requestor with the supported data types and to provide STRING data if requested).
  6. The XrwFileSelectionDialog now supports a file extension filter. It's geometry management is based on a XrwGridForm now instead of nested XrwBoxes. The width of the places list and files list can be adjusted by a XrwPaned now. And the scrollbars of the places list and the files list are updated after any place or filter change.
  7. For cascaded transient shells (e. g. XrwFileSelectionDialog invokes a XrwMessageBox) it hasn't been guaranteed that the last invoked shell is displayed on top and is activated. Now every invocation of a transient shell calls XrwApplicationShell.RequestWindowActivation.

Improvements with :

  1. Now XrwLabelBase and it's derived classes support the TextOverflowBehaviours Clip, Ellipsis, AutolinebreakClip and AutolinebreakEllipsis.
  2. Now XrwRibbonTabs, that have insufficient width to display all XrwRibbonButtons and/or XrwRibbonSplitButtons within all  XrwRibbonPanels using their PreferredSizeMode, can adopt it's size by changing the XrwRibbonButton's and/or XrwRibbonSplitButtons CurrentSizeMode. See XrwRibbonButton and/or XrwRibbonSplitButton description for details.
  3. Now the XrwRibbonButton and XrwRibbonSplitButton, displayed with CurrentSizeMode == RibbonPanelSizePolicy.Large can be displayed with slim width (44px instead 64px), if the label text fits the slim width.
  4. The XrwFileSelectionDialog, XrwBitmapAndVectorFontSelectionDialog, XrwMessageBox, XrwColorSelectionDialog and XrwColorChoseDialog now support closing with [Enter] or [Return] key (equal to OK button) and [Excape] key (equal to Cancel button).
  5. The XrwList and XrwTree now support insensitive items/nodes, that can't be selected and are displayed with InsensitiveTextColor.
  6. Added slider XrwScale, that can adjust a float value.
  7. Now horizontal oriented XrwScrollbars, if thumb is dragged, continue dragging even if the mouse pointer leaves the thumb to-above or to-below direction, but not to the right or left. And vertical oriented XrwScrollbars, if thumb is dragged, continue dragging even if the mouse pointer leaves the thumb to the right or left, but not to-above or to-below direction. This behaviour is closer to the GTK and Windows scrollbar behaviour. Furthermode this behaviour is consistent to the behaviour of column resizig of XrwList and XrwTree and dragging behaviour of XrwScale.
  8. Indroduction of basic XAML (see Writing a XAML dialog application for X11Writing a XAML ribbon application for X11 and Writing a XAML application for X11 with massive data binding and zero code).

Improvements with :

  1. Added XrwFrame, that arranges just one single child.
  2. Introduction of TStyleChar data type and StyleText class to support text styling. TStyleChar supports single font and XChar2b text output via XDrawString16() as well as fontset and TWchar text output via XwcDrawString(). StyleText class replaces Multiline and Line classes.
    ==> Added markup, widely comparable with GTK's Pango Markup Language, to XrwLabelBase and it's derived classes like XrwToggle, XrwRadio, XrwComboBox, XrwTextSpinButton and XrwLabelAndColor.
  3. Introduction of key gesture binding, that enables hot keys and shortcuts, e.g. for menus.
  4. Some more basic XAML (Writing a XAML calculator application for X11).
  5. Introduction of TColor data type to support alpha blending in future. TColor supports plain X11 TPixel API as well as RGBA colors.
    ==> All color properties have been changed from TPixel data type to TColor data type.
  6. Key gesture binding to commands.

Improvements with :

  1. Added XrwDockPanel, that arranges children into up to five regions - top, bottom, left or right of the dock panel or filling the remaining space.
  2. Added XrwUniformGrid, that arranges children into rows and columns - either set or calculated dynamically based on the children's preferred size and the availabe size of the grid.
  3. Added XrwCanvas, that manages figures like XrwArcFigureXrwEllipseFigureXrwLineFigure, XrwRectangleFigure and XrwPathFigureCollection to provide interactive and manipulatable vector graphics.
  4. Added interface X11IPicture and class X11Image in addition to X11Graphic. The X11IPicture abstracts the classes X11Image and X11Graphic and is used for most of the API from now on. While the existing X11Graphic class provides a 'static' bitmap image (that doesn't change during runtime) and provides easy access to predefined icons, the new X11Image class provides a 'volatile' bitmap image (that can change during runtime) through encapsulation of an XImage structure.
  5. Support for the two new XrwLabel properties LeftBitmapInsensitive and RightBitmapInsensitive in addition to LeftBitmap and RightBitmap to display a different set of images on sensitivity and insensitivity.
  6. Added a very simple implementation XrwClientMessageBasedTimerManager for time scheduling, that is based on repeating X11 client messages within the message loop. The XrwApplicationShell's message loop is responsible as well for invocation as for evaluation of WM_CLIENT_SHIFT_TIMER messages.
  7. Added tool tip to all widgets and most of the gadgets. The delayed display is realized via the XrwClientMessageBasedTimerManager.

Improvements with :

  1. Added Margin property to XrwRectObj. The margin is the space between this widget/gadget and other neighboring widgets/gadgets of a user interface.
  2. Finished implementation of X11LinearGradientBrushInfo class (that is also the basis for XAML LinearGradientBrush class). Linear gradients have drawn the median color only so far. They are supported now by XrwFigure and XAML Shape derived classes.
  3. Implementation of X11RadialGradientBrushInfo class (that is also the basis for XAML RadialGradientBrush class). Radial gradients have drawn nothing so far. They are supported now by XrwFigure and XAML Shape derived classes.
  4. Almost all XrwVisibleRectObj derived widgets/gadgets draw their background as a simulated linear (vertical) gradient that is based on a set of three colors, which have been accessible via *ColorDark, *ColorLight and *ColorMedium properties (like BackgroundColorDarkBackgroundColorLight and BackgroundColorMedium). All sets of such three colors properties, *ColorDark, *ColorLight and *ColorMedium, have been replaced by a single *Brush property (like BackgroundBrush). The *Brush property accepts X11LinearGradientBrushInfo instances, that provide a fully backward compatible look & feel, if powered by three color stops containing the primary *ColorDark, *ColorLight and *ColorMedium values. The XrwVisibleRectObj provides a bunch of predefined X11LinearGradientBrushInfo instances to simplify utilization of the new *Brush property, eg. InteractiveBackgroundGradientBrush, InteractiveFocusedBackgroundGradientBrush, RibbonBackgroundGradientBrush, ... This change has been made to prepare the API for new background drawing capabilities (linear gradient brushes with different direction or number of color stops, radial gradient brushes, image brushes, ...).
  5. The XrwRectObj.KeyPressChar event is sent now even if the lookup string is empty. To handle these cases, the XKeySym will be passed with the event now. And the XrwRectObj.KeyReleaseChar event has been added.
  6. Basic implementation of XAML Control templating. Now the Control.Template property is evaluated during MeasureCore(). The Button class has a default template (see reference).
  7. Basic Implementation of XAML FrameworkElement styling. Now the FrameworkElement.Stype property (Setter, Trigger and ControlTemplate) takes affect.
  8. The XrwDockPanel uses DockStyle.Left as default dock and considers the LastChildFill property now.
  9. The XrwScrollbar auto-repeat (on constantly pressed left/right or up/down button) triggered expose events, but they didn't work reliable if XrwScrollbar is placed in a dialog (XrwTransientShell). Since the auto-repeat implementation limits the processing speed of the application's event loop, there have often been two dispose events for one widget in the event queue and the event compression of the application's event loop postponed the expose event processing. This is fixed now and a new expose event is triggered only if the event queue doesn't already contain an expose event for the widget.
  10. The X11FontService class PrepareFont() method fuzzy logic to determine the best matching font (if no font matches 100% the font specification) has 6 steps now instead of three.
  11. A widget, that pops up a new WmShell (e.g. a dialog like XrwFileSelectionDialog) has been displayed focused until the focus has been changed by user interaction (e. g. mouse move) - even if the widget's parent WmShell (e. g. XrwApplicationShell) lost the focus for the benefit of the new WmShell. This is fixed now by a reset of the widget's MouseOver and Focused properties to false during Redraw() if widget's parent WmShell has HasFocus property false. To guarantee this reset WmShells, that lose the focus, invoke an additional redrawing to all windowed and windowless children.

Interim result : Verion 1.00 of Xrw widget/gadget interface is very reliable. All known bugs are fixed.

But: Some capabilities are still missing. Especially printing support is not realized and drawing capabilities have reached the limit of the X11 API. The XAML/MVVM approach is much more efficient to use for GUI creation and much more fun.

This is why i decided to focus on XrwXAML for the next view versions and to provide Cairo drawing besides X11 drawing. The alternative to Cairo would be OpenGL/Mesa, but Cairo provides PDF (--> printing) and SVG support off the cuff.

Points of Interest

It was surprising how little effort is required to create a simple widget set with an attractive design.
This work should also animate other programmers to deal with Mono on Linux or Linux-like platforms.

Still working on the completion of Athena widget set compatible widgets.

After the implementation of the biggest part of the Athena widget set compatible widgets, the idea did not let up to go beyond this and to create higher sophisticated widgets, e. g. ribbon and property grid.

The idea to create higher sophisticated widgets goes on with panned and grid form widget.

To unlesh the power of list and tree widgets, features like column resizing and reordering as well as in-place editing have been added.

Realize internationalized text output and custom color choose.

Realize basic XAML support.

Realize a little more advanved XAML support. Introduce markup strings for XrwLabelBase and derivatives.

Even more advanved XAML support focused on controls and shapes. This did require some indepth revision of the XAML interpreter code and trigger some bug fixes and extensions to the widget set.

Even more advanved XAML support focused on shapes and control templating. This did trigger some bug fixes and extensions to the widget set.

History

The first public version of the Roma Widget Set is version from 20. January 2014.
The second public version of the Roma Widget Set is version from 07. March 2014.
The third public version of the Roma Widget Set is version from 01. Aplil 2014.
The fourth public version of the Roma Widget Set is version from 13. May 2014.
The fifth public version of the Roma Widget Set is version from 15. August 2014.
The sixth public version of the Roma Widget Set is version from 5. October 2014.
The seventh public version of the Roma Widget Set is version  from 6. December 2014.
The eighth public version of the Roma Widget Set is version  from 8. March 2015.
The ninth public version of the Roma Widget Set is version  from 9. October 2015.
The tenth public version of the Roma Widget Set is version  from 27. March 2017.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Steffen Ploetz
CEO Ploetz + Zeller GmbH
Germany Germany
I am CEO at Ploetz + Zeller GmbH, Munich Germany (www.p-und-z.com)

Ploetz + Zeller GmbH is a consulting and software services company committed to pro-active and professional governance and optimization of our clients' company processes. Furthermore it offers Symbio (www.symbioworld.com) software, a very powerful and easy to use business process management suite.

My responsibilities range from product ownership of Symbio via responsibility for the architecture of some Symbio software components to implementation of software core parts (e. g. automatic layout).

I started programming 1986 with C64 BASIC and came via Pascal, Turbo Pascal, C, Turbo C, C++ and Java to C#. I like the potential of C++ very much, but now my favorite language is C#.

I believe a lot in free knowledge sharing. I'm author at German Wikipedia and, after 10 years of passive membership, author at CODE PROJECT.

You may also be interested in...

Comments and Discussions

 
QuestionKaspersky gives a warning that x11 contains malware/virus Pin
Member 115023483-Jul-16 0:23
memberMember 115023483-Jul-16 0:23 
AnswerRe: Kaspersky gives a warning that x11 contains malware/virus Pin
Steffen Ploetz3-Jul-16 15:09
professionalSteffen Ploetz3-Jul-16 15:09 
GeneralRe: Kaspersky gives a warning that x11 contains malware/virus Pin
Member 115023484-Jul-16 0:10
memberMember 115023484-Jul-16 0:10 
GeneralRe: Kaspersky gives a warning that x11 contains malware/virus Pin
Steffen Ploetz4-Jul-16 6:43
professionalSteffen Ploetz4-Jul-16 6:43 
Questionseems like a lot of work... Pin
John Torjo21-Oct-15 12:34
professionalJohn Torjo21-Oct-15 12:34 
AnswerRe: seems like a lot of work... Pin
Steffen Ploetz22-Oct-15 2:23
professionalSteffen Ploetz22-Oct-15 2:23 
GeneralRe: seems like a lot of work... Pin
John Torjo22-Oct-15 3:29
professionalJohn Torjo22-Oct-15 3:29 
GeneralRe: seems like a lot of work... Pin
Steffen Ploetz23-Oct-15 4:14
professionalSteffen Ploetz23-Oct-15 4:14 
GeneralRe: seems like a lot of work... Pin
John Torjo23-Oct-15 4:35
professionalJohn Torjo23-Oct-15 4:35 
GeneralRe: seems like a lot of work... Pin
Steffen Ploetz3-Nov-15 18:25
professionalSteffen Ploetz3-Nov-15 18:25 
GeneralRe: seems like a lot of work... Pin
John Torjo4-Nov-15 6:16
professionalJohn Torjo4-Nov-15 6:16 
GeneralRe: seems like a lot of work... Pin
Steffen Ploetz19-Nov-15 2:02
professionalSteffen Ploetz19-Nov-15 2:02 
GeneralRe: seems like a lot of work... Pin
John Torjo19-Nov-15 2:32
professionalJohn Torjo19-Nov-15 2:32 
QuestionVery confused... Pin
Thornik10-Mar-15 7:48
memberThornik10-Mar-15 7:48 
AnswerRe: Very confused... Pin
Steffen Ploetz11-Mar-15 20:27
professionalSteffen Ploetz11-Mar-15 20:27 
GeneralMy vote of 5 Pin
Prasad Khandekar13-Dec-14 19:31
professionalPrasad Khandekar13-Dec-14 19:31 
QuestionGood work, Steffen Pin
Slacker00716-Aug-14 0:26
professionalSlacker00716-Aug-14 0:26 
QuestionHoly sh*t! Pin
bombersa13-May-14 12:01
memberbombersa13-May-14 12:01 
AnswerRe: Holy sh*t! Pin
Steffen Ploetz13-May-14 21:02
professionalSteffen Ploetz13-May-14 21:02 
GeneralOutstanding work Pin
Marc Clifton8-Mar-14 8:51
protectorMarc Clifton8-Mar-14 8:51 
QuestionEpic Pin
Pieter Van Parys7-Mar-14 4:08
memberPieter Van Parys7-Mar-14 4:08 
QuestionSplit into multiple articles. Pin
Malli_S7-Mar-14 3:50
memberMalli_S7-Mar-14 3:50 
AnswerRe: Split into multiple articles. Pin
Steffen Ploetz11-Mar-14 1:24
professionalSteffen Ploetz11-Mar-14 1:24 
SuggestionRe: Split into multiple articles. Pin
Malli_S11-Mar-14 21:19
memberMalli_S11-Mar-14 21:19 
GeneralRe: Split into multiple articles. Pin
Steffen Ploetz12-Mar-14 7:33
professionalSteffen Ploetz12-Mar-14 7:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170624.1 | Last Updated 9 Mar 2015
Article Copyright 2014 by Steffen Ploetz
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid