Introduction
This article shows how to access Xlib/X11 API from C# using Mono Develop. A lot of API calls are ready-to-use defined and tested and some challenges are mastered, e.g., using transparent bitmap display or providing modal dialog.
This article is aimed to verify that programming Xlib/X11 with C# can be easyly achieved (prove of concept). It provides a sample application's complete project for 32 bit and 64 bit.
Background
A lot of little helpful Unix/Linux tools are, still today, coded in C/C++ against Xlib/X11. A migration to C# can simplify the maintenance and offer new opportunities. But developers tend to stick to their inherent development environment. On the one hand a change from the GUI development environment Xlib/X11 to GTK or Qt has many advantages, like rapid prototyping or ready-to-use high-level GUI elements. On the othrer hand it requires to leave old habits, to refuse problem-optimized solutions implemented with low-level API and to loose control over some beloved GUI implementation details. Further more programmers see GUI toolkits come and go in rapid succession, esecially on Windows platforms, and are careful with radical changes.
Those, who are willing to change from an old-fashioned language/IDE like C/GCC to a modern one like C#/Mono Develop, might be afraid of the effort or imponderables of switching the GUI development environment simultaneously. But to change the language and to stick to the approved GUI development environment is possible.
If a programmer don't want to miss the control over the bits and bobs of his GUI, if he relies on the speed and zero overhead costs or if he just has fun or feels comfortable coding against the Xlib/X11, he will find some helpful information to communicate from C# to Xlib/X11 and vice versa provided with this little sample application.
Using the code
The sample application was written with Mono Develop 2.4.1 for Mono 2.8.1 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 two projects (the complete sources are provided for download):
- X11Wrapper defines the function prototypes, structures and types for Xlib/X11 calls to the libX11.so
- X11 contains the sample application based on a very lightweight widget set - called "Roma Widget Set" (Xrw)
C# restrictions
Since C# is a dynamically interpreted language, it doesn't support features a preprocessor adds to the compiled language C/C++. This mainly affects the type declarations like the specific X11 type names, that can not be emulated adequate.
#typedef unsigned long Pixel;
The compromise i found was to define enumerations like
public enum TPixel : int {};
but there are no automatic casts and all cast operation must be specified explicitly, like
TPixel p1 = (TPixel)0;
Currently all casts are part of the application code. One approach to avoid tons of casts could be to wrap the Xlib/X11 API calls and to cast inside the wrapper. But this would work trouble-free only for types, that don't switch the bit size between 32 bit and 64 bit operation system.
32 bit vs. 64 bit
Furthermore C/C++ und C# use the same type specifier for types of different bit size. To avoid type mismatch during development those types, that might confuse through same names for different bit size or different names for same bit size, are also defined as enumeration. One sample is long
, that is always 8 bit in C#, but might be 4 bit in C/C++ for 32 bit and 8 bit in C/C++ for 64 bit.
The only difference between the 32 bit and the 64 bit solution is the definition of some types:
public enum TLong : int {};
public enum TUlong : uint {};
public enum TPixel : uint {};
public enum XtArgVal : int {};
public enum XtVersionType : uint {};
The sample application is also tested with Mono Develop 3.0.6 for
Mono 3.0.4 on OPEN SUSE 12.3 Linux 64 bit DE and GNOME desktop, IceWM,
TWM und Xfce.
The sample application
Most of the generic GUI code is released to several Xrw* classes - to provide a higher aggregation level and to organize re-usable code. The function prototypes of the Xlib/X11 and some necessary structures / enumerations are defined in the X11lib class. The application shows
- a menu bar with 4 buttons, all with callbacks,
- a dropdown menu with two entries,
- the window manager's application decoration with title and icon title,
- an application icon with transparency,
- a status bar and
- a modal message box including icon with transparency.
Original look & feel on GNOME desktop 32 bit and on Xfce 64 bit
The updated application shows
- a notebook with three pages - a menu page, ae radio button test page and a toggle button test page,
- a menu bar with 4 buttons, all with callbacks and three of them with transparent icons,
- a dropdown menu with two entries including transparent icons,
- the window manager's application decoration with title, icon title and transparent icon,
- a status bar with transparent left and right icon and
- a modal message box including transparent icons for label and buttons.
Updated look & feel on GNOME desktop 32 bit and on Xfce 64 bit
Passing data between managed/unmanaged code
Although the memory management via [MarshalAs(UnmanagedType.*)]
is very reliable in Mono, there are some rare cases in which the programmer will (or must) control the behaviour. Some simple rules dealing with the System.Runtime.InteropServices.Marshal
class, we can state, are:
- all types are marshaled (in the meaning of a deep copy of the content) between unmanaged memory and managed memory - there is absolutely no safe way to access unmanaged memory data from managed code
System.IntPtr
type wraps the unmanaged memory pointer - again there is no direct access to unmanaged memory, but System.Runtime.InteropServices.Marshal
dereferencing methods can be used Marshal.AllocHGlobal()
can be used successfully in relation to Xlib/X11 native calls
Marshaling data from Xlib/X11 to C#
The first sample to demonstrate one possible turnaround of passing complex structures between managed and unmanaged code is X11lib.XGetClassHint()
. This call returns the XClassHint
structure on success and the caller is responsible for release of the allocated memory after use - in other words: C# has to release the memory allocated during a X11lib.XGetClassHint()
call.
[DllImport("libX11", EntryPoint = "XGetClassHint")]
extern private static TInt _XGetClassHint (IntPtr x11display, IntPtr x11window,
ref _XClassHint classHint);
public static int XGetClassHint (IntPtr x11display, IntPtr x11window, out XClassHint classHint)
{
_XClassHint _classHint = _XClassHint.Zero;
if (_XGetClassHint (x11display, x11window, ref _classHint) == (TInt)0)
{
XFree (_classHint.res_name);
classHint = XClassHint.Zero;
return 0;
}
else
{
classHint = new XClassHint();
classHint.res_name = (string)Marshal.PtrToStringAnsi (_classHint.res_name );
classHint.res_class = (string)Marshal.PtrToStringAnsi (_classHint.res_class);
XFree (_classHint.res_name);
XFree (_classHint.res_class);
return 1;
}
}
The solution i've been chosen divides the call into two parts. The C# method XGetClassHint()
calls the native code via the renamed function _XGetClassHint()
and postprocesses the returned structure. To be able to release the allocated memory, the structure returned from native code is defined using the two memory pointer res_name
and res_class
. The structure itself will be created by managed code, marshalled to unmanaged code and provided with the two memory pointers to res_name
and res_class
(the caller is responsible to release), marshalled back to managed code and destroyed by the garbage collector.
[StructLayout(LayoutKind.Sequential)]
private struct _XClassHint
{
public IntPtr res_name;
public IntPtr res_class;
public static _XClassHint Zero = new _XClassHint ();
}
And the structure returned to the application is defined using two managed strings of the same name.
[StructLayout(LayoutKind.Sequential)]
public struct XClassHint
{
[MarshalAs(UnmanagedType.LPStr)] public string res_name;
[MarshalAs(UnmanagedType.LPStr)] public string res_class;
public static XClassHint Zero = new XClassHint ();
}
The C# method XGetClassHint()
manages conversion and memory release explicit and offers full control over the two memory pointer res_name
and res_class
.
Marshaling data from C# to Xlib/X11
The second sample i will show is the implementation of XrwGraphic
class, which provides the application with bitmap graphics that are very easy to handle and support transparency (actually based on white color pixel #FFFFFF). The implemented procedure to apply a transparent bitmap to a drawable includes:
- creation of the color graphic
XImage
structure from the bitmap graphic file - creation of the transparency mask
XImage
structure from the same file (using white pixel) - creation of the transparency mask
XPixmap
structure - application of the transparency mask
XImage
structure to the transparency mask XPixmap
structure - creation of a cliping graphic context based on the transparency mask
XImage
structure - application of the color graphic
XImage
to the drawable that should show the graphic using the clipping graphic context - release of all obsolete resources
Although the XrwGraphic
class is not optimized for speed, memory usage or different color depth (currently tested only with true color 24 bit display) this class took the longest time of all provided classes to get it work - because of insufficient information about the procedure to be implemented and the details to be considered.
The sample application uses XrwGraphic
class multiple times and shows transparent graphics for application icon as well as for label, command toggle, radio and menu widgets. To provide a transparent graphic for application icon some of the steps mentioned above are done by the X11lib.XSetWMHints()
automatically, but the procedure in general is the same.
The creation of the two XImage
structures for color graphic and transparency mask from a System.Drawing.Bitmap
uses managed byte[]
to process all computation in managed code and Marshal.AllocHGlobal
as well as Marshal.Copy
to transfer the conversion result to unmanaged memory.
byte[] graphicData = new byte[_height * _width * colorPixelBytes];
byte[] maskData = new byte[_height * maskLineBytes];
int graphicPixelIndex = 0;
int maskPixelIndex = 0;
Color pixelColor = Color.Black;
bool transparency = false;
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width; x++)
{
graphicPixelIndex = (y * _width + x) << 2;
maskPixelIndex = y * maskLineBytes + (x >> 3);
pixelColor = bmp.GetPixel (x,y);
graphicData[graphicPixelIndex + 0] = pixelColor.B;
graphicData[graphicPixelIndex + 1] = pixelColor.G;
graphicData[graphicPixelIndex + 2] = pixelColor.R;
graphicData[graphicPixelIndex + 3] = pixelColor.A;
if (pixelColor. B == 255 && pixelColor.G == 255 && pixelColor.R == 255)
{
byte summand = (byte)(1<<(x % 8));
maskData[maskPixelIndex] = (byte)(maskData[maskPixelIndex] + summand);
transparency = true;
}
}
}
IntPtr graphicDataHandle = Marshal.AllocHGlobal(graphicData.Length);
Marshal.Copy (graphicData, 0, graphicDataHandle, graphicData.Length);
_graphicXImage = X11lib.XCreateImage (_display, visual, (TUint)_graphicDepth,
X11lib.TImageFormat.ZPixmap, (TInt)0,
graphicDataHandle, (TUint)_width, (TUint)_height,
IMAGE_PADDING, ASSUME_CONTIGUOUS);
if (_graphicXImage == IntPtr.Zero)
throw new OperationCanceledException ("Image creation for graphic failed.");
if (transparency == true)
{
IntPtr maskDataHandle = Marshal.AllocHGlobal(maskData.Length);
Marshal.Copy (maskData, 0, maskDataHandle, maskData.Length);
_transpXImage = X11lib.XCreateImage (_display, visual,
(TUint)_clipDepth, X11lib.TImageFormat.XYBitmap,
(TInt)0, maskDataHandle, (TUint)_width, (TUint)_height,
IMAGE_PADDING, ASSUME_CONTIGUOUS);
if (_transpXImage == IntPtr.Zero)
throw new OperationCanceledException (
"Image creation for transparency mask failed.");
}
The managed byte[]
for color graphic and transparency mask are disposed by the garbage collector. The Xlib/X11 resources like XImage
s, XPixmap
s and GC
s must be destroyed manually via X11lib.XDestroyImage()
, X11lib.XFreePixmap()
and X11lib.XFreeGC()
.
To prevent a big code mixup and to "don't repeat myself", generic GUI code is released to several Xrw* classes. The widget names and functionality follow the ideas of the "Athena Widget Set" with a little influence of the "Motif Widget Set" and GTK.
The widget set is neiter complete nor fully functional. The widget hierarchy shows the state of Xrw's version 0.10. To get a complete overview or the latest information see the fifth article about native calls from C# and Mono Develop to X11 API,
Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework. Enhancements will continue there. The widget hierarchy looks as follows:
<td"> <td">
XrwObject:IDisposable | ultimate base object[1, ∅] |
⌊ XrwRectObject | fundamental base object[1, ∅] with geometry |
⌊ XrwVisibleRectObject | fundamental base object[1, ∅] with drawing |
⌊ XrwCore | universal base gadget/widget[2/3, ∅] |
⌊ XrwComposite | container[2/3, ∅], managing many children |
| ⌊ XrwConstraint | container[2/3, ∅], with geometry management |
| | ⌊ XrwBox | container[2/3], arranging children horiz./vert. |
| | | ⌊ XrwNotebook | container[2/3], arranging children on pages
|
| | | ⌊ XrwRadioBox | gadget[2], arranging XrwRadio children horiz./vert. |
| | | ⌊ XrwSpinBox | ggadget[2], spinning invisible children to visible |
| | ⌊ XrwPorthole | gadget[2], display only ***one*** child at any time |
| | ⌊ XrwViewport | container[2/3], enabling ***one*** child to scroll |
| ⌊ XrwShell | fundamental shell widget[3] |
| ⌊ XrwOverrideShell | base popup shell, not interacting with the WM[4] |
| | ⌊ XrwSimpleMenu | popup menu shell, handling XrwSme gadgets[2] |
| ⌊ XrwWmShell | base shell, interacting with the WM[4] |
| ⌊ XrwApplicationShell | the common code of an X11 application |
| ⌊ XrwTransientShell | base class for popups, interacting with WM[4] |
| ⌊ XrwDialogShell | base class for dialogs, interacting with WM[4] |
⌊ XrwLabelBase | fundamental static label[2/3, ∅] |
| ⌊ XrwLabel | static label[2/3] |
| | ⌊ XrwCommand | command button widget[3] |
| | | ⌊ XrwMenuButton | command button widget[3], pop up a simple menu |
| | ⌊ XrwSme | simple menu entry gadget[2] |
| ⌊ XrwToggle | toggle button widget[3] |
| ⌊ XrwRadio | radio button widget[3] |
⌊ XrwSimple | universal widget[3] |
⌊ XrwList | list widget[3] |
⌊ XrwScrollbar | scroll bar widget[3] |
⌊ XrwText | single line text edit widget[3] |
⌊ XrwTree | tree widget[3] |
[1] object = invisible and windowless, uses neither the ***parent*** window nor an ***onw*** window
[2] gadget = uses the ***parent*** window instead of an ***onw*** window, saves resources compared to widget, but can receive events only if forwarded from the widget it is contained in
[3] widget = has an ***onw*** window, can creceive events directly from the WM[4]
[4] WM = Windows Manager
[∅] do not instantiate
Geometry management
The geometry management starts with the shell's ConfigureEvent
event, that contains the given shell geometry.
The XrwApplicationShell
passes the event to it's own OnConfigure()
method, which stores the given geometry and calls SetAssignedGeometry()
method for every with the given geometry.
The SetAssignedGeometry()
of a child widget, which stores the given geometry, substracts the border and calls the own CalculateChildLayout()
method with the new given geometry.
The CalculateChildLayout()
method calls the PreferredSize()
method for every child to determine the total preferred size of all children and distributes on this base the given geometry to the children calling the SetAssignedGeometry()
method.
The PreferredSize()
method call on composites is passed to the children and returns the total preferred size of all children. This call can be understood as recursively call.
The SetAssignedGeometry()
method calls the CalculateChildLayout()
method and this calls the SetAssignedGeometry()
method for all children. This call sequence can be understood as recursively call.
Event loop and events
The application's event loop is implemented in the XrwApplicationShell
class. I would call it "experimental" but it works fine for the current requirements. The event loop is divided into the infinite loop RunMessageLoop()
and the single event processing DoEvent()
.
protected void RunMessageLoop ()
{
bool proceed = true;
while(proceed == true)
{
try
{
proceed = DoEvent();
}
catch (Exception e)
{
Console.WriteLine (CLASS_NAME + ":: RunMessageLoop () ERROR: " + e.StackTrace);
}
}
return;
}
public bool DoEvent()
{
...
}
The DoEvent()
method currently processes ConfigureNotify
, Expose
, KeyPress
, KeyRelease
, ButtonPress
, ButtonRelease
, FocusIn
, FocusOut
, <code><code><code>EnterNotify
, LeaveNotify
, MotionNotify
and ClientMessage
events.
Every windowed widget can receive the X11 events that are registered for the underlying window via X11lib.XSelectInput()
. Currently XrwSimple
(including its derived simple widgets), XrwOverrideShell
(including its derived XrwSimpleMenu
), XrwTransientShell
(including its derived XrwDialogShell
and XrwMessageBox
) and XrwApplicationShell
register X11 events for their underlying windows. XrwTransientShell
and XrwApplicationShell
interact with the windows manager and register eleven X11 events.
X11lib.XSelectInput(_display, _window,
EventMask.StructureNotifyMask | EventMask.ExposureMask |
EventMask.ButtonPressMask | EventMask.ButtonReleaseMask |
EventMask.KeyPressMask | EventMask.KeyReleaseMask |
EventMask.FocusChangeMask | EventMask.EnterWindowMask |
EventMask.LeaveWindowMask | EventMask.PointerMotionMask |
EventMask.SubstructureNotifyMask);
The XrwSimple
and the XrwOverrideShell
register the same X11 events except EventMask.StructureNotifyMask
. They don't neet to receive ConfigureNotify
X11 events because all configuration, mainly the size adaption, is done
- starting at the shell widget that interacts with the windows manager receiving the
ConfigureNotify
event, - goes forward through the complete widget hierarchy - including all
XrwSimple
or XrwOverrideShell
and derived widgets as well as all windowless widgets - to calculate the preferred size of all widgets calling PreferredSize()
and - goes back through the complete widget hierarchy of this shell to set the assigned geometry calling
SetAssignedGeometry()
.
The DoEvent()
method determines the best receiver of the X11 event and translates the X11 event into a C# event, that is invoked. The ClientMessage
event is an easy sample for this proceeding.
else if (xevent.type == XEventName.ClientMessage &&
xevent.ClientMessageEvent.ptr1 == _wmDeleteMessage)
{
bool childAddressed = false;
foreach (XrwTransientShell transientShell in _associatedTransientShells)
{
if (xevent.ClientMessageEvent.window == transientShell.Window)
{
transientShell.OnClose (new XrwClientMessageEvent (ref xevent.ClientMessageEvent));
childAddressed = true;
break;
}
}
if (childAddressed == true)
return true;
if (xevent.ClientMessageEvent.window == this.Window)
OnClose (new XrwClientMessageEvent (ref xevent.ClientMessageEvent));
}
The event processing checks if the event is addressed to any transient shell of the application first. Otherwise it processes the event for the application shell. The transformation from an X11 event to a C# event is done by instantiation of the appropriate wrapper class, e. g. new XrwClientMessageEvent (ref xevent.ClientMessageEvent)
, and this instance is passed to the invocation of the C# event, e. g. transientShell.OnClose()
.
To make sure, that all transient shells of an application are captured by the event processing, the registration of a transient shell is essential. Currently neither the XrwTransientShell
class nor any derived class does this automatically, so the programmer is responsible for it.
void HandleMessageBoxButtonPress (XrwRectObj source, XrwButtonEvent e)
{
...
this.AddTransientShell (messageBox);
...
}
Specifics of widgets, that interact with the windows manager
All shell widgets, that interact with the windows manager, are decorated with a frame and can be closed with the application's icon menu item "Close" on the left or the close button on the right of the windows title bar.
To ensure a controlled and complete shell close, that includes the disposal of unmanaged resources, the shell must be notified about the close event triggered by the frame. To achieve this, the XrwTransientShell
and the XrwApplicationShell
register the _wmDeleteMessage
.
_wmDeleteMessage = X11lib.XInternAtom (_display,
X11Utils.StringToSByteArray ("WM_DELETE_WINDOW\0"), false);
if (X11lib.XSetWMProtocols (_display, _window, ref _wmDeleteMessage, (X11.TInt)1) == 0)
{
Console.WriteLine (CLASS_NAME + "::InitializeApplicationShellResources () WARNING: " +
"Failed to register 'WM_DELETE_WINDOW' event.");
}
Actually the windows manager supports three protocols, WM_TAKE_FOCUS
, WM_SAVE_YOURSELF
, WM_DELETE_WINDOW
, and the X11lib.XInternAtom()
obtains the protocol to register it with X11lib.XSetWMProtocols()
to the shell's underlying window.
General widget event handling
All widgets, that register X11 events with X11lib.XSelectInput()
, are notified about these X11 events, translated to C# events by the DoEvent()
method. If the application want to process events, callback methods can be registered to the event handler introduced by the XrwRectObj
widget.
public event ExposeDelegate Expose;
public event KeyPressDelegate KeyPress;
public event KeyReleaseDelegate KeyRelease;
public event ButtonPressDelegate ButtonPress;
public event ButtonReleaseDelegate ButtonRelease;
public event FocusInDelegate FocusIn;
public event FocusOutDelegate FocusOut;
public event EnterDelegate Enter;
public event LeaveDelegate Leave;
public event MotionDelegate Motion;
Now it is straight forward to obtain event notification as usual in C#, for example cbw1.ButtonPress += HandleCloseMenuButtonPress
.
Specifics of widgets, that don't interact with the windows manager
Some widgets have predefined/build in event handler. The XrwSimpleMenu
widget, for example, uses the FocusOut
and ButtonRelease
events to hide its override shell, the Motion
event to set/unset the mouse-over effect for the menu entries and the ButtonPress
event to start a menu action. The Motion
, ButtonPress
and ButtonRelease
events are handled by the XrwSimpleMenu
widget instead of the XrwSme
widgets, besause the XrwSme
widgets have no own window (to safe resources) and therefore they don't receive events.
Or the XrwCommand
widget, as another example, uses the Enter
and Leave
events to to set/unset the mouse-over effect.
private void InitializeCommandRessources ()
{
...
Enter += HandleEnter;
Leave += HandleLeave;
}
Triggering X11 events
To achieve the mouse-over effect, XrwSme
widgets, XrwCommand
widgets and XrwMenuButton
widgets change the fill color. To make this change visible, an X11 Expose
event has to be sent. The static convenience method SendExposeEvent()
of the XrwObject
widget makes this very easy to handle.
public static TInt SendExposeEvent (IntPtr display, IntPtr receiverWindow,
IntPtr dispatcherWindow)
{
XEvent eE = new XEvent();
eE.ExposeEvent.count = 0;
eE.ExposeEvent.display = display;
eE.ExposeEvent.window = receiverWindow;
eE.ExposeEvent.type = XEventName.Expose;
return X11lib.XSendEvent (display, dispatcherWindow, (TBoolean)1,
(TLong)EventMask.ExposureMask, ref eE);
}
Modal dialog
The division of the event loop into RunMessageLoop()
and DoEvent()
enables modal shells to take over the event handling by implementing their own infinite loop, e. g., the XrwMessageBox
.
public XrwDialogShell.Result Run ()
{
this.Show();
while (_result == XrwDialogShell.Result.None)
ApplicationShell.DoEvent ();
return _result;
}
Points of Interest
It was challenging, instructive and funny driving the same road as Qt, GTK, or wxWidget developers did years before. It offers a smart migration path from C/C++ to C# where developers can keep achievements they don't want miss and conquer new ground simultaneously.
The "Roma Widget Set" (Xrw) shows how easy OOP can be achived upon the old Xlib/X11 C programming interface.
History
- 30. April 2013, This is the first article about native calls from C# and Mono Develop to X11 API. It deals with the Xlib only. Further articles are planned, that deal with Xt/Athena and Xt/Motif.
- 08. July 2013, the second article about native calls from C# and Mono Develop to X11 API, Programming Xlib with Mono Develop - Part 2: Athena widgets (proof of concept), was posted.
- 18. September 2013, the third article about native calls from C# and Mono Develop to X11 API, Programming Xlib with Mono Develop - Part 3: Motif widgets (proof of concept), was posted.
- 07. November 2013, the fourth article about native calls from C# and Mono Develop to X11 API, Programming Xlib with Mono Develop - Part 4: FWF Xt widgets, was posted.
- 18. November 2013, this article was updated. New features are:
- Clean differentiation between border and frame.
- New frame types "Chiseled" and "Ledged".
- Maintenance of XrwExposeEvent.Result within all OnExpose calls.
- XrwOverrideShell now bases on an independent window instead in an XrwApplicationShell sub-window.
- New widgets XrwToggle and XrwRadio, XrwRadioBox, XrwPorthole and XrwNotebook.
- 20. January 2013, This article was splitted - widget references have been moved to the fifth article about native calls from C# and Mono Develop to X11 API, Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework. Enhancements will continue there. To get a complete overview or the latest information see the fifth article of this series. Additionally some errors have been fixed and a lot of new functionality has been added, for instance:
- The
XEvent
's member time
is originally of type/bit size ulong
(C) that corresponds to uint
(C# 32 BIT). - The popup menu position is now calculated with
XGetWindowAttributes()
and XTranslateCoordinates()
. - Gneric theme support including two predefined themes
XrwTheme.GeneralStyle.Win95
and XrwTheme.GeneralStyle.Gtk2Clearlooks
.