Initial commit
This commit is contained in:
parent
5b4bf8ea1b
commit
40e3051046
190
backend-x11.c
Normal file
190
backend-x11.c
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
#include "backend.h"
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <X11/Xlib-xcb.h>
|
||||||
|
#include <xkbcommon/xkbcommon-x11.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <poll.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 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
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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 backend_init (struct callbacks *_callbacks) {
|
||||||
|
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) {
|
||||||
|
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 (event.xconfigure.width, event.xconfigure.height);
|
||||||
|
}
|
||||||
|
else if (event.type == Expose) {
|
||||||
|
callbacks.draw ();
|
||||||
|
}
|
||||||
|
else if (event.type == MotionNotify) {
|
||||||
|
callbacks.mouse_motion (event.xbutton.x, event.xbutton.y);
|
||||||
|
}
|
||||||
|
else if (event.type == ButtonPress) {
|
||||||
|
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) {
|
||||||
|
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 (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 (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 ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
25
backend.h
Normal file
25
backend.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
|
||||||
|
struct modifier_state {
|
||||||
|
uint32_t depressed, latched, locked, group;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct callbacks {
|
||||||
|
void (*resize) (int width, int height);
|
||||||
|
void (*draw) (void);
|
||||||
|
void (*mouse_motion) (int x, int y);
|
||||||
|
void (*mouse_button) (int button, int state);
|
||||||
|
void (*key) (int key, int state);
|
||||||
|
void (*modifiers) (struct modifier_state modifier_state);
|
||||||
|
};
|
||||||
|
|
||||||
|
void backend_init (struct callbacks *callbacks);
|
||||||
|
EGLDisplay backend_get_egl_display (void);
|
||||||
|
void backend_swap_buffers (void);
|
||||||
|
void backend_dispatch_nonblocking (void);
|
||||||
|
void backend_wait_for_events (int wayland_fd);
|
||||||
|
void backend_get_keymap (int *fd, int *size);
|
||||||
|
long backend_get_timestamp (void);
|
||||||
|
|
||||||
|
void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * data);
|
320
main.c
Normal file
320
main.c
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#ifndef __USE_GNU
|
||||||
|
#define __USE_GNU
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#include "backend.h"
|
||||||
|
|
||||||
|
#define static
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BINDFUNC(interface, implementation) \
|
||||||
|
static void interface##_bind (struct wl_client *client, void *data, uint32_t version, uint32_t id) { \
|
||||||
|
printf ("bind: " #interface "\n"); \
|
||||||
|
struct wl_resource *resource = wl_resource_create (client, &interface##_interface, 1, id); \
|
||||||
|
if (resource == NULL) { \
|
||||||
|
wl_client_post_no_memory(client); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
wl_resource_set_implementation (resource, &implementation, NULL, NULL); \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lorie_composiror {
|
||||||
|
struct wl_display *display;
|
||||||
|
struct wl_list clients;
|
||||||
|
struct wl_list surfaces;
|
||||||
|
|
||||||
|
struct surface *main_surface;
|
||||||
|
struct modifier_state modifier_state;
|
||||||
|
|
||||||
|
uint32_t width, height;
|
||||||
|
} c = {0};
|
||||||
|
|
||||||
|
struct client {
|
||||||
|
struct wl_client *client;
|
||||||
|
struct wl_resource *pointer;
|
||||||
|
struct wl_resource *keyboard;
|
||||||
|
struct wl_list link;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct client *get_client (struct wl_client *_client) {
|
||||||
|
struct client *client;
|
||||||
|
wl_list_for_each (client, &c.clients, link) {
|
||||||
|
if (client->client == _client) return client;
|
||||||
|
}
|
||||||
|
client = calloc (1, sizeof(struct client));
|
||||||
|
client->client = _client;
|
||||||
|
wl_list_insert (&c.clients, &client->link);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct surface {
|
||||||
|
struct wl_resource *surface;
|
||||||
|
//struct wl_resource *xdg_surface;
|
||||||
|
struct wl_resource *buffer;
|
||||||
|
struct wl_resource *frame_callback;
|
||||||
|
//int x, y;
|
||||||
|
//struct texture texture;
|
||||||
|
struct client *client;
|
||||||
|
struct wl_list link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lorie_client {
|
||||||
|
struct wl_client *client;
|
||||||
|
struct wl_resource *pointer;
|
||||||
|
struct wl_resource *keyboard;
|
||||||
|
struct wl_list link;
|
||||||
|
};
|
||||||
|
|
||||||
|
void *null = NULL;
|
||||||
|
|
||||||
|
// region
|
||||||
|
/*No op*/ static void region_destroy (struct wl_client *client, struct wl_resource *resource) {}
|
||||||
|
/*No op*/ static void region_add (struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) {}
|
||||||
|
/*No op*/ static void region_subtract (struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) {}
|
||||||
|
/*No op*/ static struct wl_region_interface region_interface = {®ion_destroy, ®ion_add, ®ion_subtract};
|
||||||
|
|
||||||
|
// surface
|
||||||
|
/*No op*/ static void surface_destroy (struct wl_client *client, struct wl_resource *resource) {}
|
||||||
|
static void surface_attach (struct wl_client *client, struct wl_resource *resource, struct wl_resource *buffer, int32_t x, int32_t y) {
|
||||||
|
struct surface *surface = wl_resource_get_user_data (resource);
|
||||||
|
surface->buffer = buffer;
|
||||||
|
c.main_surface = surface;
|
||||||
|
}
|
||||||
|
static void surface_damage (struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) {
|
||||||
|
printf("Surface damage\n");
|
||||||
|
}
|
||||||
|
static void surface_frame (struct wl_client *client, struct wl_resource *resource, uint32_t callback) {
|
||||||
|
struct surface *surface = wl_resource_get_user_data (resource);
|
||||||
|
surface->frame_callback = wl_resource_create (client, &wl_callback_interface, 1, callback);
|
||||||
|
}
|
||||||
|
/*No op*/ static void surface_set_opaque_region (struct wl_client *client, struct wl_resource *resource, struct wl_resource *region) {}
|
||||||
|
/*No op*/ static void surface_set_input_region (struct wl_client *client, struct wl_resource *resource, struct wl_resource *region) {}
|
||||||
|
static void surface_commit (struct wl_client *client, struct wl_resource *resource) {
|
||||||
|
printf("Surface commit\n");
|
||||||
|
}
|
||||||
|
/*No op*/ static void surface_set_buffer_transform (struct wl_client *client, struct wl_resource *resource, int32_t transform) {}
|
||||||
|
/*No op*/ static void surface_set_buffer_scale (struct wl_client *client, struct wl_resource *resource, int32_t scale) {}
|
||||||
|
static void surface_delete (struct wl_resource *resource) {
|
||||||
|
struct surface *surface = wl_resource_get_user_data (resource);
|
||||||
|
if (c.main_surface == surface) c.main_surface = NULL;
|
||||||
|
wl_list_remove (&surface->link);
|
||||||
|
free (surface);
|
||||||
|
}
|
||||||
|
static struct wl_surface_interface surface_interface = {&surface_destroy, &surface_attach, &surface_damage, &surface_frame, &surface_set_opaque_region, &surface_set_input_region, &surface_commit, &surface_set_buffer_transform, &surface_set_buffer_scale};
|
||||||
|
|
||||||
|
// compositor
|
||||||
|
static void compositor_create_surface (struct wl_client *client, struct wl_resource *resource, uint32_t id) {
|
||||||
|
struct surface *surface = calloc (1, sizeof(struct surface));
|
||||||
|
surface->surface = wl_resource_create (client, &wl_surface_interface, 3, id);
|
||||||
|
wl_resource_set_implementation (surface->surface, &surface_interface, surface, &surface_delete);
|
||||||
|
surface->client = get_client (client);
|
||||||
|
wl_list_insert (&c.surfaces, &surface->link);
|
||||||
|
}
|
||||||
|
static void compositor_create_region (struct wl_client *client, struct wl_resource *resource, uint32_t id) {
|
||||||
|
struct wl_resource *region = wl_resource_create (client, &wl_region_interface, 1, id);
|
||||||
|
wl_resource_set_implementation (region, ®ion_interface, NULL, NULL);
|
||||||
|
}
|
||||||
|
static struct wl_compositor_interface compositor_interface = {&compositor_create_surface, &compositor_create_region};
|
||||||
|
BINDFUNC(wl_compositor, compositor_interface);
|
||||||
|
|
||||||
|
|
||||||
|
// shell surface
|
||||||
|
/*No op*/ static void shell_surface_pong (struct wl_client *client, struct wl_resource *resource, uint32_t serial) {}
|
||||||
|
/*No op*/ static void shell_surface_move (struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial) {}
|
||||||
|
/*No op*/ static void shell_surface_resize (struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, uint32_t edges) {}
|
||||||
|
/*No op*/ static void shell_surface_set_toplevel (struct wl_client *client, struct wl_resource *resource) {}
|
||||||
|
/*No op*/ static void shell_surface_set_transient (struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent, int32_t x, int32_t y, uint32_t flags) {}
|
||||||
|
/*No op*/ static void shell_surface_set_fullscreen (struct wl_client *client, struct wl_resource *resource, uint32_t method, uint32_t framerate, struct wl_resource *output) {}
|
||||||
|
/*No op*/ static void shell_surface_set_popup (struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, struct wl_resource *parent, int32_t x, int32_t y, uint32_t flags) {}
|
||||||
|
/*No op*/ static void shell_surface_set_maximized (struct wl_client *client, struct wl_resource *resource, struct wl_resource *output) {}
|
||||||
|
/*No op*/ static void shell_surface_set_title (struct wl_client *client, struct wl_resource *resource, const char *title) {}
|
||||||
|
/*No op*/ static void shell_surface_set_class (struct wl_client *client, struct wl_resource *resource, const char *class_) {}
|
||||||
|
/*No op*/ static struct wl_shell_surface_interface shell_surface_interface = {&shell_surface_pong, &shell_surface_move, &shell_surface_resize, &shell_surface_set_toplevel, &shell_surface_set_transient, &shell_surface_set_fullscreen, &shell_surface_set_popup, &shell_surface_set_maximized, &shell_surface_set_title, &shell_surface_set_class};
|
||||||
|
|
||||||
|
// wl shell
|
||||||
|
static void shell_get_shell_surface (struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface) {
|
||||||
|
struct wl_resource *shell_surface = wl_resource_create (client, &wl_shell_surface_interface, 1, id);
|
||||||
|
wl_resource_set_implementation (shell_surface, &shell_surface_interface, NULL, NULL);
|
||||||
|
wl_shell_surface_send_configure(shell_surface, 0, c.width, c.height);
|
||||||
|
}
|
||||||
|
static struct wl_shell_interface shell_interface = {&shell_get_shell_surface};
|
||||||
|
BINDFUNC(wl_shell, shell_interface);
|
||||||
|
|
||||||
|
// pointer
|
||||||
|
/*No op*/ static void pointer_set_cursor (struct wl_client *client, struct wl_resource *resource, uint32_t serial, struct wl_resource *_surface, int32_t hotspot_x, int32_t hotspot_y) {}
|
||||||
|
/*No op*/ static void pointer_release (struct wl_client *client, struct wl_resource *resource) {}
|
||||||
|
/*No op*/ static struct wl_pointer_interface pointer_interface = {&pointer_set_cursor, &pointer_release};
|
||||||
|
|
||||||
|
// keyboard
|
||||||
|
/*No op*/ static void keyboard_release (struct wl_client *client, struct wl_resource *resource) {}
|
||||||
|
/*No op*/ static struct wl_keyboard_interface keyboard_interface = {&keyboard_release};
|
||||||
|
|
||||||
|
// seat
|
||||||
|
static void seat_get_pointer (struct wl_client *client, struct wl_resource *resource, uint32_t id) {
|
||||||
|
struct wl_resource *pointer = wl_resource_create (client, &wl_pointer_interface, 1, id);
|
||||||
|
wl_resource_set_implementation (pointer, &pointer_interface, NULL, NULL);
|
||||||
|
get_client(client)->pointer = pointer;
|
||||||
|
}
|
||||||
|
static void seat_get_keyboard (struct wl_client *client, struct wl_resource *resource, uint32_t id) {
|
||||||
|
struct wl_resource *keyboard = wl_resource_create (client, &wl_keyboard_interface, 1, id);
|
||||||
|
wl_resource_set_implementation (keyboard, &keyboard_interface, NULL, NULL);
|
||||||
|
//get_client(client)->keyboard = keyboard;
|
||||||
|
//int fd, size;
|
||||||
|
//backend_get_keymap (&fd, &size);
|
||||||
|
//wl_keyboard_send_keymap (keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, size);
|
||||||
|
//close (fd);
|
||||||
|
}
|
||||||
|
/*No op*/ static void seat_get_touch (struct wl_client *client, struct wl_resource *resource, uint32_t id) {}
|
||||||
|
static struct wl_seat_interface seat_interface = {&seat_get_pointer, &seat_get_keyboard, &seat_get_touch};
|
||||||
|
static void wl_seat_bind (struct wl_client *client, void *data, uint32_t version, uint32_t id) {
|
||||||
|
printf ("bind: wl_seat\n");
|
||||||
|
struct wl_resource *seat = wl_resource_create (client, &wl_seat_interface, 1, id);
|
||||||
|
wl_resource_set_implementation (seat, &seat_interface, NULL, NULL);
|
||||||
|
wl_seat_send_capabilities (seat, WL_SEAT_CAPABILITY_POINTER|WL_SEAT_CAPABILITY_KEYBOARD);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
output_release(struct wl_client *client, struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
static const struct wl_output_interface output_interface = {
|
||||||
|
output_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
wl_output_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
|
||||||
|
{
|
||||||
|
int DPI = 240;
|
||||||
|
struct wl_resource *resource = wl_resource_create(client, &wl_output_interface, version, id);
|
||||||
|
if (resource == NULL) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_resource_set_implementation(resource, &output_interface, NULL, NULL);
|
||||||
|
|
||||||
|
int mm_width = c.width/DPI*25;
|
||||||
|
int mm_height = c.height/DPI*25;
|
||||||
|
wl_output_send_geometry(resource, c.width, c.height, mm_width, mm_height, 0, "non-weston", "none", 0);
|
||||||
|
if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
|
||||||
|
wl_output_send_scale(resource, 1.0);
|
||||||
|
wl_output_send_mode(resource, 3, c.width, c.height, 60000);
|
||||||
|
|
||||||
|
if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
|
||||||
|
wl_output_send_done(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// backend callbacks
|
||||||
|
/*No op*/ static void handle_resize_event (int width, int height) {}
|
||||||
|
/*No op*/ static void handle_draw_event (void) {}
|
||||||
|
static void handle_mouse_motion_event (int x, int y) {
|
||||||
|
if (!c.main_surface || !c.main_surface->client->pointer) return;
|
||||||
|
wl_fixed_t surface_x = wl_fixed_from_double (x);
|
||||||
|
wl_fixed_t surface_y = wl_fixed_from_double (y);
|
||||||
|
wl_pointer_send_motion (c.main_surface->client->pointer, backend_get_timestamp(), surface_x, surface_y);
|
||||||
|
}
|
||||||
|
static void handle_mouse_button_event (int button, int state) {
|
||||||
|
if (!c.main_surface || !c.main_surface->client->pointer) return;
|
||||||
|
wl_pointer_send_button (c.main_surface->client->pointer, 0, backend_get_timestamp(), button, state);
|
||||||
|
}
|
||||||
|
static void handle_key_event (int key, int state) {
|
||||||
|
//if (!c.main_surface || !c.main_surface->client->keyboard) return;
|
||||||
|
//wl_keyboard_send_key (c.main_surface->client->keyboard, 0, backend_get_timestamp(), key, state);
|
||||||
|
}
|
||||||
|
static void handle_modifiers_changed (struct modifier_state new_state) {
|
||||||
|
//if (new_state.depressed == c.modifier_state.depressed && new_state.latched == c.modifier_state.latched && new_state.locked == c.modifier_state.locked && new_state.group == c.modifier_state.group) return;
|
||||||
|
//c.modifier_state = new_state;
|
||||||
|
//if (c.main_surface && c.main_surface->client->keyboard)
|
||||||
|
// wl_keyboard_send_modifiers (c.main_surface->client->keyboard, 0, c.modifier_state.depressed, c.modifier_state.latched, c.modifier_state.locked, c.modifier_state.group);
|
||||||
|
}
|
||||||
|
static struct callbacks callbacks = {&handle_resize_event, &handle_draw_event, &handle_mouse_motion_event, &handle_mouse_button_event, &handle_key_event, &handle_modifiers_changed};
|
||||||
|
|
||||||
|
void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * data);
|
||||||
|
|
||||||
|
static void draw (void) {
|
||||||
|
glClearColor (1, 1, 0, 1);
|
||||||
|
glClear (GL_COLOR_BUFFER_BIT);
|
||||||
|
//glLoadIdentity();
|
||||||
|
|
||||||
|
struct surface *surface = c.main_surface;
|
||||||
|
if (!surface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//wl_list_for_each_reverse (surface, &c.surfaces, link) {
|
||||||
|
if (surface) {
|
||||||
|
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (surface->buffer);
|
||||||
|
if (shm_buffer == NULL) return;
|
||||||
|
//if (shm_buffer == NULL) continue;
|
||||||
|
uint32_t width = wl_shm_buffer_get_width (shm_buffer);
|
||||||
|
uint32_t height = wl_shm_buffer_get_height (shm_buffer);
|
||||||
|
void *data = wl_shm_buffer_get_data (shm_buffer);
|
||||||
|
if (data) {
|
||||||
|
printf("Showing %dx%d window\n", width, height);
|
||||||
|
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
backend_swap_buffers();
|
||||||
|
wl_buffer_send_release (surface->buffer);
|
||||||
|
usleep(500000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glFlush ();
|
||||||
|
backend_swap_buffers ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("Starting lorie server\n");
|
||||||
|
signal(SIGSEGV, handler);
|
||||||
|
backend_init (&callbacks);
|
||||||
|
//setenv("WAYLAND_DEBUG", "1", 1);
|
||||||
|
memset(&c, 0, sizeof(c));
|
||||||
|
wl_list_init (&c.clients);
|
||||||
|
wl_list_init (&c.surfaces);
|
||||||
|
c.width = 1024;
|
||||||
|
c.height = 600;
|
||||||
|
c.display = wl_display_create ();
|
||||||
|
wl_display_add_socket_auto (c.display);
|
||||||
|
|
||||||
|
wl_global_create (c.display, &wl_compositor_interface, 4, NULL, &wl_compositor_bind);
|
||||||
|
wl_global_create (c.display, &wl_shell_interface, 1, NULL, &wl_shell_bind);
|
||||||
|
wl_global_create (c.display, &wl_seat_interface, 5, NULL, &wl_seat_bind);
|
||||||
|
wl_global_create (c.display, &wl_output_interface, 3, NULL, &wl_output_bind);
|
||||||
|
wl_display_init_shm (c.display);
|
||||||
|
|
||||||
|
struct wl_event_loop *event_loop = wl_display_get_event_loop (c.display);
|
||||||
|
int wayland_fd = wl_event_loop_get_fd (event_loop);
|
||||||
|
while (1) {
|
||||||
|
wl_event_loop_dispatch (event_loop, 0);
|
||||||
|
backend_dispatch_nonblocking ();
|
||||||
|
wl_display_flush_clients (c.display);
|
||||||
|
draw ();
|
||||||
|
backend_wait_for_events (wayland_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wl_display_destroy (c.display);
|
||||||
|
return 0;
|
||||||
|
}
|
39
meson.build
Normal file
39
meson.build
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
project(
|
||||||
|
'xwayland_proxy',
|
||||||
|
'c',
|
||||||
|
version: '0.0.1',
|
||||||
|
license: 'MIT',
|
||||||
|
meson_version: '>=0.47.0',
|
||||||
|
default_options: [
|
||||||
|
'c_std=c11',
|
||||||
|
'warning_level=1',
|
||||||
|
'b_lundef=false',
|
||||||
|
'prefix=/usr/local'
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
pkg = import('pkgconfig')
|
||||||
|
compiler = meson.get_compiler('c')
|
||||||
|
wayland_server = dependency('wayland-server', version: '>=1.16')
|
||||||
|
wayland_client = dependency('wayland-client')
|
||||||
|
egl = compiler.find_library('EGL')
|
||||||
|
glesv2 = compiler.find_library('GLESv2')
|
||||||
|
libx11 = dependency('x11')
|
||||||
|
libxkbcommon = dependency('xkbcommon')
|
||||||
|
libxkbcommon_x11 = dependency('xkbcommon-x11')
|
||||||
|
libx11_xcb = dependency('x11-xcb')
|
||||||
|
|
||||||
|
incdirs = include_directories('.')
|
||||||
|
proxy_srcs = [
|
||||||
|
'backend-x11.c',
|
||||||
|
'main.c',
|
||||||
|
'renderer.c'
|
||||||
|
]
|
||||||
|
|
||||||
|
proxy = executable(
|
||||||
|
'proxy',
|
||||||
|
sources: proxy_srcs,
|
||||||
|
include_directories: incdirs,
|
||||||
|
dependencies: [egl, glesv2, libx11, libx11_xcb, wayland_server, libxkbcommon, libxkbcommon_x11],
|
||||||
|
link_args: ['-lm', '-g', '-rdynamic']
|
||||||
|
)
|
186
renderer.c
Normal file
186
renderer.c
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
|
||||||
|
#define LOGI(...) (printf("(I): " __VA_ARGS__))
|
||||||
|
#define LOGW(...) (printf("(W): " __VA_ARGS__))
|
||||||
|
#define LOGE(...) (printf("(E): " __VA_ARGS__))
|
||||||
|
|
||||||
|
static GLuint gTextureProgram;
|
||||||
|
static GLuint gvTexturePositionHandle;
|
||||||
|
static GLuint gvTextureTexCoordsHandle;
|
||||||
|
static GLuint gvTextureSamplerHandle;
|
||||||
|
|
||||||
|
static const char gSimpleVS[] =
|
||||||
|
"attribute vec4 position;\n"
|
||||||
|
"attribute vec2 texCoords;\n"
|
||||||
|
"varying vec2 outTexCoords;\n"
|
||||||
|
"\nvoid main(void) {\n"
|
||||||
|
" outTexCoords = texCoords;\n"
|
||||||
|
" gl_Position = position;\n"
|
||||||
|
"}\n\n";
|
||||||
|
static const char gSimpleFS[] =
|
||||||
|
"precision mediump float;\n\n"
|
||||||
|
"varying vec2 outTexCoords;\n"
|
||||||
|
"uniform sampler2D texture;\n"
|
||||||
|
"\nvoid main(void) {\n"
|
||||||
|
" gl_FragColor = texture2D(texture, outTexCoords);\n"
|
||||||
|
"}\n\n";
|
||||||
|
|
||||||
|
static void checkGlError(const char* op) {
|
||||||
|
GLint error;
|
||||||
|
for (error = glGetError(); error; error = glGetError()) {
|
||||||
|
LOGE("after %s() glError (0x%x)\n", op, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static GLuint loadShader(GLenum shaderType, const char* pSource) {
|
||||||
|
GLuint shader = glCreateShader(shaderType);
|
||||||
|
if (shader) {
|
||||||
|
glShaderSource(shader, 1, &pSource, NULL);
|
||||||
|
glCompileShader(shader);
|
||||||
|
GLint compiled = 0;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
|
||||||
|
if (!compiled) {
|
||||||
|
GLint infoLen = 0;
|
||||||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
|
||||||
|
if (infoLen) {
|
||||||
|
char* buf = (char*) malloc(infoLen);
|
||||||
|
if (buf) {
|
||||||
|
glGetShaderInfoLog(shader, infoLen, NULL, buf);
|
||||||
|
LOGE("Could not compile shader %d:\n%s\n",
|
||||||
|
shaderType, buf);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
glDeleteShader(shader);
|
||||||
|
shader = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
|
||||||
|
GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
|
||||||
|
if (!vertexShader) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
|
||||||
|
if (!pixelShader) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint program = glCreateProgram();
|
||||||
|
if (program) {
|
||||||
|
glAttachShader(program, vertexShader);
|
||||||
|
checkGlError("glAttachShader");
|
||||||
|
glAttachShader(program, pixelShader);
|
||||||
|
checkGlError("glAttachShader");
|
||||||
|
glLinkProgram(program);
|
||||||
|
GLint linkStatus = GL_FALSE;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
||||||
|
if (linkStatus != GL_TRUE) {
|
||||||
|
GLint bufLength = 0;
|
||||||
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
|
||||||
|
if (bufLength) {
|
||||||
|
char* buf = (char*) malloc(bufLength);
|
||||||
|
if (buf) {
|
||||||
|
glGetProgramInfoLog(program, bufLength, NULL, buf);
|
||||||
|
LOGE("Could not link program:\n%s\n", buf);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glDeleteProgram(program);
|
||||||
|
program = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setupGraphics(void) {
|
||||||
|
|
||||||
|
gTextureProgram = createProgram(gSimpleVS, gSimpleFS);
|
||||||
|
if (!gTextureProgram) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
gvTexturePositionHandle = glGetAttribLocation(gTextureProgram, "position"); checkGlError("glGetAttribLocation");
|
||||||
|
gvTextureTexCoordsHandle = glGetAttribLocation(gTextureProgram, "texCoords"); checkGlError("glGetAttribLocation");
|
||||||
|
gvTextureSamplerHandle = glGetUniformLocation(gTextureProgram, "texture"); checkGlError("glGetAttribLocation");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
|
||||||
|
0.5f, -0.5f };
|
||||||
|
|
||||||
|
#define FLOAT_SIZE_BYTES 4;
|
||||||
|
const GLint TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
|
||||||
|
const GLfloat gTriangleVerticesData[] = {
|
||||||
|
// X, Y, Z, U, V
|
||||||
|
-1.0f, 1.0f, 0, 0.f, 0.f,
|
||||||
|
1.0f, 1.0f, 0, 1.f, 0.f,
|
||||||
|
-1.0f, -1.0f, 0, 0.f, 1.f,
|
||||||
|
1.0f, -1.0f, 0, 1.f, 1.f,
|
||||||
|
};
|
||||||
|
|
||||||
|
void glDrawTex(void) {
|
||||||
|
if (!gTextureProgram) {
|
||||||
|
if(!setupGraphics()) {
|
||||||
|
LOGE("Could not set up graphics.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glUseProgram(gTextureProgram); checkGlError("glUseProgram");
|
||||||
|
|
||||||
|
glVertexAttribPointer(gvTexturePositionHandle, 3, GL_FLOAT, GL_FALSE,
|
||||||
|
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, gTriangleVerticesData);
|
||||||
|
checkGlError("glVertexAttribPointer");
|
||||||
|
glVertexAttribPointer(gvTextureTexCoordsHandle, 2, GL_FLOAT, GL_FALSE,
|
||||||
|
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, &gTriangleVerticesData[3]);
|
||||||
|
checkGlError("glVertexAttribPointer");
|
||||||
|
glEnableVertexAttribArray(gvTexturePositionHandle);
|
||||||
|
glEnableVertexAttribArray(gvTextureTexCoordsHandle);
|
||||||
|
checkGlError("glEnableVertexAttribArray");
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
checkGlError("glDrawArrays");
|
||||||
|
|
||||||
|
glUseProgram(0); checkGlError("glUseProgram");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void glDrawTexCoords(float x0, float y0, float x1, float y1) {
|
||||||
|
float coords[20] = {
|
||||||
|
x0, -y0, 0.f, 0.f, 0.f,
|
||||||
|
x1, -y0, 0.f, 1.f, 0.f,
|
||||||
|
x0, -y1, 0.f, 0.f, 1.f,
|
||||||
|
x1, -y1, 0.f, 1.f, 1.f
|
||||||
|
};
|
||||||
|
|
||||||
|
glUseProgram(gTextureProgram); checkGlError("glUseProgram");
|
||||||
|
|
||||||
|
glVertexAttribPointer(gvTexturePositionHandle, 3, GL_FLOAT, GL_FALSE, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, coords); checkGlError("glVertexAttribPointer");
|
||||||
|
glVertexAttribPointer(gvTextureTexCoordsHandle, 2, GL_FLOAT, GL_FALSE, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, &coords[3]); checkGlError("glVertexAttribPointer");
|
||||||
|
glEnableVertexAttribArray(gvTexturePositionHandle); checkGlError("glEnableVertexAttribArray");
|
||||||
|
glEnableVertexAttribArray(gvTextureTexCoordsHandle); checkGlError("glEnableVertexAttribArray");
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); checkGlError("glDrawArrays");
|
||||||
|
|
||||||
|
glUseProgram(0); checkGlError("glUseProgram");
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLuint gPixelsTexture;
|
||||||
|
|
||||||
|
void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * data){
|
||||||
|
if(!gPixelsTexture) glGenTextures(1, &gPixelsTexture);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gPixelsTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, type, data);
|
||||||
|
glDrawTex();
|
||||||
|
//glDrawTexCoords(-1.0, -1.0, 1.0, 1.0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user