x11.c 4.2 KB

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