x11.c (4287B)
1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build linux,!android 6 7 #include "_cgo_export.h" 8 #include <EGL/egl.h> 9 #include <GLES2/gl2.h> 10 #include <X11/Xlib.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 14 static Atom wm_delete_window; 15 16 static Window 17 new_window(Display *x_dpy, EGLDisplay e_dpy, int w, int h, EGLContext *ctx, EGLSurface *surf) { 18 static const EGLint attribs[] = { 19 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 20 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 21 EGL_BLUE_SIZE, 8, 22 EGL_GREEN_SIZE, 8, 23 EGL_RED_SIZE, 8, 24 EGL_DEPTH_SIZE, 16, 25 EGL_CONFIG_CAVEAT, EGL_NONE, 26 EGL_NONE 27 }; 28 EGLConfig config; 29 EGLint num_configs; 30 if (!eglChooseConfig(e_dpy, attribs, &config, 1, &num_configs)) { 31 fprintf(stderr, "eglChooseConfig failed\n"); 32 exit(1); 33 } 34 EGLint vid; 35 if (!eglGetConfigAttrib(e_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { 36 fprintf(stderr, "eglGetConfigAttrib failed\n"); 37 exit(1); 38 } 39 40 XVisualInfo visTemplate; 41 visTemplate.visualid = vid; 42 int num_visuals; 43 XVisualInfo *visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals); 44 if (!visInfo) { 45 fprintf(stderr, "XGetVisualInfo failed\n"); 46 exit(1); 47 } 48 49 Window root = RootWindow(x_dpy, DefaultScreen(x_dpy)); 50 XSetWindowAttributes attr; 51 52 attr.colormap = XCreateColormap(x_dpy, root, visInfo->visual, AllocNone); 53 if (!attr.colormap) { 54 fprintf(stderr, "XCreateColormap failed\n"); 55 exit(1); 56 } 57 58 attr.event_mask = StructureNotifyMask | ExposureMask | 59 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; 60 Window win = XCreateWindow( 61 x_dpy, root, 0, 0, w, h, 0, visInfo->depth, InputOutput, 62 visInfo->visual, CWColormap | CWEventMask, &attr); 63 XFree(visInfo); 64 65 XSizeHints sizehints; 66 sizehints.width = w; 67 sizehints.height = h; 68 sizehints.flags = USSize; 69 XSetNormalHints(x_dpy, win, &sizehints); 70 XSetStandardProperties(x_dpy, win, "App", "App", None, (char **)NULL, 0, &sizehints); 71 72 static const EGLint ctx_attribs[] = { 73 EGL_CONTEXT_CLIENT_VERSION, 2, 74 EGL_NONE 75 }; 76 *ctx = eglCreateContext(e_dpy, config, EGL_NO_CONTEXT, ctx_attribs); 77 if (!*ctx) { 78 fprintf(stderr, "eglCreateContext failed\n"); 79 exit(1); 80 } 81 *surf = eglCreateWindowSurface(e_dpy, config, win, NULL); 82 if (!*surf) { 83 fprintf(stderr, "eglCreateWindowSurface failed\n"); 84 exit(1); 85 } 86 return win; 87 } 88 89 Display *x_dpy; 90 EGLDisplay e_dpy; 91 EGLContext e_ctx; 92 EGLSurface e_surf; 93 Window win; 94 95 void 96 createWindow(void) { 97 x_dpy = XOpenDisplay(NULL); 98 if (!x_dpy) { 99 fprintf(stderr, "XOpenDisplay failed\n"); 100 exit(1); 101 } 102 e_dpy = eglGetDisplay(x_dpy); 103 if (!e_dpy) { 104 fprintf(stderr, "eglGetDisplay failed\n"); 105 exit(1); 106 } 107 EGLint e_major, e_minor; 108 if (!eglInitialize(e_dpy, &e_major, &e_minor)) { 109 fprintf(stderr, "eglInitialize failed\n"); 110 exit(1); 111 } 112 eglBindAPI(EGL_OPENGL_ES_API); 113 win = new_window(x_dpy, e_dpy, 600, 800, &e_ctx, &e_surf); 114 115 wm_delete_window = XInternAtom(x_dpy, "WM_DELETE_WINDOW", True); 116 if (wm_delete_window != None) { 117 XSetWMProtocols(x_dpy, win, &wm_delete_window, 1); 118 } 119 120 XMapWindow(x_dpy, win); 121 if (!eglMakeCurrent(e_dpy, e_surf, e_surf, e_ctx)) { 122 fprintf(stderr, "eglMakeCurrent failed\n"); 123 exit(1); 124 } 125 126 // Window size and DPI should be initialized before starting app. 127 XEvent ev; 128 while (1) { 129 if (XCheckMaskEvent(x_dpy, StructureNotifyMask, &ev) == False) { 130 continue; 131 } 132 if (ev.type == ConfigureNotify) { 133 onResize(ev.xconfigure.width, ev.xconfigure.height); 134 break; 135 } 136 } 137 } 138 139 void 140 processEvents(void) { 141 while (XPending(x_dpy)) { 142 XEvent ev; 143 XNextEvent(x_dpy, &ev); 144 switch (ev.type) { 145 case ButtonPress: 146 onTouchBegin((float)ev.xbutton.x, (float)ev.xbutton.y); 147 break; 148 case ButtonRelease: 149 onTouchEnd((float)ev.xbutton.x, (float)ev.xbutton.y); 150 break; 151 case MotionNotify: 152 onTouchMove((float)ev.xmotion.x, (float)ev.xmotion.y); 153 break; 154 case ConfigureNotify: 155 onResize(ev.xconfigure.width, ev.xconfigure.height); 156 break; 157 case ClientMessage: 158 if (wm_delete_window != None && (Atom)ev.xclient.data.l[0] == wm_delete_window) { 159 onStop(); 160 return; 161 } 162 break; 163 } 164 } 165 } 166 167 void 168 swapBuffers(void) { 169 if (eglSwapBuffers(e_dpy, e_surf) == EGL_FALSE) { 170 fprintf(stderr, "eglSwapBuffer failed\n"); 171 exit(1); 172 } 173 }