#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "backend.h" #include "log.h" #define WINDOW_WIDTH 1024 #define WINDOW_HEIGHT 600 static struct { Window window; EGLContext context; EGLSurface surface; } window; static Display *x_display; static EGLDisplay egl_display; static struct callbacks callbacks; static xcb_connection_t *xcb_connection; static int32_t keyboard_device_id; static struct xkb_keymap *keymap; static struct xkb_state *state; static Atom atom1, atom2; static void create_window (void) { // setup EGL static EGLint ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, // Request opengl ES2.0 EGL_NONE }; static const EGLint attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE }; EGLConfig config; EGLint num_configs_returned; eglChooseConfig (egl_display, attribs, &config, 1, &num_configs_returned); // get the visual from the EGL config EGLint visual_id; eglGetConfigAttrib (egl_display, config, EGL_NATIVE_VISUAL_ID, &visual_id); XVisualInfo visual_template; visual_template.visualid = visual_id; int num_visuals_returned; XVisualInfo *visual = XGetVisualInfo (x_display, VisualIDMask, &visual_template, &num_visuals_returned); // create a window XSetWindowAttributes window_attributes; window_attributes.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask; window_attributes.colormap = XCreateColormap (x_display, RootWindow(x_display,DefaultScreen(x_display)), visual->visual, AllocNone); window.window = XCreateWindow ( x_display, RootWindow(x_display, DefaultScreen(x_display)), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, // border width visual->depth, // depth InputOutput, // class visual->visual, // visual CWEventMask|CWColormap, // attribute mask &window_attributes // attributes ); atom1 = XInternAtom(x_display, "WM_PROTOCOLS", 0); atom2 = XInternAtom(x_display, "WM_DELETE_WINDOW", 0); XSetWMProtocols(x_display, window.window, &atom2, 1); // EGL context and surface eglBindAPI (EGL_OPENGL_ES_API); window.context = eglCreateContext (egl_display, config, EGL_NO_CONTEXT, ctxattr); window.surface = eglCreateWindowSurface (egl_display, config, window.window, NULL); eglMakeCurrent (egl_display, window.surface, window.surface, window.context); XFree (visual); XMapWindow (x_display, window.window); } void handler(int sig) { void *array[10]; size_t size; // get void*'s for all entries on the stack size = backtrace(array, 10); // print out all the frames to stderr fprintf(stderr, "Error: signal %d:\n", sig); backtrace_symbols_fd(array, size, STDERR_FILENO); exit(1); } void backend_init (struct callbacks *_callbacks) { signal(SIGSEGV, handler); callbacks = *_callbacks; x_display = XOpenDisplay (NULL); xcb_connection = XGetXCBConnection (x_display); struct xkb_context *context = xkb_context_new (XKB_CONTEXT_NO_FLAGS); xkb_x11_setup_xkb_extension (xcb_connection, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION, 0, NULL, NULL, NULL, NULL); keyboard_device_id = xkb_x11_get_core_keyboard_device_id (xcb_connection); keymap = xkb_x11_keymap_new_from_device (context, xcb_connection, keyboard_device_id, XKB_KEYMAP_COMPILE_NO_FLAGS); state = xkb_x11_state_new_from_device (keymap, xcb_connection, keyboard_device_id); egl_display = eglGetDisplay (x_display); eglInitialize (egl_display, NULL, NULL); create_window (); } EGLDisplay backend_get_egl_display (void) { return egl_display; } void backend_swap_buffers (void) { eglSwapBuffers (egl_display, window.surface); } static void update_modifiers (void) { if (!callbacks.modifiers) return; struct modifier_state modifier_state; modifier_state.depressed = xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED); modifier_state.latched = xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED); modifier_state.locked = xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED); modifier_state.group = xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE); callbacks.modifiers (modifier_state); } void backend_dispatch_nonblocking (void) { XEvent event; while (XPending(x_display)) { XNextEvent (x_display, &event); if (event.type == ConfigureNotify && callbacks.resize) { callbacks.resize (event.xconfigure.width, event.xconfigure.height); } else if (event.type == Expose && callbacks.draw) { callbacks.draw (); } else if (event.type == MotionNotify && callbacks.mouse_motion) { callbacks.mouse_motion (event.xbutton.x, event.xbutton.y); } else if (event.type == ButtonPress && callbacks.mouse_button) { if (event.xbutton.button == Button1) callbacks.mouse_button (BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); else if (event.xbutton.button == Button2) callbacks.mouse_button (BTN_MIDDLE, WL_POINTER_BUTTON_STATE_PRESSED); else if (event.xbutton.button == Button3) callbacks.mouse_button (BTN_RIGHT, WL_POINTER_BUTTON_STATE_PRESSED); } else if (event.type == ButtonRelease && callbacks.mouse_button) { if (event.xbutton.button == Button1) callbacks.mouse_button (BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED); else if (event.xbutton.button == Button2) callbacks.mouse_button (BTN_MIDDLE, WL_POINTER_BUTTON_STATE_RELEASED); else if (event.xbutton.button == Button3) callbacks.mouse_button (BTN_RIGHT, WL_POINTER_BUTTON_STATE_RELEASED); } else if (event.type == KeyPress && callbacks.key) { callbacks.key (event.xkey.keycode - 8, WL_KEYBOARD_KEY_STATE_PRESSED); xkb_state_update_key (state, event.xkey.keycode, XKB_KEY_DOWN); update_modifiers (); } else if (event.type == KeyRelease && callbacks.key) { callbacks.key (event.xkey.keycode - 8, WL_KEYBOARD_KEY_STATE_RELEASED); xkb_state_update_key (state, event.xkey.keycode, XKB_KEY_UP); update_modifiers (); } else if (event.type == FocusIn) { xkb_state_unref (state); state = xkb_x11_state_new_from_device (keymap, xcb_connection, keyboard_device_id); update_modifiers (); } else if (event.type == ClientMessage && callbacks.terminate) { if(event.xclient.message_type == atom1 && event.xclient.data.l[0] == atom2) { //XDestroyWindow(x_display, event.xclient.window); callbacks.terminate(); } break; } else if (event.type == DestroyNotify && callbacks.terminate) { callbacks.terminate(); break; } } } void backend_wait_for_events (int wayland_fd) { struct pollfd fds[2] = {{ConnectionNumber(x_display), POLLIN}, {wayland_fd, POLLIN}}; poll (fds, 2, -1); } void backend_get_keymap (int *fd, int *size) { char *string = xkb_keymap_get_as_string (keymap, XKB_KEYMAP_FORMAT_TEXT_V1); *size = strlen (string) + 1; char *xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); *fd = open (xdg_runtime_dir, O_TMPFILE|O_RDWR|O_EXCL, 0600); ftruncate (*fd, *size); char *map = mmap (NULL, *size, PROT_READ|PROT_WRITE, MAP_SHARED, *fd, 0); strcpy (map, string); munmap (map, *size); free (string); } long backend_get_timestamp (void) { struct timespec t; clock_gettime (CLOCK_MONOTONIC, &t); return t.tv_sec * 1000 + t.tv_nsec / 1000000; } void backend_get_dimensions(uint32_t *width, uint32_t *height) { if (width != NULL) *width = WINDOW_WIDTH; if (height != NULL) *height = WINDOW_HEIGHT; } int main(int argc, char *argv[]) { #ifndef __ANDROID__ if (argc == 2 && !strcmp("-f", argv[1])) trace_funcs = 1; #endif lorie_start(); return 0; }