Round 4: Some minor build system housekeeping, as well as removing some depricated...
[theoddone33/hhexen.git] / x11 / i_x11.cpp
1 //**************************************************************************
2 //**
3 //** $Id$
4 //**
5 //**************************************************************************
6
7
8 #include <string.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <sys/time.h>
13 #include <unistd.h>
14 #include <X11/keysym.h>
15 #include "x11window.h"
16 #include "xshmext.h"
17
18 extern "C" {
19 #include "h2def.h"
20 }
21
22
23 /*
24     Nifty palette cacheing idea taken from Linux Heretic.
25
26     The Hexen palette pointer is used as a palette id, i.e. a palette
27     with another pointer value is assumed to be a different
28     palette, and, more important, if the pointer is equal,
29     the palette is assumed to be the same...
30 */
31
32 #define PAL_CACHE_ON
33 #define MAX_PAL_CACHE   5
34
35 #define MOUSE_JUMP_AT 10
36
37 struct PaletteCache
38 {
39     PaletteCache() : id( 0 ), used( 0 ) {}
40
41     void free( Display* dis, Colormap cmap )
42     {
43         if( id )
44         {
45             XFreeColors( dis, cmap, pixel, 256, 0 );
46             id = 0;
47             used = 0;
48         }
49     }
50
51     unsigned char* id;           // contains pointer / id of palette.
52     unsigned int used;
53     unsigned long pixel[ 256 ];  // xpixel lookup table.
54 };
55
56
57 class HexenWindow : public X11Window
58 {
59 public:
60
61     HexenWindow();
62
63     ~HexenWindow();
64
65     void setPalette( byte* );
66
67     void blit( unsigned char* buffer, int x, int y, int w, int h );
68
69     void grabPointer()
70     {
71         XGrabPointer( display(), window(), True,
72                 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
73                 GrabModeAsync, GrabModeAsync, window(), None, CurrentTime );
74         hideCursor();
75         _grabCursor = true;
76     }
77
78     void ungrabPointer()
79     {
80         XUngrabPointer( display(), CurrentTime );
81         showCursor();
82         _grabCursor = false;
83     }
84
85 protected:
86
87     virtual void unknownEvent( XEvent* );
88     virtual void configureEvent( XConfigureEvent* );
89     virtual void deleteEvent( XEvent* );
90     virtual void buttonDown( XButtonEvent* );
91     virtual void buttonUp( XButtonEvent* );
92     virtual void motionEvent( XMotionEvent* );
93     virtual void keyDown( XKeyEvent* );
94     virtual void keyUp( XKeyEvent* );
95     virtual void exposeEvent( XExposeEvent* );
96
97 private:
98
99     void waitForShmPut();
100     void resizeFramebuffer();
101     bool getVisualInfo( XVisualInfo* );
102     void postKey( evtype_t type, KeySym key );
103     void postMouseEvent( int dx, int dy );
104  
105     XVisualInfo _vinfo;
106     GC _gc;
107  
108     Colormap _colormap;
109     PaletteCache _palc[ MAX_PAL_CACHE ];
110     PaletteCache* _pcurrent;
111     int _cacheGamma;
112     int _cacheAge;
113
114     ShmImage* _simage;
115     int _shmEventType;
116     bool _usingShm;
117  
118     XImage* _ximage;
119
120     int _prevX, _prevY;
121     int _buttons;
122     bool _grabCursor;
123 };
124
125
126 HexenWindow* _win;
127
128
129 extern "C" {
130
131
132 // Public Data
133
134 int DisplayTicker = 0;
135
136 extern int ticcount;
137
138 extern boolean novideo; // if true, stay in text mode for debugging
139
140
141 //==================================================
142
143 #define MOUSEB1 1
144 #define MOUSEB2 2
145 #define MOUSEB3 4
146
147 //==================================================
148
149 #define KEY_TAB         9   // From am_map.h
150
151 #define KEY_INS         0x52
152 #define KEY_DEL         0x53
153 #define KEY_PGUP        0x49
154 #define KEY_PGDN        0x51
155 #define KEY_HOME        0x47
156 #define KEY_END         0x4f
157
158
159 /*
160 ============================================================================
161
162                                                                 USER INPUT
163
164 ============================================================================
165 */
166
167 //--------------------------------------------------------------------------
168 //
169 // PROC I_WaitVBL
170 //
171 //--------------------------------------------------------------------------
172
173 void I_WaitVBL(int vbls)
174 {
175         if( novideo )
176         {
177                 return;
178         }
179         while( vbls-- )
180         {
181         usleep( 16667 );
182         }
183 }
184
185 //--------------------------------------------------------------------------
186 //
187 // PROC I_SetPalette
188 //
189 // Palette source must use 8 bit RGB elements.
190 //
191 //--------------------------------------------------------------------------
192
193 void I_SetPalette( byte *palette )
194 {
195         if(novideo)
196         {
197                 return;
198         }
199
200     _win->setPalette( palette );
201 }
202
203 /*
204 ============================================================================
205
206                                                         GRAPHICS MODE
207
208 ============================================================================
209 */
210
211
212 /*
213 ==============
214 =
215 = I_Update
216 =
217 ==============
218 */
219
220 int UpdateState;
221 extern int screenblocks;
222
223 void I_Update (void)
224 {
225         int i;
226         byte *dest;
227         int tics;
228         static int lasttic;
229
230
231     // blit screen to video
232
233         if(DisplayTicker)
234         {
235 #if 0
236         // Why is it drawing to pcscreen under some conditions?
237                 if(screenblocks > 9 || UpdateState&(I_FULLSCRN|I_MESSAGES))
238                 {
239                         dest = (byte *)screen;
240                 }
241                 else
242                 {
243                         dest = (byte *)pcscreen;
244                 }
245 #else
246         dest = (byte *)screen;
247 #endif
248
249                 tics = ticcount-lasttic;
250                 lasttic = ticcount;
251                 if(tics > 20)
252                 {
253                         tics = 20;
254                 }
255                 for(i = 0; i < tics; i++)
256                 {
257                         *dest = 0xff;
258                         dest += 2;
259                 }
260                 for(i = tics; i < 20; i++)
261                 {
262                         *dest = 0x00;
263                         dest += 2;
264                 }
265         }
266
267         if(UpdateState == I_NOUPDATE)
268         {
269                 return;
270         }
271     if(UpdateState&I_FULLSCRN)
272         {
273                 UpdateState = I_NOUPDATE; // clear out all draw types
274
275         _win->blit( screen, 0, 0, SCREENWIDTH, SCREENHEIGHT );
276         }
277     if(UpdateState&I_FULLVIEW)
278         {
279                 if(UpdateState&I_MESSAGES && screenblocks > 7)
280                 {
281                         UpdateState &= ~(I_FULLVIEW|I_MESSAGES);
282
283             _win->blit( screen, 0, 0, SCREENWIDTH, viewwindowy+viewheight );
284                 }
285                 else
286                 {
287                         UpdateState &= ~I_FULLVIEW;
288
289             _win->blit( screen, viewwindowx, viewwindowy, viewwidth,
290                         viewheight );
291                 }
292         }
293         if(UpdateState&I_STATBAR)
294         {
295                 UpdateState &= ~I_STATBAR;
296
297         _win->blit( screen, 0, SCREENHEIGHT-SBARHEIGHT,
298                     SCREENWIDTH, SBARHEIGHT );
299         }
300         if(UpdateState&I_MESSAGES)
301         {
302                 UpdateState &= ~I_MESSAGES;
303
304         _win->blit( screen, 0, 0, SCREENWIDTH, 28 );
305         }
306 }
307
308 //--------------------------------------------------------------------------
309 //
310 // PROC I_InitGraphics
311 //
312 //--------------------------------------------------------------------------
313
314 void I_InitGraphics(void)
315 {
316         if( novideo )
317         {
318                 return;
319         }
320     
321     _win = new HexenWindow();
322     if( ! _win )
323     {
324         exit( 3 );
325     }
326
327     _win->show();
328
329         I_SetPalette( (byte*) W_CacheLumpName("PLAYPAL", PU_CACHE) );
330     _win->grabPointer ();
331 }
332
333 //--------------------------------------------------------------------------
334 //
335 // PROC I_ShutdownGraphics
336 //
337 //--------------------------------------------------------------------------
338
339 void I_ShutdownGraphics(void)
340 {
341 }
342
343 //--------------------------------------------------------------------------
344 //
345 // PROC I_ReadScreen
346 //
347 // Reads the screen currently displayed into a linear buffer.
348 //
349 //--------------------------------------------------------------------------
350
351 /*
352 void I_ReadScreen(byte *scr)
353 {
354         memcpy(scr, screen, SCREENWIDTH*SCREENHEIGHT);
355 }
356 */
357
358 //===========================================================================
359
360
361 void I_StartTic (void)
362 {
363     // Handle keyboard & mouse events.
364
365     while( _win->eventsPending() )
366         _win->handleNextEvent();
367
368         //I_ReadMouse();
369 }
370
371
372 /*
373 ============================================================================
374
375                                         TIMER INTERRUPT
376
377 ============================================================================
378 */
379
380
381 /*
382 ================
383 =
384 = I_TimerISR
385 =
386 ================
387 */
388
389 int I_TimerISR (void)
390 {
391         ticcount++;
392         return 0;
393 }
394
395
396 /*
397 ============================================================================
398
399                                                         MOUSE
400
401 ============================================================================
402 */
403
404
405 /*
406 ================
407 =
408 = StartupMouse
409 =
410 ================
411 */
412
413 void I_StartupCyberMan(void);
414
415 void I_StartupMouse (void)
416 {
417         I_StartupCyberMan();
418 }
419
420
421 /*
422 ================
423 =
424 = I_ReadMouse
425 =
426 ================
427 */
428
429 void I_ReadMouse (void)
430 {
431 }
432
433
434
435 //==========================================================================
436 //
437 //
438 // I_StartupReadKeys
439 //
440 //
441 //==========================================================================
442
443 void I_StartupReadKeys(void)
444 {
445    //if( KEY_ESCAPE pressed )
446    //    I_Quit ();
447 }
448
449
450 }   // extern "C"
451
452
453 //---------------------------------------------------------------------------
454
455
456 HexenWindow::HexenWindow()
457         : X11Window( "HEXEN", 0, 0, SCREENWIDTH*2, SCREENHEIGHT*2 )
458 {
459     _colormap = 0;
460     _gc = 0;
461     _simage = 0;
462     _ximage = 0;
463     _usingShm = false;
464     _grabCursor = false;
465
466     _pcurrent = 0;
467     _cacheGamma = -1;
468     _cacheAge = 0;
469
470     _buttons = 0;
471     _prevX = _prevY = 0; 
472
473     setTitle( "HHexen v1.3" );
474     setSizeHints( SCREENWIDTH, SCREENHEIGHT, SCREENWIDTH*2, SCREENHEIGHT*2 );
475     setIconName( "HEXEN" );
476
477     if( getVisualInfo( &_vinfo ) )
478     {
479         // KR
480 //        printf( "Visual: depth %d, mask %04x %04x %04x\n", _vinfo.depth,
481 //                _vinfo.red_mask, _vinfo.green_mask, _vinfo.blue_mask );
482
483         if( _vinfo.depth == 8 )
484         {
485             _colormap = XCreateColormap( display(), window(), _vinfo.visual,
486                                          AllocAll );
487             XSetWindowColormap( display(), window(), _colormap );
488         }
489         else
490         {
491             _colormap = DefaultColormapOfScreen(
492                                     ScreenOfDisplay( display(), screen() ) );
493         }
494
495         XGCValues gcv;
496         gcv.graphics_exposures = False;
497         _gc = XCreateGC( display(), window(), GCGraphicsExposures, &gcv );
498         if( ! _gc )
499             fprintf( stderr, "XCreateGC failed!\n" );
500         
501         _shmEventType = ShmImage::query( display() );
502         if( _shmEventType )
503         {
504             printf( "Using X11 MITSHM extension\n" );
505             _usingShm = true;   // May provide a user disable for Shm later.
506         }
507
508         resizeFramebuffer();
509     }
510     else
511     {
512         fprintf( stderr, "XMatchVisualInfo failed!\n" );
513     }
514 }
515
516
517 HexenWindow::~HexenWindow()
518 {
519     if( _vinfo.depth == 8 )
520     {
521         if( _colormap )
522             XFreeColormap( display(), _colormap );
523     }
524     else
525     {
526         int i;
527         for( i = 0; i < MAX_PAL_CACHE; i++ )
528             _palc[ i ].free( display(), _colormap );
529     }
530
531     if( _usingShm )
532     {
533         delete _simage;
534     }
535     else if( _ximage )
536     {
537         delete _ximage->data;
538         XDestroyImage( _ximage );
539     }
540 }
541
542
543 void HexenWindow::setPalette( byte* palette )
544 {
545     int i, c;
546
547     if( _vinfo.c_class == PseudoColor && _vinfo.depth == 8 )
548     {
549         XColor colors[ 256 ];
550
551         for( i = 0 ; i < 256 ; i++ )
552         {
553             colors[ i ].pixel = i;
554             colors[ i ].flags = DoRed | DoGreen | DoBlue;
555
556             c = gammatable[usegamma][*palette++];
557             colors[ i ].red = (c << 8) + c;
558             
559             c = gammatable[usegamma][*palette++];
560             colors[ i ].green = (c << 8) + c;
561
562             c = gammatable[usegamma][*palette++];
563             colors[ i ].blue = (c << 8) + c;
564         }
565
566         XStoreColors( display(), _colormap, colors, 256 );
567     }
568     else
569     {
570         XColor color;
571
572         // It looks like we could get away with caching as little as
573         // three palettes to avoid most re-allocations.
574
575         // Must update the entire screen when palette changes in truecolor mode.
576         UpdateState |= I_FULLSCRN;
577
578 #ifdef PAL_CACHE_ON
579         if( usegamma != _cacheGamma )
580         {
581             // The gamma has changed so the entire cache must be thrown out.
582             for( i = 0; i < MAX_PAL_CACHE; i++ )
583                 _palc[ i ].free( display(), _colormap );
584             _cacheAge = 0;
585             _cacheGamma = usegamma;
586             //printf( "palette gamma\n" );
587         }
588
589         // Search for palette in cache.
590         for( i = 0; i < MAX_PAL_CACHE; i++ )
591         {
592             if( _palc[ i ].id == palette )
593             {
594                 // Found palette.
595                 _pcurrent = &_palc[ i ];
596                 _pcurrent->used = ++_cacheAge;
597
598                 //printf( "palette %d %p - cache\n", i, palette );
599
600                 return;
601             }
602         }
603 #endif
604
605         // Search for unused cache.  Otherwise use the oldest cache.
606         _pcurrent = &_palc[ 0 ];
607
608 #ifdef PAL_CACHE_ON
609         for( i = 0; i < MAX_PAL_CACHE; i++ )
610         {
611             if( ! _palc[ i ].id )
612             {
613                 // Unused cache.
614                 _pcurrent = &_palc[ i ];
615                 break;
616             }
617             if( _palc[ i ].used < _pcurrent->used )
618                 _pcurrent = &_palc[ i ];
619         }
620 #endif
621
622         //printf( "palette %d %p - new\n", i, palette );
623
624         _pcurrent->free( display(), _colormap );
625         _pcurrent->used = ++_cacheAge;
626         _pcurrent->id = palette;
627
628         for( i = 0 ; i < 256 ; i++ )
629         {
630             color.pixel = 0;
631             color.flags = DoRed | DoGreen | DoBlue;
632
633             c = gammatable[usegamma][*palette++];
634             color.red = (c << 8);
635             
636             c = gammatable[usegamma][*palette++];
637             color.green = (c << 8);
638
639             c = gammatable[usegamma][*palette++];
640             color.blue = (c << 8);
641
642             if( ! XAllocColor( display(), _colormap, &color ) )
643             {
644                 fprintf( stderr," XAllocColor failed\n" );
645             }
646
647             _pcurrent->pixel[ i ] = color.pixel;
648         }
649     }
650 }
651
652
653 // Predicate procedure used by waitOnShmPut()
654
655 struct PPArg
656 {
657     PPArg( Window w, int type ) : window( w ), shmCompletionType( type ) {}
658
659     Window window;
660     int shmCompletionType;
661 };
662
663 static Bool _shmPredicateProc( Display* dis, XEvent* event, XPointer arg )
664 {
665     if( (event->xany.window == ((PPArg*)arg)->window) &&
666         (event->type == ((PPArg*)arg)->shmCompletionType) )
667     {
668         return True;
669     }
670     return False;
671 }
672
673 void HexenWindow::waitForShmPut()
674 {
675     XEvent event;
676     PPArg arg( window(), _shmEventType );
677     XIfEvent( display(), &event, _shmPredicateProc, (XPointer) &arg );
678 }
679
680
681 typedef unsigned char   pixel8;
682 typedef unsigned short  pixel16;
683 typedef unsigned long   pixel32;
684
685 static void blit_8_8( pixel8* source, XImage* img,
686                       int x, int y, int w, int h )
687 {
688     register pixel8* begin;
689
690     begin = (pixel8*) img->data;
691     begin += x + (y * img->bytes_per_line);
692     while( h-- )
693     {
694         memcpy( begin, source, w );
695         begin += img->bytes_per_line;
696         source += w;
697     }
698 }
699
700
701 static void blit_double_8_8( pixel8* source, XImage* img,
702                              int x, int y, int w, int h )
703 {
704     pixel8 p;
705     pixel8* begin;
706     pixel8* end;
707     register pixel8* dst;
708     register pixel8* src;
709
710     begin = (pixel8*) img->data;
711     begin += (x * 2) + (y * img->bytes_per_line * 2);
712     src = source;
713     while( h-- )
714     {
715         dst = begin;
716         end = dst + (w * 2);
717         while( dst != end )
718         {
719             p = *src++;
720             *dst++ = p;
721             *dst++ = p;
722         }
723
724         memcpy( begin + img->bytes_per_line, begin, w * 2 );
725
726         begin += img->bytes_per_line * 2;
727     }
728 }
729
730
731 static void blit_8_16( pixel8* source, XImage* img,
732                        int x, int y, int w, int h,
733                        unsigned long* pixel )
734 {
735     pixel16* begin;
736     pixel16* end;
737     register pixel16* dst;
738     register pixel8* src;
739          
740     begin = (pixel16*) img->data;
741     begin += x + (y * img->bytes_per_line / 2);
742     src = source;
743     while( h-- )
744     {
745         dst = begin;
746         end = dst + w;
747         while( dst != end )
748             *dst++ = pixel[ *src++ ];
749         begin += img->bytes_per_line / 2;
750     }
751 }
752
753
754 static void blit_double_8_16( pixel8* source, XImage* img,
755                              int x, int y, int w, int h,
756                              unsigned long* pixel )
757 {
758     pixel16 p;
759     pixel16* begin;
760     pixel16* end;
761     register pixel16* dst;
762     register pixel8* src;
763          
764     begin = (pixel16*) img->data;
765     begin += (x * 2) + (y * img->bytes_per_line);
766     src = source;
767     while( h-- )
768     {
769         dst = begin;
770         end = dst + (w * 2);
771         while( dst != end )
772         {
773             p = pixel[ *src++ ];
774             *dst++ = p;
775             *dst++ = p;
776         }
777
778         dst = begin + (img->bytes_per_line / 2);
779         memcpy( dst, begin, w * 4 );
780
781         begin += img->bytes_per_line;
782     }
783 }
784
785
786 static void blit_8_32( pixel8* source, XImage* img,
787                        int x, int y, int w, int h,
788                        unsigned long* pixel )
789 {
790     pixel32* begin;
791     pixel32* end;
792     register pixel32* dst;
793     register unsigned char* src;
794          
795     begin = (pixel32*) img->data;
796     begin += x + (y * img->bytes_per_line / 4);
797     src = source;
798     while( h-- )
799     {
800         dst = begin;
801         end = dst + w;
802         while( dst != end )
803             *dst++ = pixel[ *src++ ];
804         begin += img->bytes_per_line / 4;
805     }
806 }
807
808
809 static void blit_double_8_32( pixel8* source, XImage* img,
810                              int x, int y, int w, int h,
811                              unsigned long* pixel )
812 {
813     pixel32 p;
814     pixel32* begin;
815     pixel32* end;
816     register pixel32* dst;
817     register pixel8* src;
818          
819     begin = (pixel32*) img->data;
820     begin += (x * 2) + (y * img->bytes_per_line / 2);
821     src = source;
822     while( h-- )
823     {
824         dst = begin;
825         end = dst + (w * 2);
826         while( dst != end )
827         {
828             p = pixel[ *src++ ];
829             *dst++ = p;
830             *dst++ = p;
831         }
832
833         dst = begin + (img->bytes_per_line / 4);
834         memcpy( dst, begin, w * 8 );
835
836         begin += img->bytes_per_line / 2;
837     }
838 }
839
840
841 void HexenWindow::blit( unsigned char* buffer, int x, int y, int w, int h )
842 {
843     buffer += x + (y * w);
844
845     if( (width() >= SCREENWIDTH*2) && (height() >= SCREENHEIGHT*2) )
846     {
847         if( _vinfo.depth == 8 )
848         {
849             blit_double_8_8( buffer, _ximage, x, y, w, h );
850         }
851         else if( _vinfo.depth <= 16 )
852         {
853             blit_double_8_16( buffer, _ximage, x, y, w, h, _pcurrent->pixel );
854         }
855         else
856         {
857             blit_double_8_32( buffer, _ximage, x, y, w, h, _pcurrent->pixel );
858         }
859         x *= 2;
860         y *= 2;
861         w *= 2;
862         h *= 2;
863     }
864     else
865     {
866         if( _vinfo.depth == 8 )
867         {
868             blit_8_8( buffer, _ximage, x, y, w, h );
869         }
870         else if( _vinfo.depth <= 16 )
871         {
872             blit_8_16( buffer, _ximage, x, y, w, h, _pcurrent->pixel );
873         }
874         else
875         {
876             blit_8_32( buffer, _ximage, x, y, w, h, _pcurrent->pixel );
877         }
878     }
879
880     if( _usingShm )
881     {
882         XShmPutImage( display(), window(), _gc, _ximage, x, y, x, y,
883                       w, h, True );
884         waitForShmPut();
885     }
886     else
887     {
888         XPutImage( display(), window(), _gc, _ximage, x, y, x, y, w, h );
889         sync();
890     }
891 }
892
893
894 void HexenWindow::resizeFramebuffer()
895 {
896     if(_ximage && (_ximage->width == width()) && (_ximage->height == height()))
897     {
898        return; 
899     }
900
901     if( _usingShm )
902     {
903         delete _simage;
904         _simage = new ShmImage( display(), width(), height(), &_vinfo );
905         _ximage = _simage->image();
906     }
907     else
908     {
909         if( _ximage )
910         {
911             delete _ximage->data;
912             XDestroyImage( _ximage );
913         }
914         _ximage = XCreateImage( display(), _vinfo.visual, _vinfo.depth,
915                                 ZPixmap, 0, 0,
916                                 width(), height(),
917                                 (_vinfo.depth == 8) ? 8 : 32, 0 );
918         _ximage->data = new char[ _ximage->bytes_per_line * _ximage->height ];
919     }
920
921     UpdateState |= I_FULLSCRN;
922 }
923
924
925 bool HexenWindow::getVisualInfo( XVisualInfo* vi )
926 {
927     if( XMatchVisualInfo( display(), screen(), 8, PseudoColor, vi ) )
928         return true;
929
930     if( XMatchVisualInfo( display(), screen(), 16, TrueColor, vi ) )
931         return true;
932     if( XMatchVisualInfo( display(), screen(), 15, TrueColor, vi ) )
933         return true;
934
935     if( XMatchVisualInfo( display(), screen(), 32, TrueColor, vi ) )
936         return true;
937     if( XMatchVisualInfo( display(), screen(), 24, TrueColor, vi ) )
938         return true;
939
940 #if 0
941     if( XMatchVisualInfo( display(), screen(), 8, GrayScale, vi ) )
942         return True;
943 #endif
944  
945     return false;
946 }
947
948
949 void HexenWindow::deleteEvent( XEvent* )
950 {
951     I_Quit();
952 }
953
954 void HexenWindow::configureEvent( XConfigureEvent* e )
955 {
956     resizeFramebuffer();
957     //printf( "configure %d %d\n", width(), height() );
958 }
959
960 void HexenWindow::unknownEvent( XEvent* e )
961 {
962     //printf( "Unknown XEvent: %d\n", e->type );
963 }
964
965
966 void HexenWindow::buttonDown( XButtonEvent* e )
967 {
968     //printf( "buttonDown: %d %d,%d\n", e->button, e->x, e->y );
969
970 //    if( ! _grabCursor )
971 //        grabPointer();
972
973     switch( e->button )
974     {
975         case Button1: _buttons |= MOUSEB1 ; break;
976         case Button2: _buttons |= MOUSEB2 ; break;
977         case Button3: _buttons |= MOUSEB3 ; break;
978         default:
979             return;
980     }
981     postMouseEvent( 0, 0 );
982 }
983
984
985 void HexenWindow::buttonUp( XButtonEvent* e )
986 {
987     //printf( "buttonUp: %d %d,%d\n", e->button, e->x, e->y );
988
989     switch( e->button )
990     {
991         case Button1: _buttons &= ~MOUSEB1 ; break;
992         case Button2: _buttons &= ~MOUSEB2 ; break;
993         case Button3: _buttons &= ~MOUSEB3 ; break;
994         default:
995             return;
996     }
997     postMouseEvent( 0, 0 );
998 }
999
1000
1001 void HexenWindow::motionEvent( XMotionEvent* e )
1002 {
1003
1004     int dx,dy;
1005     
1006     if(e->x == width()/2 && e->y == height()/2)
1007     {
1008         _prevX = width()/2;
1009         _prevY = height()/2;
1010         return;
1011     }
1012     dx = (e->x - _prevX);
1013     _prevX = e->x;
1014     dy = (e->y - _prevY);
1015     _prevY = e->y;
1016
1017     if( dx || dy )
1018     {
1019         postMouseEvent( dx, dy );
1020
1021         if (_grabCursor)
1022         {
1023
1024             if( (e->x < MOUSE_JUMP_AT) || (e->x > (width() - MOUSE_JUMP_AT)) ||
1025                 (e->y < MOUSE_JUMP_AT) || (e->y > (height() - MOUSE_JUMP_AT)) )
1026             {
1027                 XWarpPointer( display(), None, window(), 0, 0, 0, 0,
1028                               width() / 2, height() / 2 );
1029                 _prevX = width()/2; _prevY = height()/2;
1030             }
1031             else
1032             {
1033                postMouseEvent( dx, dy);
1034             }
1035         }
1036         else
1037         {
1038           postMouseEvent( dx, dy);
1039         }
1040   }
1041 }
1042
1043
1044 void HexenWindow::keyDown( XKeyEvent* e )
1045 {
1046     KeySym key = keysym( e );
1047
1048     //TODO: filter key repeat.
1049
1050     //printf( "keyDown: %lx %x\n", e->time, key );
1051
1052     if( e->state & Mod1Mask )   // Control key defaults to attack.
1053     {
1054         if( key == XK_d )
1055         {
1056             if( width() == SCREENWIDTH )
1057             {
1058                 resize( SCREENWIDTH * 2, SCREENHEIGHT * 2 );
1059             }
1060             else
1061             {
1062                 resize( SCREENWIDTH, SCREENHEIGHT );
1063             }
1064         }
1065         else if( key == XK_g )
1066         {
1067             if( _grabCursor )
1068             {
1069                 ungrabPointer();
1070             }
1071             else
1072             {
1073                 grabPointer();
1074             }
1075         }   
1076     }
1077 #if 0
1078     else if( key == XK_Escape )
1079     {
1080         I_Quit();
1081     }
1082 #endif
1083     else
1084     {
1085         postKey( ev_keydown, key );
1086     }
1087 }
1088
1089
1090 void HexenWindow::keyUp( XKeyEvent* e )
1091 {
1092     //printf( "keyUp: %lx %x %x\n", e->time, e->state, e->keycode );
1093
1094     postKey( ev_keyup, keysym( e ) );
1095 }
1096
1097
1098 void HexenWindow::exposeEvent( XExposeEvent* )
1099 {
1100     //printf( "expose\n" );
1101     UpdateState |= I_FULLSCRN;
1102 }
1103
1104
1105 void HexenWindow::postKey( evtype_t type, KeySym key )
1106 {
1107         event_t ev;
1108
1109     ev.type = type;
1110
1111     switch( key )
1112     {
1113         case XK_Up:     ev.data1 = KEY_UPARROW;    break;
1114         case XK_Down:   ev.data1 = KEY_DOWNARROW;  break;
1115         case XK_Left:   ev.data1 = KEY_LEFTARROW;  break;
1116         case XK_Right:  ev.data1 = KEY_RIGHTARROW; break;
1117
1118         case XK_Escape: ev.data1 = KEY_ESCAPE;     break;
1119         case XK_Return: ev.data1 = KEY_ENTER;      break;
1120         case XK_F1:     ev.data1 = KEY_F1;         break;
1121         case XK_F2:     ev.data1 = KEY_F2;         break;
1122         case XK_F3:     ev.data1 = KEY_F3;         break;
1123         case XK_F4:     ev.data1 = KEY_F4;         break;
1124         case XK_F5:     ev.data1 = KEY_F5;         break;
1125         case XK_F6:     ev.data1 = KEY_F6;         break;
1126         case XK_F7:     ev.data1 = KEY_F7;         break;
1127         case XK_F8:     ev.data1 = KEY_F8;         break;
1128         case XK_F9:     ev.data1 = KEY_F9;         break;
1129         case XK_F10:    ev.data1 = KEY_F10;        break;
1130         case XK_F11:    ev.data1 = KEY_F11;        break;
1131         case XK_F12:    ev.data1 = KEY_F12;        break;
1132
1133         case XK_Insert:    ev.data1 = KEY_INS;     break;
1134         case XK_Delete:    ev.data1 = KEY_DEL;     break;
1135         case XK_Page_Up:   ev.data1 = KEY_PGUP;    break;
1136         case XK_Page_Down: ev.data1 = KEY_PGDN;    break;
1137         case XK_Home:      ev.data1 = KEY_HOME;    break;
1138         case XK_End:       ev.data1 = KEY_END;     break;
1139
1140         case XK_Tab:       ev.data1 = KEY_TAB;     break;
1141
1142         case XK_BackSpace: ev.data1 = KEY_BACKSPACE;  break;
1143
1144         case XK_Pause:     ev.data1 = KEY_PAUSE;      break;
1145
1146         case XK_equal:     ev.data1 = KEY_EQUALS;     break;
1147
1148         case XK_KP_Subtract:
1149         case XK_minus:     ev.data1 = KEY_MINUS;      break;
1150
1151         case XK_Shift_L:
1152         case XK_Shift_R:   ev.data1 = KEY_RSHIFT;     break;
1153
1154         case XK_Control_L:
1155         case XK_Control_R: ev.data1 = KEY_RCTRL;      break;
1156
1157         case XK_Alt_L:
1158         case XK_Alt_R:
1159         case XK_Meta_L:
1160         case XK_Meta_R:    ev.data1 = KEY_RALT;       break;
1161
1162         default:
1163             ev.data1 = key;
1164             break;
1165     }
1166
1167     H2_PostEvent( &ev );
1168 }
1169
1170
1171 void HexenWindow::postMouseEvent( int dx, int dy )
1172 {
1173         event_t ev;
1174
1175         ev.type  = ev_mouse;
1176         ev.data1 = _buttons;
1177         ev.data2 =  (short) dx << 2;
1178         ev.data3 = -(short) dy << 2;
1179
1180         H2_PostEvent( &ev );
1181 }
1182
1183
1184 //EOF