1 #ifndef __cxxtest__X11Gui_h__
2 #define __cxxtest__X11Gui_h__
3 
4 //
5 // X11Gui displays a simple progress bar using X11
6 //
7 // It accepts the following command-line arguments:
8 //  -title <title>              - Sets the application title
9 //  -fn or -font <font>         - Sets the font
10 //  -bg or -background <color>  - Sets the background color (default=Grey)
11 //  -fg or -foreground <color>  - Sets the text color (default=Black)
12 //  -green/-yellow/-red <color> - Sets the colors of the bar
13 //
14 
15 #include <cxxtest/Gui.h>
16 
17 #include <X11/Xlib.h>
18 #include <X11/Xutil.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 namespace CxxTest
24 {
25     class X11Gui : public GuiListener
26     {
27     public:
enterGui(int & argc,char ** argv)28         void enterGui( int &argc, char **argv )
29         {
30             parseCommandLine( argc, argv );
31         }
32 
enterWorld(const WorldDescription & wd)33         void enterWorld( const WorldDescription &wd )
34         {
35             openDisplay();
36             if ( _display ) {
37                 createColors();
38                 createWindow();
39                 createGc();
40                 createFont();
41                 centerWindow();
42                 initializeEvents();
43                 initializeBar( wd );
44                 processEvents();
45             }
46         }
47 
guiEnterTest(const char * suiteName,const char * testName)48         void guiEnterTest( const char *suiteName, const char *testName )
49         {
50             if ( _display ) {
51                 ++ _testsDone;
52                 setWindowName( suiteName, testName );
53                 redraw();
54             }
55         }
56 
yellowBar()57         void yellowBar()
58         {
59             if ( _display ) {
60                 _barColor = getColor( _yellowName );
61                 getTotalTests();
62                 processEvents();
63             }
64         }
65 
redBar()66         void redBar()
67         {
68             if ( _display ) {
69                 _barColor = getColor( _redName );
70                 getTotalTests();
71                 processEvents();
72             }
73         }
74 
leaveGui()75         void leaveGui()
76         {
77             if ( _display ) {
78                 freeFontInfo();
79                 destroyGc();
80                 destroyWindow();
81                 closeDisplay();
82             }
83         }
84 
85     private:
86         const char *_programName;
87         Display *_display;
88         Window _window;
89         unsigned _numTotalTests, _testsDone;
90         char _strTotalTests[WorldDescription::MAX_STRLEN_TOTAL_TESTS];
91         const char *_foregroundName, *_backgroundName;
92         const char *_greenName, *_yellowName, *_redName;
93         unsigned long _foreground, _background, _barColor;
94         int _width, _height;
95         GC _gc;
96         const char *_fontName;
97         XID _fontId;
98         XFontStruct *_fontInfo;
99         int _textHeight, _textDescent;
100         long _eventMask;
101         Colormap _colormap;
102 
parseCommandLine(int & argc,char ** argv)103         void parseCommandLine( int &argc, char **argv )
104         {
105             _programName = argv[0];
106 
107             _fontName = 0;
108             _foregroundName = "Black";
109             _backgroundName = "Grey";
110             _greenName = "Green";
111             _yellowName = "Yellow";
112             _redName = "Red";
113 
114             for ( int i = 1; i + 1 < argc; ++ i ) {
115                 if ( !strcmp( argv[i], "-title" ) )
116                     _programName = argv[++ i];
117                 else if ( !strcmp( argv[i], "-fn" ) || !strcmp( argv[i], "-font" ) )
118                     _fontName = argv[++ i];
119                 else if ( !strcmp( argv[i], "-fg" ) || !strcmp( argv[i], "-foreground" ) )
120                     _foregroundName = argv[++ i];
121                 else if ( !strcmp( argv[i], "-bg" ) || !strcmp( argv[i], "-background" ) )
122                     _backgroundName = argv[++ i];
123                 else if ( !strcmp( argv[i], "-green" ) )
124                     _greenName = argv[++ i];
125                 else if ( !strcmp( argv[i], "-yellow" ) )
126                     _yellowName = argv[++ i];
127                 else if ( !strcmp( argv[i], "-red" ) )
128                     _redName = argv[++ i];
129             }
130         }
131 
openDisplay()132         void openDisplay()
133         {
134             _display = XOpenDisplay( NULL );
135         }
136 
createColors()137         void createColors()
138         {
139             _colormap = DefaultColormap( _display, 0 );
140             _foreground = getColor( _foregroundName );
141             _background = getColor( _backgroundName );
142         }
143 
getColor(const char * colorName)144         unsigned long getColor( const char *colorName )
145         {
146             XColor color;
147             XParseColor( _display, _colormap, colorName, &color );
148             XAllocColor( _display, _colormap, &color );
149             return color.pixel;
150         }
151 
createWindow()152         void createWindow()
153         {
154             _window = XCreateSimpleWindow( _display, RootWindow( _display, 0 ), 0, 0, 1, 1, 0, 0, _background );
155         }
156 
createGc()157         void createGc()
158         {
159             _gc = XCreateGC( _display, _window, 0, 0 );
160         }
161 
createFont()162         void createFont()
163         {
164             if ( !loadFont() )
165                 useDefaultFont();
166             getFontInfo();
167             _textHeight = _fontInfo->ascent + _fontInfo->descent;
168             _textDescent = _fontInfo->descent;
169         }
170 
loadFont()171         bool loadFont()
172         {
173             if ( !_fontName )
174                 return false;
175             _fontId = XLoadFont( _display, _fontName );
176             return (XSetFont( _display, _gc, _fontId ) == Success);
177         }
178 
useDefaultFont()179         void useDefaultFont()
180         {
181             _fontId = XGContextFromGC( _gc );
182         }
183 
getFontInfo()184         void getFontInfo()
185         {
186             _fontInfo = XQueryFont( _display, _fontId );
187         }
188 
freeFontInfo()189         void freeFontInfo()
190         {
191             XFreeFontInfo( NULL, _fontInfo, 1 );
192         }
193 
initializeEvents()194         void initializeEvents()
195         {
196             _eventMask = ExposureMask;
197             XSelectInput( _display, _window, _eventMask );
198         }
199 
initializeBar(const WorldDescription & wd)200         void initializeBar( const WorldDescription &wd )
201         {
202             getTotalTests( wd );
203             _testsDone = 0;
204             _barColor = getColor( _greenName );
205         }
206 
getTotalTests()207         void getTotalTests()
208         {
209             getTotalTests( tracker().world() );
210         }
211 
getTotalTests(const WorldDescription & wd)212         void getTotalTests( const WorldDescription &wd )
213         {
214             _numTotalTests = wd.numTotalTests();
215             wd.strTotalTests( _strTotalTests );
216         }
217 
centerWindow()218         void centerWindow()
219         {
220             XMapWindow( _display, _window );
221 
222             Screen *screen = XDefaultScreenOfDisplay( _display );
223             int screenWidth = WidthOfScreen( screen );
224             int screenHeight = HeightOfScreen( screen );
225             int xCenter = screenWidth / 2;
226             int yCenter = screenHeight / 2;
227 
228             _width = (screenWidth * 4) / 5;
229             _height = screenHeight / 14;
230 
231             XMoveResizeWindow( _display, _window, xCenter - (_width / 2), yCenter - (_height / 2), _width, _height );
232         }
233 
processEvents()234         void processEvents()
235         {
236             redraw();
237 
238             XEvent event;
239             while( XCheckMaskEvent( _display, _eventMask, &event ) )
240                 redraw();
241         }
242 
setWindowName(const char * suiteName,const char * testName)243         void setWindowName( const char *suiteName, const char *testName )
244         {
245             unsigned length = strlen( _programName ) + strlen( suiteName ) + strlen( testName ) + sizeof( " - ::()" );
246             char *name = (char *)malloc( length );
247             sprintf( name, "%s - %s::%s()", _programName, suiteName, testName );
248             XSetStandardProperties( _display, _window, name, 0, 0, 0, 0, 0 );
249             free( name );
250         }
251 
redraw()252         void redraw()
253         {
254             getWindowSize();
255             drawSolidBar();
256             drawDividers();
257             drawPercentage();
258             flush();
259         }
260 
getWindowSize()261         void getWindowSize()
262         {
263             XWindowAttributes attributes;
264             XGetWindowAttributes( _display, _window, &attributes );
265             _width = attributes.width;
266             _height = attributes.height;
267         }
268 
drawSolidBar()269         void drawSolidBar()
270         {
271             unsigned barWidth = (_width * _testsDone) / _numTotalTests;
272 
273             XSetForeground( _display, _gc, _barColor );
274             XFillRectangle( _display, _window, _gc, 0, 0, barWidth, _height );
275 
276             XSetForeground( _display, _gc, _background );
277             XFillRectangle( _display, _window, _gc, barWidth, 0, _width + 1 - barWidth, _height );
278         }
279 
drawDividers()280         void drawDividers()
281         {
282             if(_width / _numTotalTests < 5)
283                 return;
284             for ( unsigned i = 1; i < _testsDone; ++ i ) {
285                 int x = (_width * i) / _numTotalTests;
286                 XDrawLine( _display, _window, _gc, x, 0, x, _height);
287             }
288         }
289 
drawPercentage()290         void drawPercentage()
291         {
292             XSetForeground( _display, _gc, _foreground );
293 
294             char str[sizeof("1000000000 of ") + sizeof(_strTotalTests) + sizeof(" (100%)")];
295             sprintf( str, "%u of %s (%u%%)", _testsDone, _strTotalTests, (_testsDone * 100) / _numTotalTests );
296             unsigned len = strlen( str );
297 
298             int textWidth = XTextWidth( _fontInfo, str, len );
299 
300             XDrawString( _display, _window, _gc,
301                          (_width - textWidth) / 2, ((_height + _textHeight) / 2) - _textDescent,
302                          str, len );
303         }
304 
flush()305         void flush()
306         {
307             XFlush( _display );
308         }
309 
destroyGc()310         void destroyGc()
311         {
312             XFreeGC( _display, _gc );
313         }
314 
destroyWindow()315         void destroyWindow()
316         {
317             XDestroyWindow( _display, _window );
318         }
319 
closeDisplay()320         void closeDisplay()
321         {
322             XCloseDisplay( _display );
323         }
324     };
325 }
326 
327 #endif //__cxxtest__X11Gui_h__
328