1 #ifndef __cxxtest__X11Gui_h__
2 #define __cxxtest__X11Gui_h__
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 //
15 #include <cxxtest/Gui.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xutil.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 namespace CxxTest
24 {
25 class X11Gui : public GuiListener
26 {
27 public:
28 void enterGui( int &argc, char **argv )
29 {
30 parseCommandLine( argc, argv );
31 }
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 }
48 void guiEnterTest( const char *suiteName, const char *testName )
49 {
50 if ( _display ) {
51 ++ _testsDone;
52 setWindowName( suiteName, testName );
53 redraw();
54 }
55 }
57 void yellowBar()
58 {
59 if ( _display ) {
60 _barColor = getColor( _yellowName );
61 getTotalTests();
62 processEvents();
63 }
64 }
66 void redBar()
67 {
68 if ( _display ) {
69 _barColor = getColor( _redName );
70 getTotalTests();
71 processEvents();
72 }
73 }
75 void leaveGui()
76 {
77 if ( _display ) {
78 freeFontInfo();
79 destroyGc();
80 destroyWindow();
81 closeDisplay();
82 }
83 }
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;
103 void parseCommandLine( int &argc, char **argv )
104 {
105 _programName = argv[0];
107 _fontName = 0;
108 _foregroundName = "Black";
109 _backgroundName = "Grey";
110 _greenName = "Green";
111 _yellowName = "Yellow";
112 _redName = "Red";
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 }
132 void openDisplay()
133 {
134 _display = XOpenDisplay( NULL );
135 }
137 void createColors()
138 {
139 _colormap = DefaultColormap( _display, 0 );
140 _foreground = getColor( _foregroundName );
141 _background = getColor( _backgroundName );
142 }
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 }
152 void createWindow()
153 {
154 _window = XCreateSimpleWindow( _display, RootWindow( _display, 0 ), 0, 0, 1, 1, 0, 0, _background );
155 }
157 void createGc()
158 {
159 _gc = XCreateGC( _display, _window, 0, 0 );
160 }
162 void createFont()
163 {
164 if ( !loadFont() )
165 useDefaultFont();
166 getFontInfo();
167 _textHeight = _fontInfo->ascent + _fontInfo->descent;
168 _textDescent = _fontInfo->descent;
169 }
171 bool loadFont()
172 {
173 if ( !_fontName )
174 return false;
175 _fontId = XLoadFont( _display, _fontName );
176 return (XSetFont( _display, _gc, _fontId ) == Success);
177 }
179 void useDefaultFont()
180 {
181 _fontId = XGContextFromGC( _gc );
182 }
184 void getFontInfo()
185 {
186 _fontInfo = XQueryFont( _display, _fontId );
187 }
189 void freeFontInfo()
190 {
191 XFreeFontInfo( NULL, _fontInfo, 1 );
192 }
194 void initializeEvents()
195 {
196 _eventMask = ExposureMask;
197 XSelectInput( _display, _window, _eventMask );
198 }
200 void initializeBar( const WorldDescription &wd )
201 {
202 getTotalTests( wd );
203 _testsDone = 0;
204 _barColor = getColor( _greenName );
205 }
207 void getTotalTests()
208 {
209 getTotalTests( tracker().world() );
210 }
212 void getTotalTests( const WorldDescription &wd )
213 {
214 _numTotalTests = wd.numTotalTests();
215 wd.strTotalTests( _strTotalTests );
216 }
218 void centerWindow()
219 {
220 XMapWindow( _display, _window );
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;
228 _width = (screenWidth * 4) / 5;
229 _height = screenHeight / 14;
231 XMoveResizeWindow( _display, _window, xCenter - (_width / 2), yCenter - (_height / 2), _width, _height );
232 }
234 void processEvents()
235 {
236 redraw();
238 XEvent event;
239 while( XCheckMaskEvent( _display, _eventMask, &event ) )
240 redraw();
241 }
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 }
252 void redraw()
253 {
254 getWindowSize();
255 drawSolidBar();
256 drawDividers();
257 drawPercentage();
258 flush();
259 }
261 void getWindowSize()
262 {
263 XWindowAttributes attributes;
264 XGetWindowAttributes( _display, _window, &attributes );
265 _width = attributes.width;
266 _height = attributes.height;
267 }
269 void drawSolidBar()
270 {
271 unsigned barWidth = (_width * _testsDone) / _numTotalTests;
273 XSetForeground( _display, _gc, _barColor );
274 XFillRectangle( _display, _window, _gc, 0, 0, barWidth, _height );
276 XSetForeground( _display, _gc, _background );
277 XFillRectangle( _display, _window, _gc, barWidth, 0, _width + 1 - barWidth, _height );
278 }
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 }
290 void drawPercentage()
291 {
292 XSetForeground( _display, _gc, _foreground );
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 );
298 int textWidth = XTextWidth( _fontInfo, str, len );
300 XDrawString( _display, _window, _gc,
301 (_width - textWidth) / 2, ((_height + _textHeight) / 2) - _textDescent,
302 str, len );
303 }
305 void flush()
306 {
307 XFlush( _display );
308 }
310 void destroyGc()
311 {
312 XFreeGC( _display, _gc );
313 }
315 void destroyWindow()
316 {
317 XDestroyWindow( _display, _window );
318 }
320 void closeDisplay()
321 {
322 XCloseDisplay( _display );
323 }
324 };
325 };
327 #endif //__cxxtest__X11Gui_h__