132001f49Smrg/*
232001f49Smrg * Copyright (C) 2010 LunarG Inc.
332001f49Smrg *
432001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
532001f49Smrg * copy of this software and associated documentation files (the "Software"),
632001f49Smrg * to deal in the Software without restriction, including without limitation
732001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
832001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the
932001f49Smrg * Software is furnished to do so, subject to the following conditions:
1032001f49Smrg *
1132001f49Smrg * The above copyright notice and this permission notice shall be included
1232001f49Smrg * in all copies or substantial portions of the Software.
1332001f49Smrg *
1432001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1532001f49Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1732001f49Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1832001f49Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1932001f49Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2032001f49Smrg * DEALINGS IN THE SOFTWARE.
2132001f49Smrg *
2232001f49Smrg * Authors:
2332001f49Smrg *    Chia-I Wu <olv@lunarg.com>
2432001f49Smrg */
2532001f49Smrg
2632001f49Smrg#include <X11/Xlib.h>
2732001f49Smrg#include <X11/Xutil.h>
2832001f49Smrg#include <X11/keysym.h>
2932001f49Smrg
3032001f49Smrg#include "eglutint.h"
3132001f49Smrg
3232001f49Smrgvoid
3332001f49Smrg_eglutNativeInitDisplay(void)
3432001f49Smrg{
3532001f49Smrg   _eglut->native_dpy = XOpenDisplay(_eglut->display_name);
3632001f49Smrg   if (!_eglut->native_dpy)
3732001f49Smrg      _eglutFatal("failed to initialize native display");
3832001f49Smrg
3932001f49Smrg   _eglut->surface_type = EGL_WINDOW_BIT;
4032001f49Smrg}
4132001f49Smrg
4232001f49Smrgvoid
4332001f49Smrg_eglutNativeFiniDisplay(void)
4432001f49Smrg{
4532001f49Smrg   XCloseDisplay(_eglut->native_dpy);
4632001f49Smrg}
4732001f49Smrg
4832001f49Smrgvoid
4932001f49Smrg_eglutNativeInitWindow(struct eglut_window *win, const char *title,
5032001f49Smrg                       int x, int y, int w, int h)
5132001f49Smrg{
5232001f49Smrg   XVisualInfo *visInfo, visTemplate;
5332001f49Smrg   int num_visuals;
5432001f49Smrg   Window root, xwin;
5532001f49Smrg   XSetWindowAttributes attr;
5632001f49Smrg   unsigned long mask;
5732001f49Smrg   EGLint vid;
5832001f49Smrg
5932001f49Smrg   if (!eglGetConfigAttrib(_eglut->dpy,
6032001f49Smrg            win->config, EGL_NATIVE_VISUAL_ID, &vid))
6132001f49Smrg      _eglutFatal("failed to get visual id");
6232001f49Smrg
6332001f49Smrg   /* The X window visual must match the EGL config */
6432001f49Smrg   visTemplate.visualid = vid;
6532001f49Smrg   visInfo = XGetVisualInfo(_eglut->native_dpy,
6632001f49Smrg         VisualIDMask, &visTemplate, &num_visuals);
6732001f49Smrg   if (!visInfo)
6832001f49Smrg      _eglutFatal("failed to get an visual of id 0x%x", vid);
6932001f49Smrg
7032001f49Smrg   root = RootWindow(_eglut->native_dpy, DefaultScreen(_eglut->native_dpy));
7132001f49Smrg
7232001f49Smrg   /* window attributes */
7332001f49Smrg   attr.background_pixel = 0;
7432001f49Smrg   attr.border_pixel = 0;
7532001f49Smrg   attr.colormap = XCreateColormap(_eglut->native_dpy,
7632001f49Smrg         root, visInfo->visual, AllocNone);
7732001f49Smrg   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
7832001f49Smrg   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
7932001f49Smrg
8032001f49Smrg   xwin = XCreateWindow(_eglut->native_dpy, root, x, y, w, h,
8132001f49Smrg         0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr);
8232001f49Smrg   if (!xwin)
8332001f49Smrg      _eglutFatal("failed to create a window");
8432001f49Smrg
8532001f49Smrg   XFree(visInfo);
8632001f49Smrg
8732001f49Smrg   /* set hints and properties */
8832001f49Smrg   {
8932001f49Smrg      XSizeHints sizehints;
9032001f49Smrg      sizehints.x = x;
9132001f49Smrg      sizehints.y = y;
9232001f49Smrg      sizehints.width  = w;
9332001f49Smrg      sizehints.height = h;
9432001f49Smrg      sizehints.flags = USSize | USPosition;
9532001f49Smrg      XSetNormalHints(_eglut->native_dpy, xwin, &sizehints);
9632001f49Smrg      XSetStandardProperties(_eglut->native_dpy, xwin,
9732001f49Smrg            title, title, None, (char **) NULL, 0, &sizehints);
9832001f49Smrg   }
9932001f49Smrg
10032001f49Smrg   XMapWindow(_eglut->native_dpy, xwin);
10132001f49Smrg
10232001f49Smrg   win->native.u.window = xwin;
10332001f49Smrg   win->native.width = w;
10432001f49Smrg   win->native.height = h;
10532001f49Smrg}
10632001f49Smrg
10732001f49Smrgvoid
10832001f49Smrg_eglutNativeFiniWindow(struct eglut_window *win)
10932001f49Smrg{
11032001f49Smrg   XDestroyWindow(_eglut->native_dpy, win->native.u.window);
11132001f49Smrg}
11232001f49Smrg
11332001f49Smrgstatic int
11432001f49Smrglookup_keysym(KeySym sym)
11532001f49Smrg{
11632001f49Smrg   int special;
11732001f49Smrg
11832001f49Smrg   switch (sym) {
11932001f49Smrg   case XK_F1:
12032001f49Smrg      special = EGLUT_KEY_F1;
12132001f49Smrg      break;
12232001f49Smrg   case XK_F2:
12332001f49Smrg      special = EGLUT_KEY_F2;
12432001f49Smrg      break;
12532001f49Smrg   case XK_F3:
12632001f49Smrg      special = EGLUT_KEY_F3;
12732001f49Smrg      break;
12832001f49Smrg   case XK_F4:
12932001f49Smrg      special = EGLUT_KEY_F4;
13032001f49Smrg      break;
13132001f49Smrg   case XK_F5:
13232001f49Smrg      special = EGLUT_KEY_F5;
13332001f49Smrg      break;
13432001f49Smrg   case XK_F6:
13532001f49Smrg      special = EGLUT_KEY_F6;
13632001f49Smrg      break;
13732001f49Smrg   case XK_F7:
13832001f49Smrg      special = EGLUT_KEY_F7;
13932001f49Smrg      break;
14032001f49Smrg   case XK_F8:
14132001f49Smrg      special = EGLUT_KEY_F8;
14232001f49Smrg      break;
14332001f49Smrg   case XK_F9:
14432001f49Smrg      special = EGLUT_KEY_F9;
14532001f49Smrg      break;
14632001f49Smrg   case XK_F10:
14732001f49Smrg      special = EGLUT_KEY_F10;
14832001f49Smrg      break;
14932001f49Smrg   case XK_F11:
15032001f49Smrg      special = EGLUT_KEY_F11;
15132001f49Smrg      break;
15232001f49Smrg   case XK_F12:
15332001f49Smrg      special = EGLUT_KEY_F12;
15432001f49Smrg      break;
15532001f49Smrg   case XK_KP_Left:
15632001f49Smrg   case XK_Left:
15732001f49Smrg      special = EGLUT_KEY_LEFT;
15832001f49Smrg      break;
15932001f49Smrg   case XK_KP_Up:
16032001f49Smrg   case XK_Up:
16132001f49Smrg      special = EGLUT_KEY_UP;
16232001f49Smrg      break;
16332001f49Smrg   case XK_KP_Right:
16432001f49Smrg   case XK_Right:
16532001f49Smrg      special = EGLUT_KEY_RIGHT;
16632001f49Smrg      break;
16732001f49Smrg   case XK_KP_Down:
16832001f49Smrg   case XK_Down:
16932001f49Smrg      special = EGLUT_KEY_DOWN;
17032001f49Smrg      break;
17132001f49Smrg   default:
17232001f49Smrg      special = -1;
17332001f49Smrg      break;
17432001f49Smrg   }
17532001f49Smrg
17632001f49Smrg   return special;
17732001f49Smrg}
17832001f49Smrg
17932001f49Smrgstatic void
18032001f49Smrgnext_event(struct eglut_window *win)
18132001f49Smrg{
18232001f49Smrg   int redraw = 0;
18332001f49Smrg   XEvent event;
18432001f49Smrg
18532001f49Smrg   if (!XPending(_eglut->native_dpy)) {
18632001f49Smrg      /* there is an idle callback */
18732001f49Smrg      if (_eglut->idle_cb) {
18832001f49Smrg         _eglut->idle_cb();
18932001f49Smrg         return;
19032001f49Smrg      }
19132001f49Smrg
19232001f49Smrg      /* the app requests re-display */
19332001f49Smrg      if (_eglut->redisplay)
19432001f49Smrg         return;
19532001f49Smrg   }
19632001f49Smrg
19732001f49Smrg   /* block for next event */
19832001f49Smrg   XNextEvent(_eglut->native_dpy, &event);
19932001f49Smrg
20032001f49Smrg   switch (event.type) {
20132001f49Smrg   case Expose:
20232001f49Smrg      redraw = 1;
20332001f49Smrg      break;
20432001f49Smrg   case ConfigureNotify:
20532001f49Smrg      win->native.width = event.xconfigure.width;
20632001f49Smrg      win->native.height = event.xconfigure.height;
20732001f49Smrg      if (win->reshape_cb)
20832001f49Smrg         win->reshape_cb(win->native.width, win->native.height);
20932001f49Smrg      break;
21032001f49Smrg   case KeyPress:
21132001f49Smrg      {
21232001f49Smrg         char buffer[1];
21332001f49Smrg         KeySym sym;
21432001f49Smrg         int r;
21532001f49Smrg
21632001f49Smrg         r = XLookupString(&event.xkey,
21732001f49Smrg               buffer, sizeof(buffer), &sym, NULL);
21832001f49Smrg         if (r && win->keyboard_cb) {
21932001f49Smrg            win->keyboard_cb(buffer[0]);
22032001f49Smrg         }
22132001f49Smrg         else if (!r && win->special_cb) {
22232001f49Smrg            r = lookup_keysym(sym);
22332001f49Smrg            if (r >= 0)
22432001f49Smrg               win->special_cb(r);
22532001f49Smrg         }
22632001f49Smrg      }
22732001f49Smrg      redraw = 1;
22832001f49Smrg      break;
22932001f49Smrg   default:
23032001f49Smrg      ; /*no-op*/
23132001f49Smrg   }
23232001f49Smrg
23332001f49Smrg   _eglut->redisplay = redraw;
23432001f49Smrg}
23532001f49Smrg
23632001f49Smrgvoid
23732001f49Smrg_eglutNativeEventLoop(void)
23832001f49Smrg{
23932001f49Smrg   while (1) {
24032001f49Smrg      struct eglut_window *win = _eglut->current;
24132001f49Smrg
24232001f49Smrg      next_event(win);
24332001f49Smrg
24432001f49Smrg      if (_eglut->redisplay) {
24532001f49Smrg         _eglut->redisplay = 0;
24632001f49Smrg
24732001f49Smrg         if (win->display_cb)
24832001f49Smrg            win->display_cb();
24932001f49Smrg         eglSwapBuffers(_eglut->dpy, win->surface);
25032001f49Smrg      }
25132001f49Smrg   }
25232001f49Smrg}
253