diff --git a/Xwayland.arch b/Xwayland.arch new file mode 100644 index 0000000..332aad7 --- /dev/null +++ b/Xwayland.arch @@ -0,0 +1,18 @@ +Xwayland depends on these Wayland interfaces: +1. wl_display (libwayland builtin) +2. wl_registry (libwayland builtin) +3. wl_shm (libwayland builtin) +4. wl_shm_pool (libwayland builtin) +5. wl_compositor +6. wl_shell +7. wl_region +8. wl_surface +9. wl_shell_surface +10. wl_seat +11. wl_pointer +12. wl_keyboard +13. wl_drm (glamor only) +14. xdg_surface +15. xdg_shell +16. zwp_relative_pointer_manager_v1 +17. zwp_pointer_constraints_v1 diff --git a/backend-x11.c b/backend-x11.c index 9d3c090..b78b7c5 100644 --- a/backend-x11.c +++ b/backend-x11.c @@ -30,6 +30,7 @@ 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 @@ -75,6 +76,10 @@ static void create_window (void) { &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); @@ -163,6 +168,18 @@ void backend_dispatch_nonblocking (void) { state = xkb_x11_state_new_from_device (keymap, xcb_connection, keyboard_device_id); update_modifiers (); } + else if (event.type == ClientMessage) { + 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(); + break; + } } } diff --git a/backend.h b/backend.h index c5fed71..024004d 100644 --- a/backend.h +++ b/backend.h @@ -12,6 +12,7 @@ struct callbacks { void (*mouse_button) (int button, int state); void (*key) (int key, int state); void (*modifiers) (struct modifier_state modifier_state); + void (*terminate) (); }; void backend_init (struct callbacks *callbacks); diff --git a/main.c b/main.c index 435baa8..5efa6a3 100644 --- a/main.c +++ b/main.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "backend.h" @@ -30,10 +31,10 @@ void handler(int sig) { exit(1); } -#define BINDFUNC(interface, implementation) \ - static void interface##_bind (struct wl_client *client, void *data, uint32_t version, uint32_t id) { \ +#define BINDFUNC(interface, version, 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); \ + struct wl_resource *resource = wl_resource_create (client, &interface##_interface, version, id); \ if (resource == NULL) { \ wl_client_post_no_memory(client); \ return; \ @@ -45,10 +46,15 @@ struct lorie_composiror { struct wl_display *display; struct wl_list clients; struct wl_list surfaces; + struct wl_list shell_surfaces; - struct surface *main_surface; + struct surface *toplevel; + struct surface *cursor; struct modifier_state modifier_state; + bool running; + bool redraw_needed; + uint32_t width, height; } c = {0}; @@ -78,6 +84,14 @@ struct surface { //int x, y; //struct texture texture; struct client *client; + struct shell_surface *shell_surface; + struct wl_list link; + bool entered; +}; + +struct shell_surface { + struct wl_resource *shell_surface; + struct surface* surface; struct wl_list link; }; @@ -101,10 +115,11 @@ void *null = NULL; 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; + //c.toplevel = 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"); + c.redraw_needed = true; } static void surface_frame (struct wl_client *client, struct wl_resource *resource, uint32_t callback) { struct surface *surface = wl_resource_get_user_data (resource); @@ -119,7 +134,7 @@ static void surface_commit (struct wl_client *client, struct wl_resource *resour /*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; + if (c.toplevel == surface) c.toplevel = NULL; wl_list_remove (&surface->link); free (surface); } @@ -128,7 +143,7 @@ static struct wl_surface_interface surface_interface = {&surface_destroy, &surfa // 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); + surface->surface = wl_resource_create (client, &wl_surface_interface, 4, id); wl_resource_set_implementation (surface->surface, &surface_interface, surface, &surface_delete); surface->client = get_client (client); wl_list_insert (&c.surfaces, &surface->link); @@ -138,33 +153,43 @@ static void compositor_create_region (struct wl_client *client, struct wl_resour 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); +BINDFUNC(wl_compositor, 4, 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) {} +static void shell_surface_set_toplevel (struct wl_client *client, struct wl_resource *resource) { + struct shell_surface *shell_surface = wl_resource_get_user_data (resource); + c.toplevel = shell_surface->surface; + wl_shell_surface_send_configure(shell_surface->shell_surface, 0, c.width, c.height); +} /*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}; +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 void shell_get_shell_surface (struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *res_surface) { + struct shell_surface *shell_surface = calloc (1, sizeof(struct surface)); + struct surface *surface = wl_resource_get_user_data (res_surface); + shell_surface->shell_surface = wl_resource_create (client, &wl_shell_surface_interface, 1, id); + wl_resource_set_implementation (shell_surface->shell_surface, &shell_surface_interface, shell_surface, NULL); + shell_surface->surface = surface; + surface->shell_surface = shell_surface; } static struct wl_shell_interface shell_interface = {&shell_get_shell_surface}; -BINDFUNC(wl_shell, shell_interface); +BINDFUNC(wl_shell, 1, 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) {} +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) { + //struct surface *surface = wl_resource_get_user_data (_surface); + //cursor = surface; +} /*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}; @@ -174,12 +199,12 @@ BINDFUNC(wl_shell, shell_interface); // 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); + struct wl_resource *pointer = wl_resource_create (client, &wl_pointer_interface, 7, 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); + struct wl_resource *keyboard = wl_resource_create (client, &wl_keyboard_interface, 7, id); wl_resource_set_implementation (keyboard, &keyboard_interface, NULL, NULL); //get_client(client)->keyboard = keyboard; //int fd, size; @@ -191,7 +216,7 @@ static void seat_get_keyboard (struct wl_client *client, struct wl_resource *res 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); + struct wl_resource *seat = wl_resource_create (client, &wl_seat_interface, 7, id); wl_resource_set_implementation (seat, &seat_interface, NULL, NULL); wl_seat_send_capabilities (seat, WL_SEAT_CAPABILITY_POINTER|WL_SEAT_CAPABILITY_KEYBOARD); } @@ -209,7 +234,7 @@ 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); + struct wl_resource *resource = wl_resource_create(client, &wl_output_interface, 3, id); if (resource == NULL) { wl_client_post_no_memory(client); return; @@ -217,9 +242,9 @@ wl_output_bind(struct wl_client *client, void *data, uint32_t version, uint32_t 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); + int mm_width = c.width/DPI*25*2; + int mm_height = c.height/DPI*25*2; + wl_output_send_geometry(resource, 0, 0, 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); @@ -230,87 +255,112 @@ wl_output_bind(struct wl_client *client, void *data, uint32_t version, uint32_t // backend callbacks /*No op*/ static void handle_resize_event (int width, int height) {} -/*No op*/ static void handle_draw_event (void) {} +static void handle_draw_event (void) { + c.redraw_needed = true; +} static void handle_mouse_motion_event (int x, int y) { - if (!c.main_surface || !c.main_surface->client->pointer) return; + if (!c.toplevel || !c.toplevel->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); + if (!c.toplevel->entered) { + wl_pointer_send_enter (c.toplevel->client->pointer, 0, c.toplevel->surface, surface_x, surface_y); + c.toplevel->entered = true; + } + wl_pointer_send_motion (c.toplevel->client->pointer, backend_get_timestamp(), surface_x, surface_y); + + if (wl_resource_get_version(c.toplevel->client->pointer) >= + WL_POINTER_FRAME_SINCE_VERSION) { + wl_pointer_send_frame(c.toplevel->client->pointer); + } } 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); + if (!c.toplevel || !c.toplevel->client->pointer) return; + wl_pointer_send_button (c.toplevel->client->pointer, 0, backend_get_timestamp(), button, state); + if (wl_resource_get_version(c.toplevel->client->pointer) >= + WL_POINTER_FRAME_SINCE_VERSION) { + wl_pointer_send_frame(c.toplevel->client->pointer); + } } 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); + //if (!c.toplevel || !c.toplevel->client->keyboard) return; + //wl_keyboard_send_key (c.toplevel->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); + //if (c.toplevel && c.toplevel->client->keyboard) + // wl_keyboard_send_modifiers (c.toplevel->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}; +static void handle_terminate() { + c.running = false; +} +static struct callbacks callbacks = {&handle_resize_event, &handle_draw_event, &handle_mouse_motion_event, &handle_mouse_button_event, &handle_key_event, &handle_modifiers_changed, &handle_terminate}; void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * data); +static void draw_surface(struct surface *surface) { + if (!surface) { + return; + } + struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (surface->buffer); + if (shm_buffer == NULL) return; + 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) { + glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); + wl_buffer_send_release (surface->buffer); + } + + if (surface->frame_callback) { + wl_callback_send_done (surface->frame_callback, backend_get_timestamp()); + wl_resource_destroy (surface->frame_callback); + surface->frame_callback = NULL; + } +} + 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); - } - } - + draw_surface(c.toplevel); + glFlush (); backend_swap_buffers (); + c.redraw_needed = false; } int main(void) { printf("Starting lorie server\n"); signal(SIGSEGV, handler); backend_init (&callbacks); - //setenv("WAYLAND_DEBUG", "1", 1); + setenv("WAYLAND_DEBUG", "1", 1); memset(&c, 0, sizeof(c)); wl_list_init (&c.clients); wl_list_init (&c.surfaces); + wl_list_init (&c.shell_surfaces); c.width = 1024; c.height = 600; + c.running = true; 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_seat_interface, 4, 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) { + while (c.running) { wl_event_loop_dispatch (event_loop, 0); backend_dispatch_nonblocking (); wl_display_flush_clients (c.display); - draw (); + if (c.redraw_needed) + draw (); + // usleep(50000); backend_wait_for_events (wayland_fd); } diff --git a/renderer.c b/renderer.c index 9a1d3ae..36246a8 100644 --- a/renderer.c +++ b/renderer.c @@ -26,7 +26,9 @@ static const char gSimpleFS[] = "varying vec2 outTexCoords;\n" "uniform sampler2D texture;\n" "\nvoid main(void) {\n" - " gl_FragColor = texture2D(texture, outTexCoords);\n" + //" gl_FragColor = texture2D(texture, outTexCoords);\n" + " gl_FragColor = texture2D(texture, outTexCoords).bgra;\n" + //" gl_FragColor = vec4(outTexCoords.x/outTexCoords.y,outTexCoords.y/outTexCoords.x, 0.0, 0.0);\n" "}\n\n"; static void checkGlError(const char* op) { diff --git a/test_xwayland b/test_xwayland new file mode 100755 index 0000000..e410d3c --- /dev/null +++ b/test_xwayland @@ -0,0 +1,8 @@ +#!/bin/bash +export WAYLAND_DEBUG=1 +export DISPLAY=:1 +Xwayland $DISPLAY & +sleep 0.3 +openbox & +sleep 0.3 +pcmanfm