1704 lines
50 KiB
C
1704 lines
50 KiB
C
#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;
|
|
}
|