From 36b4602804594b1dab55b2c16a73b61316ce5010 Mon Sep 17 00:00:00 2001 From: Christopher Michael Date: Sun, 22 Jan 2012 16:32:39 +0000 Subject: [PATCH] E Comp Module (wayland client support): Break large file into several smaller ones (easier to maintain & read). Finish off lots of todos from original file. NB: This STILL will not render wayland clients in our compositor. Anyone with experience wrt this ?? Any help would be appreciated !! SVN revision: 67451 --- src/modules/comp/Makefile.am | 16 +- src/modules/comp/e_mod_comp.c | 6 +- src/modules/comp/e_mod_comp_wayland.c | 1703 ---------------------- src/modules/comp/e_mod_comp_wayland.h | 19 - src/modules/comp/e_mod_comp_wl.c | 280 ++++ src/modules/comp/e_mod_comp_wl.h | 245 ++++ src/modules/comp/e_mod_comp_wl_comp.c | 504 +++++++ src/modules/comp/e_mod_comp_wl_comp.h | 15 + src/modules/comp/e_mod_comp_wl_input.c | 172 +++ src/modules/comp/e_mod_comp_wl_input.h | 12 + src/modules/comp/e_mod_comp_wl_output.c | 468 ++++++ src/modules/comp/e_mod_comp_wl_output.h | 13 + src/modules/comp/e_mod_comp_wl_shell.c | 631 ++++++++ src/modules/comp/e_mod_comp_wl_shell.h | 11 + src/modules/comp/e_mod_comp_wl_shm.c | 62 + src/modules/comp/e_mod_comp_wl_shm.h | 11 + src/modules/comp/e_mod_comp_wl_surface.c | 514 +++++++ src/modules/comp/e_mod_comp_wl_surface.h | 23 + 18 files changed, 2978 insertions(+), 1727 deletions(-) delete mode 100644 src/modules/comp/e_mod_comp_wayland.c delete mode 100644 src/modules/comp/e_mod_comp_wayland.h create mode 100644 src/modules/comp/e_mod_comp_wl.c create mode 100644 src/modules/comp/e_mod_comp_wl.h create mode 100644 src/modules/comp/e_mod_comp_wl_comp.c create mode 100644 src/modules/comp/e_mod_comp_wl_comp.h create mode 100644 src/modules/comp/e_mod_comp_wl_input.c create mode 100644 src/modules/comp/e_mod_comp_wl_input.h create mode 100644 src/modules/comp/e_mod_comp_wl_output.c create mode 100644 src/modules/comp/e_mod_comp_wl_output.h create mode 100644 src/modules/comp/e_mod_comp_wl_shell.c create mode 100644 src/modules/comp/e_mod_comp_wl_shell.h create mode 100644 src/modules/comp/e_mod_comp_wl_shm.c create mode 100644 src/modules/comp/e_mod_comp_wl_shm.h create mode 100644 src/modules/comp/e_mod_comp_wl_surface.c create mode 100644 src/modules/comp/e_mod_comp_wl_surface.h diff --git a/src/modules/comp/Makefile.am b/src/modules/comp/Makefile.am index 66d99b973..371c218d6 100644 --- a/src/modules/comp/Makefile.am +++ b/src/modules/comp/Makefile.am @@ -32,8 +32,20 @@ module_la_SOURCES = e_mod_main.c \ e_mod_comp_cfdata.c \ e_mod_comp_cfdata.h if HAVE_WAYLAND -module_la_SOURCES += e_mod_comp_wayland.h \ - e_mod_comp_wayland.c +module_la_SOURCES += e_mod_comp_wl.h \ + e_mod_comp_wl.c \ + e_mod_comp_wl_comp.h \ + e_mod_comp_wl_comp.c \ + e_mod_comp_wl_shm.h \ + e_mod_comp_wl_shm.c \ + e_mod_comp_wl_output.h \ + e_mod_comp_wl_output.c \ + e_mod_comp_wl_input.h \ + e_mod_comp_wl_input.c \ + e_mod_comp_wl_shell.h \ + e_mod_comp_wl_shell.c \ + e_mod_comp_wl_surface.h \ + e_mod_comp_wl_surface.c endif module_la_LIBADD = @e_libs@ @dlopen_libs@ @WAYLAND_LIBS@ diff --git a/src/modules/comp/e_mod_comp.c b/src/modules/comp/e_mod_comp.c index 242f0170a..d4a1f5c51 100644 --- a/src/modules/comp/e_mod_comp.c +++ b/src/modules/comp/e_mod_comp.c @@ -3,7 +3,7 @@ #include "e_mod_comp.h" #include "e_mod_comp_update.h" #ifdef HAVE_WAYLAND -#include "e_mod_comp_wayland.h" +#include "e_mod_comp_wl.h" #endif #define OVER_FLOW 2 @@ -3488,7 +3488,7 @@ e_mod_comp_init(void) } #ifdef HAVE_WAYLAND - if (!e_mod_comp_wayland_init()) + if (!e_mod_comp_wl_init()) EINA_LOG_ERR("Failed to initialize Wayland Client Support !!\n"); #endif @@ -3515,7 +3515,7 @@ e_mod_comp_shutdown(void) E_FREE_LIST(handlers, ecore_event_handler_del); #ifdef HAVE_WAYLAND - e_mod_comp_wayland_shutdown(); + e_mod_comp_wl_shutdown(); #endif if (damages) eina_hash_free(damages); diff --git a/src/modules/comp/e_mod_comp_wayland.c b/src/modules/comp/e_mod_comp_wayland.c deleted file mode 100644 index fc1d0815f..000000000 --- a/src/modules/comp/e_mod_comp_wayland.c +++ /dev/null @@ -1,1703 +0,0 @@ -#include "e.h" -#include "e_mod_main.h" -#include "e_mod_comp.h" -#ifdef HAVE_WAYLAND -# include "e_mod_comp_wayland.h" -#endif - -#define WL_OUTPUT_FLIPPED 0x01 - -/* local typedefs */ -typedef enum _Wayland_Shell_Surface_Type Wayland_Shell_Surface_Type; -typedef struct _Wayland_Output Wayland_Output; -typedef struct _Wayland_Input Wayland_Input; -typedef struct _Wayland_Shell Wayland_Shell; -typedef struct _Wayland_Surface Wayland_Surface; -typedef struct _Wayland_Shell_Surface Wayland_Shell_Surface; -typedef struct _Wayland_Frame_Callback Wayland_Frame_Callback; -typedef struct _Wayland_Shader Wayland_Shader; - -enum _Wayland_Shell_Surface_Type -{ - SHELL_SURFACE_NONE, - SHELL_SURFACE_PANEL, - SHELL_SURFACE_BACKGROUND, - SHELL_SURFACE_LOCK, - SHELL_SURFACE_SCREENSAVER, - SHELL_SURFACE_TOPLEVEL, - SHELL_SURFACE_TRANSIENT, - SHELL_SURFACE_FULLSCREEN, - SHELL_SURFACE_POPUP -}; - -struct _Wayland_Output -{ - int x, y, width, height; - char *make, *model; - uint32_t subpixel, flags; - - struct - { - Eina_Bool needed : 1; - Eina_Bool scheduled : 1; - } repaint; - - struct - { - uint32_t flags; - int32_t w, h; - uint32_t refresh; - /* link ?? struct wl_list link */ - } mode; - - EGLSurface egl_surface; - - struct wl_object *output; - struct wl_event_source *frame_timer; - - pixman_region32_t region, previous_damage; - - Eina_Bool (*prepare_render) (Wayland_Output *output); - Eina_Bool (*present) (Wayland_Output *output); - Eina_Bool (*prepare_scanout_surface) (Wayland_Output *output, Wayland_Surface *surface); - Eina_Bool (*set_hardware_cursor) (Wayland_Output *output, Wayland_Input *input_dev); - void (*destroy) (Wayland_Output *output); -}; - -struct _Wayland_Shell -{ - Eina_Bool locked : 1; - struct wl_surface *lock_surface; - struct wl_listener lock_listener; - - void (*lock) (Wayland_Shell *shell); - void (*unlock) (Wayland_Shell *shell); - void (*map) (Wayland_Shell *shell, Wayland_Surface *surface, int32_t width, int32_t height); - void (*configure) (Wayland_Shell *shell, Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height); - void (*destroy) (Wayland_Shell *shell); -}; - -struct _Wayland_Surface -{ - struct wl_surface surface; - - GLuint texture, saved_texture; - - pixman_region32_t damage, opaque; - - int32_t x, y, width, height; - - struct wl_list buffer_link; - struct wl_buffer *buffer; - struct wl_listener buffer_destroy_listener; - struct wl_list link; - - uint32_t visual; -}; - -struct _Wayland_Shell_Surface -{ - struct wl_resource resource; - Wayland_Surface *surface; - struct wl_listener surface_destroy_listener; - Wayland_Shell_Surface *parent; - int32_t saved_x, saved_y; - Wayland_Output *output; - struct wl_list link; - Wayland_Shell_Surface_Type type; - /* TODO: Handle popup */ -}; - -struct _Wayland_Input -{ - struct wl_input_device input_dev; - Wayland_Surface *sprite; - int32_t hotspot_x, hotspot_y; -}; - -struct _Wayland_Frame_Callback -{ - struct wl_resource resource; - struct wl_list link; -}; - -struct _Wayland_Shader -{ - GLuint program; - GLuint vertex, fragment; - struct - { - GLuint proj, tex, alpha, color; - } uniform; -}; - -struct wl_shell -{ - Wayland_Shell shell; - - struct - { - struct wl_client *client; - struct wl_resource *desktop_shell; - } child; - - Wayland_Shell_Surface *lock_surface; - struct wl_listener lock_surface_listener; - struct wl_list hidden_surface_list; - - Eina_Bool locked : 1; - Eina_Bool prepare_event_sent : 1; -}; - -/* local function prototypes */ -static Eina_Bool _e_mod_comp_wayland_backend_init(void); -static void _e_mod_comp_wayland_backend_shutdown(void); - -static Eina_Bool _e_mod_comp_wayland_egl_init(void); -static void _e_mod_comp_wayland_egl_shutdown(void); - -static Eina_Bool _e_mod_comp_wayland_compositor_init(void); -static void _e_mod_comp_wayland_compositor_shutdown(void); -static void _e_mod_comp_wayland_compositor_bind(struct wl_client *client, void *data __UNUSED__, uint32_t version __UNUSED__, uint32_t id); -static void _e_mod_comp_wayland_compositor_repick(void); - -static Eina_Bool _e_mod_comp_wayland_output_init(void); -static void _e_mod_comp_wayland_output_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id); -static int _e_mod_comp_wayland_output_frame_handle(void *data); -static void _e_mod_comp_wayland_output_repaint(void *data); -static void _e_mod_comp_wayland_output_destroy(Wayland_Output *output); -static void _e_mod_comp_wayland_repaint_output(Wayland_Output *output); -static Eina_Bool _e_mod_comp_wayland_output_prepare_render(Wayland_Output *output); -static Eina_Bool _e_mod_comp_wayland_output_present(Wayland_Output *output); -static Eina_Bool _e_mod_comp_wayland_output_prepare_scanout_surface(Wayland_Output *output __UNUSED__, Wayland_Surface *surface __UNUSED__); -static Eina_Bool _e_mod_comp_wayland_output_set_hardware_cursor(Wayland_Output *output __UNUSED__, Wayland_Input *input __UNUSED__); - -static Eina_Bool _e_mod_comp_wayland_input_init(void); -static void _e_mod_comp_wayland_input_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id); -static void _e_mod_comp_wayland_input_unbind(struct wl_resource *resource); -static void _e_mod_comp_wayland_input_attach(struct wl_client *client, struct wl_resource *resource, uint32_t timestamp, struct wl_resource *buffer_resource, int32_t x, int32_t y); -static void _e_mod_comp_wayland_input_repick(void); - -static Eina_Bool _e_mod_comp_wayland_shell_init(void); -static void _e_mod_comp_wayland_shell_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id); -static void _e_mod_comp_wayland_shell_get_shell_surface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource); -static void _e_mod_comp_wayland_shell_lock(Wayland_Shell *base); -static void _e_mod_comp_wayland_shell_unlock(Wayland_Shell *base); -static void _e_mod_comp_wayland_shell_map(Wayland_Shell *base, Wayland_Surface *surface, int32_t width, int32_t height); -static void _e_mod_comp_wayland_shell_configure(Wayland_Shell *base, Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height); -static void _e_mod_comp_wayland_shell_destroy(Wayland_Shell *base); -static void _e_mod_comp_wayland_shell_surface_destroy_handle(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp); - -static int _e_mod_comp_wayland_idle_handle(void *data __UNUSED__); -static Eina_Bool _e_mod_comp_wayland_fd_handle(void *data, Ecore_Fd_Handler *hdl __UNUSED__); - -static void _e_mod_comp_wayland_surface_create(struct wl_client *client, struct wl_resource *resource, uint32_t id); -static void _e_mod_comp_wayland_surface_destroy(struct wl_client *client __UNUSED__, struct wl_resource *resource); -static void _e_mod_comp_wayland_surface_attach(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *buffer_resource, int32_t x, int32_t y); -static void _e_mod_comp_wayland_surface_damage(struct wl_client *client __UNUSED__, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); -static void _e_mod_comp_wayland_surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback); -static void _e_mod_comp_wayland_surface_configure(Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height); -static Eina_Bool _e_mod_comp_wayland_surface_move(Wayland_Surface *surface, Wayland_Input *input, uint32_t timestamp); -static Eina_Bool _e_mod_comp_wayland_surface_resize(Wayland_Surface *surface, Wayland_Input *input, uint32_t timestamp, uint32_t edges); -static Wayland_Surface *_e_mod_comp_wayland_create_surface(int32_t x, int32_t y, int32_t width, int32_t height); -static void _e_mod_comp_wayland_surface_damage_below(Wayland_Surface *surface); - -static void _e_mod_comp_wayland_destroy_shell_surface(struct wl_resource *resource); -static void _e_mod_comp_wayland_destroy_surface(struct wl_resource *resource); -static void _e_mod_comp_wayland_destroy_buffer(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp __UNUSED__); -static void _e_mod_comp_wayland_destroy_frame(struct wl_resource *resource); -static void _e_mod_comp_wayland_damage_surface(Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height); - -static void _e_mod_comp_wayland_shm_buffer_created(struct wl_buffer *buffer); -static void _e_mod_comp_wayland_shm_buffer_damaged(struct wl_buffer *buffer, int32_t x __UNUSED__, int32_t y __UNUSED__, int32_t width __UNUSED__, int32_t height __UNUSED__); -static void _e_mod_comp_wayland_shm_buffer_destroyed(struct wl_buffer *buffer); - -static void _e_mod_comp_wayland_buffer_attach(struct wl_buffer *buffer, struct wl_surface *surface); - -static void _e_mod_comp_wayland_shell_surface_move(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp); -static void _e_mod_comp_wayland_shell_surface_resize(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp, uint32_t edges); -static void _e_mod_comp_wayland_shell_surface_set_toplevel(struct wl_client *client __UNUSED__, struct wl_resource *resource); -static void _e_mod_comp_wayland_shell_surface_set_transient(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *parent_resource, int x, int y, uint32_t flags __UNUSED__); -static void _e_mod_comp_wayland_shell_surface_set_fullscreen(struct wl_client *client __UNUSED__, struct wl_resource *resource); -static void _e_mod_comp_wayland_shell_surface_set_popup(struct wl_client *client, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp, struct wl_resource *parent_resource, int32_t x, int32_t y, uint32_t flags); -static Eina_Bool _e_mod_comp_wayland_shell_surface_type_reset(Wayland_Shell_Surface *shell_surface); - -static Wayland_Shell_Surface *_e_mod_comp_wayland_get_shell_surface(Wayland_Surface *surface); - -/* wayland interfaces */ -static const struct wl_compositor_interface _wl_comp_interface = -{ - _e_mod_comp_wayland_surface_create, -}; - -static const struct wl_shm_callbacks _wl_shm_callbacks = -{ - _e_mod_comp_wayland_shm_buffer_created, - _e_mod_comp_wayland_shm_buffer_damaged, - _e_mod_comp_wayland_shm_buffer_destroyed -}; - -static const struct wl_input_device_interface _wl_input_interface = -{ - _e_mod_comp_wayland_input_attach, -}; -static const struct wl_shell_interface _wl_shell_interface = -{ - _e_mod_comp_wayland_shell_get_shell_surface -}; -static const struct wl_surface_interface _wl_surface_interface = -{ - _e_mod_comp_wayland_surface_destroy, - _e_mod_comp_wayland_surface_attach, - _e_mod_comp_wayland_surface_damage, - _e_mod_comp_wayland_surface_frame -}; -static const struct wl_shell_surface_interface _wl_shell_surface_interface = -{ - _e_mod_comp_wayland_shell_surface_move, - _e_mod_comp_wayland_shell_surface_resize, - _e_mod_comp_wayland_shell_surface_set_toplevel, - _e_mod_comp_wayland_shell_surface_set_transient, - _e_mod_comp_wayland_shell_surface_set_fullscreen, - _e_mod_comp_wayland_shell_surface_set_popup -}; - -/* private variables */ -static struct wl_display *_wl_disp; -static struct wl_compositor *_wl_comp; -static struct wl_shm *_wl_shm; -static struct wl_event_source *_wl_idle_timer; -static struct wl_event_source *_wl_event_source; -static struct wl_list _wl_comp_surface_list; - -static Ecore_Fd_Handler *_wl_fd_handler = NULL; -static EGLDisplay _wl_egl_disp; -static EGLContext _wl_egl_context; -static EGLConfig _wl_egl_config; -static Wayland_Output *_wl_output; -static Wayland_Input *_wl_input; -static Wayland_Shell *_wl_shell; - -Eina_Bool -e_mod_comp_wayland_init(void) -{ - /* init wayland display */ - if (!(_wl_disp = wl_display_create())) - { - EINA_LOG_ERR("Failed to create wayland display\n"); - return EINA_FALSE; - } - - /* TODO: Add signal handlers for SIGTERM, etc */ - - /* INIT BACKEND */ - if (!_e_mod_comp_wayland_backend_init()) - { - EINA_LOG_ERR("Failed to init wayland backend\n"); - if (_wl_disp) wl_display_terminate(_wl_disp); - _wl_disp = NULL; - return EINA_FALSE; - } - - return EINA_TRUE; -} - -void -e_mod_comp_wayland_shutdown(void) -{ - if (!_wl_disp) return; - _e_mod_comp_wayland_backend_shutdown(); -} - -void -e_mod_comp_wayland_repaint(void) -{ - struct wl_event_loop *loop; - - loop = wl_display_get_event_loop(_wl_disp); - - if (_wl_output) - { - _wl_output->repaint.needed = EINA_TRUE; - if (_wl_output->repaint.scheduled) return; - wl_event_loop_add_idle(loop, - _e_mod_comp_wayland_output_repaint, _wl_output); - _wl_output->repaint.scheduled = EINA_TRUE; - } -} - -/* local functions */ -static Eina_Bool -_e_mod_comp_wayland_backend_init(void) -{ - struct wl_event_loop *loop; - int fd = 0; - - /* init egl */ - if (!_e_mod_comp_wayland_egl_init()) return EINA_FALSE; - - /* init compositor */ - if (!_e_mod_comp_wayland_compositor_init()) return EINA_FALSE; - - /* init output */ - if (!_e_mod_comp_wayland_output_init()) return EINA_FALSE; - - /* init input */ - if (!_e_mod_comp_wayland_input_init()) return EINA_FALSE; - - loop = wl_display_get_event_loop(_wl_disp); - fd = wl_event_loop_get_fd(loop); - - _wl_fd_handler = - ecore_main_fd_handler_add(fd, ECORE_FD_READ, - _e_mod_comp_wayland_fd_handle, - _wl_disp, NULL, NULL); - - /* init shell */ - if (!_e_mod_comp_wayland_shell_init()) return EINA_FALSE; - - if (wl_display_add_socket(_wl_disp, NULL)) - { - EINA_LOG_ERR("Failed to add display socket\n"); - /* _e_mod_comp_wayland_input_shutdown(); */ - /* _e_mod_comp_wayland_output_shutdown(); */ - _e_mod_comp_wayland_compositor_shutdown(); - return EINA_FALSE; - } - - /* wake the compositor */ - wl_event_source_timer_update(_wl_idle_timer, 300 * 1000); - - /* run the display */ - wl_event_loop_dispatch(loop, 0); - - /* wl_display_run(_wl_disp); */ - - return EINA_TRUE; -} - -static void -_e_mod_comp_wayland_backend_shutdown(void) -{ - /* remove main event source */ - if (_wl_event_source) - wl_event_source_remove(_wl_event_source); - - /* input destroy */ - if (_wl_input) - { - wl_input_device_release(&_wl_input->input_dev); - free(_wl_input); - } - - /* compositor destroy */ - _e_mod_comp_wayland_compositor_shutdown(); - - /* shutdown egl */ - _e_mod_comp_wayland_egl_shutdown(); -} - -static Eina_Bool -_e_mod_comp_wayland_egl_init(void) -{ - EGLint major, minor, n; - const char *extensions; - EGLint cfg_attribs[] = - { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 1, - EGL_GREEN_SIZE, 1, - EGL_BLUE_SIZE, 1, - EGL_DEPTH_SIZE, 1, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE - }; - static const EGLint ctxt_attribs[] = - { - EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE - }; - - /* NB: Due to the way mesa init's egl, we need to pass a 'NULL' display here - * in order to avoid a segfault due to xlib vs xcb of ecore_x */ - if (!(_wl_egl_disp = eglGetDisplay(NULL))) - { - EINA_LOG_ERR("Failed to create Egl Display\n"); - return EINA_FALSE; - } - if (!eglInitialize(_wl_egl_disp, &major, &minor)) - { - EINA_LOG_ERR("Failed to init Egl\n"); - return EINA_FALSE; - } - - /* init extensions */ - extensions = eglQueryString(_wl_egl_disp, EGL_EXTENSIONS); - if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) - { - EINA_LOG_ERR("EGL_KHR_surfaceless_gles2 extension not available\n"); - return EINA_FALSE; - } - - if (!eglBindAPI(EGL_OPENGL_ES_API)) - { - EINA_LOG_ERR("Failed to bind EGL_OPENGL_ES_API\n"); - return EINA_FALSE; - } - - if ((!eglChooseConfig(_wl_egl_disp, cfg_attribs, &_wl_egl_config, 1, &n) || - (n == 0))) - { - EINA_LOG_ERR("Failed to choose egl config\n"); - return EINA_FALSE; - } - - _wl_egl_context = - eglCreateContext(_wl_egl_disp, _wl_egl_config, EGL_NO_CONTEXT, ctxt_attribs); - if (!_wl_egl_context) - { - EINA_LOG_ERR("Failed to create egl context\n"); - return EINA_FALSE; - } - - if (!eglMakeCurrent(_wl_egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, - _wl_egl_context)) - { - EINA_LOG_ERR("Failed to make context current\n"); - return EINA_FALSE; - } - - return EINA_TRUE; -} - -static void -_e_mod_comp_wayland_egl_shutdown(void) -{ - if (!_wl_egl_disp) return; - eglMakeCurrent(_wl_egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(_wl_egl_disp); - eglReleaseThread(); -} - -static Eina_Bool -_e_mod_comp_wayland_compositor_init(void) -{ - struct wl_event_loop *loop; - - memset(&_wl_comp, 0, sizeof(_wl_comp)); - if (!wl_display_add_global(_wl_disp, &wl_compositor_interface, _wl_comp, - _e_mod_comp_wayland_compositor_bind)) - { - EINA_LOG_ERR("Failed to init wayland compositor\n"); - return EINA_FALSE; - } - - _wl_shm = wl_shm_init(_wl_disp, &_wl_shm_callbacks); - - wl_list_init(&_wl_comp_surface_list); - - /* TODO: Maybe need egl wl bind display ?? */ - - wl_data_device_manager_init(_wl_disp); - - glActiveTexture(GL_TEXTURE0); - - /* TODO: Shader init */ - - loop = wl_display_get_event_loop(_wl_disp); - - _wl_idle_timer = - wl_event_loop_add_timer(loop, _e_mod_comp_wayland_idle_handle, NULL); - wl_event_source_timer_update(_wl_idle_timer, 300 * 1000); - - e_mod_comp_wayland_repaint(); - - return EINA_TRUE; -} - -static void -_e_mod_comp_wayland_compositor_shutdown(void) -{ - if (_wl_idle_timer) - wl_event_source_remove(_wl_idle_timer); - - if (_wl_output) _wl_output->destroy(_wl_output); - if (_wl_shm) wl_shm_finish(_wl_shm); -} - -static void -_e_mod_comp_wayland_compositor_bind(struct wl_client *client, void *data __UNUSED__, uint32_t version __UNUSED__, uint32_t id) -{ - wl_client_add_object(client, &wl_compositor_interface, - &_wl_comp_interface, id, _wl_comp); -} - -static void -_e_mod_comp_wayland_compositor_repick(void) -{ - _e_mod_comp_wayland_input_repick(); -} - -static Eina_Bool -_e_mod_comp_wayland_output_init(void) -{ - struct wl_event_loop *loop; - Ecore_X_Window *roots; - int rnum = 0, rx = 0, ry = 0, rw, rh; - - roots = ecore_x_window_root_list(&rnum); - if ((!roots) || (rnum <= 0)) - { - EINA_LOG_ERR("Failed to get root window list\n"); - return EINA_FALSE; - } - - /* get root window properties */ - ecore_x_window_size_get(roots[0], &rw, &rh); - free(roots); - - /* init output */ - /* FIXME: Handle more than one root window ?? */ - if (!(_wl_output = malloc(sizeof(Wayland_Output)))) - { - EINA_LOG_ERR("Failed to malloc wayland output\n"); - return EINA_FALSE; - } - - _wl_output->mode.flags = (WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED); - _wl_output->mode.w = rw; - _wl_output->mode.h = rh; - _wl_output->mode.refresh = 60; - - /* set variables */ - _wl_output->x = rx; - _wl_output->y = ry; - _wl_output->width = rw; - _wl_output->height = rh; - _wl_output->flags = WL_OUTPUT_FLIPPED; - - /* FIXME: Handle weston_output_move ?? */ - - if (!wl_display_add_global(_wl_disp, &wl_output_interface, _wl_output, - _e_mod_comp_wayland_output_bind)) - { - EINA_LOG_ERR("Failed to add wayland output\n"); - return EINA_FALSE; - } - - /* TODO: Fix me */ - /* _wl_output->egl_surface = */ - /* eglCreateWindowSurface(_wl_egl_disp, _wl_egl_config, _wl_output->window, NULL); */ - /* eglMakeCurrent(_wl_egl_disp, _wl_output->egl_surface, _wl_output->egl_surface, */ - /* _wl_egl_context); */ - - loop = wl_display_get_event_loop(_wl_disp); - _wl_output->frame_timer = - wl_event_loop_add_timer(loop, _e_mod_comp_wayland_output_frame_handle, - _wl_output); - - _wl_output->prepare_render = _e_mod_comp_wayland_output_prepare_render; - _wl_output->present = _e_mod_comp_wayland_output_present; - _wl_output->prepare_scanout_surface = - _e_mod_comp_wayland_output_prepare_scanout_surface; - _wl_output->set_hardware_cursor = - _e_mod_comp_wayland_output_set_hardware_cursor; - _wl_output->destroy = _e_mod_comp_wayland_output_destroy; - - return EINA_TRUE; -} - -static void -_e_mod_comp_wayland_output_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id) -{ - Wayland_Output *output; - struct wl_resource *resource; - - if (!(output = data)) return; - - resource = - wl_client_add_object(client, &wl_output_interface, NULL, id, data); - - wl_resource_post_event(resource, WL_OUTPUT_GEOMETRY, - output->x, output->y, output->width, output->height, - output->subpixel, output->make, output->model); - - /* TODO: iterate mode list */ - - wl_resource_post_event(resource, WL_OUTPUT_MODE, output->mode.flags, - output->mode.w, output->mode.h, output->mode.refresh); -} - -static int -_e_mod_comp_wayland_output_frame_handle(void *data) -{ - Wayland_Output *output; - uint32_t sec; - struct timeval val; - - if (!(output = data)) return 0; - - gettimeofday(&val, NULL); - sec = val.tv_sec * 1000 + val.tv_usec / 1000; - - /* TODO: weston output finish frame */ - - return 1; -} - -static void -_e_mod_comp_wayland_output_repaint(void *data) -{ - Wayland_Output *output; - - if (!(output = data)) return; - - _e_mod_comp_wayland_repaint_output(output); - - output->repaint.needed = EINA_FALSE; - output->repaint.scheduled = EINA_TRUE; - if (output->present) output->present(output); - - /* TODO: Loop output frame callback list */ - /* call resource_post_event */ - /* call resource destroy */ - - /* TODO: Handle animation frame */ -} - -static void -_e_mod_comp_wayland_output_destroy(Wayland_Output *output) -{ - if (!output) return; - - if (output->frame_timer) wl_event_source_remove(output->frame_timer); - - if (output->egl_surface) - eglDestroySurface(_wl_egl_disp, output->egl_surface); - - free(output); -} - -static void -_e_mod_comp_wayland_repaint_output(Wayland_Output *output) -{ - Wayland_Surface *ws; - pixman_region32_t opaque, new_damage, total_damage, repaint; - - printf("Comp Wayland Output Repaint\n"); - if (!output) return; - - output->prepare_render(output); - - glViewport(0, 0, output->width, output->height); - - /* gluseprogram, gluniformmatrix, etc */ - - /* TODO: Set cursor */ - - pixman_region32_init(&new_damage); - pixman_region32_init(&opaque); - - wl_list_for_each(ws, &_wl_comp_surface_list, link) - { - pixman_region32_subtract(&ws->damage, &ws->damage, &opaque); - pixman_region32_union(&new_damage, &new_damage, &ws->damage); - pixman_region32_union(&opaque, &opaque, &ws->opaque); - } - - pixman_region32_init(&total_damage); - pixman_region32_union(&total_damage, &new_damage, &output->previous_damage); - pixman_region32_intersect(&output->previous_damage, &new_damage, - &output->region); - - pixman_region32_fini(&opaque); - pixman_region32_fini(&new_damage); - - ws = container_of(_wl_comp_surface_list.next, Wayland_Surface, link); - /* TODO: Scanout_surface */ - - /* TODO: Handle fullscreen */ - /* if (ws->type == SHELL_SURFACE_FULLSCREEN) */ - /* { */ - /* if ((ws->width < output->width) || */ - /* (ws->height < output->height)) */ - /* glClear(GL_COLOR_BUFFER_BIT); */ - /* } */ - /* else */ - { - wl_list_for_each(ws, &_wl_comp_surface_list, link) - { - pixman_region32_copy(&ws->damage, &total_damage); - pixman_region32_subtract(&total_damage, &total_damage, &ws->opaque); - } - wl_list_for_each_reverse(ws, &_wl_comp_surface_list, link) - { - pixman_region32_init(&repaint); - pixman_region32_intersect(&repaint, &output->region, &ws->damage); - /* TODO: surface draw */ - pixman_region32_subtract(&ws->damage, &ws->damage, &output->region); - pixman_region32_fini(&repaint); - } - } - - pixman_region32_fini(&total_damage); -} - -static Eina_Bool -_e_mod_comp_wayland_output_prepare_render(Wayland_Output *output) -{ - printf("Comp Wayland Output Prepare Render\n"); - if (!output->egl_surface) return EINA_FALSE; - - if (!eglMakeCurrent(_wl_egl_disp, output->egl_surface, output->egl_surface, - _wl_egl_context)) - return EINA_FALSE; - - return EINA_TRUE; -} - -static Eina_Bool -_e_mod_comp_wayland_output_present(Wayland_Output *output) -{ - printf("Comp Wayland Output Present\n"); - - if (_e_mod_comp_wayland_output_prepare_render(output)) - return EINA_FALSE; - - if (!output->egl_surface) return EINA_FALSE; - eglSwapBuffers(_wl_egl_disp, output->egl_surface); - wl_event_source_timer_update(output->frame_timer, 10); - - return EINA_TRUE; -} - -static Eina_Bool -_e_mod_comp_wayland_output_prepare_scanout_surface(Wayland_Output *output __UNUSED__, Wayland_Surface *surface __UNUSED__) -{ - return EINA_FALSE; -} - -static Eina_Bool -_e_mod_comp_wayland_output_set_hardware_cursor(Wayland_Output *output __UNUSED__, Wayland_Input *input __UNUSED__) -{ - return EINA_FALSE; -} - -static Eina_Bool -_e_mod_comp_wayland_input_init(void) -{ - if (!(_wl_input = malloc(sizeof(Wayland_Input)))) - { - EINA_LOG_ERR("Failed to malloc wayland input\n"); - return EINA_FALSE; - } - - wl_input_device_init(&_wl_input->input_dev); - - wl_display_add_global(_wl_disp, &wl_input_device_interface, - _wl_input, _e_mod_comp_wayland_input_bind); - - return EINA_TRUE; -} - -static void -_e_mod_comp_wayland_input_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id) -{ - struct wl_input_device *dev; - struct wl_resource *resource; - - if (!(dev = data)) return; - - resource = - wl_client_add_object(client, &wl_input_device_interface, - &_wl_input_interface, id, data); - - wl_list_insert(&dev->resource_list, &resource->link); - resource->destroy = _e_mod_comp_wayland_input_unbind; -} - -static void -_e_mod_comp_wayland_input_unbind(struct wl_resource *resource) -{ - printf("Comp Module Wayland Input Unbind\n"); - wl_list_remove(&resource->link); - free(resource); -} - -static void -_e_mod_comp_wayland_input_attach(struct wl_client *client, struct wl_resource *resource, uint32_t timestamp, struct wl_resource *buffer_resource, int32_t x, int32_t y) -{ - Wayland_Input *wi; - struct wl_buffer *buffer; - - printf("Comp Module Wayland Input Attach\n"); - - wi = resource->data; - if (timestamp < wi->input_dev.pointer_focus_time) return; - if (!wi->input_dev.pointer_focus) return; - if (wi->input_dev.pointer_focus->resource.client != client) return; - - if (wi->sprite) - _e_mod_comp_wayland_surface_damage_below(wi->sprite); - - if (!buffer_resource) - { - if (wi->sprite) - { - _e_mod_comp_wayland_destroy_surface(&wi->sprite->surface.resource); - wi->sprite = NULL; - } - return; - } - - if (!wi->sprite) - { - wi->sprite = - _e_mod_comp_wayland_create_surface(wi->input_dev.x, - wi->input_dev.y, 32, 32); - wl_list_init(&wi->sprite->link); - } - - buffer = buffer_resource->data; - _e_mod_comp_wayland_buffer_attach(buffer, &wi->sprite->surface); - - wi->hotspot_x = x; - wi->hotspot_y = y; - wi->sprite->width = buffer->width; - wi->sprite->height = buffer->height; - wi->sprite->x = wi->input_dev.x - wi->hotspot_x; - wi->sprite->y = wi->input_dev.y - wi->hotspot_y; - - _e_mod_comp_wayland_damage_surface(wi->sprite, 0, 0, 32, 32); -} - -static void -_e_mod_comp_wayland_input_repick(void) -{ - /* TODO: Code me (compositor.c: 347) */ -} - -static Eina_Bool -_e_mod_comp_wayland_shell_init(void) -{ - /* init shell */ - if (!(_wl_shell = malloc(sizeof(Wayland_Shell)))) - { - EINA_LOG_ERR("Failed to malloc wayland shell\n"); - return EINA_FALSE; - } - -// wl_list_init(&); - - _wl_shell->lock = _e_mod_comp_wayland_shell_lock; - _wl_shell->unlock = _e_mod_comp_wayland_shell_unlock; - _wl_shell->map = _e_mod_comp_wayland_shell_map; - _wl_shell->configure = _e_mod_comp_wayland_shell_configure; - _wl_shell->destroy = _e_mod_comp_wayland_shell_destroy; - - /* FIXME: Maybe handle shell_configure to setup screensaver ? */ - - if (!wl_display_add_global(_wl_disp, &wl_shell_interface, _wl_shell, - _e_mod_comp_wayland_shell_bind)) - { - EINA_LOG_ERR("Failed to add wayland shell\n"); - return EINA_FALSE; - } - - /* TODO: Maybe add desktop_shell interface ?? */ - /* if (!wl_display_add_global(_wl_disp, &wl_shell_interface, _wl_shell, */ - /* _e_mod_comp_wayland_shell_bind)) */ - /* { */ - /* EINA_LOG_ERR("Failed to add wayland shell\n"); */ - /* return EINA_FALSE; */ - /* } */ - - /* TODO: Maybe add screensaver interface ?? */ - - return EINA_TRUE; -} - -static void -_e_mod_comp_wayland_shell_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id) -{ - Wayland_Shell *shell; - - if (!(shell = data)) return; - wl_client_add_object(client, &wl_shell_interface, - &_wl_shell_interface, id, shell); -} - -static void -_e_mod_comp_wayland_shell_get_shell_surface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource) -{ - Wayland_Surface *ws; - Wayland_Shell_Surface *wss; - - printf("Comp Module Wayland Shell Get Shell Surface\n"); - - ws = surface_resource->data; - - if (_e_mod_comp_wayland_get_shell_surface(ws)) - { - wl_resource_post_error(surface_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "get_shell_surface already requested"); - return; - } - - if (!(wss = calloc(1, sizeof(Wayland_Shell_Surface)))) - { - wl_resource_post_no_memory(resource); - return; - } - - wss->resource.destroy = _e_mod_comp_wayland_destroy_shell_surface; - wss->resource.object.id = id; - wss->resource.object.interface = &wl_shell_surface_interface; - wss->resource.object.implementation = - (void (**)(void)) &_wl_shell_surface_interface; - wss->resource.data = wss; - - wss->surface = ws; - wss->surface_destroy_listener.func = - _e_mod_comp_wayland_shell_surface_destroy_handle; - - wl_list_insert(ws->surface.resource.destroy_listener_list.prev, - &wss->surface_destroy_listener.link); - wl_list_init(&wss->link); - - wss->type = 0; - wl_client_add_resource(client, &wss->resource); -} - -static void -_e_mod_comp_wayland_shell_lock(Wayland_Shell *base) -{ - Wayland_Surface *cur, *tmp; - struct wl_shell *shell; - struct wl_list *surface_list; - - printf("Comp Module Wayland Shell Lock\n"); - shell = container_of(base, struct wl_shell, shell); - surface_list = &_wl_comp_surface_list; - - if (shell->locked) return; - shell->locked = EINA_TRUE; - - /* TODO: Handle hidden surfaces */ - if (!wl_list_empty(&shell->hidden_surface_list)) - EINA_LOG_ERR("Hidden surface list not empty\n"); - - /* TODO: loop surface list */ - wl_list_for_each_safe(cur, tmp, surface_list, link) - { - if (!cur->surface.resource.client) continue; - /* TODO: Get shell surface type */ - /* cur->output = NULL; */ - wl_list_remove(&cur->link); - wl_list_insert(shell->hidden_surface_list.prev, &cur->link); - } - - /* TODO: Handle screensaver surfaces ? */ - - /* skip input device sprites */ - - /* compositor repick for pointer focus */ - - /* reset keyboard focus */ -} - -static void -_e_mod_comp_wayland_shell_unlock(Wayland_Shell *base) -{ - struct wl_shell *shell; - - printf("Comp Module Wayland Shell Unlock\n"); - - shell = container_of(base, struct wl_shell, shell); - if ((!shell->locked) || (shell->lock_surface)) - { - /* TODO: Wake compositor */ - return; - } - - /* TODO: Desktop shell ?? */ - - if (shell->prepare_event_sent) return; - wl_resource_post_event(shell->child.desktop_shell, 1); - shell->prepare_event_sent = EINA_TRUE; -} - -static void -_e_mod_comp_wayland_shell_map(Wayland_Shell *base, Wayland_Surface *surface, int32_t width, int32_t height) -{ - struct wl_shell *shell; - struct wl_list *list; - Wayland_Shell_Surface *wss; - Eina_Bool do_configure = EINA_FALSE; - - printf("Comp Module Wayland Shell Map\n"); - - shell = container_of(base, struct wl_shell, shell); - wss = _e_mod_comp_wayland_get_shell_surface(surface); - if (shell->locked) - { - list = &shell->hidden_surface_list; - do_configure = EINA_FALSE; - } - else - { - list = &_wl_comp_surface_list; - do_configure = EINA_TRUE; - } - surface->width = width; - surface->height = height; - - /* initial position */ - switch (wss->type) - { - case SHELL_SURFACE_TOPLEVEL: - surface->x = 10 + random() % 400; - surface->y = 10 + random() % 400; - break; - case SHELL_SURFACE_SCREENSAVER: - case SHELL_SURFACE_FULLSCREEN: - /* TODO: Center on output */ - break; - case SHELL_SURFACE_LOCK: - /* TODO: Center on output */ - break; - default: - break; - } - - /* stacking order */ - switch (wss->type) - { - case SHELL_SURFACE_BACKGROUND: - wl_list_insert(_wl_comp_surface_list.prev, &surface->link); - do_configure = EINA_TRUE; - break; - case SHELL_SURFACE_PANEL: - wl_list_insert(list, &surface->link); - break; - case SHELL_SURFACE_LOCK: - wl_list_insert(&_wl_comp_surface_list, &surface->link); - _e_mod_comp_wayland_compositor_repick(); - /* TODO: wake */ - do_configure = EINA_TRUE; - break; - case SHELL_SURFACE_SCREENSAVER: - do_configure = EINA_FALSE; - break; - default: - /* NB: We skip 'panel' here */ - wl_list_insert(list, &surface->link); - break; - } - - /* TODO: Handle popups */ - - surface->width = width; - surface->height = height; - if (do_configure) - { - _e_mod_comp_wayland_surface_configure(surface, surface->x, surface->y, - width, height); - _e_mod_comp_wayland_compositor_repick(); - } - - switch (wss->type) - { - case SHELL_SURFACE_TOPLEVEL: - case SHELL_SURFACE_TRANSIENT: - case SHELL_SURFACE_FULLSCREEN: - if (!shell->locked) - { - /* TODO: activate */ - } - break; - default: - break; - } - - if (wss->type == SHELL_SURFACE_TOPLEVEL) - { - /* TODO: Use zoom effect ?? */ - } -} - -static void -_e_mod_comp_wayland_shell_configure(Wayland_Shell *base, Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - Wayland_Shell_Surface *wss; - struct wl_shell *shell; - Eina_Bool do_configure = EINA_FALSE; - - printf("Comp Module Wayland Shell Configure\n"); - shell = container_of(base, struct wl_shell, shell); - do_configure = !shell->locked; - wss = _e_mod_comp_wayland_get_shell_surface(surface); - - surface->width = width; - surface->height = height; - - switch (wss->type) - { - case SHELL_SURFACE_SCREENSAVER: - do_configure = !do_configure; - break; - case SHELL_SURFACE_FULLSCREEN: - /* TODO: center on output */ - break; - default: - break; - } - - if (do_configure) - _e_mod_comp_wayland_surface_configure(surface, x, y, width, height); -} - -static void -_e_mod_comp_wayland_shell_destroy(Wayland_Shell *base) -{ - struct wl_shell *shell; - - printf("Comp Module Wayland Shell Destroy\n"); - shell = container_of(base, struct wl_shell, shell); - if (shell->child.client) - wl_client_destroy(shell->child.client); - free(shell); -} - -static void -_e_mod_comp_wayland_shell_surface_destroy_handle(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp) -{ - Wayland_Shell_Surface *wss; - - wss = container_of(listener, Wayland_Shell_Surface, surface_destroy_listener); - wss->surface = NULL; - wl_resource_destroy(&wss->resource, timestamp); -} - -static int -_e_mod_comp_wayland_idle_handle(void *data __UNUSED__) -{ - printf("Comp Module Wayland Idle Handle\n"); - return EINA_TRUE; -} - -static Eina_Bool -_e_mod_comp_wayland_fd_handle(void *data, Ecore_Fd_Handler *hdl __UNUSED__) -{ - struct wl_display *disp; - struct wl_event_loop *loop; - - if (!(disp = data)) return ECORE_CALLBACK_RENEW; - if (disp != _wl_disp) return ECORE_CALLBACK_RENEW; - - printf("Wayland FD Updated. Process Events\n"); - - loop = wl_display_get_event_loop(disp); - wl_event_loop_dispatch(loop, -1); - - return ECORE_CALLBACK_RENEW; -} - -static void -_e_mod_comp_wayland_surface_create(struct wl_client *client, struct wl_resource *resource, uint32_t id) -{ - Wayland_Surface *ws; - - printf("Comp Create Surface\n"); - - if (!(ws = _e_mod_comp_wayland_create_surface(0, 0, 0, 0))) - { - wl_resource_post_no_memory(resource); - return; - } - - ws->surface.resource.client = NULL; - ws->surface.resource.destroy = _e_mod_comp_wayland_destroy_surface; - ws->surface.resource.object.id = id; - ws->surface.resource.object.interface = &wl_surface_interface; - ws->surface.resource.object.implementation = - (void (**)(void))&_wl_surface_interface; - ws->surface.resource.data = ws; - - wl_client_add_resource(client, &ws->surface.resource); -} - -static void -_e_mod_comp_wayland_surface_destroy(struct wl_client *client __UNUSED__, struct wl_resource *resource) -{ - printf("Comp Surface Destroy\n"); - wl_resource_destroy(resource, ecore_x_current_time_get()); -} - -static void -_e_mod_comp_wayland_surface_attach(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *buffer_resource, int32_t x, int32_t y) -{ - Wayland_Surface *ws; - struct wl_buffer *buffer; - - printf("Comp Surface Attach\n"); - if (!(ws = resource->data)) return; - - buffer = buffer_resource->data; - - _e_mod_comp_wayland_surface_damage_below(ws); - - if (ws->buffer) - { - wl_resource_queue_event(&ws->buffer->resource, WL_BUFFER_RELEASE); - wl_list_remove(&ws->buffer_destroy_listener.link); - } - - ws->buffer = buffer; - wl_list_insert(ws->buffer->resource.destroy_listener_list.prev, - &ws->buffer_destroy_listener.link); - - if (!ws->visual) - _wl_shell->map(_wl_shell, ws, buffer->width, buffer->height); - else if ((x != 0) || (y != 0) || (ws->width != buffer->width) || - (ws->height != buffer->height)) - { - _wl_shell->configure(_wl_shell, ws, ws->x + x, ws->y + y, - buffer->width, buffer->height); - } - - _e_mod_comp_wayland_buffer_attach(buffer, &ws->surface); -} - -static void -_e_mod_comp_wayland_surface_damage(struct wl_client *client __UNUSED__, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) -{ - Wayland_Surface *ws; - - printf("Comp Surface Damage\n"); - - ws = resource->data; - _e_mod_comp_wayland_damage_surface(ws, x, y, width, height); -} - -static void -_e_mod_comp_wayland_surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback) -{ - Wayland_Surface *ws; - Wayland_Frame_Callback *cb; - - printf("Comp Surface Frame\n"); - - ws = resource->data; - if (!(cb = malloc(sizeof(Wayland_Frame_Callback)))) - { - wl_resource_post_no_memory(resource); - return; - } - - cb->resource.object.interface = &wl_callback_interface; - cb->resource.object.id = callback; - cb->resource.destroy = _e_mod_comp_wayland_destroy_frame; - cb->resource.client = client; - cb->resource.data = cb; - - wl_client_add_resource(client, &cb->resource); - - /* TODO: Add to frame callback list */ -} - -static void -_e_mod_comp_wayland_surface_configure(Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - printf("Comp Surface Configure\n"); - - _e_mod_comp_wayland_surface_damage_below(surface); - - surface->x = x; - surface->y = y; - surface->width = width; - surface->height = height; - - /* TODO: Assign output */ - - _e_mod_comp_wayland_damage_surface(surface, 0, 0, surface->width, - surface->height); - - /* TODO: Pixman opaque stuff (compositor.c: 319) */ -} - -static Eina_Bool -_e_mod_comp_wayland_surface_move(Wayland_Surface *surface, Wayland_Input *input, uint32_t timestamp) -{ - /* TODO: Handle mouse grab */ - - wl_input_device_set_pointer_focus(&input->input_dev, NULL, timestamp, - 0, 0, 0, 0); - - return EINA_TRUE; -} - -static Eina_Bool -_e_mod_comp_wayland_surface_resize(Wayland_Surface *surface, Wayland_Input *input, uint32_t timestamp, uint32_t edges) -{ - /* TODO: Handle resize grab */ - - wl_input_device_set_pointer_focus(&input->input_dev, NULL, timestamp, - 0, 0, 0, 0); - return EINA_TRUE; -} - -static Wayland_Surface * -_e_mod_comp_wayland_create_surface(int32_t x, int32_t y, int32_t width, int32_t height) -{ - Wayland_Surface *ws; - - if (!(ws = calloc(1, sizeof(Wayland_Surface)))) - return NULL; - - wl_list_init(&ws->link); - wl_list_init(&ws->buffer_link); - - /* Setup gl texture for surface */ - glGenTextures(1, &ws->texture); - glBindTexture(GL_TEXTURE_2D, ws->texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - ws->x = x; - ws->y = y; - ws->width = width; - ws->height = height; - ws->saved_texture = 0; - ws->buffer = NULL; - ws->buffer_destroy_listener.func = _e_mod_comp_wayland_destroy_buffer; - ws->visual = 0; - - pixman_region32_init(&ws->damage); - - /* ws->surface.resource.client = NULL; */ - /* ws->surface.resource.destroy = _e_mod_comp_wayland_destroy_surface; */ - /* ws->surface.resource.object.id = id; */ - /* ws->surface.resource.object.interface = &wl_surface_interface; */ - /* ws->surface.resource.object.implementation = */ - /* (void (**)(void))&_wl_surface_interface; */ - /* ws->surface.resource.data = ws; */ - - /* wl_client_add_resource(client, &ws->surface.resource); */ - - return ws; -} - -static void -_e_mod_comp_wayland_surface_damage_below(Wayland_Surface *surface) -{ - Wayland_Surface *below; - - if (surface->link.next == &_wl_comp_surface_list) return; - below = container_of(surface->link.next, Wayland_Surface, link); - pixman_region32_union_rect(&below->damage, &below->damage, - surface->x, surface->y, surface->width, - surface->height); - e_mod_comp_wayland_repaint(); -} - -static void -_e_mod_comp_wayland_destroy_shell_surface(struct wl_resource *resource) -{ - Wayland_Shell_Surface *wss; - - wss = resource->data; - /* TODO: Handle popup grab */ - if (wss->surface) - wl_list_remove(&wss->surface_destroy_listener.link); - wl_list_remove(&wss->link); - free(wss); -} - -static void -_e_mod_comp_wayland_destroy_surface(struct wl_resource *resource) -{ - Wayland_Surface *ws; - - printf("Comp Destroy Surface\n"); - - ws = container_of(resource, Wayland_Surface, surface.resource); - - _e_mod_comp_wayland_surface_damage_below(ws); - - /* TODO: flush damage */ - - wl_list_remove(&ws->link); - - _e_mod_comp_wayland_compositor_repick(); - - if (!ws->saved_texture) - glDeleteTextures(1, &ws->texture); - else - glDeleteTextures(1, &ws->saved_texture); - - if (ws->buffer) - wl_list_remove(&ws->buffer_destroy_listener.link); - - /* TODO: Destroy Image */ - - wl_list_remove(&ws->buffer_link); - pixman_region32_fini(&ws->damage); - - free(ws); -} - -static void -_e_mod_comp_wayland_destroy_buffer(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp __UNUSED__) -{ - Wayland_Surface *ws; - - ws = container_of(listener, Wayland_Surface, buffer_destroy_listener); - ws->buffer = NULL; -} - -static void -_e_mod_comp_wayland_destroy_frame(struct wl_resource *resource) -{ - Wayland_Frame_Callback *cb; - - cb = resource->data; - wl_list_remove(&cb->link); - free(cb); -} - -static void -_e_mod_comp_wayland_damage_surface(Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height) -{ - pixman_region32_union_rect(&surface->damage, &surface->damage, - surface->x + x, surface->y + y, width, height); - e_mod_comp_wayland_repaint(); -} - -static void -_e_mod_comp_wayland_shm_buffer_created(struct wl_buffer *buffer) -{ - struct wl_list *attached; - - printf("Shm Buffer Created\n"); - - buffer->user_data = NULL; - if ((attached = malloc(sizeof(*attached)))) - { - wl_list_init(attached); - buffer->user_data = attached; - } -} - -static void -_e_mod_comp_wayland_shm_buffer_damaged(struct wl_buffer *buffer, int32_t x __UNUSED__, int32_t y __UNUSED__, int32_t width __UNUSED__, int32_t height __UNUSED__) -{ - Wayland_Surface *ws; - struct wl_list *attached; - GLsizei tex_width; - - printf("Shm Buffer Damaged\n"); - attached = buffer->user_data; - tex_width = wl_shm_buffer_get_stride(buffer) / 4; - wl_list_for_each(ws, attached, buffer_link) - { - glBindTexture(GL_TEXTURE_2D, ws->texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, - tex_width, buffer->height, 0, - GL_BGRA_EXT, GL_UNSIGNED_BYTE, - wl_shm_buffer_get_data(buffer)); - } -} - -static void -_e_mod_comp_wayland_shm_buffer_destroyed(struct wl_buffer *buffer) -{ - Wayland_Surface *ws, *next; - struct wl_list *attached; - - printf("Shm Buffer Destroyed\n"); - - attached = buffer->user_data; - wl_list_for_each_safe(ws, next, attached, buffer_link) - { - wl_list_remove(&ws->buffer_link); - wl_list_init(&ws->buffer_link); - } - - free(attached); -} - -static void -_e_mod_comp_wayland_buffer_attach(struct wl_buffer *buffer, struct wl_surface *surface) -{ - Wayland_Surface *ws; - - printf("Buffer Attach\n"); - - ws = (Wayland_Surface *)surface; - if (ws->saved_texture != 0) ws->texture = ws->saved_texture; - glBindTexture(GL_TEXTURE_2D, ws->texture); - if (wl_buffer_is_shm(buffer)) - { - struct wl_list *attached; - - glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, - wl_shm_buffer_get_stride(buffer) / 4, buffer->height, 0, - GL_BGRA_EXT, GL_UNSIGNED_BYTE, - wl_shm_buffer_get_data(buffer)); - switch (wl_shm_buffer_get_format(buffer)) - { - case WL_SHM_FORMAT_ARGB8888: - ws->visual = 0; - break; - case WL_SHM_FORMAT_XRGB8888: - ws->visual = 1; - break; - } - attached = buffer->user_data; - wl_list_remove(&ws->buffer_link); - wl_list_insert(attached, &ws->buffer_link); - } - else - { - /* TODO: Handle image */ - } -} - -static void -_e_mod_comp_wayland_shell_surface_move(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp) -{ - Wayland_Input *wi; - Wayland_Shell_Surface *wss; - - wss = resource->data; - wi = input_resource->data; - if ((wi->input_dev.button_count == 0) || - (wi->input_dev.grab_time != timestamp) || - (wi->input_dev.pointer_focus != &wss->surface->surface)) - return; - - if (!_e_mod_comp_wayland_surface_move(wss->surface, wi, timestamp)) - wl_resource_post_no_memory(resource); -} - -static void -_e_mod_comp_wayland_shell_surface_resize(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp, uint32_t edges) -{ - Wayland_Input *wi; - Wayland_Shell_Surface *wss; - - wi = input_resource->data; - wss = resource->data; - - if ((wi->input_dev.button_count == 0) || - (wi->input_dev.grab_time != timestamp) | - (wi->input_dev.pointer_focus != &wss->surface->surface)) - return; - - if (!_e_mod_comp_wayland_surface_resize(wss->surface, wi, timestamp, edges)) - wl_resource_post_no_memory(resource); -} - -static void -_e_mod_comp_wayland_shell_surface_set_toplevel(struct wl_client *client __UNUSED__, struct wl_resource *resource) -{ - Wayland_Shell_Surface *wss; - - wss = resource->data; - - if (!_e_mod_comp_wayland_shell_surface_type_reset(wss)) - return; - - _e_mod_comp_wayland_damage_surface(wss->surface, 0, 0, wss->surface->width, - wss->surface->height); - - wss->type = SHELL_SURFACE_TOPLEVEL; -} - -static void -_e_mod_comp_wayland_shell_surface_set_transient(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *parent_resource, int x, int y, uint32_t flags __UNUSED__) -{ - Wayland_Shell_Surface *wss, *pwss; - - wss = resource->data; - pwss = parent_resource->data; - - if (!_e_mod_comp_wayland_shell_surface_type_reset(wss)) - return; - - wss->surface->x = pwss->surface->x + x; - wss->surface->y = pwss->surface->y + y; - _e_mod_comp_wayland_damage_surface(wss->surface, 0, 0, wss->surface->width, - wss->surface->height); - - wss->type = SHELL_SURFACE_TRANSIENT; -} - -static void -_e_mod_comp_wayland_shell_surface_set_fullscreen(struct wl_client *client __UNUSED__, struct wl_resource *resource) -{ - Wayland_Shell_Surface *wss; - - wss = resource->data; - - if (!_e_mod_comp_wayland_shell_surface_type_reset(wss)) - return; - - wss->saved_x = wss->surface->x; - wss->saved_y = wss->surface->y; - wss->surface->x = (_wl_output->width - wss->surface->width) / 2; - wss->surface->y = (_wl_output->height - wss->surface->height) / 2; - _e_mod_comp_wayland_damage_surface(wss->surface, 0, 0, wss->surface->width, - wss->surface->height); - wss->type = SHELL_SURFACE_FULLSCREEN; -} - -static void -_e_mod_comp_wayland_shell_surface_set_popup(struct wl_client *client, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp, struct wl_resource *parent_resource, int32_t x, int32_t y, uint32_t flags) -{ - -} - -static Eina_Bool -_e_mod_comp_wayland_shell_surface_type_reset(Wayland_Shell_Surface *shell_surface) -{ - switch (shell_surface->type) - { - case SHELL_SURFACE_FULLSCREEN: - shell_surface->surface->x = shell_surface->saved_x; - shell_surface->surface->y = shell_surface->saved_y; - break; - case SHELL_SURFACE_PANEL: - case SHELL_SURFACE_BACKGROUND: - wl_list_remove(&shell_surface->link); - wl_list_init(&shell_surface->link); - break; - case SHELL_SURFACE_SCREENSAVER: - case SHELL_SURFACE_LOCK: - wl_resource_post_error(&shell_surface->resource, - WL_DISPLAY_ERROR_INVALID_METHOD, - "cannot reassign surface type"); - return EINA_FALSE; - break; - default: - break; - } - shell_surface->type = SHELL_SURFACE_NONE; - return EINA_TRUE; -} - -static Wayland_Shell_Surface * -_e_mod_comp_wayland_get_shell_surface(Wayland_Surface *surface) -{ - struct wl_list *list; - struct wl_listener *listener; - - list = &surface->surface.resource.destroy_listener_list; - wl_list_for_each(listener, list, link) - { - if (listener->func == _e_mod_comp_wayland_shell_surface_destroy_handle) - return container_of(listener, Wayland_Shell_Surface, - surface_destroy_listener); - } - return NULL; -} diff --git a/src/modules/comp/e_mod_comp_wayland.h b/src/modules/comp/e_mod_comp_wayland.h deleted file mode 100644 index 8ac26abb3..000000000 --- a/src/modules/comp/e_mod_comp_wayland.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifdef E_TYPEDEFS -#else -# ifndef E_MOD_COMP_WAYLAND_H -# define E_MOD_COMP_WAYLAND_H - -# include -# include -# include -# include -# include -# include - -/* variables & functions here */ -Eina_Bool e_mod_comp_wayland_init(void); -void e_mod_comp_wayland_shutdown(void); -void e_mod_comp_wayland_repaint(void); - -# endif -#endif diff --git a/src/modules/comp/e_mod_comp_wl.c b/src/modules/comp/e_mod_comp_wl.c new file mode 100644 index 000000000..e5b78f2bf --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl.c @@ -0,0 +1,280 @@ +#include "e.h" +#include "e_mod_main.h" +#include "e_mod_comp.h" +#ifdef HAVE_WAYLAND +# include "e_mod_comp_wl.h" +# include "e_mod_comp_wl_comp.h" +# include "e_mod_comp_wl_output.h" +# include "e_mod_comp_wl_input.h" +# include "e_mod_comp_wl_shell.h" +#endif +#include +#include + +/* local function prototypes */ +static Eina_Bool _e_mod_comp_wl_fd_handle(void *data, Ecore_Fd_Handler *hdl __UNUSED__); + +/* private variables */ +static Ecore_Fd_Handler *_wl_fd_handler = NULL; + +/* extern variables */ +struct wl_display *_wl_disp; + +Eina_Bool +e_mod_comp_wl_init(void) +{ + struct wl_event_loop *loop; + int fd = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* init wayland display */ + if (!(_wl_disp = wl_display_create())) + { + printf("Failed to create wayland display\n"); + EINA_LOG_ERR("Failed to create wayland display\n"); + return EINA_FALSE; + } + + /* TODO: Add signal handlers ? */ + + /* init wayland compositor */ + if (!e_mod_comp_wl_comp_init()) + { + wl_display_terminate(_wl_disp); + printf("Failed to initialize compositor\n"); + EINA_LOG_ERR("Failed to initialize compositor\n"); + return EINA_FALSE; + } + + /* init output */ + if (!e_mod_comp_wl_output_init()) + { + e_mod_comp_wl_comp_shutdown(); + wl_display_terminate(_wl_disp); + printf("Failed to initialize output\n"); + EINA_LOG_ERR("Failed to initialize output\n"); + return EINA_FALSE; + } + + /* init input */ + if (!e_mod_comp_wl_input_init()) + { + e_mod_comp_wl_output_shutdown(); + e_mod_comp_wl_comp_shutdown(); + wl_display_terminate(_wl_disp); + printf("Failed to initialize input\n"); + EINA_LOG_ERR("Failed to initialize input\n"); + return EINA_FALSE; + } + + /* init shell */ + if (!e_mod_comp_wl_shell_init()) + { + e_mod_comp_wl_input_shutdown(); + e_mod_comp_wl_output_shutdown(); + e_mod_comp_wl_comp_shutdown(); + wl_display_terminate(_wl_disp); + printf("Failed to initialize shell\n"); + EINA_LOG_ERR("Failed to initialize shell\n"); + return EINA_FALSE; + } + + if (wl_display_add_socket(_wl_disp, NULL)) + { + e_mod_comp_wl_shell_shutdown(); + e_mod_comp_wl_input_shutdown(); + e_mod_comp_wl_output_shutdown(); + e_mod_comp_wl_comp_shutdown(); + wl_display_terminate(_wl_disp); + printf("Failed to add display socket\n"); + EINA_LOG_ERR("Failed to add display socket\n"); + return EINA_FALSE; + } + + loop = wl_display_get_event_loop(_wl_disp); + fd = wl_event_loop_get_fd(loop); + printf("Got Wayland Event Loop FD: %d\n", fd); + + /* add handler */ + _wl_fd_handler = + ecore_main_fd_handler_add(fd, ECORE_FD_READ, + _e_mod_comp_wl_fd_handle, _wl_disp, NULL, NULL); + + e_mod_comp_wl_comp_wake(); + +// wl_event_loop_dispatch(loop, 0); + + return EINA_TRUE; +} + +void +e_mod_comp_wl_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + e_mod_comp_wl_shell_shutdown(); + e_mod_comp_wl_input_shutdown(); + e_mod_comp_wl_output_shutdown(); + e_mod_comp_wl_comp_shutdown(); + wl_display_terminate(_wl_disp); +} + +uint32_t +e_mod_comp_wl_time_get(void) +{ + struct timeval tv; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +void +e_mod_comp_wl_matrix_init(Wayland_Matrix *matrix) +{ + static const Wayland_Matrix identity = + { + { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 } + }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + memcpy(matrix, &identity, sizeof(identity)); +} + +void +e_mod_comp_wl_matrix_translate(Wayland_Matrix *matrix, GLfloat x, GLfloat y, GLfloat z) +{ + Wayland_Matrix translate = + { + { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 } + }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + e_mod_comp_wl_matrix_multiply(matrix, &translate); +} + +void +e_mod_comp_wl_matrix_scale(Wayland_Matrix *matrix, GLfloat x, GLfloat y, GLfloat z) +{ + Wayland_Matrix scale = + { + { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 } + }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + e_mod_comp_wl_matrix_multiply(matrix, &scale); +} + +void +e_mod_comp_wl_matrix_multiply(Wayland_Matrix *m, const Wayland_Matrix *n) +{ + Wayland_Matrix tmp; + const GLfloat *row, *column; + div_t d; + int i, j; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + for (i = 0; i < 16; i++) { + tmp.d[i] = 0; + d = div(i, 4); + row = m->d + d.quot * 4; + column = n->d + d.rem; + for (j = 0; j < 4; j++) + tmp.d[i] += row[j] * column[j * 4]; + } + memcpy(m, &tmp, sizeof tmp); +} + +void +e_mod_comp_wl_matrix_transform(Wayland_Matrix *matrix, Wayland_Vector *v) +{ + int i, j; + Wayland_Vector t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + for (i = 0; i < 4; i++) + { + t.f[i] = 0; + for (j = 0; j < 4; j++) + t.f[i] += v->f[j] * matrix->d[i + j * 4]; + } + + *v = t; +} + +void +e_mod_comp_wl_buffer_attach(struct wl_buffer *buffer, struct wl_surface *surface) +{ + Wayland_Surface *ws; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ws = (Wayland_Surface *)surface; + + if (ws->saved_texture != 0) + ws->texture = ws->saved_texture; + + glBindTexture(GL_TEXTURE_2D, ws->texture); + + if (wl_buffer_is_shm(buffer)) + { + struct wl_list *attached; + + ws->pitch = wl_shm_buffer_get_stride(buffer) / 4; + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, ws->pitch, buffer->height, + 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, + wl_shm_buffer_get_data(buffer)); + + switch (wl_shm_buffer_get_format(buffer)) + { + case WL_SHM_FORMAT_ARGB8888: + ws->visual = WAYLAND_ARGB_VISUAL; + break; + case WL_SHM_FORMAT_XRGB8888: + ws->visual = WAYLAND_RGB_VISUAL; + break; + } + + attached = buffer->user_data; + wl_list_remove(&ws->buffer_link); + wl_list_insert(attached, &ws->buffer_link); + } + else + { + /* TODO: Handle image */ + printf("Handle Image\n"); + } +} + +void +e_mod_comp_wl_buffer_post_release(struct wl_buffer *buffer) +{ + if (--buffer->busy_count > 0) return; + assert(buffer->resource.client != NULL); + wl_resource_queue_event(&buffer->resource, WL_BUFFER_RELEASE); +} + +/* local functions */ +static Eina_Bool +_e_mod_comp_wl_fd_handle(void *data, Ecore_Fd_Handler *hdl __UNUSED__) +{ + struct wl_display *disp; + struct wl_event_loop *loop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(disp = data)) return ECORE_CALLBACK_RENEW; + if (disp != _wl_disp) return ECORE_CALLBACK_RENEW; + + loop = wl_display_get_event_loop(disp); + wl_event_loop_dispatch(loop, 0); + + return ECORE_CALLBACK_RENEW; +} diff --git a/src/modules/comp/e_mod_comp_wl.h b/src/modules/comp/e_mod_comp_wl.h new file mode 100644 index 000000000..1f0de766e --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl.h @@ -0,0 +1,245 @@ +#ifdef E_TYPEDEFS +#else +# ifndef E_MOD_COMP_WL_H +# define E_MOD_COMP_WL_H + +# include +# include +# include +# include +# include +# include + +# define LOGFNS 1 + +# ifdef LOGFNS +# include +# define LOGFN(fl, ln, fn) printf("-E-COMP-WL: %25s: %5i - %s\n", fl, ln, fn); +# else +# define LOGFN(fl, ln, fn) +# endif + +typedef enum _Wayland_Shell_Surface_Type Wayland_Shell_Surface_Type; +typedef enum _Wayland_Visual Wayland_Visual; +typedef struct _Wayland_Matrix Wayland_Matrix; +typedef struct _Wayland_Vector Wayland_Vector; +typedef struct _Wayland_Shader Wayland_Shader; +typedef struct _Wayland_Mode Wayland_Mode; +typedef struct _Wayland_Compositor Wayland_Compositor; +typedef struct _Wayland_Output Wayland_Output; +typedef struct _Wayland_Frame_Callback Wayland_Frame_Callback; +typedef struct _Wayland_Transform Wayland_Transform; +typedef struct _Wayland_Surface Wayland_Surface; +typedef struct _Wayland_Input Wayland_Input; +typedef struct _Wayland_Shell_Surface Wayland_Shell_Surface; +typedef struct _Wayland_Shell Wayland_Shell; + +enum _Wayland_Shell_Surface_Type +{ + SHELL_SURFACE_NONE, + SHELL_SURFACE_PANEL, + SHELL_SURFACE_BACKGROUND, + SHELL_SURFACE_LOCK, + SHELL_SURFACE_SCREENSAVER, + SHELL_SURFACE_TOPLEVEL, + SHELL_SURFACE_TRANSIENT, + SHELL_SURFACE_FULLSCREEN, + SHELL_SURFACE_POPUP +}; + +enum _Wayland_Visual +{ + WAYLAND_NONE_VISUAL, + WAYLAND_ARGB_VISUAL, + WAYLAND_RGB_VISUAL +}; + +struct _Wayland_Matrix +{ + GLfloat d[16]; +}; + +struct _Wayland_Vector +{ + GLfloat f[4]; +}; + +struct _Wayland_Shader +{ + GLuint program; + GLuint vertex_shader; + GLuint fragment_shader; + GLuint proj_uniform; + GLuint tex_uniform; + GLuint alpha_uniform; + GLuint color_uniform; +}; + +struct _Wayland_Mode +{ + uint32_t flags, refresh; + int32_t width, height; + struct wl_list link; +}; + +struct _Wayland_Compositor +{ + struct wl_shm *shm; + + struct + { + EGLDisplay display; + EGLContext context; + EGLConfig config; + } egl; + + Wayland_Shader texture_shader; + Wayland_Shader solid_shader; + + struct wl_array vertices, indices; + struct wl_list surfaces; + + struct wl_event_source *idle_source; + + PFNEGLBINDWAYLANDDISPLAYWL bind_display; + PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display; + Eina_Bool has_bind : 1; + + uint32_t current_alpha; + + void (*destroy) (void); +}; + +struct _Wayland_Output +{ + int x, y, width, height; + char *make, *model; + uint32_t subpixel; + + EGLSurface egl_surface; + + Wayland_Mode mode; + Wayland_Matrix matrix; + + Eina_Bool repaint_needed : 1; + Eina_Bool repaint_scheduled : 1; + + struct wl_event_source *finish_frame_timer; + + struct wl_list link; + struct wl_list frame_callbacks; + + pixman_region32_t region, prev_damage; + + struct wl_buffer *scanout_buffer; + struct wl_listener scanout_buffer_destroy_listener; + struct wl_buffer *pending_scanout_buffer; + struct wl_listener pending_scanout_buffer_destroy_listener; + + int (*prepare_render) (Wayland_Output *output); + int (*present) (Wayland_Output *output); + int (*prepare_scanout_surface) (Wayland_Output *output, Wayland_Surface *ws); +}; + +struct _Wayland_Frame_Callback +{ + struct wl_resource resource; + struct wl_list link; +}; + +struct _Wayland_Transform +{ + Wayland_Matrix matrix, inverse; +}; + +struct _Wayland_Surface +{ + struct wl_surface surface; + GLuint texture, saved_texture; + pixman_region32_t damage, opaque; + int32_t x, y, width, height; + int32_t pitch; + + Wayland_Transform *transform; + uint32_t visual, alpha; + + struct wl_list link; + struct wl_list buffer_link; + struct wl_list frame_callbacks; + + struct wl_buffer *buffer; + struct wl_listener buffer_destroy_listener; +}; + +struct _Wayland_Input +{ + struct wl_input_device input_device; + Wayland_Surface *sprite; + int32_t hotspot_x, hotspot_y; + struct wl_list link; +}; + +struct _Wayland_Shell +{ + void (*lock) (Wayland_Shell *shell); + void (*unlock) (Wayland_Shell *shell); + void (*map) (Wayland_Shell *shell, Wayland_Surface *surface, int32_t width, int32_t height); + void (*configure) (Wayland_Shell *shell, Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height); + void (*destroy) (Wayland_Shell *shell); +}; + +struct _Wayland_Shell_Surface +{ + struct wl_resource resource; + Wayland_Surface *surface; + struct wl_listener surface_destroy_listener; + Wayland_Shell_Surface *parent; + Wayland_Shell_Surface_Type type; + + int32_t saved_x, saved_y; + + struct + { + struct wl_grab grab; + uint32_t timestmap; + int32_t x, y; + int32_t initial_up; + } popup; + + struct wl_list link; +}; + +struct wl_shell +{ + Wayland_Shell shell; + + Eina_Bool locked : 1; + Eina_Bool prepare_event_sent : 1; + + Wayland_Shell_Surface *lock_surface; + struct wl_listener lock_surface_listener; + struct wl_list hidden_surfaces; + + struct + { + struct wl_resource *desktop_shell; + struct wl_client *client; + } child; +}; + +Eina_Bool e_mod_comp_wl_init(void); +void e_mod_comp_wl_shutdown(void); +uint32_t e_mod_comp_wl_time_get(void); + +void e_mod_comp_wl_matrix_init(Wayland_Matrix *matrix); +void e_mod_comp_wl_matrix_translate(Wayland_Matrix *matrix, GLfloat x, GLfloat y, GLfloat z); +void e_mod_comp_wl_matrix_scale(Wayland_Matrix *matrix, GLfloat x, GLfloat y, GLfloat z); +void e_mod_comp_wl_matrix_multiply(Wayland_Matrix *m, const Wayland_Matrix *n); +void e_mod_comp_wl_matrix_transform(Wayland_Matrix *matrix, Wayland_Vector *v); +void e_mod_comp_wl_buffer_attach(struct wl_buffer *buffer, struct wl_surface *surface); +void e_mod_comp_wl_buffer_post_release(struct wl_buffer *buffer); + +extern struct wl_display *_wl_disp; + +# endif +#endif diff --git a/src/modules/comp/e_mod_comp_wl_comp.c b/src/modules/comp/e_mod_comp_wl_comp.c new file mode 100644 index 000000000..1a71b69c7 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_comp.c @@ -0,0 +1,504 @@ +#include "e.h" +#include "e_mod_main.h" +#ifdef HAVE_WAYLAND +# include "e_mod_comp_wl.h" +# include "e_mod_comp_wl_comp.h" +# include "e_mod_comp_wl_shm.h" +# include "e_mod_comp_wl_input.h" +# include "e_mod_comp_wl_output.h" +# include "e_mod_comp_wl_surface.h" +#endif + +/* local function prototypes */ +static Eina_Bool _e_mod_comp_wl_comp_egl_init(void); +static void _e_mod_comp_wl_comp_egl_shutdown(void); +static Eina_Bool _e_mod_comp_wl_comp_shader_init(Wayland_Shader *shader, const char *vertex_source, const char *fragment_source); +/* static void _e_mod_comp_wl_comp_shader_shutdown(void); */ +static Eina_Bool _e_mod_comp_wl_comp_solid_shader_init(Wayland_Shader *shader, GLuint vertex_shader, const char *fragment_source); +/* static void _e_mod_comp_wl_comp_solid_shader_shutdown(); */ +static int _e_mod_comp_wl_comp_compile_shader(GLenum type, const char *source); +static void _e_mod_comp_wl_comp_destroy(void); +static void _e_mod_comp_wl_comp_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id); +static void _e_mod_comp_wl_comp_surface_create(struct wl_client *client, struct wl_resource *resource, uint32_t id); +static int _e_mod_comp_wl_comp_idle_handler(void *data); + +/* wayland interfaces */ +static const struct wl_compositor_interface _wl_comp_interface = +{ + _e_mod_comp_wl_comp_surface_create +}; + +static const struct wl_shm_callbacks _wl_shm_callbacks = +{ + e_mod_comp_wl_shm_buffer_created, + e_mod_comp_wl_shm_buffer_damaged, + e_mod_comp_wl_shm_buffer_destroyed +}; +static const struct wl_surface_interface _wl_surface_interface = +{ + e_mod_comp_wl_surface_destroy, + e_mod_comp_wl_surface_attach, + e_mod_comp_wl_surface_damage, + e_mod_comp_wl_surface_frame +}; + +/* private variables */ +static Wayland_Compositor *_wl_comp; +static const char vertex_shader[] = +{ + "uniform mat4 proj;\n" + "attribute vec2 position;\n" + "attribute vec2 texcoord;\n" + "varying vec2 v_texcoord;\n" + "void main()\n" + "{\n" + " gl_Position = proj * vec4(position, 0.0, 1.0);\n" + " v_texcoord = texcoord;\n" + "}\n" +}; + +static const char texture_fragment_shader[] = +{ + "precision mediump float;\n" + "varying vec2 v_texcoord;\n" + "uniform sampler2D tex;\n" + "uniform float alpha;\n" + "void main()\n" + "{\n" + " gl_FragColor = texture2D(tex, v_texcoord)\n;" + " gl_FragColor = alpha * gl_FragColor;\n" + "}\n" +}; + +static const char solid_fragment_shader[] = +{ + "precision mediump float;\n" + "uniform vec4 color;\n" + "void main()\n" + "{\n" + " gl_FragColor = color\n;" + "}\n" +}; + +Eina_Bool +e_mod_comp_wl_comp_init(void) +{ + const char *extensions; + struct wl_event_loop *loop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(_wl_comp = malloc(sizeof(Wayland_Compositor)))) + { + EINA_LOG_ERR("Could not allocate space for compositor\n"); + return EINA_FALSE; + } + + memset(_wl_comp, 0, sizeof(*_wl_comp)); + + if (!_e_mod_comp_wl_comp_egl_init()) + { + EINA_LOG_ERR("Failed to init EGL\n"); + free(_wl_comp); + return EINA_FALSE; + } + + _wl_comp->destroy = _e_mod_comp_wl_comp_destroy; + + if (!wl_display_add_global(_wl_disp, &wl_compositor_interface, _wl_comp, + _e_mod_comp_wl_comp_bind)) + { + EINA_LOG_ERR("Failed to add compositor to wayland\n"); + free(_wl_comp); + return EINA_FALSE; + } + + _wl_comp->shm = wl_shm_init(_wl_disp, &_wl_shm_callbacks); + + _wl_comp->bind_display = + (void *)eglGetProcAddress("eglBindWaylandDisplayWL"); + _wl_comp->unbind_display = + (void *)eglGetProcAddress("eglUnbindWaylandDisplayWL"); + + extensions = (const char *)glGetString(GL_EXTENSIONS); + if (!strstr(extensions, "GL_EXT_texture_format_BGRA8888")) + { + EINA_LOG_ERR("GL_EXT_texture_format_BGRA8888 not available\n"); + free(_wl_comp); + return EINA_FALSE; + } + + extensions = + (const char *)eglQueryString(_wl_comp->egl.display, EGL_EXTENSIONS); + if (strstr(extensions, "EGL_WL_bind_wayland_display")) + _wl_comp->has_bind = EINA_TRUE; + if (_wl_comp->has_bind) + _wl_comp->bind_display(_wl_comp->egl.display, _wl_disp); + + wl_list_init(&_wl_comp->surfaces); + + wl_data_device_manager_init(_wl_disp); + + glActiveTexture(GL_TEXTURE0); + + /* init shader */ + if (!_e_mod_comp_wl_comp_shader_init(&_wl_comp->texture_shader, + vertex_shader, texture_fragment_shader)) + { + EINA_LOG_ERR("Failed to initialize texture shader\n"); + free(_wl_comp); + return EINA_FALSE; + } + + /* init solid shader */ + if (!_e_mod_comp_wl_comp_solid_shader_init(&_wl_comp->solid_shader, + _wl_comp->texture_shader.vertex_shader, + solid_fragment_shader)) + { + EINA_LOG_ERR("Failed to initialize solid shader\n"); + free(_wl_comp); + return EINA_FALSE; + } + + loop = wl_display_get_event_loop(_wl_disp); + _wl_comp->idle_source = + wl_event_loop_add_timer(loop, _e_mod_comp_wl_comp_idle_handler, _wl_comp); + wl_event_source_timer_update(_wl_comp->idle_source, 300 * 1000); + + e_mod_comp_wl_comp_schedule_repaint(); + + return EINA_TRUE; +} + +Eina_Bool +e_mod_comp_wl_comp_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!_wl_comp) return EINA_TRUE; + if (_wl_comp->destroy) _wl_comp->destroy(); + return EINA_TRUE; +} + +Wayland_Compositor * +e_mod_comp_wl_comp_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _wl_comp; +} + +void +e_mod_comp_wl_comp_repick(void) +{ + Wayland_Input *device; + uint32_t timestamp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + device = e_mod_comp_wl_input_get(); + timestamp = e_mod_comp_wl_time_get(); + e_mod_comp_wl_input_repick(&device->input_device, timestamp); +} + +Wayland_Surface * +e_mod_comp_wl_comp_surface_pick(int32_t x, int32_t y, int32_t *sx, int32_t *sy) +{ + Wayland_Surface *surface; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wl_list_for_each(surface, &_wl_comp->surfaces, link) + { + if (!surface->surface.resource.client) continue; + e_mod_comp_wl_surface_transform(surface, x, y, sx, sy); + if ((0 <= *sx) && (*sx < surface->width) && + (0 <= *sy) && (*sy < surface->height)) + return surface; + } + + return NULL; +} + +void +e_mod_comp_wl_comp_schedule_repaint(void) +{ + Wayland_Output *output; + struct wl_event_loop *loop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(output = e_mod_comp_wl_output_get())) return; + loop = wl_display_get_event_loop(_wl_disp); + output->repaint_needed = EINA_TRUE; + if (output->repaint_scheduled) return; + wl_event_loop_add_idle(loop, e_mod_comp_wl_output_idle_repaint, output); + output->repaint_scheduled = EINA_TRUE; +} + +void +e_mod_comp_wl_comp_wake(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wl_event_source_timer_update(_wl_comp->idle_source, + 300 * 1000); +} + +/* local functions */ +static Eina_Bool +_e_mod_comp_wl_comp_egl_init(void) +{ + EGLint major, minor, n; + const char *extensions; + EGLint config_attribs[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, + EGL_DEPTH_SIZE, 1, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE + }; + EGLint context_attribs[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE + }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(_wl_comp->egl.display = eglGetDisplay(NULL))) + { + EINA_LOG_ERR("Failed to create EGL display\n"); + return EINA_FALSE; + } + + if (!eglInitialize(_wl_comp->egl.display, &major, &minor)) + { + EINA_LOG_ERR("Failed to initialize EGL\n"); + eglTerminate(_wl_comp->egl.display); + return EINA_FALSE; + } + + extensions = eglQueryString(_wl_comp->egl.display, EGL_EXTENSIONS); + if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) + { + EINA_LOG_ERR("EGL_KHR_surfaceless_gles2 not supported\n"); + eglTerminate(_wl_comp->egl.display); + return EINA_FALSE; + } + + if (!eglBindAPI(EGL_OPENGL_ES_API)) + { + EINA_LOG_ERR("Failed to bind EGL API\n"); + eglTerminate(_wl_comp->egl.display); + return EINA_FALSE; + } + + if ((!eglChooseConfig(_wl_comp->egl.display, config_attribs, + &_wl_comp->egl.config, 1, &n) || (n == 0))) + { + EINA_LOG_ERR("Failed to choose EGL config\n"); + eglTerminate(_wl_comp->egl.display); + return EINA_FALSE; + } + + if (!(_wl_comp->egl.context = + eglCreateContext(_wl_comp->egl.display, _wl_comp->egl.config, + EGL_NO_CONTEXT, context_attribs))) + { + EINA_LOG_ERR("Failed to create EGL context\n"); + eglTerminate(_wl_comp->egl.display); + return EINA_FALSE; + } + + if (!eglMakeCurrent(_wl_comp->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, + _wl_comp->egl.context)) + { + EINA_LOG_ERR("Failed to make EGL context current\n"); + eglTerminate(_wl_comp->egl.display); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static void +_e_mod_comp_wl_comp_egl_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + eglMakeCurrent(_wl_comp->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglTerminate(_wl_comp->egl.display); + eglReleaseThread(); +} + +static Eina_Bool +_e_mod_comp_wl_comp_shader_init(Wayland_Shader *shader, const char *vertex_source, const char *fragment_source) +{ + GLint status; + char msg[512]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + shader->vertex_shader = + _e_mod_comp_wl_comp_compile_shader(GL_VERTEX_SHADER, vertex_source); + shader->fragment_shader = + _e_mod_comp_wl_comp_compile_shader(GL_FRAGMENT_SHADER, fragment_source); + + shader->program = glCreateProgram(); + glAttachShader(shader->program, shader->vertex_shader); + glAttachShader(shader->program, shader->fragment_shader); + glBindAttribLocation(shader->program, 0, "position"); + glBindAttribLocation(shader->program, 1, "texcoord"); + + glLinkProgram(shader->program); + glGetProgramiv(shader->program, GL_LINK_STATUS, &status); + if (!status) + { + glGetProgramInfoLog(shader->program, sizeof(msg), NULL, msg); + EINA_LOG_ERR("Link info: %s\n", msg); + return EINA_FALSE; + } + + shader->proj_uniform = glGetUniformLocation(shader->program, "proj"); + shader->tex_uniform = glGetUniformLocation(shader->program, "tex"); + shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha"); + + return EINA_TRUE; +} + +/* static void */ +/* _e_mod_comp_wl_comp_shader_shutdown(void) */ +/* { */ + +/* } */ + +static Eina_Bool +_e_mod_comp_wl_comp_solid_shader_init(Wayland_Shader *shader, GLuint vertex_shader, const char *fragment_source) +{ + GLint status; + char msg[512]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + shader->vertex_shader = vertex_shader; + shader->fragment_shader = + _e_mod_comp_wl_comp_compile_shader(GL_FRAGMENT_SHADER, fragment_source); + + shader->program = glCreateProgram(); + glAttachShader(shader->program, shader->vertex_shader); + glAttachShader(shader->program, shader->fragment_shader); + glBindAttribLocation(shader->program, 0, "position"); + glBindAttribLocation(shader->program, 1, "texcoord"); + + glLinkProgram(shader->program); + glGetProgramiv(shader->program, GL_LINK_STATUS, &status); + if (!status) + { + glGetProgramInfoLog(shader->program, sizeof(msg), NULL, msg); + EINA_LOG_ERR("Link info: %s\n", msg); + return EINA_FALSE; + } + + shader->proj_uniform = glGetUniformLocation(shader->program, "proj"); + shader->color_uniform = glGetUniformLocation(shader->program, "color"); + + return EINA_TRUE; +} + +/* static void */ +/* _e_mod_comp_wl_comp_solid_shader_shutdown() */ +/* { */ + +/* } */ + +static int +_e_mod_comp_wl_comp_compile_shader(GLenum type, const char *source) +{ + GLuint s; + GLint status; + char msg[512]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + s = glCreateShader(type); + glShaderSource(s, 1, &source, NULL); + glCompileShader(s); + glGetShaderiv(s, GL_COMPILE_STATUS, &status); + if (!status) + { + glGetShaderInfoLog(s, sizeof(msg), NULL, msg); + EINA_LOG_ERR("shader info: %s\n", msg); + return GL_NONE; + } + + return s; +} + +static void +_e_mod_comp_wl_comp_destroy(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (_wl_comp->has_bind) + _wl_comp->unbind_display(_wl_comp->egl.display, _wl_disp); + + if (_wl_comp->idle_source) wl_event_source_remove(_wl_comp->idle_source); + + wl_shm_finish(_wl_comp->shm); + + wl_array_release(&_wl_comp->vertices); + wl_array_release(&_wl_comp->indices); + + _e_mod_comp_wl_comp_egl_shutdown(); + + free(_wl_comp); +} + +static void +_e_mod_comp_wl_comp_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wl_client_add_object(client, &wl_compositor_interface, + &_wl_comp_interface, id, data); +} + +static void +_e_mod_comp_wl_comp_surface_create(struct wl_client *client, struct wl_resource *resource, uint32_t id) +{ + Wayland_Surface *surface; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(surface = e_mod_comp_wl_surface_create(0, 0, 0, 0))) + { + wl_resource_post_no_memory(resource); + return; + } + + surface->surface.resource.destroy = e_mod_comp_wl_surface_destroy_surface; + surface->surface.resource.object.id = id; + surface->surface.resource.object.interface = &wl_surface_interface; + surface->surface.resource.object.implementation = + (void (**)(void))&_wl_surface_interface; + surface->surface.resource.data = surface; + + wl_client_add_resource(client, &surface->surface.resource); +} + +static int +_e_mod_comp_wl_comp_idle_handler(void *data) +{ + Wayland_Compositor *wc; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(wc = data)) return 1; + + /* TODO: Check idle inhibit */ + + /* TODO: fade */ + + return 1; +} diff --git a/src/modules/comp/e_mod_comp_wl_comp.h b/src/modules/comp/e_mod_comp_wl_comp.h new file mode 100644 index 000000000..f040007d1 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_comp.h @@ -0,0 +1,15 @@ +#ifdef E_TYPEDEFS +#else +# ifndef E_MOD_COMP_WL_COMP_H +# define E_MOD_COMP_WL_COMP_H + +Eina_Bool e_mod_comp_wl_comp_init(void); +Eina_Bool e_mod_comp_wl_comp_shutdown(void); +Wayland_Compositor *e_mod_comp_wl_comp_get(void); +void e_mod_comp_wl_comp_repick(void); +Wayland_Surface *e_mod_comp_wl_comp_surface_pick(int32_t x, int32_t y, int32_t *sx, int32_t *sy); +void e_mod_comp_wl_comp_schedule_repaint(void); +void e_mod_comp_wl_comp_wake(void); + +# endif +#endif diff --git a/src/modules/comp/e_mod_comp_wl_input.c b/src/modules/comp/e_mod_comp_wl_input.c new file mode 100644 index 000000000..6ff673403 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_input.c @@ -0,0 +1,172 @@ +#include "e.h" +#include "e_mod_main.h" +#ifdef HAVE_WAYLAND +# include "e_mod_comp_wl.h" +# include "e_mod_comp_wl_comp.h" +# include "e_mod_comp_wl_input.h" +# include "e_mod_comp_wl_surface.h" +#endif + +/* local function prototypes */ +static void _e_mod_comp_wl_input_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id); +static void _e_mod_comp_wl_input_unbind(struct wl_resource *resource); +static void _e_mod_comp_wl_input_attach(struct wl_client *client, struct wl_resource *resource, uint32_t timestamp, struct wl_resource *buffer_resource, int32_t x, int32_t y); + +/* wayland interfaces */ +static const struct wl_input_device_interface _wl_input_interface = +{ + _e_mod_comp_wl_input_attach, +}; + +/* private variables */ +static Wayland_Input *_wl_input; + +Eina_Bool +e_mod_comp_wl_input_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(_wl_input = malloc(sizeof(Wayland_Input)))) + { + EINA_LOG_ERR("Could not allocate space for input\n"); + return EINA_FALSE; + } + + memset(_wl_input, 0, sizeof(*_wl_input)); + + wl_input_device_init(&_wl_input->input_device); + wl_display_add_global(_wl_disp, &wl_input_device_interface, _wl_input, + _e_mod_comp_wl_input_bind); + + _wl_input->sprite = NULL; + _wl_input->hotspot_x = 16; + _wl_input->hotspot_y = 16; + + return EINA_TRUE; +} + +Eina_Bool +e_mod_comp_wl_input_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!_wl_input) return EINA_TRUE; + + if (_wl_input->sprite) + e_mod_comp_wl_surface_destroy_surface(&_wl_input->sprite->surface.resource); + + wl_input_device_release(&_wl_input->input_device); + + free(_wl_input); + return EINA_TRUE; +} + +Wayland_Input * +e_mod_comp_wl_input_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _wl_input; +} + +void +e_mod_comp_wl_input_repick(struct wl_input_device *device, uint32_t timestamp) +{ + const struct wl_grab_interface *interface; + Wayland_Surface *surface, *focus; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + surface = + e_mod_comp_wl_comp_surface_pick(device->x, device->y, + &device->current_x, &device->current_y); + + if (&surface->surface != device->current) + { + interface = device->grab->interface; + interface->focus(device->grab, timestamp, &surface->surface, + device->current_x, device->current_y); + device->current = &surface->surface; + } + + if ((focus = (Wayland_Surface *)device->grab->focus)) + { + e_mod_comp_wl_surface_transform(focus, device->x, device->y, + &device->grab->x, &device->grab->y); + } +} + +/* local functions */ +static void +_e_mod_comp_wl_input_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id) +{ + struct wl_input_device *device; + struct wl_resource *resource; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + device = data; + resource = + wl_client_add_object(client, &wl_input_device_interface, + &_wl_input_interface, id, data); + wl_list_insert(&device->resource_list, &resource->link); + resource->destroy = _e_mod_comp_wl_input_unbind; +} + +static void +_e_mod_comp_wl_input_unbind(struct wl_resource *resource) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wl_list_remove(&resource->link); + free(resource); +} + +static void +_e_mod_comp_wl_input_attach(struct wl_client *client, struct wl_resource *resource, uint32_t timestamp, struct wl_resource *buffer_resource, int32_t x, int32_t y) +{ + Wayland_Input *device; + struct wl_buffer *buffer; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + device = resource->data; + if (timestamp < device->input_device.pointer_focus_time) return; + if (!device->input_device.pointer_focus) return; + if (device->input_device.pointer_focus->resource.client != client) + return; + + if (device->sprite) + e_mod_comp_wl_surface_damage_below(device->sprite); + + if (!buffer_resource) + { + if (device->sprite) + { + e_mod_comp_wl_surface_destroy_surface(&device->sprite->surface.resource); + device->sprite = NULL; + } + return; + } + + if (!device->sprite) + { + device->sprite = + e_mod_comp_wl_surface_create(device->input_device.x, + device->input_device.y, 32, 32); + wl_list_init(&device->sprite->link); + } + + buffer = buffer_resource->data; + + e_mod_comp_wl_buffer_attach(buffer, &device->sprite->surface); + + device->hotspot_x = x; + device->hotspot_y = y; + device->sprite->width = buffer->width; + device->sprite->height = buffer->height; + device->sprite->x = device->input_device.x - device->hotspot_x; + device->sprite->y = device->input_device.y - device->hotspot_y; + + e_mod_comp_wl_surface_damage_surface(device->sprite); +} diff --git a/src/modules/comp/e_mod_comp_wl_input.h b/src/modules/comp/e_mod_comp_wl_input.h new file mode 100644 index 000000000..29bd8cd15 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_input.h @@ -0,0 +1,12 @@ +#ifdef E_TYPEDEFS +#else +# ifndef E_MOD_COMP_WL_INPUT_H +# define E_MOD_COMP_WL_INPUT_H + +Eina_Bool e_mod_comp_wl_input_init(void); +Eina_Bool e_mod_comp_wl_input_shutdown(void); +Wayland_Input *e_mod_comp_wl_input_get(void); +void e_mod_comp_wl_input_repick(struct wl_input_device *device, uint32_t timestamp); + +# endif +#endif diff --git a/src/modules/comp/e_mod_comp_wl_output.c b/src/modules/comp/e_mod_comp_wl_output.c new file mode 100644 index 000000000..66cc6cc20 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_output.c @@ -0,0 +1,468 @@ +#include "e.h" +#include "e_mod_main.h" +#ifdef HAVE_WAYLAND +# include "e_mod_comp_wl.h" +# include "e_mod_comp_wl_comp.h" +# include "e_mod_comp_wl_output.h" +# include "e_mod_comp_wl_surface.h" +#endif + +/* local function prototypes */ +static void _e_mod_comp_wl_output_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id); +static void _e_mod_comp_wl_output_scanout_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp __UNUSED__); +static void _e_mod_comp_wl_output_pending_scanout_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp __UNUSED__); +static int _e_mod_comp_wl_output_finish_frame_handler(void *data); +static void _e_mod_comp_wl_output_finish_frame(Wayland_Output *output, int secs); +static void _e_mod_comp_wl_output_repaint(Wayland_Output *output, int secs); +static void _e_mod_comp_wl_output_schedule_repaint(void); +static Eina_Bool _e_mod_comp_wl_output_setup_scanout_surface(Wayland_Output *output, Wayland_Surface *ws); +static int _e_mod_comp_wl_output_prepare_render(Wayland_Output *output); +static int _e_mod_comp_wl_output_present(Wayland_Output *output); +static int _e_mod_comp_wl_output_prepare_scanout_surface(Wayland_Output *output __UNUSED__, Wayland_Surface *surface __UNUSED__); +static void _e_mod_comp_wl_output_move(Wayland_Output *output, int32_t x, int32_t y); + +/* private variables */ +static Wayland_Output *_wl_output; + +Eina_Bool +e_mod_comp_wl_output_init(void) +{ + Wayland_Compositor *comp; + struct wl_event_loop *loop; + Ecore_X_Window *roots; + int num = 0, rw, rh; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + roots = ecore_x_window_root_list(&num); + if ((!roots) || (num <= 0)) + { + EINA_LOG_ERR("Could not get root window list\n"); + return EINA_FALSE; + } + ecore_x_window_size_get(roots[0], &rw, &rh); + + if (!(_wl_output = malloc(sizeof(Wayland_Output)))) + { + EINA_LOG_ERR("Could not allocate space for output\n"); + return EINA_FALSE; + } + + memset(_wl_output, 0, sizeof(*_wl_output)); + + _wl_output->mode.flags = + (WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED); + + _wl_output->x = 0; + _wl_output->y = 0; + _wl_output->width = rw; + _wl_output->height = rh; + + _wl_output->mode.width = rw; + _wl_output->mode.height = rh; + _wl_output->mode.refresh = 60; + + _e_mod_comp_wl_output_move(_wl_output, 0, 0); + + _wl_output->scanout_buffer_destroy_listener.func = + _e_mod_comp_wl_output_scanout_buffer_destroy; + _wl_output->pending_scanout_buffer_destroy_listener.func = + _e_mod_comp_wl_output_pending_scanout_buffer_destroy; + + wl_list_init(&_wl_output->link); + wl_list_init(&_wl_output->frame_callbacks); + + if (!wl_display_add_global(_wl_disp, &wl_output_interface, _wl_output, + _e_mod_comp_wl_output_bind)) + { + EINA_LOG_ERR("Failed to add wayland output\n"); + free(_wl_output); + return EINA_FALSE; + } + + comp = e_mod_comp_wl_comp_get(); + + _wl_output->egl_surface = + eglCreateWindowSurface(comp->egl.display, comp->egl.config, + roots[0], NULL); + free(roots); + + if (!_wl_output->egl_surface) + { + EINA_LOG_ERR("Failed to create EGL Surface\n"); + free(_wl_output); + return EINA_FALSE; + } + if (!eglMakeCurrent(comp->egl.display, _wl_output->egl_surface, + _wl_output->egl_surface, comp->egl.context)) + { + EINA_LOG_ERR("Failed to make current\n"); + free(_wl_output); + return EINA_FALSE; + } + + loop = wl_display_get_event_loop(_wl_disp); + _wl_output->finish_frame_timer = + wl_event_loop_add_timer(loop, _e_mod_comp_wl_output_finish_frame_handler, + _wl_output); + + _wl_output->prepare_render = _e_mod_comp_wl_output_prepare_render; + _wl_output->present = _e_mod_comp_wl_output_present; + _wl_output->prepare_scanout_surface = + _e_mod_comp_wl_output_prepare_scanout_surface; + + return EINA_TRUE; +} + +Eina_Bool +e_mod_comp_wl_output_shutdown(void) +{ + Wayland_Compositor *comp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!_wl_output) return EINA_TRUE; + + comp = e_mod_comp_wl_comp_get(); + + wl_list_remove(&_wl_output->frame_callbacks); + wl_list_remove(&_wl_output->link); + + if (_wl_output->finish_frame_timer) + wl_event_source_remove(_wl_output->finish_frame_timer); + + eglDestroySurface(comp->egl.display, _wl_output->egl_surface); + + pixman_region32_fini(&_wl_output->region); + pixman_region32_fini(&_wl_output->prev_damage); + + free(_wl_output); + + return EINA_TRUE; +} + +void +e_mod_comp_wl_output_damage(Wayland_Output *output) +{ + Wayland_Compositor *comp; + Wayland_Surface *ws; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + if (wl_list_empty(&comp->surfaces)) return; + ws = container_of(comp->surfaces.next, Wayland_Surface, link); + pixman_region32_union(&ws->damage, &ws->damage, &output->region); + e_mod_comp_wl_comp_schedule_repaint(); +} + +Wayland_Output * +e_mod_comp_wl_output_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _wl_output; +} + +void +e_mod_comp_wl_output_idle_repaint(void *data) +{ + Wayland_Output *output; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(output = data)) return; + if (output->repaint_needed) + { + struct timeval tv; + uint32_t timestamp; + + gettimeofday(&tv, NULL); + timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000; + _e_mod_comp_wl_output_repaint(output, timestamp); + } +} + +/* local functions */ +static void +_e_mod_comp_wl_output_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id) +{ + Wayland_Output *output; + struct wl_resource *resource; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(output = data)) return; + + resource = + wl_client_add_object(client, &wl_output_interface, NULL, id, output); + + wl_resource_post_event(resource, WL_OUTPUT_GEOMETRY, output->x, output->y, + output->width, output->height, output->subpixel, + output->make, output->model); + + wl_resource_post_event(resource, WL_OUTPUT_MODE, output->mode.flags, + output->mode.width, output->mode.height, + output->mode.refresh); +} + +static void +_e_mod_comp_wl_output_scanout_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp __UNUSED__) +{ + Wayland_Output *output; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + output = + container_of(listener, Wayland_Output, scanout_buffer_destroy_listener); + + output->scanout_buffer = NULL; + + if (!output->pending_scanout_buffer) + _e_mod_comp_wl_output_schedule_repaint(); +} + +static void +_e_mod_comp_wl_output_pending_scanout_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp __UNUSED__) +{ + Wayland_Output *output; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + output = + container_of(listener, Wayland_Output, + pending_scanout_buffer_destroy_listener); + + output->pending_scanout_buffer = NULL; + + _e_mod_comp_wl_output_schedule_repaint(); +} + +static int +_e_mod_comp_wl_output_finish_frame_handler(void *data) +{ + Wayland_Output *output; + uint32_t msec; + struct timeval tv; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(output = data)) return 1; + + gettimeofday(&tv, NULL); + msec = tv.tv_sec * 1000 + tv.tv_usec / 1000; + _e_mod_comp_wl_output_finish_frame(output, msec); + + return 1; +} + +static void +_e_mod_comp_wl_output_finish_frame(Wayland_Output *output, int secs) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!output) return; + if (output->scanout_buffer) + { + e_mod_comp_wl_buffer_post_release(output->scanout_buffer); + wl_list_remove(&output->scanout_buffer_destroy_listener.link); + output->scanout_buffer = NULL; + } + if (output->pending_scanout_buffer) + { + output->scanout_buffer = output->pending_scanout_buffer; + wl_list_remove(&output->pending_scanout_buffer_destroy_listener.link); + wl_list_insert(output->scanout_buffer->resource.destroy_listener_list.prev, + &output->scanout_buffer_destroy_listener.link); + output->pending_scanout_buffer = NULL; + } + if (output->repaint_needed) + _e_mod_comp_wl_output_repaint(output, secs); + else + output->repaint_scheduled = EINA_FALSE; +} + +static void +_e_mod_comp_wl_output_repaint(Wayland_Output *output, int secs) +{ + Wayland_Frame_Callback *cb, *cnext; + Wayland_Compositor *comp; + Wayland_Surface *ws; + pixman_region32_t opaque, new_damage, total_damage, repaint; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!output) return; + + comp = e_mod_comp_wl_comp_get(); + + /* start weston output repaint */ + output->prepare_render(output); + glViewport(0, 0, output->width, output->height); + glUseProgram(comp->texture_shader.program); + glUniformMatrix4fv(comp->texture_shader.proj_uniform, 1, GL_FALSE, + output->matrix.d); + glUniform1i(comp->texture_shader.tex_uniform, 0); + + /* TODO: Set cursor */ + + pixman_region32_init(&new_damage); + pixman_region32_init(&opaque); + + wl_list_for_each(ws, &comp->surfaces, link) + { + pixman_region32_subtract(&ws->damage, &ws->damage, &opaque); + pixman_region32_union(&new_damage, &new_damage, &ws->damage); + pixman_region32_union(&opaque, &opaque, &ws->opaque); + } + + pixman_region32_init(&total_damage); + pixman_region32_union(&total_damage, &new_damage, &output->prev_damage); + pixman_region32_intersect(&output->prev_damage, &new_damage, &output->region); + + pixman_region32_fini(&opaque); + pixman_region32_fini(&new_damage); + + ws = container_of(comp->surfaces.next, Wayland_Surface, link); + + if (_e_mod_comp_wl_output_setup_scanout_surface(output, ws)) + return; + + /* TODO: Handle Fullscreen */ + { + wl_list_for_each(ws, &comp->surfaces, link) + { + pixman_region32_copy(&ws->damage, &total_damage); + pixman_region32_subtract(&total_damage, &total_damage, &ws->opaque); + } + + wl_list_for_each_reverse(ws, &comp->surfaces, link) + { + pixman_region32_init(&repaint); + pixman_region32_intersect(&repaint, &output->region, &ws->damage); + e_mod_comp_wl_surface_draw(ws, output, &repaint); + pixman_region32_subtract(&ws->damage, &ws->damage, &output->region); + pixman_region32_fini(&repaint); + } + } + + /* TODO: Fade out */ + + pixman_region32_fini(&total_damage); + + /* end weston output repaint */ + + output->repaint_needed = EINA_FALSE; + output->repaint_scheduled = EINA_TRUE; + output->present(output); + + wl_list_for_each_safe(cb, cnext, &output->frame_callbacks, link) + { + wl_resource_post_event(&cb->resource, WL_CALLBACK_DONE, secs); + wl_resource_destroy(&cb->resource, 0); + } + + /* TODO: Handle animations */ +} + +static void +_e_mod_comp_wl_output_schedule_repaint(void) +{ + struct wl_event_loop *loop; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + loop = wl_display_get_event_loop(_wl_disp); + _wl_output->repaint_needed = EINA_TRUE; + if (_wl_output->repaint_scheduled) return; + wl_event_loop_add_idle(loop, e_mod_comp_wl_output_idle_repaint, _wl_output); + _wl_output->repaint_scheduled = EINA_TRUE; +} + +static Eina_Bool +_e_mod_comp_wl_output_setup_scanout_surface(Wayland_Output *output, Wayland_Surface *ws) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if ((!output) || (!ws)) return EINA_FALSE; + + if ((ws->visual != WAYLAND_RGB_VISUAL) || + (!output->prepare_scanout_surface(output, ws))) + return EINA_FALSE; + + output->pending_scanout_buffer = ws->buffer; + output->pending_scanout_buffer->busy_count++; + + wl_list_insert(output->pending_scanout_buffer->resource.destroy_listener_list.prev, + &output->pending_scanout_buffer_destroy_listener.link); + + return EINA_TRUE; +} + +static int +_e_mod_comp_wl_output_prepare_render(Wayland_Output *output) +{ + Wayland_Compositor *comp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!output) return -1; + comp = e_mod_comp_wl_comp_get(); + + if (!eglMakeCurrent(comp->egl.display, output->egl_surface, + output->egl_surface, comp->egl.context)) + { + EINA_LOG_ERR("Failed to make current\n"); + return -1; + } + + return 0; +} + +static int +_e_mod_comp_wl_output_present(Wayland_Output *output) +{ + Wayland_Compositor *comp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!output) return -1; + + comp = e_mod_comp_wl_comp_get(); + + if (_e_mod_comp_wl_output_prepare_render(output)) return -1; + + eglSwapBuffers(comp->egl.display, output->egl_surface); + + wl_event_source_timer_update(output->finish_frame_timer, 10); + + return 0; +} + +static int +_e_mod_comp_wl_output_prepare_scanout_surface(Wayland_Output *output __UNUSED__, Wayland_Surface *surface __UNUSED__) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return -1; +} + +static void +_e_mod_comp_wl_output_move(Wayland_Output *output, int32_t x, int32_t y) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!output) return; + + pixman_region32_init(&output->prev_damage); + pixman_region32_init_rect(&_wl_output->region, x, y, + output->width, output->height); + + e_mod_comp_wl_matrix_init(&output->matrix); + e_mod_comp_wl_matrix_translate(&output->matrix, + -output->x - output->width / 2.0, + -output->y - output->height / 2.0, 0); + e_mod_comp_wl_matrix_scale(&output->matrix, 2.0 / output->width, + -1 * 2.0 / output->height, 1); + e_mod_comp_wl_output_damage(output); +} diff --git a/src/modules/comp/e_mod_comp_wl_output.h b/src/modules/comp/e_mod_comp_wl_output.h new file mode 100644 index 000000000..19dbcdb0c --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_output.h @@ -0,0 +1,13 @@ +#ifdef E_TYPEDEFS +#else +# ifndef E_MOD_COMP_WL_OUTPUT_H +# define E_MOD_COMP_WL_OUTPUT_H + +Eina_Bool e_mod_comp_wl_output_init(void); +Eina_Bool e_mod_comp_wl_output_shutdown(void); +void e_mod_comp_wl_output_damage(Wayland_Output *output); +Wayland_Output *e_mod_comp_wl_output_get(void); +void e_mod_comp_wl_output_idle_repaint(void *data); + +# endif +#endif diff --git a/src/modules/comp/e_mod_comp_wl_shell.c b/src/modules/comp/e_mod_comp_wl_shell.c new file mode 100644 index 000000000..a54774541 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_shell.c @@ -0,0 +1,631 @@ +#include "e.h" +#include "e_mod_main.h" +#ifdef HAVE_WAYLAND +# include "e_mod_comp_wl.h" +# include "e_mod_comp_wl_comp.h" +# include "e_mod_comp_wl_input.h" +# include "e_mod_comp_wl_output.h" +# include "e_mod_comp_wl_surface.h" +# include "e_mod_comp_wl_shell.h" +#endif + +/* local function prototypes */ +static void _e_mod_comp_wl_shell_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id); +static void _e_mod_comp_wl_shell_lock(Wayland_Shell *base); +static void _e_mod_comp_wl_shell_unlock(Wayland_Shell *base); +static void _e_mod_comp_wl_shell_map(Wayland_Shell *base, Wayland_Surface *surface, int32_t width, int32_t height); +static void _e_mod_comp_wl_shell_configure(Wayland_Shell *base, Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height); +static void _e_mod_comp_wl_shell_destroy(Wayland_Shell *base); + +static void _e_mod_comp_wl_shell_surface_destroy_handle(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp); + +static Wayland_Shell_Surface *_e_mod_comp_wl_shell_get_shell_surface(Wayland_Surface *surface); +static Wayland_Shell_Surface_Type _e_mod_comp_wl_shell_get_shell_surface_type(Wayland_Surface *surface); +static void _e_mod_comp_wl_shell_center_on_output(Wayland_Surface *ws); +static void _e_mod_comp_wl_shell_activate(Wayland_Shell *base, Wayland_Surface *ws, Wayland_Input *device, uint32_t timestamp); + +static void _e_mod_comp_wl_shell_shell_surface_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource); +static void _e_mod_comp_wl_shell_surface_destroy(struct wl_resource *resource); +static void _e_mod_comp_wl_shell_surface_move(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp); +static void _e_mod_comp_wl_shell_surface_resize(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp, uint32_t edges); +static void _e_mod_comp_wl_shell_surface_set_toplevel(struct wl_client *client __UNUSED__, struct wl_resource *resource); +static void _e_mod_comp_wl_shell_surface_set_transient(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *parent_resource, int32_t x, int32_t y, uint32_t flags __UNUSED__); +static void _e_mod_comp_wl_shell_surface_set_fullscreen(struct wl_client *client __UNUSED__, struct wl_resource *resource); +static void _e_mod_comp_wl_shell_surface_set_popup(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource __UNUSED__, uint32_t timestamp __UNUSED__, struct wl_resource *parent_resource, int32_t x, int32_t y, uint32_t flags __UNUSED__); +static Eina_Bool _e_mod_comp_wl_shell_surface_type_reset(Wayland_Shell_Surface *wss); + +/* wayland interfaces */ +static const struct wl_shell_interface _wl_shell_interface = +{ + _e_mod_comp_wl_shell_shell_surface_get +}; +static const struct wl_shell_surface_interface _wl_shell_surface_interface = +{ + _e_mod_comp_wl_shell_surface_move, + _e_mod_comp_wl_shell_surface_resize, + _e_mod_comp_wl_shell_surface_set_toplevel, + _e_mod_comp_wl_shell_surface_set_transient, + _e_mod_comp_wl_shell_surface_set_fullscreen, + _e_mod_comp_wl_shell_surface_set_popup +}; + +/* private variables */ +struct wl_shell *_wl_shell; + +Eina_Bool +e_mod_comp_wl_shell_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(_wl_shell = malloc(sizeof(*_wl_shell)))) + { + EINA_LOG_ERR("Cannot allocate space for shell\n"); + return EINA_FALSE; + } + + memset(_wl_shell, 0, sizeof(*_wl_shell)); + + _wl_shell->shell.lock = _e_mod_comp_wl_shell_lock; + _wl_shell->shell.unlock = _e_mod_comp_wl_shell_unlock; + _wl_shell->shell.map = _e_mod_comp_wl_shell_map; + _wl_shell->shell.configure = _e_mod_comp_wl_shell_configure; + _wl_shell->shell.destroy = _e_mod_comp_wl_shell_destroy; + + wl_list_init(&_wl_shell->hidden_surfaces); + + /* FIXME: Shell configuration for screensaver ? */ + + if (!wl_display_add_global(_wl_disp, &wl_shell_interface, _wl_shell, + _e_mod_comp_wl_shell_bind)) + { + EINA_LOG_ERR("Could not create shell\n"); + free(_wl_shell); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +Eina_Bool +e_mod_comp_wl_shell_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _wl_shell->shell.destroy(&_wl_shell->shell); + return EINA_TRUE; +} + +Wayland_Shell * +e_mod_comp_wl_shell_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return &_wl_shell->shell; +} + +/* local functions */ +static void +_e_mod_comp_wl_shell_bind(struct wl_client *client, void *data, uint32_t version __UNUSED__, uint32_t id) +{ + struct wl_shell *shell; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + shell = data; + wl_client_add_object(client, &wl_shell_interface, &_wl_shell_interface, + id, shell); +} + +static void +_e_mod_comp_wl_shell_lock(Wayland_Shell *base) +{ + Wayland_Compositor *comp; + Wayland_Surface *cur, *tmp; + Wayland_Input *input; + struct wl_shell *shell; + uint32_t timestamp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + shell = container_of(base, struct wl_shell, shell); + + if (shell->locked) return; + shell->locked = EINA_TRUE; + + if (!wl_list_empty(&shell->hidden_surfaces)) + EINA_LOG_ERR("Shell Hidden Surface list is not empty\n"); + + wl_list_for_each_safe(cur, tmp, &comp->surfaces, link) + { + if (!cur->surface.resource.client) continue; + + if (_e_mod_comp_wl_shell_get_shell_surface_type(cur) == + SHELL_SURFACE_BACKGROUND) + continue; + + wl_list_remove(&cur->link); + wl_list_insert(shell->hidden_surfaces.prev, &cur->link); + } + + e_mod_comp_wl_comp_repick(); + + /* reset keyboard focus */ + input = e_mod_comp_wl_input_get(); + timestamp = e_mod_comp_wl_time_get(); + wl_input_device_set_keyboard_focus(&input->input_device, NULL, timestamp); +} + +static void +_e_mod_comp_wl_shell_unlock(Wayland_Shell *base) +{ + struct wl_shell *shell; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + shell = container_of(base, struct wl_shell, shell); + if ((!shell->locked) || (shell->lock_surface)) + { + e_mod_comp_wl_comp_wake(); + return; + } + + if (!shell->child.desktop_shell) + { + /* TODO: Resume desktop */ + return; + } + + if (shell->prepare_event_sent) return; + wl_resource_post_event(shell->child.desktop_shell, 1); + shell->prepare_event_sent = EINA_TRUE; +} + +static void +_e_mod_comp_wl_shell_map(Wayland_Shell *base, Wayland_Surface *surface, int32_t width, int32_t height) +{ + struct wl_shell *shell; + struct wl_list *list; + Wayland_Compositor *comp; + Wayland_Shell_Surface *shsurf; + Wayland_Shell_Surface_Type type; + Eina_Bool do_configure = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + type = SHELL_SURFACE_NONE; + comp = e_mod_comp_wl_comp_get(); + shell = container_of(base, struct wl_shell, shell); + + if ((shsurf = _e_mod_comp_wl_shell_get_shell_surface(surface))) + type = shsurf->type; + if (shell->locked) + { + list = &shell->hidden_surfaces; + do_configure = EINA_FALSE; + } + else + { + list = &comp->surfaces; + do_configure = EINA_TRUE; + } + + surface->width = width; + surface->height = height; + + /* initial position */ + switch (type) + { + case SHELL_SURFACE_TOPLEVEL: + surface->x = 10 + random() % 400; + surface->y = 10 + random() % 400; + break; + case SHELL_SURFACE_SCREENSAVER: + case SHELL_SURFACE_FULLSCREEN: + _e_mod_comp_wl_shell_center_on_output(surface); + break; + case SHELL_SURFACE_LOCK: + _e_mod_comp_wl_shell_center_on_output(surface); + break; + default: + break; + } + + /* surface stacking */ + switch (type) + { + case SHELL_SURFACE_BACKGROUND: + wl_list_insert(comp->surfaces.prev, &surface->link); + do_configure = EINA_TRUE; + break; + case SHELL_SURFACE_PANEL: + wl_list_insert(list, &surface->link); + break; + case SHELL_SURFACE_LOCK: + wl_list_insert(&comp->surfaces, &surface->link); + e_mod_comp_wl_comp_repick(); + e_mod_comp_wl_comp_wake(); + do_configure = EINA_TRUE; + break; + case SHELL_SURFACE_SCREENSAVER: + /* TODO: Handle show of screensaver */ + do_configure = EINA_FALSE; + break; + default: + /* skip panels */ + wl_list_insert(list, &surface->link); + break; + } + + switch (type) + { + case SHELL_SURFACE_TOPLEVEL: + surface->x = 10 + random() % 400; + surface->y = 10 + random() % 400; + break; + case SHELL_SURFACE_POPUP: + /* TODO: handle popup map */ + break; + default: + break; + } + + surface->width = width; + surface->height = height; + if (do_configure) + { + e_mod_comp_wl_surface_configure(surface, surface->x, surface->y, + width, height); + e_mod_comp_wl_comp_repick(); + } + + switch (type) + { + case SHELL_SURFACE_TOPLEVEL: + case SHELL_SURFACE_TRANSIENT: + case SHELL_SURFACE_FULLSCREEN: + if (!shell->locked) + _e_mod_comp_wl_shell_activate(base, surface, + e_mod_comp_wl_input_get(), + e_mod_comp_wl_time_get()); + break; + default: + break; + } + + /* NB: Maybe handle zoom ?? */ +} + +static void +_e_mod_comp_wl_shell_configure(Wayland_Shell *base, Wayland_Surface *surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + struct wl_shell *shell; + Wayland_Shell_Surface *shsurf; + Wayland_Shell_Surface_Type type; + Eina_Bool do_configure = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + type = SHELL_SURFACE_NONE; + shell = container_of(base, struct wl_shell, shell); + do_configure = !shell->locked; + if ((shsurf = _e_mod_comp_wl_shell_get_shell_surface(surface))) + type = shsurf->type; + + surface->width = width; + surface->height = height; + + switch (type) + { + case SHELL_SURFACE_SCREENSAVER: + do_configure = !do_configure; + case SHELL_SURFACE_FULLSCREEN: + _e_mod_comp_wl_shell_center_on_output(surface); + break; + default: + break; + } + + if (do_configure) + e_mod_comp_wl_surface_configure(surface, x, y, width, height); +} + +static void +_e_mod_comp_wl_shell_destroy(Wayland_Shell *base) +{ + struct wl_shell *shell; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + shell = container_of(base, struct wl_shell, shell); + if (shell->child.client) wl_client_destroy(shell->child.client); + free(shell); +} + +static void +_e_mod_comp_wl_shell_surface_destroy_handle(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp) +{ + Wayland_Shell_Surface *shsurf; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + shsurf = container_of(listener, Wayland_Shell_Surface, surface_destroy_listener); + shsurf->surface = NULL; + wl_resource_destroy(&shsurf->resource, timestamp); +} + +static Wayland_Shell_Surface * +_e_mod_comp_wl_shell_get_shell_surface(Wayland_Surface *surface) +{ + struct wl_list *lst; + struct wl_listener *listener; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + lst = &surface->surface.resource.destroy_listener_list; + wl_list_for_each(listener, lst, link) + { + if (listener->func == _e_mod_comp_wl_shell_surface_destroy_handle) + return container_of(listener, Wayland_Shell_Surface, + surface_destroy_listener); + } + + return NULL; +} + +static Wayland_Shell_Surface_Type +_e_mod_comp_wl_shell_get_shell_surface_type(Wayland_Surface *surface) +{ + Wayland_Shell_Surface *shsurf; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(shsurf = _e_mod_comp_wl_shell_get_shell_surface(surface))) + return SHELL_SURFACE_NONE; + + return shsurf->type; +} + +static void +_e_mod_comp_wl_shell_center_on_output(Wayland_Surface *ws) +{ + Wayland_Output *output; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + output = e_mod_comp_wl_output_get(); + ws->x = output->x + (output->mode.width - ws->width) / 2; + ws->y = output->y + (output->mode.height - ws->height) / 2; +} + +static void +_e_mod_comp_wl_shell_activate(Wayland_Shell *base, Wayland_Surface *ws, Wayland_Input *device, uint32_t timestamp) +{ + Wayland_Compositor *comp; + struct wl_shell *shell; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + shell = container_of(base, struct wl_shell, shell); + + e_mod_comp_wl_surface_activate(ws, device, timestamp); + + switch (_e_mod_comp_wl_shell_get_shell_surface_type(ws)) + { + case SHELL_SURFACE_BACKGROUND: + wl_list_remove(&ws->link); + wl_list_insert(comp->surfaces.prev, &ws->link); + break; + case SHELL_SURFACE_PANEL: + break; + case SHELL_SURFACE_SCREENSAVER: + break; + default: + if (!shell->locked) + { + /* TODO: bring panel on top */ + } + break; + } +} + +static void +_e_mod_comp_wl_shell_shell_surface_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource) +{ + Wayland_Surface *ws; + Wayland_Shell_Surface *shsurf; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ws = surface_resource->data; + if (_e_mod_comp_wl_shell_get_shell_surface(ws)) + { + wl_resource_post_error(surface_resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "get_shell_surface already requested"); + return; + } + + if (!(shsurf = calloc(1, sizeof(*shsurf)))) + { + wl_resource_post_no_memory(resource); + return; + } + + shsurf->resource.destroy = _e_mod_comp_wl_shell_surface_destroy; + shsurf->resource.object.id = id; + shsurf->resource.object.interface = &wl_shell_surface_interface; + shsurf->resource.object.implementation = + (void (**)(void)) &_wl_shell_surface_interface; + shsurf->resource.data = shsurf; + + shsurf->surface = ws; + shsurf->surface_destroy_listener.func = + _e_mod_comp_wl_shell_surface_destroy_handle; + wl_list_insert(ws->surface.resource.destroy_listener_list.prev, + &shsurf->surface_destroy_listener.link); + + wl_list_init(&shsurf->link); + + shsurf->type = SHELL_SURFACE_NONE; + wl_client_add_resource(client, &shsurf->resource); +} + +static void +_e_mod_comp_wl_shell_surface_destroy(struct wl_resource *resource) +{ + Wayland_Shell_Surface *wss; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wss = resource->data; + /* TODO: popup grab input */ + if (wss->surface) + wl_list_remove(&wss->surface_destroy_listener.link); + wl_list_remove(&wss->link); + free(wss); +} + +static void +_e_mod_comp_wl_shell_surface_move(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp) +{ + Wayland_Input *wi; + Wayland_Shell_Surface *wss; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wi = input_resource->data; + wss = resource->data; + + if ((!wi->input_device.button_count) || + (wi->input_device.grab_time != timestamp) || + (wi->input_device.pointer_focus != &wss->surface->surface)) + return; + + if (!e_mod_comp_wl_surface_move(wss->surface, wi, timestamp)) + wl_resource_post_no_memory(resource); +} + +static void +_e_mod_comp_wl_shell_surface_resize(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource, uint32_t timestamp, uint32_t edges) +{ + Wayland_Input *wi; + Wayland_Shell_Surface *wss; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wi = input_resource->data; + wss = resource->data; + + if ((!wi->input_device.button_count) || + (wi->input_device.grab_time != timestamp) || + (wi->input_device.pointer_focus != &wss->surface->surface)) + return; + + if (!e_mod_comp_wl_surface_resize(wss, wi, timestamp, edges)) + wl_resource_post_no_memory(resource); +} + +static void +_e_mod_comp_wl_shell_surface_set_toplevel(struct wl_client *client __UNUSED__, struct wl_resource *resource) +{ + Wayland_Shell_Surface *wss; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wss = resource->data; + if (!_e_mod_comp_wl_shell_surface_type_reset(wss)) return; + e_mod_comp_wl_surface_damage_surface(wss->surface); + wss->type = SHELL_SURFACE_TOPLEVEL; +} + +static void +_e_mod_comp_wl_shell_surface_set_transient(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *parent_resource, int32_t x, int32_t y, uint32_t flags __UNUSED__) +{ + Wayland_Shell_Surface *wss, *pss; + Wayland_Surface *ws, *pws; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wss = resource->data; + pss = parent_resource->data; + ws = wss->surface; + pws = pss->surface; + + if (!_e_mod_comp_wl_shell_surface_type_reset(wss)) return; + ws->x = pws->x + x; + ws->y = pws->y + y; + e_mod_comp_wl_surface_damage_surface(ws); + wss->type = SHELL_SURFACE_TRANSIENT; +} + +static void +_e_mod_comp_wl_shell_surface_set_fullscreen(struct wl_client *client __UNUSED__, struct wl_resource *resource) +{ + Wayland_Shell_Surface *wss; + Wayland_Surface *ws; + Wayland_Output *output; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wss = resource->data; + ws = wss->surface; + if (!_e_mod_comp_wl_shell_surface_type_reset(wss)) return; + + output = e_mod_comp_wl_output_get(); + wss->saved_x = ws->x; + wss->saved_y = ws->y; + ws->x = (output->width - ws->width) / 2; + ws->y = (output->height - ws->height) / 2; + e_mod_comp_wl_surface_damage_surface(ws); + wss->type = SHELL_SURFACE_FULLSCREEN; +} + +static void +_e_mod_comp_wl_shell_surface_set_popup(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *input_resource __UNUSED__, uint32_t timestamp __UNUSED__, struct wl_resource *parent_resource, int32_t x, int32_t y, uint32_t flags __UNUSED__) +{ + Wayland_Shell_Surface *wss; + Wayland_Surface *ws; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wss = resource->data; + ws = wss->surface; + e_mod_comp_wl_surface_damage_surface(ws); + wss->type = SHELL_SURFACE_POPUP; + wss->parent = parent_resource->data; + wss->popup.x = x; + wss->popup.y = y; +} + +static Eina_Bool +_e_mod_comp_wl_shell_surface_type_reset(Wayland_Shell_Surface *wss) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + switch (wss->type) + { + case SHELL_SURFACE_FULLSCREEN: + wss->surface->x = wss->saved_x; + wss->surface->y = wss->saved_y; + break; + case SHELL_SURFACE_PANEL: + case SHELL_SURFACE_BACKGROUND: + wl_list_remove(&wss->link); + wl_list_init(&wss->link); + break; + case SHELL_SURFACE_SCREENSAVER: + case SHELL_SURFACE_LOCK: + wl_resource_post_error(&wss->resource, + WL_DISPLAY_ERROR_INVALID_METHOD, + "Cannot reassign surface type"); + return EINA_FALSE; + break; + default: + break; + } + + wss->type = SHELL_SURFACE_NONE; + return EINA_TRUE; +} diff --git a/src/modules/comp/e_mod_comp_wl_shell.h b/src/modules/comp/e_mod_comp_wl_shell.h new file mode 100644 index 000000000..93a9c0dbf --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_shell.h @@ -0,0 +1,11 @@ +#ifdef E_TYPEDEFS +#else +# ifndef E_MOD_COMP_WL_SHELL_H +# define E_MOD_COMP_WL_SHELL_H + +Eina_Bool e_mod_comp_wl_shell_init(void); +Eina_Bool e_mod_comp_wl_shell_shutdown(void); +Wayland_Shell *e_mod_comp_wl_shell_get(void); + +# endif +#endif diff --git a/src/modules/comp/e_mod_comp_wl_shm.c b/src/modules/comp/e_mod_comp_wl_shm.c new file mode 100644 index 000000000..9b56b16c6 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_shm.c @@ -0,0 +1,62 @@ +#include "e.h" +#include "e_mod_main.h" +#ifdef HAVE_WAYLAND +# include "e_mod_comp_wl.h" +# include "e_mod_comp_wl_shm.h" +#endif + +void +e_mod_comp_wl_shm_buffer_created(struct wl_buffer *buffer) +{ + struct wl_list *attached; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(attached = malloc(sizeof(*attached)))) + { + EINA_LOG_ERR("Failed to allocate attached list\n"); + buffer->user_data = NULL; + return; + } + wl_list_init(attached); + buffer->user_data = attached; +} + +void +e_mod_comp_wl_shm_buffer_damaged(struct wl_buffer *buffer, int32_t x __UNUSED__, int32_t y __UNUSED__, int32_t width __UNUSED__, int32_t height __UNUSED__) +{ + struct wl_list *attached; + GLsizei tex_width; + Wayland_Surface *ws; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + attached = buffer->user_data; + tex_width = wl_shm_buffer_get_stride(buffer) / 4; + + wl_list_for_each(ws, attached, buffer_link) + { + glBindTexture(GL_TEXTURE_2D, ws->texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, + tex_width, buffer->height, 0, GL_BGRA_EXT, + GL_UNSIGNED_BYTE, wl_shm_buffer_get_data(buffer)); + } +} + +void +e_mod_comp_wl_shm_buffer_destroyed(struct wl_buffer *buffer) +{ + struct wl_list *attached; + Wayland_Surface *ws, *next; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + attached = buffer->user_data; + wl_list_for_each_safe(ws, next, attached, buffer_link) + { + wl_list_remove(&ws->buffer_link); + wl_list_init(&ws->buffer_link); + } + free(attached); +} + diff --git a/src/modules/comp/e_mod_comp_wl_shm.h b/src/modules/comp/e_mod_comp_wl_shm.h new file mode 100644 index 000000000..b32abec30 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_shm.h @@ -0,0 +1,11 @@ +#ifdef E_TYPEDEFS +#else +# ifndef E_MOD_COMP_WL_SHM_H +# define E_MOD_COMP_WL_SHM_H + +void e_mod_comp_wl_shm_buffer_created(struct wl_buffer *buffer); +void e_mod_comp_wl_shm_buffer_damaged(struct wl_buffer *buffer, int32_t x __UNUSED__, int32_t y __UNUSED__, int32_t width __UNUSED__, int32_t height __UNUSED__); +void e_mod_comp_wl_shm_buffer_destroyed(struct wl_buffer *buffer); + +# endif +#endif diff --git a/src/modules/comp/e_mod_comp_wl_surface.c b/src/modules/comp/e_mod_comp_wl_surface.c new file mode 100644 index 000000000..2a5289c00 --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_surface.c @@ -0,0 +1,514 @@ +#include "e.h" +#include "e_mod_main.h" +#ifdef HAVE_WAYLAND +# include "e_mod_comp_wl.h" +# include "e_mod_comp_wl_comp.h" +# include "e_mod_comp_wl_output.h" +# include "e_mod_comp_wl_surface.h" +# include "e_mod_comp_wl_shell.h" +#endif + +/* local function prototypes */ +static void _e_mod_comp_wl_surface_buffer_destroy_handle(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp __UNUSED__); +static int _e_mod_comp_wl_surface_texture_region(Wayland_Surface *ws, pixman_region32_t *region); +static int _e_mod_comp_wl_surface_texture_transformed_surface(Wayland_Surface *ws); +static void _e_mod_comp_wl_surface_transform_vertex(Wayland_Surface *ws, GLfloat x, GLfloat y, GLfloat u, GLfloat v, GLfloat *r); +static void _e_mod_comp_wl_surface_frame_destroy_callback(struct wl_resource *resource); +static void _e_mod_comp_wl_surface_damage_rectangle(Wayland_Surface *ws, int32_t x, int32_t y, int32_t width, int32_t height); +static void _e_mod_comp_wl_surface_flush_damage(Wayland_Surface *ws); +static void _e_mod_comp_wl_surface_raise(Wayland_Surface *ws); + +Wayland_Surface * +e_mod_comp_wl_surface_create(int32_t x, int32_t y, int32_t width, int32_t height) +{ + Wayland_Surface *surface; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(surface = calloc(1, sizeof(Wayland_Surface)))) return NULL; + + wl_list_init(&surface->link); + wl_list_init(&surface->buffer_link); + + glGenTextures(1, &surface->texture); + glBindTexture(GL_TEXTURE_2D, surface->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + surface->surface.resource.client = NULL; + + surface->visual = WAYLAND_NONE_VISUAL; + surface->saved_texture = 0; + surface->x = x; + surface->y = y; + surface->width = width; + surface->height = height; + surface->buffer = NULL; + + pixman_region32_init(&surface->damage); + pixman_region32_init(&surface->opaque); + + wl_list_init(&surface->frame_callbacks); + + surface->buffer_destroy_listener.func = + _e_mod_comp_wl_surface_buffer_destroy_handle; + + return surface; +} + +void +e_mod_comp_wl_surface_destroy(struct wl_client *client __UNUSED__, struct wl_resource *resource) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wl_resource_destroy(resource, e_mod_comp_wl_time_get()); +} + +void +e_mod_comp_wl_surface_attach(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *buffer_resource, int32_t x, int32_t y) +{ + Wayland_Surface *ws; + Wayland_Shell *shell; + struct wl_buffer *buffer; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ws = resource->data; + buffer = buffer_resource->data; + shell = e_mod_comp_wl_shell_get(); + + e_mod_comp_wl_surface_damage_below(ws); + + if (ws->buffer) + { + e_mod_comp_wl_buffer_post_release(ws->buffer); + wl_list_remove(&ws->buffer_destroy_listener.link); + } + + buffer->busy_count++; + ws->buffer = buffer; + wl_list_insert(ws->buffer->resource.destroy_listener_list.prev, + &ws->buffer_destroy_listener.link); + + if (!ws->visual) + shell->map(shell, ws, buffer->width, buffer->height); + else if ((x != 0) || (y != 0) || (ws->width != buffer->width) || + (ws->height != buffer->height)) + shell->configure(shell, ws, ws->x + x, ws->y + y, + buffer->width, buffer->height); + + e_mod_comp_wl_buffer_attach(buffer, &ws->surface); +} + +void +e_mod_comp_wl_surface_damage(struct wl_client *client __UNUSED__, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) +{ + Wayland_Surface *ws; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ws = resource->data; + _e_mod_comp_wl_surface_damage_rectangle(ws, x, y, width, height); +} + +void +e_mod_comp_wl_surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback) +{ + Wayland_Surface *ws; + Wayland_Frame_Callback *cb; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ws = resource->data; + + if (!(cb = malloc(sizeof(*cb)))) + { + wl_resource_post_no_memory(resource); + return; + } + + cb->resource.object.interface = &wl_callback_interface; + cb->resource.object.id = callback; + cb->resource.destroy = _e_mod_comp_wl_surface_frame_destroy_callback; + cb->resource.client = client; + cb->resource.data = cb; + + wl_client_add_resource(client, &cb->resource); + + wl_list_insert(ws->frame_callbacks.prev, &cb->link); +} + +void +e_mod_comp_wl_surface_destroy_surface(struct wl_resource *resource) +{ + Wayland_Surface *ws; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ws = container_of(resource, Wayland_Surface, surface.resource); + + e_mod_comp_wl_surface_damage_below(ws); + + _e_mod_comp_wl_surface_flush_damage(ws); + + wl_list_remove(&ws->link); + + e_mod_comp_wl_comp_repick(); + + if (!ws->saved_texture) + glDeleteTextures(1, &ws->texture); + else + glDeleteTextures(1, &ws->saved_texture); + + if (ws->buffer) + wl_list_remove(&ws->buffer_destroy_listener.link); + + wl_list_remove(&ws->buffer_link); + + pixman_region32_fini(&ws->damage); + pixman_region32_fini(&ws->opaque); + + free(ws); +} + +void +e_mod_comp_wl_surface_draw(Wayland_Surface *ws, Wayland_Output *output __UNUSED__, pixman_region32_t *clip) +{ + Wayland_Compositor *comp; + GLfloat *v; + pixman_region32_t repaint; + GLint filter; + int n = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + pixman_region32_init_rect(&repaint, ws->x, ws->y, ws->width, ws->height); + pixman_region32_intersect(&repaint, &repaint, clip); + if (!pixman_region32_not_empty(&repaint)) return; + switch (ws->visual) + { + case WAYLAND_ARGB_VISUAL: + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + break; + case WAYLAND_RGB_VISUAL: + glDisable(GL_BLEND); + break; + default: + break; + } + + if (ws->alpha != comp->current_alpha) + { + glUniform1f(comp->texture_shader.alpha_uniform, ws->alpha / 255.0); + comp->current_alpha = ws->alpha; + } + + if (ws->transform == NULL) + { + filter = GL_NEAREST; + n = _e_mod_comp_wl_surface_texture_region(ws, &repaint); + } + else + { + filter = GL_LINEAR; + n = _e_mod_comp_wl_surface_texture_transformed_surface(ws); + } + + glBindTexture(GL_TEXTURE_2D, ws->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + + v = comp->vertices.data; + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(*v), &v[0]); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(*v), &v[2]); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glDrawElements(GL_TRIANGLES, n * 6, GL_UNSIGNED_INT, comp->indices.data); + + comp->vertices.size = 0; + comp->indices.size = 0; + pixman_region32_fini(&repaint); +} + +void +e_mod_comp_wl_surface_damage_surface(Wayland_Surface *ws) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _e_mod_comp_wl_surface_damage_rectangle(ws, 0, 0, ws->width, ws->height); +} + +void +e_mod_comp_wl_surface_transform(Wayland_Surface *ws, int32_t x, int32_t y, int32_t *sx, int32_t *sy) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + *sx = x - ws->x; + *sy = y - ws->y; +} + +void +e_mod_comp_wl_surface_configure(Wayland_Surface *ws, int32_t x, int32_t y, int32_t width, int32_t height) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + e_mod_comp_wl_surface_damage_below(ws); + + ws->x = x; + ws->y = y; + ws->width = width; + ws->height = height; + + e_mod_comp_wl_surface_assign_output(ws); + e_mod_comp_wl_surface_damage_surface(ws); + + pixman_region32_fini(&ws->opaque); + if (ws->visual == WAYLAND_RGB_VISUAL) + pixman_region32_init_rect(&ws->opaque, ws->x, ws->y, ws->width, ws->height); + else + pixman_region32_init(&ws->opaque); +} + +void +e_mod_comp_wl_surface_assign_output(Wayland_Surface *ws) +{ + Wayland_Output *output; + pixman_region32_t region; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + output = e_mod_comp_wl_output_get(); + pixman_region32_init_rect(®ion, ws->x, ws->y, ws->width, ws->height); + pixman_region32_intersect(®ion, ®ion, &output->region); + + /* NB: maybe region32_extents if we handle more than one output */ + + if (!wl_list_empty(&ws->frame_callbacks)) + { + wl_list_insert_list(output->frame_callbacks.prev, + &ws->frame_callbacks); + wl_list_init(&ws->frame_callbacks); + } +} + +void +e_mod_comp_wl_surface_damage_below(Wayland_Surface *ws) +{ + Wayland_Compositor *comp; + Wayland_Surface *below; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + if (ws->link.next == &comp->surfaces) return; + below = container_of(ws->link.next, Wayland_Surface, link); + pixman_region32_union_rect(&below->damage, &below->damage, + ws->x, ws->y, ws->width, ws->height); + e_mod_comp_wl_comp_schedule_repaint(); +} + +void +e_mod_comp_wl_surface_activate(Wayland_Surface *ws, Wayland_Input *device, uint32_t timestamp) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _e_mod_comp_wl_surface_raise(ws); + wl_input_device_set_keyboard_focus(&device->input_device, &ws->surface, timestamp); + wl_data_device_set_keyboard_focus(&device->input_device); +} + +Eina_Bool +e_mod_comp_wl_surface_move(Wayland_Surface *ws, Wayland_Input *wi, uint32_t timestamp) +{ + /* TODO: Code me */ + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wl_input_device_set_pointer_focus(&wi->input_device, NULL, timestamp, + 0, 0, 0, 0); + return EINA_TRUE; +} + +Eina_Bool +e_mod_comp_wl_surface_resize(Wayland_Shell_Surface *wss, Wayland_Input *wi, uint32_t timestamp, uint32_t edges) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* TODO: Code me */ + + wl_input_device_set_pointer_focus(&wi->input_device, NULL, timestamp, + 0, 0, 0, 0); + return EINA_TRUE; +} + +/* local functions */ +static void +_e_mod_comp_wl_surface_buffer_destroy_handle(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, uint32_t timestamp __UNUSED__) +{ + Wayland_Surface *ws; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ws = container_of(listener, Wayland_Surface, buffer_destroy_listener); + ws->buffer = NULL; +} + +static int +_e_mod_comp_wl_surface_texture_region(Wayland_Surface *ws, pixman_region32_t *region) +{ + Wayland_Compositor *comp; + GLfloat *v, inv_width, inv_height; + pixman_box32_t *rects; + unsigned int *p; + int i, n; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + rects = pixman_region32_rectangles(region, &n); + v = wl_array_add(&comp->vertices, n * 16 * sizeof *v); + p = wl_array_add(&comp->indices, n * 6 * sizeof *p); + inv_width = 1.0 / ws->pitch; + inv_height = 1.0 / ws->height; + + for (i = 0; i < n; i++, v += 16, p += 6) { + v[ 0] = rects[i].x1; + v[ 1] = rects[i].y1; + v[ 2] = (GLfloat) (rects[i].x1 - ws->x) * inv_width; + v[ 3] = (GLfloat) (rects[i].y1 - ws->y) * inv_height; + + v[ 4] = rects[i].x1; + v[ 5] = rects[i].y2; + v[ 6] = v[ 2]; + v[ 7] = (GLfloat) (rects[i].y2 - ws->y) * inv_height; + + v[ 8] = rects[i].x2; + v[ 9] = rects[i].y1; + v[10] = (GLfloat) (rects[i].x2 - ws->x) * inv_width; + v[11] = v[ 3]; + + v[12] = rects[i].x2; + v[13] = rects[i].y2; + v[14] = v[10]; + v[15] = v[ 7]; + + p[0] = i * 4 + 0; + p[1] = i * 4 + 1; + p[2] = i * 4 + 2; + p[3] = i * 4 + 2; + p[4] = i * 4 + 1; + p[5] = i * 4 + 3; + } + + return n; +} + +static int +_e_mod_comp_wl_surface_texture_transformed_surface(Wayland_Surface *ws) +{ + Wayland_Compositor *comp; + GLfloat *v; + unsigned int *p; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + v = wl_array_add(&comp->vertices, 16 * sizeof *v); + p = wl_array_add(&comp->indices, 6 * sizeof *p); + + _e_mod_comp_wl_surface_transform_vertex(ws, ws->x, ws->y, 0.0, 0.0, &v[0]); + _e_mod_comp_wl_surface_transform_vertex(ws, ws->x, ws->y + ws->height, + 0.0, 1.0, &v[4]); + _e_mod_comp_wl_surface_transform_vertex(ws, ws->x + ws->width, ws->y, + 1.0, 0.0, &v[8]); + _e_mod_comp_wl_surface_transform_vertex(ws, ws->x + ws->width, + ws->y + ws->height, 1.0, 1.0, + &v[12]); + + p[0] = 0; + p[1] = 1; + p[2] = 2; + p[3] = 2; + p[4] = 1; + p[5] = 3; + + return 1; +} + +static void +_e_mod_comp_wl_surface_transform_vertex(Wayland_Surface *ws, GLfloat x, GLfloat y, GLfloat u, GLfloat v, GLfloat *r) +{ + Wayland_Vector t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + t.f[0] = x; + t.f[1] = y; + t.f[2] = 0.0; + t.f[3] = 1.0; + + e_mod_comp_wl_matrix_transform(&ws->transform->matrix, &t); + + r[ 0] = t.f[0]; + r[ 1] = t.f[1]; + r[ 2] = u; + r[ 3] = v; +} + +static void +_e_mod_comp_wl_surface_frame_destroy_callback(struct wl_resource *resource) +{ + Wayland_Frame_Callback *cb; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + cb = resource->data; + wl_list_remove(&cb->link); + free(cb); +} + +static void +_e_mod_comp_wl_surface_damage_rectangle(Wayland_Surface *ws, int32_t x, int32_t y, int32_t width, int32_t height) +{ + Wayland_Compositor *comp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + pixman_region32_union_rect(&ws->damage, &ws->damage, + ws->x + x, ws->y + y, width, height); + e_mod_comp_wl_comp_schedule_repaint(); +} + +static void +_e_mod_comp_wl_surface_flush_damage(Wayland_Surface *ws) +{ + Wayland_Compositor *comp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + if (ws->link.next != &comp->surfaces) + { + Wayland_Surface *below; + + below = container_of(ws->link.next, Wayland_Surface, link); + pixman_region32_union(&below->damage, &below->damage, &ws->damage); + } +} + +static void +_e_mod_comp_wl_surface_raise(Wayland_Surface *ws) +{ + Wayland_Compositor *comp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + comp = e_mod_comp_wl_comp_get(); + wl_list_remove(&ws->link); + wl_list_insert(&comp->surfaces, &ws->link); + e_mod_comp_wl_comp_repick(); + e_mod_comp_wl_surface_damage_surface(ws); +} diff --git a/src/modules/comp/e_mod_comp_wl_surface.h b/src/modules/comp/e_mod_comp_wl_surface.h new file mode 100644 index 000000000..78a0dd06b --- /dev/null +++ b/src/modules/comp/e_mod_comp_wl_surface.h @@ -0,0 +1,23 @@ +#ifdef E_TYPEDEFS +#else +# ifndef E_MOD_COMP_WL_SURFACE_H +# define E_MOD_COMP_WL_SURFACE_H + +Wayland_Surface *e_mod_comp_wl_surface_create(int32_t x, int32_t y, int32_t width, int32_t height); +void e_mod_comp_wl_surface_destroy(struct wl_client *client __UNUSED__, struct wl_resource *resource); +void e_mod_comp_wl_surface_attach(struct wl_client *client __UNUSED__, struct wl_resource *resource, struct wl_resource *buffer_resource, int32_t x, int32_t y); +void e_mod_comp_wl_surface_damage(struct wl_client *client __UNUSED__, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); +void e_mod_comp_wl_surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback); +void e_mod_comp_wl_surface_destroy_surface(struct wl_resource *resource); +void e_mod_comp_wl_surface_draw(Wayland_Surface *ws, Wayland_Output *output __UNUSED__, pixman_region32_t *clip); +void e_mod_comp_wl_surface_damage_surface(Wayland_Surface *ws); +void e_mod_comp_wl_surface_transform(Wayland_Surface *ws, int32_t x, int32_t y, int32_t *sx, int32_t *sy); +void e_mod_comp_wl_surface_configure(Wayland_Surface *ws, int32_t x, int32_t y, int32_t width, int32_t height); +void e_mod_comp_wl_surface_assign_output(Wayland_Surface *ws); +void e_mod_comp_wl_surface_damage_below(Wayland_Surface *ws); +void e_mod_comp_wl_surface_activate(Wayland_Surface *ws, Wayland_Input *device, uint32_t timestamp); +Eina_Bool e_mod_comp_wl_surface_move(Wayland_Surface *ws, Wayland_Input *wi, uint32_t timestamp); +Eina_Bool e_mod_comp_wl_surface_resize(Wayland_Shell_Surface *wss, Wayland_Input *wi, uint32_t timestamp, uint32_t edges); + +# endif +#endif