Initial revision
[theoddone33/hhexen.git] / x11 / x11window.cpp
1 //============================================================================
2 //
3 // $Id$
4 //
5 //============================================================================
6
7
8 #include "x11window.h"
9
10
11 /**
12   \class X11Window x11window.h
13   \brief The X11Window class
14
15   Note that most methods will not take effect until a call to XPending,
16   XNextEvent, or XWindowEvent.  If you want to make sure a method takes
17   effect before your program continues use sync();
18 */
19
20
21 char* X11Window::ErrorMessage[] =
22 {
23     "No error",
24     "Can't open X display"
25 };
26
27
28 /**
29    The specified name is used as the class and window/icon property name.
30 */
31
32 X11Window::X11Window( const char* name, Display* dis, int scr,
33                       int swidth, int sheight, long inputMask )
34 {
35     _flags = 0;
36     _err = 0;
37     _win = 0;
38     _screen = 0;
39     _nullCursor = (Cursor) -1;
40
41     if( dis )
42     {
43         _display = dis;
44     }
45     else
46     {
47         _display = XOpenDisplay( 0 );
48         if( ! _display )
49         {
50             _err = kOpenDisplay;
51             return;
52         }
53         _set( kOpenedDisplay );
54         }
55
56     if( scr )
57     {
58         _screen = scr;
59     }
60     else
61     {
62         _screen = DefaultScreen( _display );
63     }
64
65     _width = swidth;
66     _height = sheight;
67
68     unsigned long black = BlackPixel( _display, _screen );
69         _win = XCreateSimpleWindow( _display, DefaultRootWindow( _display ),
70                                                 0, 0, _width, _height, 0, black, black );
71
72
73         // Enable the delete window protocol.
74
75         _wmDeleteAtom = XInternAtom( _display, "WM_DELETE_WINDOW", False );
76         XSetWMProtocols( _display, _win, &_wmDeleteAtom, 1 );
77
78
79 #if 0
80     // Set the window manager properties
81
82     XWMHints wmHints;
83     XClassHint classHints;
84     XSizeHints sizeHints;
85     XTextProperty nameProp;
86         char* argv[ 2 ] = { (char*) name, NULL };
87
88     wmHints.flags = InputHint | StateHint;
89     wmHints.input = True;     
90     wmHints.initial_state = NormalState;
91
92     sizeHints.flags  = PSize;
93     sizeHints.width  = _width;
94     sizeHints.height = _height;
95
96     classHints.res_name  = (char*) name;
97     classHints.res_class = (char*) name;
98
99     if( XStringListToTextProperty( (char**) &name, 1, &nameProp ) )
100     {
101         XSetWMProperties( _display, _win, &nameProp, &nameProp, argv, 1,
102                           &sizeHints, &wmHints, &classHints );
103     }
104 #endif
105
106         // Set up the events to wait for.
107         XSelectInput( _display, _win, inputMask );
108 }
109
110
111 X11Window::~X11Window()
112 {
113         if( _display )
114     {
115         if( _win )
116         {
117             if( _nullCursor != (Cursor) -1 )
118                 XFreeCursor( _display, _nullCursor );
119
120             XDestroyWindow( _display, _win );
121         }
122
123         if( _flags & kOpenedDisplay )
124         {
125             XCloseDisplay( _display );
126         }
127     }
128 }
129
130
131 void X11Window::setTitle( const char* title )
132 {
133     XStoreName( _display, _win, title );
134 }
135
136
137 void X11Window::setIconName( const char* text )
138 {
139     XSetIconName( _display, _win, text );
140 }
141
142
143 void X11Window::move( int x, int y )
144 {
145     XMoveWindow( _display, _win, x, y );
146 }
147
148
149 void X11Window::moveResize( int x, int y, unsigned int w, unsigned int h )
150 {
151     XMoveResizeWindow( _display, _win, x, y, w, h );
152 }
153
154
155 void X11Window::resize( unsigned int w, unsigned int h )
156 {
157     XResizeWindow( _display, _win, w, h );
158 }
159
160
161 void X11Window::setSizeHints( int minW, int minH, int maxW, int maxH )
162 {
163     XSizeHints* hints = XAllocSizeHints();
164     if( hints )
165     {
166         hints->flags      = PMinSize | PMaxSize;
167         hints->min_width  = minW;
168         hints->min_height = minH;
169         hints->max_width  = maxW;
170         hints->max_height = maxH;
171
172         XSetWMNormalHints( _display, _win, hints );
173         XFree( hints );
174     }
175 }
176
177
178 void X11Window::raise()
179 {
180     XRaiseWindow( _display, _win );
181 }
182
183
184 void X11Window::show()
185 {
186     XMapWindow( _display, _win );
187
188 #if 0
189     // Wait for the window to be mapped.
190         XEvent event;
191     do
192     {
193         XNextEvent( _display, &event );
194     }
195     while( event.type != MapNotify );
196 #endif
197 }
198
199
200 void X11Window::hide()
201 {
202     XUnmapWindow( _display, _win );
203 }
204
205
206 void X11Window::iconify()
207 {
208     /*
209     XWMHints* hints = XAllocWMHints();
210     if( hints )
211     {
212         hints->flags = StateHint;
213         hints->initial_state = IconicState;
214         XSetWMHints( _display, _win, hints );
215         XFree(hints);
216
217         XIconifyWindow( _display, _win, _screen );
218     }
219     */
220
221     XIconifyWindow( _display, _win, _screen );
222 }
223
224
225 void X11Window::unIconify()
226 {
227     /*
228     XWMHints* hints = XAllocWMHints();
229     if( hints )
230     {
231         hints->flags = StateHint;
232         hints->initial_state = NormalState;
233         XSetWMHints( _display, _win, hints );
234         XFree(hints);
235
236         show();
237     }
238     */
239
240     show();
241 }
242
243
244 int X11Window::isIconified()
245 {
246     return 0;
247 }
248
249
250 /**
251   Calls XNextEvent() and then the appropriate virtual funtion based on event
252   type.
253 */
254
255 void X11Window::handleNextEvent()
256 {
257     XEvent event;
258
259     XNextEvent( _display, &event );
260
261     switch( event.type )
262     {
263         case ClientMessage:
264             if( event.xclient.format == 32 && 
265                 event.xclient.data.l[ 0 ] == (int) _wmDeleteAtom )
266             {
267                 deleteEvent( &event );
268             }
269             else
270             {
271                 unknownEvent( &event );
272             }
273             break;
274
275         case ConfigureNotify:
276             if( event.xconfigure.window == _win )
277             {
278                 _width  = event.xconfigure.width;
279                 _height = event.xconfigure.height;
280                 configureEvent( &event.xconfigure );
281             }
282             break;
283                                                 
284         case ButtonPress:
285             buttonDown( &event.xbutton );
286             break;
287
288         case ButtonRelease:
289             buttonUp( &event.xbutton );
290             break;
291
292         case MotionNotify:
293             motionEvent( &event.xmotion );
294             break;
295                                     
296         case KeyPress:
297             keyDown( &event.xkey );
298             break;
299
300         case KeyRelease:
301             keyUp( &event.xkey );
302             break;
303
304         case FocusIn:
305             focusIn( &event.xfocus );
306             break;
307
308         case FocusOut:
309             focusOut( &event.xfocus );
310             break;
311
312         case Expose:
313             exposeEvent( &event.xexpose );
314             break;
315
316         default:
317             unknownEvent( &event );
318             break;
319     }
320 }
321
322
323 /**
324   All events not passed to other virtual event methods are sent here.
325 */
326
327 void X11Window::unknownEvent( XEvent* ) {}
328
329
330 void X11Window::deleteEvent( XEvent* ) {}
331
332 void X11Window::focusIn( XFocusChangeEvent* ) {}
333
334 void X11Window::focusOut( XFocusChangeEvent* ) {}
335
336 void X11Window::exposeEvent( XExposeEvent* ) {}
337
338
339 /**
340   Called when the window is moved or resized by the user.
341   width() and height() can be used to check the new size.
342 */
343
344 void X11Window::configureEvent( XConfigureEvent* ) {}
345
346
347 /**
348   From XButtonEvent structure in Xlib.h:
349
350   \code
351       int x, y;             // pointer x, y coordinates in event window
352       int x_root, y_root;   // coordinates relative to root
353       unsigned int state;   // key or button mask
354       unsigned int button;  // detail
355   \endcode
356 */
357
358 void X11Window::buttonDown( XButtonEvent* ) {}
359 void X11Window::buttonUp( XButtonEvent* ) {}
360
361
362 void X11Window::motionEvent( XMotionEvent* ) {}
363
364
365 void X11Window::keyDown( XKeyEvent* ) {}
366 void X11Window::keyUp( XKeyEvent* ) {}
367
368
369 KeySym X11Window::keysym( XKeyEvent* e )
370 {
371     return XKeycodeToKeysym( display(), e->keycode, 0 );
372
373     /*
374     KeySym sym;
375     char buf[ 2 ];
376
377     XLookupString( event, buf, 1, &sym, NULL );
378     //printf( "XLookupString %x: %x %x\n", event->keycode, buf[ 0 ], sym );
379     return sym;
380     */
381 }
382
383
384 void X11Window::hideCursor()
385 {
386     if( _nullCursor == (Cursor) -1 )
387         _nullCursor = _createNullCursor();
388
389     XDefineCursor( _display, _win, _nullCursor );
390 }
391
392
393 void X11Window::showCursor()
394 {
395     XUndefineCursor( _display, _win );
396 }
397
398
399 Cursor X11Window::_createNullCursor()
400 {
401     Pixmap cursormask;
402     XGCValues xgc;
403     GC gc;
404     XColor dummycolour;
405     Cursor cursor;
406
407     cursormask = XCreatePixmap( _display, _win, 1, 1, 1/*depth*/);
408     xgc.function = GXclear;
409     gc = XCreateGC( _display, cursormask, GCFunction, &xgc );
410     XFillRectangle( _display, cursormask, gc, 0, 0, 1, 1 );
411     dummycolour.pixel = 0;
412     dummycolour.red   = 0;
413     dummycolour.flags = 04;
414     cursor = XCreatePixmapCursor( _display, cursormask, cursormask,
415                                   &dummycolour, &dummycolour, 0, 0 );
416     XFreePixmap( _display, cursormask );
417     XFreeGC( _display, gc );
418
419     return cursor;
420 }
421
422
423 #if 0
424 void X11Window::enableBackingStore()
425 {
426     if( DoesBackingStore( ScreenOfDisplay( _display, _screen ) ) == Always )
427     {
428         XSetWindowAttributes attr;
429         winattr.backing_store = Always;
430         XChangeWindowAttributes( _display, _win, CWBackingStore, &attr );
431     }
432 }
433 #endif
434
435
436 #if 0
437 // g++ x11window.cpp -g -L/usr/X11R6/lib -lX11
438
439 #include <stdio.h>
440 #include <unistd.h>
441 #include <ctype.h>
442
443 class TestWindow : public X11Window
444 {
445 public:
446
447     TestWindow( const char* name, Display* dis = 0 )
448               : X11Window( name, dis )
449     {
450         setTitle( name );
451     }
452
453     void wait()
454     {
455         sync();
456
457         sleep( 1 );
458         putchar( '.' );
459         fflush( stdout );
460
461         sleep( 1 );
462         putchar( '.' );
463         putchar( '\n' );
464         fflush( stdout );
465     }
466
467     void testHide()
468     {
469         wait();
470
471         printf( "resize\n" );
472         resize( 100, 200 );
473         wait();
474
475         printf( "hiding\n" );
476         hide();
477         wait();
478         printf( "showing\n" );
479         show();
480         wait();
481
482         printf( "iconifying\n" );
483         iconify();
484         wait();
485         printf( "showing\n" );
486         show();
487         wait();
488     }
489     
490     void testEvents()
491     {
492         _exit = false;
493         while( _exit == false )
494         {
495             _ecnt = 0;
496
497             while( eventsPending() )
498                 handleNextEvent();
499
500             if( _ecnt )
501                 printf( "  events %d\n", _ecnt );
502
503             usleep( 16000 );
504         }
505     }
506
507 protected:
508     
509     void deleteEvent( XEvent* )
510     {
511         printf( "delete\n" );
512         _exit = true;
513         _ecnt++;
514     }
515
516     void configureEvent( XConfigureEvent* )
517     {
518         printf( "configure %d %d\n", width(), height() );
519         _ecnt++;
520     }
521
522     void unknownEvent( XEvent* e )
523     {
524         printf( "Unknown XEvent: %d\n", e->type );
525         _ecnt++;
526     }
527     
528     void buttonDown( XButtonEvent* e )
529     {
530         printf( "buttonDown: %d %d,%d\n", e->button, e->x, e->y );
531         _ecnt++;
532     }
533
534     void buttonUp( XButtonEvent* e )
535     {
536         printf( "buttonUp: %d %d,%d\n", e->button, e->x, e->y );
537         _ecnt++;
538     }
539
540     void motionEvent( XMotionEvent* e )
541     {
542         printf( "motion: %lx %d %d\n", e->time, e->x, e->y );
543         _ecnt++;
544     }
545
546     void keyDown( XKeyEvent* e )
547     {
548         int a = keysym( e );
549         if( isascii( a ) )
550             printf( "keyDown: %lx %x %x (%c)\n", e->time, e->state, e->keycode, (char) a );
551         else
552             printf( "keyDown: %lx %x %x %x\n", e->time, e->state, e->keycode, a );
553         _ecnt++;
554
555         if( a == 0x1b ) // ASCII ESC 
556             _exit = true;
557         if( a == 'h' )
558             hideCursor();
559         if( a == 'u' )
560             showCursor();
561     }
562
563     void keyUp( XKeyEvent* e )
564     {
565         int a = keysym( e );
566         if( isascii( a ) )
567             printf( "keyUp: %lx %x %x (%c)\n", e->time, e->state, e->keycode, (char) a );
568         else
569             printf( "keyUp: %lx %x %x %x\n", e->time, e->state, e->keycode, a );
570         _ecnt++;
571     }
572
573 private:
574     
575     int _ecnt;
576     int _exit;
577 };
578
579
580 int main()
581 {
582     TestWindow win( "X11Window Test" );
583
584     if( win.error() )
585     {
586         printf( "error %d\n", win.error() );
587         return 1;
588     }
589
590     printf( "sizeof X11Window: %d\n", sizeof( X11Window ) );
591     printf( "screen size: %d %d\n", win.displayWidth(), win.displayHeight() );
592
593     win.show();
594
595     win.testEvents();
596     //win.testHide();
597
598     printf( "done!\n" );
599     return 0;
600 }
601 #endif
602
603
604 //EOF