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