source: project/gl-display-glx/glx_display.c @ 3547

Last change on this file since 3547 was 3547, checked in by thu, 14 years ago

commit before removal of non gl-display files

File size: 17.7 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <math.h>
4
5#include <GL/glx.h>
6#include <X11/keysym.h>
7#include <X11/extensions/shape.h>
8
9#include <sys/time.h>
10
11#include "glx_display.h"
12
13
14#ifdef GLX_DISPLAY_SINGLESTATE
15 static gl_window_t _gl_window;
16 static gl_window_t * gl_window;
17#endif
18
19/* TODO clean file organization */
20void shape_window( gl_window_t  * gl_window, int width, int height );
21
22#ifdef GLX_DISPLAY_SINGLESTATE
23unsigned int
24get_width()
25{
26  return gl_window->width;
27}
28unsigned int
29get_height()
30{
31  return gl_window->height;
32}
33unsigned int
34get_screen_width()
35{
36  return gl_window->screen_width;
37}
38unsigned int
39get_screen_height()
40{
41  return gl_window->screen_height;
42}
43#else
44unsigned int
45get_width( gl_window_t  * gl_window )
46{
47  return gl_window->width;
48}
49unsigned int
50get_height( gl_window_t  * gl_window )
51{
52  return gl_window->height;
53}
54unsigned int
55get_screen_width( gl_window_t  * gl_window )
56{
57  return gl_window->screen_width;
58}
59unsigned int
60get_screen_height( gl_window_t  * gl_window )
61{
62  return gl_window->screen_height;
63}
64#endif
65 
66void
67enable_autorepeat (
68#ifndef GLX_DISPLAY_SINGLESTATE
69  gl_window_t  * gl_window
70#endif
71  )
72{
73  gl_window->autorepeat_flag = 1;
74}
75
76void
77disable_autorepeat (
78#ifndef GLX_DISPLAY_SINGLESTATE
79  gl_window_t  * gl_window
80#endif
81  )
82{
83  gl_window->autorepeat_flag = 0;
84}
85
86void
87enable_centered_cursor (
88#ifndef GLX_DISPLAY_SINGLESTATE
89  gl_window_t  * gl_window
90#endif
91  )
92{
93  gl_window->center_cursor_flag = 1;
94  gl_window->cycling_cursor_flag = 0;
95}
96
97void
98disable_centered_cursor (
99#ifndef GLX_DISPLAY_SINGLESTATE
100  gl_window_t  * gl_window
101#endif
102  )
103{
104  gl_window->center_cursor_flag = 0;
105}
106
107void
108enable_cycling_cursor (
109#ifndef GLX_DISPLAY_SINGLESTATE
110  gl_window_t  * gl_window
111#endif
112  )
113{
114  gl_window->cycling_cursor_flag = 1;
115  gl_window->center_cursor_flag = 0;
116}
117
118void
119disable_cycling_cursor (
120#ifndef GLX_DISPLAY_SINGLESTATE
121  gl_window_t  * gl_window
122#endif
123  )
124{
125  gl_window->cycling_cursor_flag = 0;
126}
127
128void
129destroy_gl_window (
130#ifndef GLX_DISPLAY_SINGLESTATE
131  gl_window_t  * gl_window
132#endif
133  )
134{
135  if ( gl_window->glx_context )
136  {
137    glXMakeCurrent( gl_window->display, None, NULL );
138    glXDestroyContext( gl_window->display, gl_window->glx_context );
139    gl_window->glx_context = NULL;
140  }
141  /* TODO */
142  glXDestroyWindow(gl_window->display, gl_window->glx_window);
143  XDestroyWindow(gl_window->display, gl_window->window);
144   /* if (GLWin.fs)
145    {
146        XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode);
147        XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
148    }*/
149
150  XCloseDisplay(gl_window->display);
151}
152
153/* local routines */
154int query_extensions_glx (Display * display);
155void exit_on_err (char * s);
156
157/*
158**
159*/
160
161#ifndef GLX_DISPLAY_SINGLESTATE
162  gl_window_t  *
163#else
164  void
165#endif
166create_gl_window (
167/*              const char * title, */
168                unsigned int width,
169                unsigned int height,
170                int double_buffered,
171                int fullscreen,
172                int no_border,
173                int use_shape_extension)
174{
175  int nelements;
176  GLXFBConfig * fbconfigs;
177  XVisualInfo * vi;
178 
179  int attrlist[] = {
180  /*  GLX_RGBA, */
181    GLX_DOUBLEBUFFER, double_buffered ? True : False,
182    GLX_RED_SIZE, 4,
183    GLX_GREEN_SIZE, 4,
184    GLX_BLUE_SIZE, 4,
185    GLX_DEPTH_SIZE, 16,
186    None };
187
188  XWindowAttributes root_attributes;
189
190#ifdef GLX_DISPLAY_SINGLESTATE
191  gl_window = & _gl_window;
192#else
193  gl_window_t  * gl_window = (gl_window_t *)malloc( sizeof(gl_window_t) );
194#endif
195
196  gl_window->width                = width;
197  gl_window->height               = height;
198  gl_window->double_buffered_flag = double_buffered;
199  gl_window->fullscreen_flag      = fullscreen;
200  gl_window->motion_dx = 0;
201  gl_window->motion_dy = 0;
202
203
204  gl_window->display = XOpenDisplay( NULL );
205  if( !gl_window->display )
206    exit_on_err(" XOpenDisplay failed.");
207 
208  gl_window->screen = DefaultScreen( gl_window->display );
209
210  /* TODO error handling */
211  XGetWindowAttributes( gl_window->display,
212                  RootWindow( gl_window->display,
213                              gl_window->screen ),
214                  &root_attributes);
215  gl_window->screen_width  = root_attributes.width;
216  gl_window->screen_height = root_attributes.height;
217
218  if ( fullscreen )
219  {
220    width  = gl_window->width  = gl_window->screen_width;
221    height = gl_window->height = gl_window->screen_height;
222  }
223
224  if( ! query_extensions_glx(gl_window->display) )
225    exit_on_err(" No supported glX extension.");
226
227  fbconfigs = glXChooseFBConfig( gl_window->display,
228                                 gl_window->screen,
229                                 attrlist,
230                                 &nelements );
231
232  vi = glXGetVisualFromFBConfig( gl_window->display, fbconfigs[0] );
233
234  gl_window->attributes.colormap = XCreateColormap( gl_window->display,
235                                   RootWindow( gl_window->display,
236                                               vi->screen ),
237                                   vi->visual, AllocNone);
238  gl_window->attributes.border_pixel = 0;
239  gl_window->attributes.background_pixel = 0;
240  gl_window->attributes.event_mask =
241    StructureNotifyMask | ExposureMask      |
242    KeyPressMask        | KeyReleaseMask    |
243    ButtonPressMask     | ButtonReleaseMask |
244    PointerMotionMask   | LeaveWindowMask   |
245    EnterWindowMask;
246  /* gl_window->attributes.override_redirect = 1; */
247
248  gl_window->window = XCreateWindow( gl_window->display,
249                       RootWindow( gl_window->display, vi->screen ),
250                      (1280-width)/2,(800-height)/2, width,height , 0,
251                      vi->depth, InputOutput, vi->visual,
252
253                      CWBorderPixel | CWBackPixel |
254                      CWColormap | CWEventMask /*| CWOverrideRedirect*/,
255
256                      &gl_window->attributes);
257  /* FIXME handle this ?*/
258  if ( !fullscreen && no_border )
259  {
260    shape_window( gl_window, width, height );
261  }
262
263  gl_window->glx_window = glXCreateWindow( gl_window->display, fbconfigs[0], gl_window->window, 0);
264
265  gl_window->glx_context = glXCreateNewContext( gl_window->display, fbconfigs[0],
266                           GLX_RGBA_TYPE, 0, GL_TRUE);
267
268  glXMakeContextCurrent( gl_window->display, gl_window->glx_window, gl_window->glx_window, gl_window->glx_context);
269
270  XMapWindow(gl_window->display, gl_window->window);
271  for (;;)
272  {
273    XEvent e;
274    XNextEvent( gl_window->display, &e );
275    if ( e.type == MapNotify ) break;
276  }
277
278  /* TODO provide the following to scheme side
279  if( glXIsDirect(gl_window->display, gl_window->glx_context) )
280    printf(" Direct Rendering.\n");
281  else
282    printf(" No Direct Rendering.\n");
283  */
284
285  XFree(fbconfigs);
286  XFree(vi);
287 
288#ifndef GLX_DISPLAY_SINGLESTATE
289  return gl_window;
290#endif
291}
292
293void
294grab_keyboard(
295#ifndef GLX_DISPLAY_SINGLESTATE
296  gl_window_t  * gl_window
297#endif
298  )
299{
300  XGrabKeyboard(gl_window->display, gl_window->window, True,
301                  GrabModeAsync, GrabModeAsync, CurrentTime); 
302}
303
304void
305grab_mouse(
306#ifndef GLX_DISPLAY_SINGLESTATE
307  gl_window_t  * gl_window
308#endif
309  )
310{
311  XGrabPointer(gl_window->display, gl_window->window, True, ButtonPressMask,
312                  GrabModeAsync, GrabModeAsync,
313                  gl_window->window, None, CurrentTime);
314}
315
316void
317warp_mouse(
318#ifndef GLX_DISPLAY_SINGLESTATE
319  gl_window_t  * gl_window,
320#endif
321  int x, int y
322  )
323{
324  XWarpPointer( gl_window->display, None, gl_window->window, 0,0,0,0,
325               /* gl_window->screen_width/2 , gl_window->screen_height/2 ); */
326                  x , y );
327}
328
329
330void
331swap_buffers (
332#ifndef GLX_DISPLAY_SINGLESTATE
333  gl_window_t  * gl_window
334#endif
335  )
336{
337  if ( gl_window->double_buffered_flag )
338  {
339    glXSwapBuffers( gl_window->display, gl_window->glx_window );
340  }
341  else
342  {
343    glFlush();
344  }
345}
346
347/* TODO make those function accept a gl_wondow_t *,
348 * no more an XEvent, like the event_dx function.
349 */
350int event_type( XEvent * e ) { return e->type; }
351int event_x( XButtonEvent * e ) { return e->x; }
352int event_y( XButtonEvent * e ) { return e->y; }
353int event_button( XButtonEvent * e ) { return e->button; }
354int event_xkeycode( XEvent * e ) { return XLookupKeysym( &e->xkey, 0 ); }
355int
356event_dx (
357#ifndef GLX_DISPLAY_SINGLESTATE
358  gl_window_t  * gl_window
359#endif
360  )
361{
362  return gl_window->motion_dx;
363}
364int
365event_dy (
366#ifndef GLX_DISPLAY_SINGLESTATE
367  gl_window_t  * gl_window
368#endif
369  )
370{
371  return gl_window->motion_dy;
372}
373
374/*
375 * Returns a (pointer to a) XEvent.
376 * The type of the event could be LASTEvent + 1 if there's no actual event.
377 */
378XEvent *
379receive_event (
380#ifndef GLX_DISPLAY_SINGLESTATE
381  gl_window_t  * gl_window
382#endif
383  )
384{
385  int repeating = 1;
386  int need_warp = 0;
387
388  if ( gl_window->pending == 0 )
389    gl_window->pending = XPending( gl_window->display );
390 
391  while ( gl_window->pending > 0 && repeating )
392  {
393    repeating = 0;
394    XNextEvent( gl_window->display, &gl_window->e );
395    gl_window->pending--;
396
397    /* Handle autorepeat.
398     * The mechanic is taken from Quake3.
399     * In Quake3, they assume the KeyRelease and
400     * the following KeyPress have the same time.
401     * Here, I've added a delta of 10 because
402     * I experienced different times for
403     * autorepeating events (actually, it was only
404     * a delta of 1 millisecond...).
405     */
406    if ( gl_window->e.type == KeyRelease && !gl_window->autorepeat_flag )
407    {
408      if ( gl_window->pending == 0 )
409        gl_window->pending = XPending( gl_window->display );
410      if ( gl_window->pending > 0 )
411      {
412        XEvent peekevent;
413        XPeekEvent( gl_window->display, &peekevent );
414        if ((peekevent.type == KeyPress) &&
415            (peekevent.xkey.keycode == gl_window->e.xkey.keycode) &&
416            (peekevent.xkey.time >= gl_window->e.xkey.time &&
417             peekevent.xkey.time <= gl_window->e.xkey.time + 10))
418        {
419          /* it's autorepeating, remove the KeyPress. */
420          XNextEvent( gl_window->display, &gl_window->e );
421          gl_window->pending--;
422          repeating = 1;
423        }
424      }
425    }
426  }
427 
428  if ( repeating )  /* No event. */
429  {
430    gl_window->e.type = LASTEvent + 1; /* means 'no event' */
431  }
432  else              /* We have a meaningful event structure to return. */
433  {
434    if ( gl_window->e.type == MotionNotify )
435    {
436      int x, y;
437      x = gl_window->e.xmotion.x;
438      y = gl_window->e.xmotion.y;
439
440      if ( gl_window->center_cursor_flag &&
441          x == gl_window->width  / 2 &&
442          y == gl_window->height / 2 )
443      { /* Cursor goes to center because we've warped it. */
444        gl_window->last_x = gl_window->width  / 2;
445        gl_window->last_y = gl_window->height / 2;
446
447        gl_window->e.type = LASTEvent + 1; /* means 'no event' */
448      }
449      else
450      {
451        gl_window->motion_dx = x - gl_window->last_x;
452        gl_window->motion_dy = y - gl_window->last_y;
453        gl_window->last_x = x;
454        gl_window->last_y = y;
455
456        if ( gl_window->center_cursor_flag &&
457            (abs(x - gl_window->width  / 2) > gl_window->width  / 3 ||
458             abs(y - gl_window->height / 2) > gl_window->height / 3 ) )
459          warp_mouse( gl_window, gl_window->width / 2, gl_window->height / 2 );
460      }
461    }
462    else if ( gl_window->cycling_cursor_flag && gl_window->e.type == LeaveNotify )
463    {
464      int x, y;
465      x = gl_window->e.xmotion.x;
466      y = gl_window->e.xmotion.y;
467     
468      while ( x >= gl_window->width )
469        x -= gl_window->width;
470      while ( y >= gl_window->height )
471        y -= gl_window->height;
472      while ( x < 0 )
473        x += gl_window->width;
474      while ( y < 0 )
475        y += gl_window->height;
476
477      gl_window->last_x = x;
478      gl_window->last_y = y;
479
480      /* This will generate an EnterNotify, not a MotionNotify. */
481      warp_mouse( gl_window, x, y );
482    }
483  }
484
485
486  return (void *) &gl_window->e;
487}
488
489/*
490** local routines
491*/
492int query_extensions_glx(Display * dpy)
493{
494  int major, minor;
495
496
497  if(! glXQueryExtension(dpy, NULL, NULL))
498    return 0;
499
500  glXQueryVersion(dpy, &major, &minor);
501  if( (major == 1) && (minor < 3) )
502    {
503      printf(" glX version unsupported : less than 1.3\n");
504      return 0;
505    }
506
507  /* provide to scheme side
508  printf(" glX vendor     : %s\n",
509         glXGetClientString(dpy, GLX_VENDOR) );
510  printf(" glX version    : %s\n",
511         glXGetClientString(dpy, GLX_VERSION) );
512  printf(" glX extensions : %s\n",
513         glXGetClientString(dpy, GLX_EXTENSIONS) );
514  */
515
516  return 1;
517
518}
519
520void exit_on_err(char * s)
521{
522  fprintf(stderr, "%s\n", s);
523  exit(1);
524}
525
526
527void
528shape_window( gl_window_t  * gl_window, int width, int height )
529{
530  XRectangle rectangles[3];
531  int n_rectangles = 3;
532
533  rectangles[0].x = 1;
534  rectangles[0].y = 0;
535  rectangles[0].width = width - 2;
536  rectangles[0].height = 1;
537 
538  rectangles[1].x = 0;
539  rectangles[1].y = 1;
540  rectangles[1].width = width;
541  rectangles[1].height = height - 2;
542  rectangles[2].x = 1;
543  rectangles[2].y = height - 1;
544  rectangles[2].width = width - 2;
545  rectangles[2].height = 1;
546
547  XShapeCombineRectangles(gl_window->display, gl_window->window, ShapeBounding, 0, 0,
548                  rectangles, n_rectangles, ShapeSet, 0);
549}
550
551
552Cursor CreateNullPointer (
553#ifndef GLX_DISPLAY_SINGLESTATE
554  gl_window_t  * gl_window
555#endif
556  )
557{
558  Cursor cursor;
559  Pixmap pm;
560  GC ctx;
561  XGCValues val;
562  XColor color;
563
564  pm = XCreatePixmap( gl_window->display, RootWindow(gl_window->display, gl_window->screen), 1, 1, 1);
565  val.function = GXclear;
566  ctx = XCreateGC(gl_window->display, pm, GCFunction, &val);
567
568  color.pixel = 0;
569  color.red = 0;
570  color.flags = 0; /*04;*/
571  cursor = XCreatePixmapCursor(gl_window->display, pm, pm, &color, &color, 0,0);
572
573  XFreePixmap(gl_window->display, pm);
574  XFreeGC(gl_window->display, ctx);
575
576  return cursor;
577}
578
579void disable_cursor (
580#ifndef GLX_DISPLAY_SINGLESTATE
581  gl_window_t  * gl_window
582#endif
583  )
584{
585  XDefineCursor( gl_window->display, gl_window->window, CreateNullPointer(gl_window) );
586}
587
588
589
590
591
592int time_milliseconds( void )
593{
594  static unsigned long time_base = 0;
595  struct timeval tp;
596 
597  gettimeofday (&tp, NULL);
598  if ( !time_base )
599  {
600    time_base = tp.tv_sec;
601    return tp.tv_usec / 1000;
602  }
603
604  int current = (tp.tv_sec - time_base)*1000 + tp.tv_usec/1000;
605  return current;
606}
607
608
609/* Translate an XKeyPressed or XKeyReleased event to a
610 * gl-display keycode (i.e. translate the enclosed X keycode
611 * to a gl-display keycode).
612 * X keycodes are in [8-255], so gl-display keycodes are.
613 */
614
615unsigned int
616event_keycode( XKeyEvent * e )
617{
618  KeySym keysym;
619
620  unsigned int keycode = 0;
621
622  keysym = event_xkeycode( (XEvent *) e );
623
624  /* printf("keysym : %x\n", keysym); */
625 
626  if ( keysym >= 33 && keysym <= 127 )
627  {
628    keycode = (unsigned int) keysym;
629    /* printf("between ! and _ : %x\n", keysym);
630    printf("between ! and _ : %x\n", keycode); */
631  }
632  else
633  {
634  switch ( keysym )
635  {
636    case XK_KP_Page_Up:
637    case XK_KP_9:        keycode = K_KP_PAGE_UP; break;
638    case XK_Page_Up:     keycode = K_PAGE_UP;    break;
639
640    case XK_KP_Page_Down:
641    case XK_KP_3:        keycode = K_KP_PAGE_DOWN; break;
642    case XK_Page_Down:   keycode = K_PAGE_DOWN;    break;
643
644    case XK_KP_Home:     keycode = K_KP_HOME; break;
645    case XK_KP_7:        keycode = K_KP_HOME; break;
646    case XK_Home:        keycode = K_HOME;    break;
647
648    case XK_KP_End:
649    case XK_KP_1:        keycode = K_KP_END; break;
650    case XK_End:         keycode = K_END;    break;
651
652    case XK_KP_Left:     keycode = K_KP_LEFT_ARROW; break;
653    case XK_KP_4:        keycode = K_KP_LEFT_ARROW; break;
654    case XK_Left:        keycode = K_LEFT_ARROW;    break;
655
656    case XK_KP_Right:    keycode = K_KP_RIGHT_ARROW; break;
657    case XK_KP_6:        keycode = K_KP_RIGHT_ARROW; break;
658    case XK_Right:       keycode = K_RIGHT_ARROW;    break;
659
660    case XK_KP_Down:
661    case XK_KP_2:        keycode = K_KP_DOWN_ARROW; break;
662    case XK_Down:        keycode = K_DOWN_ARROW;    break;
663
664    case XK_KP_Up:
665    case XK_KP_8:        keycode = K_KP_UP_ARROW;   break;
666    case XK_Up:          keycode = K_UP_ARROW; break;
667
668    case XK_Escape:      keycode = K_ESCAPE;  break;
669
670    case XK_KP_Enter:    keycode = K_KP_ENTER; break;
671    case XK_Return:      keycode = K_ENTER;    break;
672
673    case XK_Tab: keycode = K_TAB;      break;
674
675    case XK_F1:  keycode = K_F1;       break;
676    case XK_F2:  keycode = K_F2;       break;
677    case XK_F3:  keycode = K_F3;       break;
678    case XK_F4:  keycode = K_F4;       break;
679    case XK_F5:  keycode = K_F5;       break;
680    case XK_F6:  keycode = K_F6;       break;
681    case XK_F7:  keycode = K_F7;       break;
682    case XK_F8:  keycode = K_F8;       break;
683    case XK_F9:  keycode = K_F9;       break;
684    case XK_F10: keycode = K_F10;      break;
685    case XK_F11: keycode = K_F11;      break;
686    case XK_F12: keycode = K_F12;      break;
687
688    case XK_BackSpace: keycode = K_BACKSPACE; break;
689
690    case XK_KP_Delete:
691    case XK_KP_Decimal: keycode = K_KP_DELETE; break;
692    case XK_Delete:     keycode = K_DELETE;    break;
693
694    case XK_Pause:      keycode = K_PAUSE;  break;
695
696    case XK_Shift_L: keycode = K_LEFT_SHIFT;  break;
697    case XK_Shift_R: keycode = K_RIGHT_SHIFT; break;
698
699    case XK_Control_L: keycode = K_LEFT_CONTROL;  break;
700    case XK_Control_R: keycode = K_RIGHT_CONTROL; break;
701
702    case XK_Alt_L:
703    case XK_Meta_L: keycode = K_LEFT_ALT;  break;
704    case XK_Alt_R:
705    case XK_Meta_R: keycode = K_RIGHT_ALT; break;
706
707    case XK_KP_Begin:    keycode = K_KP_5;      break;
708
709    case XK_Insert:      keycode = K_INSERT;    break;
710    case XK_KP_Insert:
711    case XK_KP_0:        keycode = K_KP_INSERT; break;
712    case XK_KP_Multiply: keycode = K_KP_STAR;   break;
713    case XK_KP_Add:      keycode = K_KP_PLUS;   break;
714    case XK_KP_Subtract: keycode = K_KP_MINUS;  break;
715    case XK_KP_Divide:   keycode = K_KP_SLASH;  break;
716
717    case XK_space:
718    case XK_KP_Space: keycode = K_SPACE; break;
719  }
720
721  /*
722    printf("not between ! and _ : %x\n", keysym);
723    printf("not between ! and _ : %x\n", keycode);
724    */
725
726  } /* else */ 
727
728  return keycode;
729}
730
731/* TODO */
732/* Translate an XKeyPressed or XKeyReleased event to a
733 * gl-display keysym (i.e. translate the enclosed X keycode
734 * to a gl-display keysym).
735 * Are gl-display keysyms in unicode ?
736 */
737unsigned int
738event_keysym( XKeyEvent * e )
739{
740  KeySym keysym;
741  int found;
742
743  found = XLookupString( e, NULL, 0, &keysym, 0 );
744  if ( found == NoSymbol )
745    keysym = 0;
746
747  /* printf("keysym : %x\n", keysym); */
748
749  return (unsigned int) keysym;
750}
751/* TODO ask people who use chinese/japanese/... keyboards how to handle them. */
Note: See TracBrowser for help on using the repository browser.