#include #include #include #include #include #include #include #include #include static EGLint const attr_list[] = { EGL_CONFORMANT, EGL_OPENGL_BIT, /**/ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, /**/ EGL_DEPTH_SIZE, 16, /**/ EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, /**/ EGL_RED_SIZE, 5, /**/ EGL_GREEN_SIZE, 5, /**/ EGL_BLUE_SIZE, 3, /**/ EGL_NONE }; static EGLint const context_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, /* */ EGL_NONE }; static uint32_t const window_opts[] = { 0 }; static int get_xcb_conn_error(xcb_connection_t *connection); static int get_xcb_error(xcb_generic_error_t *error); static int main_task(int fd); static int child_task(int fd); static void set_egl_error(void); int main(void) { int pipes[2]; if (-1 == pipe(pipes)) { perror("pipe"); exit(EXIT_FAILURE); } pid_t child = fork(); if (0 == child) { close(pipes[0]); return child_task(pipes[1]); } close(pipes[1]); return main_task(pipes[0]); } static int child_task(int fd) { int errnum; unsigned screen_number; xcb_connection_t *connection; { int xx; connection = xcb_connect(NULL, &xx); if (NULL == connection) { errnum = ENOSYS; goto destroy_pool; } screen_number = (unsigned)xx; } xcb_screen_t *screen = NULL; { xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); for (size_t ii = 0U; ii < screen_number; ++ii) { if (0 == iter.rem) break; xcb_screen_next(&iter); } if (0 == iter.rem) { errnum = EINVAL; goto close_display; } screen = iter.data; } xcb_window_t window = xcb_generate_id(connection); errnum = get_xcb_conn_error(connection); if (errnum != 0) goto close_display; xcb_void_cookie_t create_win_ck = xcb_create_window_checked( connection, XCB_COPY_FROM_PARENT, window, screen->root, 0, 0, 640, 480, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, 0, window_opts); errnum = get_xcb_conn_error(connection); if (errnum != 0) goto close_display; xcb_intern_atom_cookie_t protocols_ck = xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS"); errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; xcb_intern_atom_cookie_t delete_ck = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW"); errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; xcb_atom_t wm_delete_window_atom; xcb_atom_t wm_protocols_atom; { xcb_intern_atom_reply_t *proto_reply; xcb_generic_error_t *proto_err; { xcb_generic_error_t *xx = NULL; proto_reply = xcb_intern_atom_reply(connection, protocols_ck, &xx); proto_err = xx; } errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; if (proto_err != NULL) { errnum = get_xcb_error(proto_err); free(proto_err); goto destroy_window; } wm_protocols_atom = proto_reply->atom; free(proto_reply); } { xcb_intern_atom_reply_t *delete_ck_reply; xcb_generic_error_t *delete_ck_err; { xcb_generic_error_t *xx = NULL; delete_ck_reply = xcb_intern_atom_reply(connection, delete_ck, &xx); delete_ck_err = xx; } errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; if (delete_ck_err != NULL) { errnum = get_xcb_error(delete_ck_err); free(delete_ck_err); goto destroy_window; } wm_delete_window_atom = delete_ck_reply->atom; free(delete_ck_reply); } xcb_void_cookie_t ch_prop_ck = xcb_change_property_checked( connection, XCB_PROP_MODE_REPLACE, window, wm_protocols_atom, 4, 32, 1, &wm_delete_window_atom); errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; xcb_void_cookie_t map_ck = xcb_map_window(connection, window); errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; xcb_generic_error_t *create_win_err = xcb_request_check(connection, create_win_ck); if (create_win_err != NULL) { errnum = get_xcb_error(create_win_err); free(create_win_err); goto destroy_window; } errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; xcb_generic_error_t *ch_prop_err = xcb_request_check(connection, ch_prop_ck); errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; if (ch_prop_err != NULL) { errnum = get_xcb_error(ch_prop_err); free(ch_prop_err); goto destroy_window; } xcb_generic_error_t *map_err = xcb_request_check(connection, map_ck); errnum = get_xcb_conn_error(connection); if (errnum != 0) goto destroy_window; if (map_err != NULL) { errnum = get_xcb_error(map_err); free(map_err); goto destroy_window; } if (-1 == write(fd, &window, sizeof window)) { perror("write"); exit(EXIT_FAILURE); } for (;;) pause(); close_display: destroy_pool: destroy_window: errno = errnum; perror("stuff"); return EXIT_FAILURE; } static int main_task(int fd) { Display *native_display = XOpenDisplay(NULL); if (NULL) { fputs("err!\n", stderr); exit(EXIT_FAILURE); } Window window; ssize_t bytes = read(fd, &window, sizeof window); if (0 == bytes) exit(EXIT_FAILURE); if (-1 == bytes) { perror("read"); exit(EXIT_FAILURE); } EGLDisplay display = eglGetDisplay(native_display); if (EGL_NO_DISPLAY == display) { perror("eglGetDisplay"); exit(EXIT_FAILURE); } if (EGL_FALSE == eglInitialize(display, NULL, NULL)) { perror("eglInitialize"); exit(EXIT_FAILURE); } EGLConfig config; { EGLConfig xx; EGLint yy; if (EGL_FALSE == eglChooseConfig(display, attr_list, &xx, 1U, &yy)) { set_egl_error(); perror("eglChooseConfig"); exit(EXIT_FAILURE); } config = xx; } EGLSurface surface = eglCreateWindowSurface(display, config, window, NULL); if (EGL_NO_SURFACE == surface) { set_egl_error(); perror("eglCreateWindowSurface"); exit(EXIT_FAILURE); } EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attr); if (EGL_NO_CONTEXT == context) exit(EXIT_FAILURE); if (EGL_FALSE == eglMakeCurrent(display, surface, surface, context)) { exit(EXIT_FAILURE); } for (;;) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (EGL_FALSE == eglSwapBuffers(display, surface)) { set_egl_error(); perror("eglSwapBuffers"); exit(EXIT_FAILURE); } } return 0; } static void set_egl_error(void) { switch (eglGetError()) { case EGL_SUCCESS: errno = 0; break; case EGL_NOT_INITIALIZED: errno = EINVAL; break; case EGL_BAD_ACCESS: errno = EAGAIN; break; case EGL_BAD_ALLOC: errno = ENOMEM; break; case EGL_BAD_ATTRIBUTE: case EGL_BAD_CONTEXT: case EGL_BAD_CONFIG: case EGL_BAD_CURRENT_SURFACE: case EGL_BAD_DISPLAY: case EGL_BAD_SURFACE: case EGL_BAD_MATCH: case EGL_BAD_PARAMETER: case EGL_BAD_NATIVE_PIXMAP: case EGL_BAD_NATIVE_WINDOW: errno = EINVAL; break; case EGL_CONTEXT_LOST: errno = ENOSYS; break; } } static int get_xcb_conn_error(xcb_connection_t *connection) { switch (xcb_connection_has_error(connection)) { case 0: return 0; case XCB_CONN_ERROR: return EPROTO; case XCB_CONN_CLOSED_EXT_NOTSUPPORTED: return ENOSYS; case XCB_CONN_CLOSED_MEM_INSUFFICIENT: return ENOMEM; case XCB_CONN_CLOSED_REQ_LEN_EXCEED: return EINVAL; case XCB_CONN_CLOSED_PARSE_ERR: return EINVAL; } } static int get_xcb_error(xcb_generic_error_t *error) { /* For now just be crappy. */ return ENOSYS; }