forked from enlightenment/enlightenment
E17 (wayland): Add wayland drm compositing module.
Add wayland shell module. Add wayland screenshot module. NB: I am adding these modules but NOT adding the needed build infrastructure just yet because people should not even 'play' with this yet (still some buggers to iron out). SVN revision: 69709
This commit is contained in:
parent
56c31ab510
commit
648f558aa8
|
@ -190,3 +190,15 @@ endif
|
|||
if USE_MODULE_TASKS
|
||||
SUBDIRS += tasks
|
||||
endif
|
||||
|
||||
if HAVE_WAYLAND_DRM
|
||||
SUBDIRS += wl_drm
|
||||
endif
|
||||
|
||||
if HAVE_WAYLAND_SHELL
|
||||
SUBDIRS += wl_shell
|
||||
endif
|
||||
|
||||
if HAVE_WAYLAND_SCREENSHOT
|
||||
SUBDIRS += wl_screenshot
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
MAINTAINERCLEANFILES = Makefile.in
|
||||
MODULE = wl_drm
|
||||
|
||||
# data files for the module
|
||||
filesdir = $(libdir)/enlightenment/modules/$(MODULE)
|
||||
files_DATA = \
|
||||
e-module-$(MODULE).edj module.desktop
|
||||
|
||||
EXTRA_DIST = $(files_DATA)
|
||||
|
||||
# the module .so file
|
||||
INCLUDES = -I. \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/src/modules/$(MODULE) \
|
||||
-I$(top_srcdir)/src/bin/e_wayland \
|
||||
-I$(top_builddir)/src/bin/e_wayland \
|
||||
-I$(top_srcdir)/src/modules \
|
||||
@e_wl_cflags@ @WAYLAND_DRM_CFLAGS@
|
||||
|
||||
pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH)
|
||||
pkg_LTLIBRARIES = module.la
|
||||
|
||||
module_la_SOURCES = e_mod_main.c \
|
||||
e_mod_main.h \
|
||||
e_tty.c \
|
||||
e_sprite.c \
|
||||
e_drm_output.c \
|
||||
e_evdev.c
|
||||
|
||||
module_la_LIBADD = @e_wl_libs@ @dlopen_libs@ @WAYLAND_DRM_LIBS@
|
||||
module_la_LDFLAGS = -module -avoid-version
|
||||
module_la_DEPENDENCIES = $(top_builddir)/config.h
|
||||
|
||||
uninstall:
|
||||
rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE)
|
Binary file not shown.
|
@ -0,0 +1,604 @@
|
|||
#include "e.h"
|
||||
#include "e_mod_main.h"
|
||||
|
||||
EINTERN int
|
||||
e_drm_output_subpixel_convert(int value)
|
||||
{
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case DRM_MODE_SUBPIXEL_NONE:
|
||||
return WL_OUTPUT_SUBPIXEL_NONE;
|
||||
case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
|
||||
return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
|
||||
case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
|
||||
return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
|
||||
case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
|
||||
return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
|
||||
case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
|
||||
return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
|
||||
case DRM_MODE_SUBPIXEL_UNKNOWN:
|
||||
default:
|
||||
return WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
EINTERN Eina_Bool
|
||||
e_drm_output_add_mode(E_Drm_Output *output, drmModeModeInfo *info)
|
||||
{
|
||||
E_Drm_Output_Mode *mode;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(mode = malloc(sizeof(E_Drm_Output_Mode))))
|
||||
return EINA_FALSE;
|
||||
|
||||
mode->base.flags = 0;
|
||||
mode->base.w = info->hdisplay;
|
||||
mode->base.h = info->vdisplay;
|
||||
mode->base.refresh = info->vrefresh;
|
||||
mode->info = *info;
|
||||
|
||||
wl_list_insert(output->base.modes.prev, &mode->base.link);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_set_modes(E_Drm_Compositor *dcomp)
|
||||
{
|
||||
E_Drm_Output *output;
|
||||
E_Drm_Output_Mode *mode;
|
||||
int ret = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
wl_list_for_each(output, &dcomp->base.outputs, base.link)
|
||||
{
|
||||
mode = (E_Drm_Output_Mode *)output->base.current;
|
||||
ret = drmModeSetCrtc(dcomp->drm.fd, output->crtc_id,
|
||||
output->fb_id[output->current ^ 1], 0, 0,
|
||||
&output->conn_id, 1, &mode->info);
|
||||
if (ret < 0)
|
||||
printf("Failed to set drm mode: %m\n");
|
||||
}
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_scanout_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, unsigned int timestamp __UNUSED__)
|
||||
{
|
||||
E_Drm_Output *output;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
output = container_of(listener, E_Drm_Output, scanout_buffer_destroy_listener);
|
||||
output->scanout_buffer = NULL;
|
||||
if (!output->pending_scanout_buffer)
|
||||
e_compositor_schedule_repaint(output->base.compositor);
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_pending_scanout_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, unsigned int timestamp __UNUSED__)
|
||||
{
|
||||
E_Drm_Output *output;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
output = container_of(listener, E_Drm_Output,
|
||||
pending_scanout_buffer_destroy_listener);
|
||||
output->pending_scanout_buffer = NULL;
|
||||
e_compositor_schedule_repaint(output->base.compositor);
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_repaint(E_Output *base, pixman_region32_t *damage)
|
||||
{
|
||||
E_Drm_Output *output;
|
||||
E_Drm_Compositor *dcomp;
|
||||
E_Surface *es;
|
||||
E_Sprite *sprite;
|
||||
unsigned int fb_id = 0;
|
||||
int ret = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
output = (E_Drm_Output *)base;
|
||||
dcomp = (E_Drm_Compositor *)output->base.compositor;
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, output->rbo[output->current]);
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
return;
|
||||
|
||||
e_drm_output_prepare_scanout_surface(output);
|
||||
|
||||
wl_list_for_each_reverse(es, &dcomp->base.surfaces, link)
|
||||
e_surface_draw(es, &output->base, damage);
|
||||
|
||||
glFlush();
|
||||
|
||||
output->current ^= 1;
|
||||
|
||||
if (output->pending_fs_surf_fb_id != 0)
|
||||
fb_id = output->pending_fs_surf_fb_id;
|
||||
else
|
||||
fb_id = output->fb_id[output->current ^ 1];
|
||||
|
||||
if (drmModePageFlip(dcomp->drm.fd, output->crtc_id, fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
|
||||
return;
|
||||
|
||||
wl_list_for_each(sprite, &dcomp->sprites, link)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
drmVBlank vbl;
|
||||
|
||||
vbl.request.type = (DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT);
|
||||
vbl.request.sequence = 1;
|
||||
if (!e_sprite_crtc_supported(base, sprite->possible_crtcs))
|
||||
continue;
|
||||
ret = drmModeSetPlane(dcomp->drm.fd, sprite->plane_id, output->crtc_id,
|
||||
sprite->pending_fb_id, flags, sprite->dx,
|
||||
sprite->dy, sprite->dw, sprite->dh, sprite->sx,
|
||||
sprite->sy, sprite->sw, sprite->sh);
|
||||
if (ret)
|
||||
printf("Setplane Failed: %s\n", strerror(errno));
|
||||
|
||||
vbl.request.signal = (unsigned long)sprite;
|
||||
ret = drmWaitVBlank(dcomp->drm.fd, &vbl);
|
||||
if (ret)
|
||||
printf("VBlank event request failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_destroy(E_Output *base)
|
||||
{
|
||||
E_Drm_Output *output;
|
||||
E_Drm_Compositor *dcomp;
|
||||
drmModeCrtcPtr ocrtc;
|
||||
int i = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
output = (E_Drm_Output *)base;
|
||||
dcomp = (E_Drm_Compositor *)output->base.compositor;
|
||||
ocrtc = output->orig_crtc;
|
||||
|
||||
/* TODO: backlight */
|
||||
/* if (base->backlight) */
|
||||
|
||||
e_drm_output_set_cursor(&output->base, NULL);
|
||||
|
||||
drmModeSetCrtc(dcomp->drm.fd, ocrtc->crtc_id, ocrtc->buffer_id,
|
||||
ocrtc->x, ocrtc->y, &output->conn_id, 1, &ocrtc->mode);
|
||||
drmModeFreeCrtc(ocrtc);
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, 0);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glDeleteRenderbuffers(2, output->rbo);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
drmModeRmFB(dcomp->drm.fd, output->fb_id[i]);
|
||||
dcomp->base.destroy_image(dcomp->base.egl_display, output->image[i]);
|
||||
gbm_bo_destroy(output->bo[i]);
|
||||
}
|
||||
|
||||
dcomp->crtc_alloc &= ~(1 << output->crtc_id);
|
||||
dcomp->conn_alloc &= ~(1 << output->conn_id);
|
||||
|
||||
e_output_destroy(&output->base);
|
||||
wl_list_remove(&output->base.link);
|
||||
|
||||
free(output);
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_assign_planes(E_Output *base)
|
||||
{
|
||||
E_Compositor *comp;
|
||||
E_Surface *es;
|
||||
pixman_region32_t overlap, soverlap;
|
||||
E_Input_Device *dev;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
comp = base->compositor;
|
||||
pixman_region32_init(&overlap);
|
||||
wl_list_for_each(es, &comp->surfaces, link)
|
||||
{
|
||||
pixman_region32_init(&soverlap);
|
||||
pixman_region32_intersect(&soverlap, &overlap, &es->transform.box);
|
||||
dev = (E_Input_Device *)comp->input_device;
|
||||
if (es == dev->sprite)
|
||||
{
|
||||
e_drm_output_set_cursor_region(base, dev, &soverlap);
|
||||
if (!dev->hw_cursor)
|
||||
pixman_region32_union(&overlap, &overlap, &es->transform.box);
|
||||
}
|
||||
else if (!e_drm_output_prepare_overlay_surface(base, es, &soverlap))
|
||||
{
|
||||
pixman_region32_fini(&es->damage);
|
||||
pixman_region32_init(&es->damage);
|
||||
}
|
||||
else
|
||||
pixman_region32_union(&overlap, &overlap, &es->transform.box);
|
||||
|
||||
pixman_region32_fini(&soverlap);
|
||||
}
|
||||
pixman_region32_fini(&overlap);
|
||||
|
||||
e_drm_output_disable_sprites(base);
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_set_dpms(E_Output *base, E_Dpms_Level level)
|
||||
{
|
||||
E_Drm_Output *output;
|
||||
E_Compositor *comp;
|
||||
E_Drm_Compositor *dcomp;
|
||||
drmModeConnectorPtr conn;
|
||||
drmModePropertyPtr prop;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
output = (E_Drm_Output *)base;
|
||||
comp = base->compositor;
|
||||
dcomp = (E_Drm_Compositor *)comp;
|
||||
|
||||
if (!(conn = drmModeGetConnector(dcomp->drm.fd, output->conn_id)))
|
||||
return;
|
||||
if (!(prop = e_drm_output_get_property(dcomp->drm.fd, conn, "DPMS")))
|
||||
{
|
||||
drmModeFreeConnector(conn);
|
||||
return;
|
||||
}
|
||||
drmModeConnectorSetProperty(dcomp->drm.fd, conn->connector_id,
|
||||
prop->prop_id, level);
|
||||
drmModeFreeProperty(prop);
|
||||
drmModeFreeConnector(conn);
|
||||
}
|
||||
|
||||
EINTERN Eina_Bool
|
||||
e_drm_output_prepare_scanout_surface(E_Drm_Output *output)
|
||||
{
|
||||
E_Drm_Compositor *dcomp;
|
||||
E_Surface *es;
|
||||
EGLint hdl, stride;
|
||||
int ret = 0;
|
||||
unsigned int fb_id = 0;
|
||||
struct gbm_bo *bo;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
dcomp = (E_Drm_Compositor *)output->base.compositor;
|
||||
es = container_of(dcomp->base.surfaces.next, E_Surface, link);
|
||||
|
||||
/* Need to verify output->region contained in surface opaque
|
||||
* region. Or maybe just that format doesn't have alpha. */
|
||||
return EINA_TRUE;
|
||||
|
||||
if ((es->geometry.x != output->base.x) ||
|
||||
(es->geometry.y != output->base.y) ||
|
||||
(es->geometry.w != output->base.current->w) ||
|
||||
(es->geometry.h != output->base.current->h) ||
|
||||
(es->transform.enabled) || (es->image == EGL_NO_IMAGE_KHR))
|
||||
return EINA_FALSE;
|
||||
|
||||
bo = gbm_bo_create_from_egl_image(dcomp->gbm, dcomp->base.egl_display,
|
||||
es->image, es->geometry.w,
|
||||
es->geometry.h, GBM_BO_USE_SCANOUT);
|
||||
hdl = gbm_bo_get_handle(bo).s32;
|
||||
stride = gbm_bo_get_pitch(bo);
|
||||
|
||||
gbm_bo_destroy(bo);
|
||||
|
||||
if (hdl == 0) return EINA_FALSE;
|
||||
|
||||
ret = drmModeAddFB(dcomp->drm.fd, output->base.current->w,
|
||||
output->base.current->h, 24, 32, stride, hdl, &fb_id);
|
||||
if (ret) return EINA_FALSE;
|
||||
|
||||
output->pending_fs_surf_fb_id = fb_id;
|
||||
|
||||
output->pending_scanout_buffer = es->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);
|
||||
|
||||
pixman_region32_fini(&es->damage);
|
||||
pixman_region32_init(&es->damage);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_disable_sprites(E_Output *base)
|
||||
{
|
||||
E_Compositor *comp;
|
||||
E_Drm_Compositor *dcomp;
|
||||
E_Drm_Output *output;
|
||||
E_Sprite *s;
|
||||
int ret = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
comp = base->compositor;
|
||||
dcomp = (E_Drm_Compositor *)comp;
|
||||
output = (E_Drm_Output *)base;
|
||||
|
||||
wl_list_for_each(s, &dcomp->sprites, link)
|
||||
{
|
||||
if (s->pending_fb_id) continue;
|
||||
ret = drmModeSetPlane(dcomp->drm.fd, s->plane_id, output->crtc_id,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
if (ret)
|
||||
printf("Failed to disable plane: %s\n", strerror(errno));
|
||||
drmModeRmFB(dcomp->drm.fd, s->fb_id);
|
||||
s->surface = NULL;
|
||||
s->pending_surface = NULL;
|
||||
s->fb_id = 0;
|
||||
s->pending_fb_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EINTERN drmModePropertyPtr
|
||||
e_drm_output_get_property(int fd, drmModeConnectorPtr conn, const char *name)
|
||||
{
|
||||
drmModePropertyPtr props;
|
||||
int i = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
for (i = 0; i < conn->count_props; i++)
|
||||
{
|
||||
if (!(props = drmModeGetProperty(fd, conn->props[i])))
|
||||
continue;
|
||||
if (!strcmp(props->name, name)) return props;
|
||||
drmModeFreeProperty(props);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EINTERN int
|
||||
e_drm_output_prepare_overlay_surface(E_Output *base, E_Surface *es, pixman_region32_t *overlap)
|
||||
{
|
||||
E_Compositor *comp;
|
||||
E_Drm_Compositor *dcomp;
|
||||
E_Sprite *s;
|
||||
Eina_Bool found = EINA_FALSE;
|
||||
EGLint hdl, stride;
|
||||
struct gbm_bo *bo;
|
||||
unsigned int fb_id = 0;
|
||||
unsigned int hdls[4], pitches[4], offsets[4];
|
||||
int ret = 0;
|
||||
pixman_region32_t drect, srect;
|
||||
pixman_box32_t *box;
|
||||
unsigned int format;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
comp = base->compositor;
|
||||
dcomp = (E_Drm_Compositor *)comp;
|
||||
|
||||
if (dcomp->sprites_broken) return -1;
|
||||
if (e_surface_is_primary(comp, es)) return -1;
|
||||
if (es->image == EGL_NO_IMAGE_KHR) return -1;
|
||||
|
||||
if (!e_drm_output_surface_transform_supported(es))
|
||||
return -1;
|
||||
if (!e_drm_output_surface_overlap_supported(base, overlap))
|
||||
return -1;
|
||||
|
||||
wl_list_for_each(s, &dcomp->sprites, link)
|
||||
{
|
||||
if (!e_sprite_crtc_supported(base, s->possible_crtcs))
|
||||
continue;
|
||||
if (!s->pending_fb_id)
|
||||
{
|
||||
found = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) return -1;
|
||||
|
||||
bo = gbm_bo_create_from_egl_image(dcomp->gbm, dcomp->base.egl_display,
|
||||
es->image, es->geometry.w,
|
||||
es->geometry.h, GBM_BO_USE_SCANOUT);
|
||||
format = gbm_bo_get_format(bo);
|
||||
hdl = gbm_bo_get_handle(bo).s32;
|
||||
stride = gbm_bo_get_pitch(bo);
|
||||
|
||||
gbm_bo_destroy(bo);
|
||||
|
||||
if (!e_drm_output_surface_format_supported(s, format))
|
||||
return -1;
|
||||
|
||||
if (!hdl) return -1;
|
||||
|
||||
hdls[0] = hdl;
|
||||
pitches[0] = stride;
|
||||
offsets[0] = 0;
|
||||
|
||||
ret = drmModeAddFB2(dcomp->drm.fd, es->geometry.w, es->geometry.h,
|
||||
format, hdls, pitches, offsets, &fb_id, 0);
|
||||
if (ret)
|
||||
{
|
||||
dcomp->sprites_broken = EINA_TRUE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((s->surface) && (s->surface != es))
|
||||
{
|
||||
E_Surface *os;
|
||||
|
||||
os = s->surface;
|
||||
pixman_region32_fini(&os->damage);
|
||||
pixman_region32_init_rect(&os->damage, os->geometry.x, os->geometry.y,
|
||||
os->geometry.w, os->geometry.h);
|
||||
}
|
||||
|
||||
s->pending_fb_id = fb_id;
|
||||
s->pending_surface = es;
|
||||
es->buffer->busy_count++;
|
||||
|
||||
pixman_region32_init(&drect);
|
||||
pixman_region32_intersect(&drect, &es->transform.box, &base->region);
|
||||
pixman_region32_translate(&drect, -base->x, -base->y);
|
||||
|
||||
box = pixman_region32_extents(&drect);
|
||||
s->dx = box->x1;
|
||||
s->dy = box->y1;
|
||||
s->dw = (box->x2 - box->x1);
|
||||
s->dh = (box->y2 - box->y1);
|
||||
pixman_region32_fini(&drect);
|
||||
|
||||
pixman_region32_init(&srect);
|
||||
pixman_region32_intersect(&srect, &es->transform.box, &base->region);
|
||||
pixman_region32_translate(&srect, -es->geometry.x, -es->geometry.y);
|
||||
|
||||
box = pixman_region32_extents(&srect);
|
||||
s->sx = box->x1 << 16;
|
||||
s->sy = box->y1 << 16;
|
||||
s->sw = (box->x2 - box->x1) << 16;
|
||||
s->sh = (box->y2 - box->y1) << 16;
|
||||
pixman_region32_fini(&srect);
|
||||
|
||||
wl_list_insert(es->buffer->resource.destroy_listener_list.prev,
|
||||
&s->pending_destroy_listener.link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EINTERN Eina_Bool
|
||||
e_drm_output_surface_transform_supported(E_Surface *es)
|
||||
{
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if ((es) && (es->transform.enabled)) return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
EINTERN Eina_Bool
|
||||
e_drm_output_surface_overlap_supported(E_Output *base __UNUSED__, pixman_region32_t *overlap)
|
||||
{
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (pixman_region32_not_empty(overlap)) return EINA_TRUE;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
EINTERN Eina_Bool
|
||||
e_drm_output_surface_format_supported(E_Sprite *s, unsigned int format)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
for (i = 0; i < s->format_count; i++)
|
||||
if (s->formats[i] == format) return EINA_TRUE;
|
||||
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_drm_output_set_cursor_region(E_Output *output, E_Input_Device *device, pixman_region32_t *overlap)
|
||||
{
|
||||
pixman_region32_t cregion;
|
||||
Eina_Bool prior = EINA_FALSE;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!device->sprite) return;
|
||||
pixman_region32_init(&cregion);
|
||||
pixman_region32_intersect(&cregion, &device->sprite->transform.box,
|
||||
&output->region);
|
||||
if (!pixman_region32_not_empty(&cregion))
|
||||
{
|
||||
e_drm_output_set_cursor(output, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
prior = device->hw_cursor;
|
||||
if ((pixman_region32_not_empty(overlap)) ||
|
||||
(!e_drm_output_set_cursor(output, device)))
|
||||
{
|
||||
if (prior)
|
||||
{
|
||||
e_surface_damage(device->sprite);
|
||||
e_drm_output_set_cursor(output, NULL);
|
||||
}
|
||||
device->hw_cursor = EINA_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!prior) e_surface_damage_below(device->sprite);
|
||||
pixman_region32_fini(&device->sprite->damage);
|
||||
pixman_region32_init(&device->sprite->damage);
|
||||
device->hw_cursor = EINA_TRUE;
|
||||
}
|
||||
|
||||
out:
|
||||
pixman_region32_fini(&cregion);
|
||||
}
|
||||
|
||||
EINTERN Eina_Bool
|
||||
e_drm_output_set_cursor(E_Output *output, E_Input_Device *device)
|
||||
{
|
||||
E_Drm_Output *doutput;
|
||||
E_Drm_Compositor *dcomp;
|
||||
EGLint hdl, stride;
|
||||
int ret = -1;
|
||||
struct gbm_bo *bo;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
doutput = (E_Drm_Output *)output;
|
||||
dcomp = (E_Drm_Compositor *)doutput->base.compositor;
|
||||
|
||||
if (!device)
|
||||
{
|
||||
drmModeSetCursor(dcomp->drm.fd, doutput->crtc_id, 0, 0, 0);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
if (device->sprite->image == EGL_NO_IMAGE_KHR) return EINA_FALSE;
|
||||
|
||||
if ((device->sprite->geometry.w > 64) ||
|
||||
(device->sprite->geometry.h > 64))
|
||||
return EINA_FALSE;
|
||||
|
||||
bo = gbm_bo_create_from_egl_image(dcomp->gbm, dcomp->base.egl_display,
|
||||
device->sprite->image, 64, 64,
|
||||
GBM_BO_USE_CURSOR_64X64);
|
||||
if (!bo) return EINA_FALSE;
|
||||
|
||||
hdl = gbm_bo_get_handle(bo).s32;
|
||||
stride = gbm_bo_get_pitch(bo);
|
||||
gbm_bo_destroy(bo);
|
||||
|
||||
if (stride != (64 * 4)) return EINA_FALSE;
|
||||
|
||||
if ((ret = drmModeSetCursor(dcomp->drm.fd, doutput->crtc_id, hdl, 64, 64)))
|
||||
{
|
||||
drmModeSetCursor(dcomp->drm.fd, doutput->crtc_id, 0, 0, 0);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
ret = drmModeMoveCursor(dcomp->drm.fd, doutput->crtc_id,
|
||||
device->sprite->geometry.x - doutput->base.x,
|
||||
device->sprite->geometry.y - doutput->base.y);
|
||||
if (ret)
|
||||
{
|
||||
drmModeSetCursor(dcomp->drm.fd, doutput->crtc_id, 0, 0, 0);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
|
@ -0,0 +1,664 @@
|
|||
#include "e.h"
|
||||
#include "e_mod_main.h"
|
||||
|
||||
#define E_EVDEV_ABSOLUTE_MOTION (1 << 0)
|
||||
#define E_EVDEV_ABSOLUTE_MT_DOWN (1 << 1)
|
||||
#define E_EVDEV_ABSOLUTE_MT_MOTION (1 << 2)
|
||||
#define E_EVDEV_ABSOLUTE_MT_UP (1 << 3)
|
||||
#define E_EVDEV_RELATIVE_MOTION (1 << 4)
|
||||
|
||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
|
||||
#define OFF(x) ((x)%BITS_PER_LONG)
|
||||
#define BIT(x) (1UL<<OFF(x))
|
||||
#define LONG(x) ((x)/BITS_PER_LONG)
|
||||
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
||||
|
||||
#define MODIFIER_CTRL (1 << 8)
|
||||
#define MODIFIER_ALT (1 << 9)
|
||||
#define MODIFIER_SUPER (1 << 10)
|
||||
|
||||
/* local function prototypes */
|
||||
static Eina_Bool _e_evdev_config_udev_monitor(struct udev *udev, E_Evdev_Input *master);
|
||||
static E_Evdev_Input_Device *_e_evdev_input_device_create(E_Evdev_Input *master, struct wl_display *display __UNUSED__, const char *path);
|
||||
static Eina_Bool _e_evdev_configure_device(E_Evdev_Input_Device *dev);
|
||||
static Eina_Bool _e_evdev_is_motion_event(struct input_event *e);
|
||||
static void _e_evdev_flush_motion(E_Evdev_Input_Device *dev, unsigned int timestamp);
|
||||
static void _e_evdev_process_touch(E_Evdev_Input_Device *device, struct input_event *e);
|
||||
static void _e_evdev_process_events(E_Evdev_Input_Device *device, struct input_event *ev, int count);
|
||||
|
||||
static int _e_evdev_cb_udev(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data);
|
||||
static void _e_evdev_cb_device_added(struct udev_device *dev, E_Evdev_Input *master);
|
||||
static void _e_evdev_cb_device_removed(struct udev_device *dev, E_Evdev_Input *master);
|
||||
static int _e_evdev_cb_device_data(int fd, unsigned int mask __UNUSED__, void *data);
|
||||
|
||||
/* local variables */
|
||||
/* wayland interfaces */
|
||||
/* external variables */
|
||||
|
||||
EINTERN void
|
||||
e_evdev_add_devices(struct udev *udev, E_Input_Device *base)
|
||||
{
|
||||
E_Evdev_Input *input;
|
||||
struct udev_enumerate *ue;
|
||||
struct udev_list_entry *entry;
|
||||
struct udev_device *device;
|
||||
const char *path = NULL;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
input = (E_Evdev_Input *)base;
|
||||
ue = udev_enumerate_new(udev);
|
||||
udev_enumerate_add_match_subsystem(ue, "input");
|
||||
udev_enumerate_scan_devices(ue);
|
||||
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(ue))
|
||||
{
|
||||
path = udev_list_entry_get_name(entry);
|
||||
device = udev_device_new_from_syspath(udev, path);
|
||||
if (strncmp("event", udev_device_get_sysname(device), 5) != 0)
|
||||
continue;
|
||||
_e_evdev_cb_device_added(device, input);
|
||||
udev_device_unref(device);
|
||||
}
|
||||
udev_enumerate_unref(ue);
|
||||
|
||||
if (wl_list_empty(&input->devices))
|
||||
printf("No Input Devices Found\n");
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_evdev_remove_devices(E_Input_Device *base)
|
||||
{
|
||||
E_Evdev_Input *input;
|
||||
E_Evdev_Input_Device *device, *next;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
input = (E_Evdev_Input *)base;
|
||||
wl_list_for_each_safe(device, next, &input->devices, link)
|
||||
{
|
||||
wl_event_source_remove(device->source);
|
||||
wl_list_remove(&device->link);
|
||||
if (device->mtdev) mtdev_close_delete(device->mtdev);
|
||||
close(device->fd);
|
||||
free(device->devnode);
|
||||
free(device);
|
||||
}
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_evdev_input_create(E_Compositor *comp, struct udev *udev, const char *seat)
|
||||
{
|
||||
E_Evdev_Input *input;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(input = malloc(sizeof(E_Evdev_Input)))) return;
|
||||
memset(input, 0, sizeof(E_Evdev_Input));
|
||||
e_input_device_init(&input->base, comp);
|
||||
wl_list_init(&input->devices);
|
||||
input->seat = strdup(seat);
|
||||
if (!_e_evdev_config_udev_monitor(udev, input))
|
||||
{
|
||||
free(input->seat);
|
||||
free(input);
|
||||
return;
|
||||
}
|
||||
e_evdev_add_devices(udev, &input->base);
|
||||
comp->input_device = &input->base.input_device;
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_evdev_input_destroy(E_Input_Device *base)
|
||||
{
|
||||
E_Evdev_Input *input;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
input = (E_Evdev_Input *)base;
|
||||
e_evdev_remove_devices(base);
|
||||
wl_list_remove(&input->base.link);
|
||||
free(input->seat);
|
||||
free(input);
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
static Eina_Bool
|
||||
_e_evdev_config_udev_monitor(struct udev *udev, E_Evdev_Input *master)
|
||||
{
|
||||
struct wl_event_loop *loop;
|
||||
E_Compositor *comp;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
comp = master->base.compositor;
|
||||
if (!(master->monitor = udev_monitor_new_from_netlink(udev, "udev")))
|
||||
return EINA_FALSE;
|
||||
udev_monitor_filter_add_match_subsystem_devtype(master->monitor, "input", NULL);
|
||||
if (udev_monitor_enable_receiving(master->monitor))
|
||||
return EINA_FALSE;
|
||||
loop = wl_display_get_event_loop(comp->display);
|
||||
wl_event_loop_add_fd(loop, udev_monitor_get_fd(master->monitor),
|
||||
WL_EVENT_READABLE, _e_evdev_cb_udev, master);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static E_Evdev_Input_Device *
|
||||
_e_evdev_input_device_create(E_Evdev_Input *master, struct wl_display *display __UNUSED__, const char *path)
|
||||
{
|
||||
E_Evdev_Input_Device *device;
|
||||
E_Compositor *comp;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(device = malloc(sizeof(E_Evdev_Input_Device)))) return NULL;
|
||||
comp = master->base.compositor;
|
||||
device->output = container_of(comp->outputs.next, E_Output, link);
|
||||
device->master = master;
|
||||
device->is_pad = EINA_FALSE;
|
||||
device->is_mt = EINA_FALSE;
|
||||
device->mtdev = NULL;
|
||||
device->devnode = strdup(path);
|
||||
device->mt.slot = -1;
|
||||
device->rel.dx = 0;
|
||||
device->rel.dy = 0;
|
||||
|
||||
device->fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||
if (device->fd < 0) goto err0;
|
||||
|
||||
if (!_e_evdev_configure_device(device)) goto err1;
|
||||
|
||||
if (device->is_mt)
|
||||
{
|
||||
if (!(device->mtdev = mtdev_new_open(device->fd)))
|
||||
printf("mtdev Failed to open device: %s\n", path);
|
||||
}
|
||||
|
||||
device->source =
|
||||
wl_event_loop_add_fd(comp->input_loop, device->fd, WL_EVENT_READABLE,
|
||||
_e_evdev_cb_device_data, device);
|
||||
if (!device->source) goto err1;
|
||||
|
||||
wl_list_insert(master->devices.prev, &device->link);
|
||||
|
||||
return device;
|
||||
|
||||
err1:
|
||||
close(device->fd);
|
||||
|
||||
err0:
|
||||
free(device->devnode);
|
||||
free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_e_evdev_configure_device(E_Evdev_Input_Device *dev)
|
||||
{
|
||||
struct input_absinfo absinfo;
|
||||
unsigned long ebits[NBITS(EV_MAX)];
|
||||
unsigned long abits[NBITS(ABS_MAX)];
|
||||
unsigned long kbits[NBITS(KEY_MAX)];
|
||||
Eina_Bool has_key = EINA_FALSE, has_abs = EINA_FALSE;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
ioctl(dev->fd, EVIOCGBIT(0, sizeof(ebits)), ebits);
|
||||
if (TEST_BIT(ebits, EV_ABS))
|
||||
{
|
||||
has_abs = EINA_TRUE;
|
||||
ioctl(dev->fd, EVIOCGBIT(EV_ABS, sizeof(abits)), abits);
|
||||
if (TEST_BIT(abits, ABS_X))
|
||||
{
|
||||
ioctl(dev->fd, EVIOCGABS(ABS_X), &absinfo);
|
||||
dev->absolute.min_x = absinfo.minimum;
|
||||
dev->absolute.max_x = absinfo.maximum;
|
||||
}
|
||||
if (TEST_BIT(abits, ABS_Y))
|
||||
{
|
||||
ioctl(dev->fd, EVIOCGABS(ABS_Y), &absinfo);
|
||||
dev->absolute.min_y = absinfo.minimum;
|
||||
dev->absolute.max_y = absinfo.maximum;
|
||||
}
|
||||
if (TEST_BIT(abits, ABS_MT_SLOT))
|
||||
{
|
||||
dev->is_mt = EINA_TRUE;
|
||||
dev->mt.slot = 0;
|
||||
}
|
||||
}
|
||||
if (TEST_BIT(ebits, EV_KEY))
|
||||
{
|
||||
has_key = EINA_TRUE;
|
||||
ioctl(dev->fd, EVIOCGBIT(EV_KEY, sizeof(kbits)), kbits);
|
||||
if ((TEST_BIT(kbits, BTN_TOOL_FINGER)) &&
|
||||
(!TEST_BIT(kbits, BTN_TOOL_PEN)))
|
||||
dev->is_pad = EINA_TRUE;
|
||||
}
|
||||
|
||||
if ((has_abs) && (!has_key)) return EINA_FALSE;
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_e_evdev_is_motion_event(struct input_event *e)
|
||||
{
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
switch (e->type)
|
||||
{
|
||||
case EV_REL:
|
||||
switch (e->code)
|
||||
{
|
||||
case REL_X:
|
||||
case REL_Y:
|
||||
return EINA_TRUE;
|
||||
}
|
||||
case EV_ABS:
|
||||
switch (e->code)
|
||||
{
|
||||
case ABS_X:
|
||||
case ABS_Y:
|
||||
case ABS_MT_POSITION_X:
|
||||
case ABS_MT_POSITION_Y:
|
||||
return EINA_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_e_evdev_flush_motion(E_Evdev_Input_Device *dev, unsigned int timestamp)
|
||||
{
|
||||
struct wl_input_device *master;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!dev->type) return;
|
||||
master = &dev->master->base.input_device;
|
||||
if (dev->type & E_EVDEV_RELATIVE_MOTION)
|
||||
{
|
||||
e_input_notify_motion(master, timestamp,
|
||||
master->x + dev->rel.dx,
|
||||
master->y + dev->rel.dy);
|
||||
dev->type &= ~E_EVDEV_RELATIVE_MOTION;
|
||||
dev->rel.dx = 0;
|
||||
dev->rel.dy = 0;
|
||||
}
|
||||
if (dev->type & E_EVDEV_ABSOLUTE_MT_DOWN)
|
||||
{
|
||||
e_input_notify_touch(master, timestamp, dev->mt.slot,
|
||||
dev->mt.x[dev->mt.slot],
|
||||
dev->mt.y[dev->mt.slot],
|
||||
WL_INPUT_DEVICE_TOUCH_DOWN);
|
||||
dev->type &= ~E_EVDEV_ABSOLUTE_MT_DOWN;
|
||||
dev->type &= ~E_EVDEV_ABSOLUTE_MT_MOTION;
|
||||
}
|
||||
if (dev->type & E_EVDEV_ABSOLUTE_MT_MOTION)
|
||||
{
|
||||
e_input_notify_touch(master, timestamp, dev->mt.slot,
|
||||
dev->mt.x[dev->mt.slot],
|
||||
dev->mt.y[dev->mt.slot],
|
||||
WL_INPUT_DEVICE_TOUCH_MOTION);
|
||||
dev->type &= ~E_EVDEV_ABSOLUTE_MT_DOWN;
|
||||
dev->type &= ~E_EVDEV_ABSOLUTE_MT_MOTION;
|
||||
}
|
||||
if (dev->type & E_EVDEV_ABSOLUTE_MT_UP)
|
||||
{
|
||||
e_input_notify_touch(master, timestamp, dev->mt.slot, 0, 0,
|
||||
WL_INPUT_DEVICE_TOUCH_UP);
|
||||
dev->type &= ~E_EVDEV_ABSOLUTE_MT_UP;
|
||||
}
|
||||
if (dev->type & E_EVDEV_ABSOLUTE_MOTION)
|
||||
{
|
||||
e_input_notify_motion(master, timestamp,
|
||||
dev->absolute.x, dev->absolute.y);
|
||||
dev->type &= ~E_EVDEV_ABSOLUTE_MOTION;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_e_evdev_process_key(E_Evdev_Input_Device *device, struct input_event *e, int timestamp)
|
||||
{
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (e->value == 2) return;
|
||||
|
||||
switch (e->code)
|
||||
{
|
||||
case BTN_TOOL_PEN:
|
||||
case BTN_TOOL_RUBBER:
|
||||
case BTN_TOOL_BRUSH:
|
||||
case BTN_TOOL_PENCIL:
|
||||
case BTN_TOOL_AIRBRUSH:
|
||||
case BTN_TOOL_FINGER:
|
||||
case BTN_TOOL_MOUSE:
|
||||
case BTN_TOOL_LENS:
|
||||
if (device->is_pad)
|
||||
{
|
||||
device->absolute.rx = 1;
|
||||
device->absolute.ry = 1;
|
||||
}
|
||||
break;
|
||||
case BTN_TOUCH:
|
||||
if (device->is_mt) break;
|
||||
e->code = BTN_LEFT;
|
||||
case BTN_LEFT:
|
||||
case BTN_RIGHT:
|
||||
case BTN_MIDDLE:
|
||||
case BTN_SIDE:
|
||||
case BTN_EXTRA:
|
||||
case BTN_FORWARD:
|
||||
case BTN_BACK:
|
||||
case BTN_TASK:
|
||||
e_input_notify_button(&device->master->base.input_device,
|
||||
timestamp, e->code, e->value);
|
||||
break;
|
||||
default:
|
||||
e_input_notify_key(&device->master->base.input_device,
|
||||
timestamp, e->code, e->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_e_evdev_process_absolute_motion(E_Evdev_Input_Device *device, struct input_event *e)
|
||||
{
|
||||
int sw, sh;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
sw = device->output->current->w;
|
||||
sh = device->output->current->h;
|
||||
|
||||
switch (e->code)
|
||||
{
|
||||
case ABS_X:
|
||||
device->absolute.x =
|
||||
(e->value - device->absolute.min_x) * sw /
|
||||
(device->absolute.max_x - device->absolute.min_x) +
|
||||
device->output->x;
|
||||
device->type |= E_EVDEV_ABSOLUTE_MOTION;
|
||||
break;
|
||||
case ABS_Y:
|
||||
device->absolute.y =
|
||||
(e->value - device->absolute.min_y) * sh /
|
||||
(device->absolute.max_y - device->absolute.min_y) +
|
||||
device->output->y;
|
||||
device->type |= E_EVDEV_ABSOLUTE_MOTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_e_evdev_process_absolute_motion_touchpad(E_Evdev_Input_Device *device, struct input_event *e)
|
||||
{
|
||||
/* FIXME: Make this configurable. */
|
||||
const int touchpad_speed = 700;
|
||||
|
||||
switch (e->code)
|
||||
{
|
||||
case ABS_X:
|
||||
e->value -= device->absolute.min_x;
|
||||
if (device->absolute.rx)
|
||||
device->absolute.rx = 0;
|
||||
else
|
||||
{
|
||||
device->rel.dx =
|
||||
(e->value - device->absolute.ox) * touchpad_speed /
|
||||
(device->absolute.max_x - device->absolute.min_x);
|
||||
}
|
||||
device->absolute.ox = e->value;
|
||||
device->type |= E_EVDEV_RELATIVE_MOTION;
|
||||
break;
|
||||
case ABS_Y:
|
||||
e->value -= device->absolute.min_y;
|
||||
if (device->absolute.ry)
|
||||
device->absolute.ry = 0;
|
||||
else
|
||||
{
|
||||
device->rel.dy =
|
||||
(e->value - device->absolute.oy) * touchpad_speed /
|
||||
(device->absolute.max_y - device->absolute.min_y);
|
||||
}
|
||||
device->absolute.oy = e->value;
|
||||
device->type |= E_EVDEV_RELATIVE_MOTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_e_evdev_process_relative(E_Evdev_Input_Device *device, struct input_event *e, unsigned int timestamp)
|
||||
{
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
switch (e->code)
|
||||
{
|
||||
case REL_X:
|
||||
device->rel.dx += e->value;
|
||||
device->type |= E_EVDEV_RELATIVE_MOTION;
|
||||
break;
|
||||
case REL_Y:
|
||||
device->rel.dy += e->value;
|
||||
device->type |= E_EVDEV_RELATIVE_MOTION;
|
||||
break;
|
||||
case REL_WHEEL:
|
||||
e_input_notify_axis(&device->master->base.input_device, timestamp,
|
||||
WL_INPUT_DEVICE_AXIS_VERTICAL_SCROLL, e->value);
|
||||
break;
|
||||
case REL_HWHEEL:
|
||||
e_input_notify_axis(&device->master->base.input_device, timestamp,
|
||||
WL_INPUT_DEVICE_AXIS_HORIZONTAL_SCROLL, e->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_e_evdev_process_absolute(E_Evdev_Input_Device *device, struct input_event *e)
|
||||
{
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (device->is_pad)
|
||||
_e_evdev_process_absolute_motion_touchpad(device, e);
|
||||
else if (device->is_mt)
|
||||
_e_evdev_process_touch(device, e);
|
||||
else
|
||||
_e_evdev_process_absolute_motion(device, e);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_evdev_process_touch(E_Evdev_Input_Device *device, struct input_event *e)
|
||||
{
|
||||
int sw, sh;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
sw = device->output->current->w;
|
||||
sh = device->output->current->h;
|
||||
|
||||
switch (e->code)
|
||||
{
|
||||
case ABS_MT_SLOT:
|
||||
device->mt.slot = e->value;
|
||||
break;
|
||||
case ABS_MT_TRACKING_ID:
|
||||
if (e->value >= 0)
|
||||
device->type |= E_EVDEV_ABSOLUTE_MT_DOWN;
|
||||
else
|
||||
device->type |= E_EVDEV_ABSOLUTE_MT_UP;
|
||||
break;
|
||||
case ABS_MT_POSITION_X:
|
||||
device->mt.x[device->mt.slot] =
|
||||
(e->value - device->absolute.min_x) * sw /
|
||||
(device->absolute.max_x - device->absolute.min_x) +
|
||||
device->output->x;
|
||||
device->type |= E_EVDEV_ABSOLUTE_MT_MOTION;
|
||||
break;
|
||||
case ABS_MT_POSITION_Y:
|
||||
device->mt.y[device->mt.slot] =
|
||||
(e->value - device->absolute.min_y) * sh /
|
||||
(device->absolute.max_y - device->absolute.min_y) +
|
||||
device->output->y;
|
||||
device->type |= E_EVDEV_ABSOLUTE_MT_MOTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_e_evdev_process_events(E_Evdev_Input_Device *device, struct input_event *ev, int count)
|
||||
{
|
||||
struct input_event *e, *end;
|
||||
unsigned int timestamp = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
device->type = 0;
|
||||
e = ev;
|
||||
end = e + count;
|
||||
for (e = ev; e < end; e++)
|
||||
{
|
||||
timestamp = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
|
||||
if (!_e_evdev_is_motion_event(e))
|
||||
_e_evdev_flush_motion(device, timestamp);
|
||||
switch (e->type)
|
||||
{
|
||||
case EV_REL:
|
||||
_e_evdev_process_relative(device, e, timestamp);
|
||||
break;
|
||||
case EV_ABS:
|
||||
_e_evdev_process_absolute(device, e);
|
||||
break;
|
||||
case EV_KEY:
|
||||
_e_evdev_process_key(device, e, timestamp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_e_evdev_flush_motion(device, timestamp);
|
||||
}
|
||||
|
||||
static int
|
||||
_e_evdev_cb_udev(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data)
|
||||
{
|
||||
E_Evdev_Input *master;
|
||||
struct udev_device *dev;
|
||||
const char *action;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(master = data)) return 1;
|
||||
if (!(dev = udev_monitor_receive_device(master->monitor)))
|
||||
return 1;
|
||||
if ((action = udev_device_get_action(dev)))
|
||||
{
|
||||
if (strncmp("event", udev_device_get_sysname(dev), 5) != 0)
|
||||
return 0;
|
||||
if (!strcmp(action, "add"))
|
||||
_e_evdev_cb_device_added(dev, master);
|
||||
else if (!strcmp(action, "remove"))
|
||||
_e_evdev_cb_device_removed(dev, master);
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_e_evdev_cb_device_added(struct udev_device *dev, E_Evdev_Input *master)
|
||||
{
|
||||
E_Compositor *comp;
|
||||
const char *node, *seat;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(seat = udev_device_get_property_value(dev, "ID_SEAT")))
|
||||
seat = "seat0";
|
||||
if (strcmp(seat, master->seat)) return;
|
||||
comp = master->base.compositor;
|
||||
node = udev_device_get_devnode(dev);
|
||||
_e_evdev_input_device_create(master, comp->display, node);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_evdev_cb_device_removed(struct udev_device *dev, E_Evdev_Input *master)
|
||||
{
|
||||
const char *node;
|
||||
E_Evdev_Input_Device *device, *next;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
node = udev_device_get_devnode(dev);
|
||||
wl_list_for_each_safe(device, next, &master->devices, link)
|
||||
{
|
||||
if (!strcmp(device->devnode, node))
|
||||
{
|
||||
wl_event_source_remove(device->source);
|
||||
wl_list_remove(&device->link);
|
||||
if (device->mtdev) mtdev_close_delete(device->mtdev);
|
||||
close(device->fd);
|
||||
free(device->devnode);
|
||||
free(device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_e_evdev_cb_device_data(int fd, unsigned int mask __UNUSED__, void *data)
|
||||
{
|
||||
E_Compositor *comp;
|
||||
E_Evdev_Input_Device *device;
|
||||
struct input_event ev[32];
|
||||
int len = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
device = data;
|
||||
comp = device->master->base.compositor;
|
||||
if (!comp->focus) return 1;
|
||||
|
||||
do
|
||||
{
|
||||
if (device->mtdev)
|
||||
len = mtdev_get(device->mtdev, fd, ev,
|
||||
(sizeof(ev) / sizeof(ev)[0]) *
|
||||
sizeof(struct input_event));
|
||||
else
|
||||
len = read(fd, &ev, sizeof(ev));
|
||||
|
||||
if ((len < 0) || (len % sizeof(ev[0]) != 0))
|
||||
return 1;
|
||||
|
||||
printf("Process Input Events Len: %d\n", len);
|
||||
|
||||
_e_evdev_process_events(device, ev, (len / sizeof(ev[0])));
|
||||
|
||||
} while (len > 0);
|
||||
|
||||
/* len = read(fd, &ev, sizeof(ev)); */
|
||||
|
||||
/* device->type = 0; */
|
||||
/* e = ev; */
|
||||
/* end = (void *)ev + len; */
|
||||
/* for (e = ev; e < end; e++) */
|
||||
/* { */
|
||||
/* timestamp = (e->time.tv_sec * 1000 + e->time.tv_usec / 1000); */
|
||||
/* if (!_e_evdev_is_motion_event(e)) */
|
||||
/* _e_evdev_flush_motion(device, timestamp); */
|
||||
/* switch (e->type) */
|
||||
/* { */
|
||||
/* case EV_REL: */
|
||||
/* _e_evdev_process_relative_motion(device, e); */
|
||||
/* break; */
|
||||
/* case EV_ABS: */
|
||||
/* _e_evdev_process_absolute(device, e); */
|
||||
/* break; */
|
||||
/* case EV_KEY: */
|
||||
/* _e_evdev_process_key(device, e, timestamp); */
|
||||
/* break; */
|
||||
/* } */
|
||||
/* } */
|
||||
|
||||
/* _e_evdev_flush_motion(device, timestamp); */
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,713 @@
|
|||
#include "e.h"
|
||||
#include "e_mod_main.h"
|
||||
|
||||
/* local function prototypes */
|
||||
static void _cb_tty(E_Compositor *comp, int event);
|
||||
static int _cb_drm_input(int fd, unsigned int mask __UNUSED__, void *data __UNUSED__);
|
||||
static int _cb_drm_udev_event(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data);
|
||||
static void _cb_drm_page_flip(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec, unsigned int usec, void *data);
|
||||
static void _cb_drm_vblank(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec __UNUSED__, unsigned int usec __UNUSED__, void *data);
|
||||
static Eina_Bool _egl_init(E_Drm_Compositor *dcomp, struct udev_device *dev);
|
||||
static void _sprites_init(E_Drm_Compositor *dcomp);
|
||||
static void _sprites_shutdown(E_Drm_Compositor *dcomp);
|
||||
static Eina_Bool _outputs_init(E_Drm_Compositor *dcomp, unsigned int conn, struct udev_device *drm_device);
|
||||
static Eina_Bool _output_create(E_Drm_Compositor *dcomp, drmModeRes *res, drmModeConnector *conn, int x, int y, struct udev_device *drm_device);
|
||||
static void _outputs_update(E_Drm_Compositor *dcomp, struct udev_device *drm_device);
|
||||
static Eina_Bool _udev_event_is_hotplug(E_Drm_Compositor *dcomp, struct udev_device *dev);
|
||||
|
||||
/* local variables */
|
||||
static drmModeModeInfo builtin_mode =
|
||||
{
|
||||
63500, /* clock */
|
||||
1024, 1072, 1176, 1328, 0,
|
||||
768, 771, 775, 798, 0,
|
||||
59920,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
|
||||
0,
|
||||
"1024x768"
|
||||
};
|
||||
|
||||
/* external variables */
|
||||
E_Drm_Compositor *_drm_comp = NULL;
|
||||
|
||||
EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Drm" };
|
||||
|
||||
EAPI void *
|
||||
e_modapi_init(E_Module *m)
|
||||
{
|
||||
struct wl_display *disp;
|
||||
struct udev_enumerate *ue;
|
||||
struct udev_list_entry *entry;
|
||||
struct udev_device *drm_dev = NULL;
|
||||
struct wl_event_loop *loop;
|
||||
const char *seat = NULL;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
/* try to get the wayland display */
|
||||
if (!(disp = (struct wl_display *)m->data)) return NULL;
|
||||
|
||||
/* allocate space for the drm compositor */
|
||||
if (!(_drm_comp = malloc(sizeof(E_Drm_Compositor)))) return NULL;
|
||||
|
||||
memset(_drm_comp, 0, sizeof(E_Drm_Compositor));
|
||||
|
||||
if (!(_drm_comp->udev = udev_new()))
|
||||
{
|
||||
free(_drm_comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_drm_comp->base.display = disp;
|
||||
if (!(_drm_comp->tty = e_tty_create(&_drm_comp->base, _cb_tty, 0)))
|
||||
{
|
||||
free(_drm_comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ue = udev_enumerate_new(_drm_comp->udev);
|
||||
udev_enumerate_add_match_subsystem(ue, "drm");
|
||||
udev_enumerate_add_match_sysname(ue, "card[0-9]*");
|
||||
|
||||
udev_enumerate_scan_devices(ue);
|
||||
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(ue))
|
||||
{
|
||||
struct udev_device *dev;
|
||||
const char *path = NULL;
|
||||
|
||||
path = udev_list_entry_get_name(entry);
|
||||
dev = udev_device_new_from_syspath(_drm_comp->udev, path);
|
||||
if (!(seat = udev_device_get_property_value(dev, "ID_SEAT")))
|
||||
seat = "seat0";
|
||||
if (!strcmp(seat, "seat0"))
|
||||
{
|
||||
drm_dev = dev;
|
||||
break;
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
|
||||
if (!drm_dev)
|
||||
{
|
||||
free(_drm_comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* init egl */
|
||||
if (!_egl_init(_drm_comp, drm_dev))
|
||||
{
|
||||
free(_drm_comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* _drm_comp->base.destroy = _cb_destroy; */
|
||||
_drm_comp->base.focus = EINA_TRUE;
|
||||
|
||||
_drm_comp->prev_state = E_COMPOSITOR_STATE_ACTIVE;
|
||||
|
||||
glGenFramebuffers(1, &_drm_comp->base.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _drm_comp->base.fbo);
|
||||
|
||||
if (!e_compositor_init(&_drm_comp->base, disp))
|
||||
{
|
||||
free(_drm_comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_list_init(&_drm_comp->sprites);
|
||||
_sprites_init(_drm_comp);
|
||||
|
||||
if (!_outputs_init(_drm_comp, 0, drm_dev))
|
||||
{
|
||||
free(_drm_comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
udev_device_unref(drm_dev);
|
||||
udev_enumerate_unref(ue);
|
||||
|
||||
e_evdev_input_create(&_drm_comp->base, _drm_comp->udev, seat);
|
||||
|
||||
loop = wl_display_get_event_loop(_drm_comp->base.display);
|
||||
_drm_comp->drm_source =
|
||||
wl_event_loop_add_fd(loop, _drm_comp->drm.fd, WL_EVENT_READABLE,
|
||||
_cb_drm_input, _drm_comp);
|
||||
|
||||
_drm_comp->udev_monitor =
|
||||
udev_monitor_new_from_netlink(_drm_comp->udev, "udev");
|
||||
if (!_drm_comp->udev_monitor)
|
||||
{
|
||||
free(_drm_comp);
|
||||
return NULL;
|
||||
}
|
||||
udev_monitor_filter_add_match_subsystem_devtype(_drm_comp->udev_monitor,
|
||||
"drm", NULL);
|
||||
|
||||
_drm_comp->udev_drm_source =
|
||||
wl_event_loop_add_fd(loop, udev_monitor_get_fd(_drm_comp->udev_monitor),
|
||||
WL_EVENT_READABLE, _cb_drm_udev_event, _drm_comp);
|
||||
if (udev_monitor_enable_receiving(_drm_comp->udev_monitor) < 0)
|
||||
{
|
||||
free(_drm_comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &_drm_comp->base;
|
||||
}
|
||||
|
||||
EAPI int
|
||||
e_modapi_shutdown(E_Module *m __UNUSED__)
|
||||
{
|
||||
E_Input_Device *input, *next;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
e_compositor_shutdown(&_drm_comp->base);
|
||||
gbm_device_destroy(_drm_comp->gbm);
|
||||
_sprites_shutdown(_drm_comp);
|
||||
drmDropMaster(_drm_comp->drm.fd);
|
||||
e_tty_destroy(_drm_comp->tty);
|
||||
|
||||
wl_list_for_each_safe(input, next, &_drm_comp->base.inputs, link)
|
||||
e_evdev_input_destroy(input);
|
||||
|
||||
free(_drm_comp);
|
||||
_drm_comp = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
EAPI int
|
||||
e_modapi_save(E_Module *m __UNUSED__)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* local function prototypes */
|
||||
static void
|
||||
_cb_tty(E_Compositor *comp, int event)
|
||||
{
|
||||
E_Output *output;
|
||||
E_Drm_Output *doutput;
|
||||
E_Sprite *sprite;
|
||||
E_Input_Device *input;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case 0: // TTY_ENTER_VT
|
||||
comp->focus = EINA_TRUE;
|
||||
if (drmSetMaster(_drm_comp->drm.fd))
|
||||
{
|
||||
printf("Failed to set master: %m\n");
|
||||
wl_display_terminate(comp->display);
|
||||
}
|
||||
comp->state = _drm_comp->prev_state;
|
||||
e_drm_output_set_modes(_drm_comp);
|
||||
e_compositor_damage_all(comp);
|
||||
wl_list_for_each(input, &comp->inputs, link)
|
||||
e_evdev_add_devices(_drm_comp->udev, input);
|
||||
break;
|
||||
case 1: // TTY_LEAVE_VT
|
||||
comp->focus = EINA_FALSE;
|
||||
_drm_comp->prev_state = comp->state;
|
||||
comp->state = E_COMPOSITOR_STATE_SLEEPING;
|
||||
wl_list_for_each(output, &comp->outputs, link)
|
||||
{
|
||||
output->repaint_needed = EINA_FALSE;
|
||||
e_drm_output_set_cursor(output, NULL);
|
||||
}
|
||||
doutput =
|
||||
container_of(comp->outputs.next, E_Drm_Output, base.link);
|
||||
|
||||
wl_list_for_each(sprite, &_drm_comp->sprites, link)
|
||||
drmModeSetPlane(_drm_comp->drm.fd, sprite->plane_id,
|
||||
doutput->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
wl_list_for_each(input, &comp->inputs, link)
|
||||
e_evdev_remove_devices(input);
|
||||
|
||||
if (drmDropMaster(_drm_comp->drm.fd < 0))
|
||||
printf("Failed to drop master: %m\n");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_cb_drm_input(int fd, unsigned int mask __UNUSED__, void *data __UNUSED__)
|
||||
{
|
||||
drmEventContext ectxt;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
memset(&ectxt, 0, sizeof(ectxt));
|
||||
|
||||
ectxt.version = DRM_EVENT_CONTEXT_VERSION;
|
||||
ectxt.page_flip_handler = _cb_drm_page_flip;
|
||||
ectxt.vblank_handler = _cb_drm_vblank;
|
||||
drmHandleEvent(fd, &ectxt);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_cb_drm_udev_event(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data)
|
||||
{
|
||||
E_Drm_Compositor *dcomp;
|
||||
struct udev_device *event;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(dcomp = data)) return 1;
|
||||
event = udev_monitor_receive_device(dcomp->udev_monitor);
|
||||
if (_udev_event_is_hotplug(dcomp, event))
|
||||
_outputs_update(dcomp, event);
|
||||
udev_device_unref(event);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_drm_page_flip(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec, unsigned int usec, void *data)
|
||||
{
|
||||
E_Drm_Output *doutput;
|
||||
E_Drm_Compositor *dcomp;
|
||||
unsigned int msecs;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(doutput = data)) return;
|
||||
dcomp = (E_Drm_Compositor *)doutput->base.compositor;
|
||||
|
||||
if (doutput->scanout_buffer)
|
||||
{
|
||||
e_buffer_post_release(doutput->scanout_buffer);
|
||||
wl_list_remove(&doutput->scanout_buffer_destroy_listener.link);
|
||||
doutput->scanout_buffer = NULL;
|
||||
drmModeRmFB(dcomp->drm.fd, doutput->fs_surf_fb_id);
|
||||
doutput->fs_surf_fb_id = 0;
|
||||
}
|
||||
|
||||
if (doutput->pending_scanout_buffer)
|
||||
{
|
||||
doutput->scanout_buffer = doutput->pending_scanout_buffer;
|
||||
wl_list_remove(&doutput->pending_scanout_buffer_destroy_listener.link);
|
||||
wl_list_insert(doutput->scanout_buffer->resource.destroy_listener_list.prev,
|
||||
&doutput->scanout_buffer_destroy_listener.link);
|
||||
doutput->pending_scanout_buffer = NULL;
|
||||
doutput->fs_surf_fb_id = doutput->pending_fs_surf_fb_id;
|
||||
doutput->pending_fs_surf_fb_id = 0;
|
||||
}
|
||||
|
||||
msecs = sec * 1000 + usec / 1000;
|
||||
e_output_finish_frame(&doutput->base, msecs);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_drm_vblank(int fd __UNUSED__, unsigned int frame __UNUSED__, unsigned int sec __UNUSED__, unsigned int usec __UNUSED__, void *data)
|
||||
{
|
||||
E_Sprite *es;
|
||||
E_Drm_Compositor *dcomp;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(es = data)) return;
|
||||
dcomp = es->compositor;
|
||||
|
||||
if (es->surface)
|
||||
{
|
||||
e_buffer_post_release(es->surface->buffer);
|
||||
wl_list_remove(&es->destroy_listener.link);
|
||||
es->surface = NULL;
|
||||
drmModeRmFB(dcomp->drm.fd, es->fb_id);
|
||||
es->fb_id = 0;
|
||||
}
|
||||
|
||||
if (es->pending_surface)
|
||||
{
|
||||
wl_list_remove(&es->pending_destroy_listener.link);
|
||||
wl_list_insert(es->pending_surface->buffer->resource.destroy_listener_list.prev,
|
||||
&es->destroy_listener.link);
|
||||
es->surface = es->pending_surface;
|
||||
es->pending_surface = NULL;
|
||||
es->fb_id = es->pending_fb_id;
|
||||
es->pending_fb_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_egl_init(E_Drm_Compositor *dcomp, struct udev_device *dev)
|
||||
{
|
||||
EGLint maj, min;
|
||||
const char *ext, *fname, *snum;
|
||||
int fd = 0;
|
||||
static const EGLint ctxt_att[] =
|
||||
{
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
|
||||
};
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if ((snum = udev_device_get_sysnum(dev)))
|
||||
dcomp->drm.id = atoi(snum);
|
||||
if ((!snum) || (dcomp->drm.id < 0))
|
||||
return EINA_FALSE;
|
||||
|
||||
fname = udev_device_get_devnode(dev);
|
||||
if (!(fd = open(fname, (O_RDWR | O_CLOEXEC))))
|
||||
return EINA_FALSE;
|
||||
|
||||
dcomp->drm.fd = fd;
|
||||
dcomp->gbm = gbm_create_device(dcomp->drm.fd);
|
||||
|
||||
// dcomp->base.egl_display = eglGetDisplay(dcomp->base.display);
|
||||
dcomp->base.egl_display = eglGetDisplay(dcomp->gbm);
|
||||
if (!dcomp->base.egl_display)
|
||||
return EINA_FALSE;
|
||||
|
||||
if (!eglInitialize(dcomp->base.egl_display, &maj, &min))
|
||||
return EINA_FALSE;
|
||||
|
||||
ext = eglQueryString(dcomp->base.egl_display, EGL_EXTENSIONS);
|
||||
if (!strstr(ext, "EGL_KHR_surfaceless_gles2"))
|
||||
return EINA_FALSE;
|
||||
|
||||
if (!eglBindAPI(EGL_OPENGL_ES_API)) return EINA_FALSE;
|
||||
|
||||
dcomp->base.egl_context =
|
||||
eglCreateContext(dcomp->base.egl_display, NULL, EGL_NO_CONTEXT, ctxt_att);
|
||||
if (!dcomp->base.egl_context) return EINA_FALSE;
|
||||
|
||||
if (!eglMakeCurrent(dcomp->base.egl_display, EGL_NO_SURFACE,
|
||||
EGL_NO_SURFACE, dcomp->base.egl_context))
|
||||
return EINA_FALSE;
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_sprites_init(E_Drm_Compositor *dcomp)
|
||||
{
|
||||
E_Sprite *es;
|
||||
drmModePlaneRes *res;
|
||||
drmModePlane *plane;
|
||||
unsigned int i = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(res = drmModeGetPlaneResources(dcomp->drm.fd)))
|
||||
return;
|
||||
|
||||
for (i = 0; i < res->count_planes; i++)
|
||||
{
|
||||
if (!(plane = drmModeGetPlane(dcomp->drm.fd, res->planes[i])))
|
||||
continue;
|
||||
if (!(es = e_sprite_create(dcomp, plane)))
|
||||
{
|
||||
free(plane);
|
||||
continue;
|
||||
}
|
||||
drmModeFreePlane(plane);
|
||||
wl_list_insert(&dcomp->sprites, &es->link);
|
||||
}
|
||||
free(res->planes);
|
||||
free(res);
|
||||
}
|
||||
|
||||
static void
|
||||
_sprites_shutdown(E_Drm_Compositor *dcomp)
|
||||
{
|
||||
E_Drm_Output *doutput;
|
||||
E_Sprite *es, *next;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
doutput = container_of(dcomp->base.outputs.next, E_Drm_Output, base.link);
|
||||
|
||||
wl_list_for_each_safe(es, next, &dcomp->sprites, link)
|
||||
{
|
||||
drmModeSetPlane(dcomp->drm.fd, es->plane_id, doutput->crtc_id,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
drmModeRmFB(dcomp->drm.fd, es->fb_id);
|
||||
free(es);
|
||||
}
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_outputs_init(E_Drm_Compositor *dcomp, unsigned int conn, struct udev_device *drm_device)
|
||||
{
|
||||
drmModeConnector *connector;
|
||||
drmModeRes *res;
|
||||
int i = 0, x = 0, y = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(res = drmModeGetResources(dcomp->drm.fd)))
|
||||
return EINA_FALSE;
|
||||
|
||||
if (!(dcomp->crtcs = calloc(res->count_crtcs, sizeof(unsigned int))))
|
||||
{
|
||||
drmModeFreeResources(res);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
dcomp->num_crtcs = res->count_crtcs;
|
||||
memcpy(dcomp->crtcs, res->crtcs, sizeof(unsigned int) * dcomp->num_crtcs);
|
||||
|
||||
for (i = 0; i < res->count_connectors; i++)
|
||||
{
|
||||
if (!(connector =
|
||||
drmModeGetConnector(dcomp->drm.fd, res->connectors[i])))
|
||||
continue;
|
||||
if ((connector->connection == DRM_MODE_CONNECTED) &&
|
||||
((conn == 0) || (connector->connector_id == conn)))
|
||||
{
|
||||
if (!_output_create(dcomp, res, connector, x, y, drm_device))
|
||||
{
|
||||
drmModeFreeConnector(connector);
|
||||
continue;
|
||||
}
|
||||
x += container_of(dcomp->base.outputs.prev, E_Output,
|
||||
link)->current->w;
|
||||
}
|
||||
drmModeFreeConnector(connector);
|
||||
}
|
||||
|
||||
if (wl_list_empty(&dcomp->base.outputs))
|
||||
{
|
||||
drmModeFreeResources(res);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
drmModeFreeResources(res);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_output_create(E_Drm_Compositor *dcomp, drmModeRes *res, drmModeConnector *conn, int x, int y, struct udev_device *drm_device)
|
||||
{
|
||||
E_Drm_Output *output;
|
||||
E_Drm_Output_Mode *mode, *next;
|
||||
drmModeEncoder *encoder;
|
||||
int i = 0, ret = 0;
|
||||
unsigned int hdl, stride;
|
||||
|
||||
if (!(encoder = drmModeGetEncoder(dcomp->drm.fd, conn->encoders[0])))
|
||||
return EINA_FALSE;
|
||||
|
||||
for (i = 0; i < res->count_crtcs; i++)
|
||||
{
|
||||
if ((encoder->possible_crtcs & (1 << i)) &&
|
||||
!(dcomp->crtc_alloc & (1 << res->crtcs[i])))
|
||||
break;
|
||||
}
|
||||
if (i == res->count_crtcs)
|
||||
{
|
||||
drmModeFreeEncoder(encoder);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
if (!(output = malloc(sizeof(E_Drm_Output))))
|
||||
{
|
||||
drmModeFreeEncoder(encoder);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
memset(output, 0, sizeof(E_Drm_Output));
|
||||
|
||||
output->fb_id[0] = -1;
|
||||
output->fb_id[1] = -1;
|
||||
output->base.subpixel = e_drm_output_subpixel_convert(conn->subpixel);
|
||||
output->base.make = "unknown";
|
||||
output->base.model = "unknown";
|
||||
wl_list_init(&output->base.modes);
|
||||
|
||||
output->crtc_id = res->crtcs[i];
|
||||
dcomp->crtc_alloc |= (1 << output->crtc_id);
|
||||
output->conn_id = conn->connector_id;
|
||||
dcomp->conn_alloc |= (1 << output->conn_id);
|
||||
|
||||
output->orig_crtc = drmModeGetCrtc(dcomp->drm.fd, output->crtc_id);
|
||||
drmModeFreeEncoder(encoder);
|
||||
|
||||
for (i = 0; i < conn->count_modes; i++)
|
||||
{
|
||||
if (!e_drm_output_add_mode(output, &conn->modes[i]))
|
||||
goto efree;
|
||||
}
|
||||
|
||||
if (conn->count_modes == 0)
|
||||
{
|
||||
if (!e_drm_output_add_mode(output, &builtin_mode))
|
||||
goto efree;
|
||||
}
|
||||
|
||||
mode = container_of(output->base.modes.next, E_Drm_Output_Mode, base.link);
|
||||
output->base.current = &mode->base;
|
||||
mode->base.flags = (WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED);
|
||||
|
||||
glGenRenderbuffers(2, output->rbo);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
|
||||
output->bo[i] =
|
||||
gbm_bo_create(dcomp->gbm, output->base.current->w,
|
||||
output->base.current->h, GBM_BO_FORMAT_XRGB8888,
|
||||
(GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING));
|
||||
if (!output->bo[i]) goto ebuffs;
|
||||
output->image[i] =
|
||||
dcomp->base.create_image(dcomp->base.egl_display, NULL,
|
||||
EGL_NATIVE_PIXMAP_KHR, output->bo[i], NULL);
|
||||
if (!output->image[i]) goto ebuffs;
|
||||
dcomp->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
|
||||
output->image[i]);
|
||||
stride = gbm_bo_get_pitch(output->bo[i]);
|
||||
hdl = gbm_bo_get_handle(output->bo[i]).u32;
|
||||
ret = drmModeAddFB(dcomp->drm.fd, output->base.current->w,
|
||||
output->base.current->h, 24, 32, stride, hdl,
|
||||
&output->fb_id[i]);
|
||||
if (ret) goto ebuffs;
|
||||
}
|
||||
|
||||
output->current = 0;
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, output->rbo[output->current]);
|
||||
ret = drmModeSetCrtc(dcomp->drm.fd, output->crtc_id,
|
||||
output->fb_id[output->current ^ 1], 0, 0,
|
||||
&output->conn_id, 1, &mode->info);
|
||||
if (ret) goto efb;
|
||||
|
||||
/* TODO: backlight init */
|
||||
|
||||
e_output_init(&output->base, &dcomp->base, x, y,
|
||||
conn->mmWidth, conn->mmHeight, 0);
|
||||
|
||||
wl_list_insert(dcomp->base.outputs.prev, &output->base.link);
|
||||
|
||||
output->scanout_buffer_destroy_listener.func =
|
||||
e_drm_output_scanout_buffer_destroy;
|
||||
output->pending_scanout_buffer_destroy_listener.func =
|
||||
e_drm_output_pending_scanout_buffer_destroy;
|
||||
|
||||
output->pending_fs_surf_fb_id = 0;
|
||||
output->base.repaint = e_drm_output_repaint;
|
||||
output->base.destroy = e_drm_output_destroy;
|
||||
output->base.assign_planes = e_drm_output_assign_planes;
|
||||
output->base.set_dpms = e_drm_output_set_dpms;
|
||||
|
||||
return EINA_TRUE;
|
||||
|
||||
efb:
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, 0);
|
||||
|
||||
ebuffs:
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if ((int)output->fb_id[i] != -1)
|
||||
drmModeRmFB(dcomp->drm.fd, output->fb_id[i]);
|
||||
if (output->image[i])
|
||||
dcomp->base.destroy_image(dcomp->base.egl_display, output->image[i]);
|
||||
if (output->bo[i]) gbm_bo_destroy(output->bo[i]);
|
||||
}
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glDeleteRenderbuffers(2, output->rbo);
|
||||
|
||||
efree:
|
||||
wl_list_for_each_safe(mode, next, &output->base.modes, base.link)
|
||||
{
|
||||
wl_list_remove(&mode->base.link);
|
||||
free(mode);
|
||||
}
|
||||
drmModeFreeCrtc(output->orig_crtc);
|
||||
dcomp->crtc_alloc &= ~(1 << output->crtc_id);
|
||||
dcomp->conn_alloc &= ~(1 << output->conn_id);
|
||||
free(output);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_outputs_update(E_Drm_Compositor *dcomp, struct udev_device *drm_device)
|
||||
{
|
||||
drmModeConnector *conn;
|
||||
drmModeRes *res;
|
||||
E_Drm_Output *doutput, *next;
|
||||
int x = 0, y = 0;
|
||||
int xo = 0, yo = 0;
|
||||
unsigned int connected = 0, disconnects = 0;
|
||||
int i = 0;
|
||||
|
||||
if (!(res = drmModeGetResources(dcomp->drm.fd)))
|
||||
return;
|
||||
|
||||
for (i = 0; i < res->count_connectors; i++)
|
||||
{
|
||||
int conn_id;
|
||||
|
||||
conn_id = res->connectors[i];
|
||||
if (!(conn = drmModeGetConnector(dcomp->drm.fd, conn_id)))
|
||||
continue;
|
||||
if (conn->connection != DRM_MODE_CONNECTED)
|
||||
{
|
||||
drmModeFreeConnector(conn);
|
||||
continue;
|
||||
}
|
||||
connected |= (1 << conn_id);
|
||||
if (!(dcomp->conn_alloc & (1 << conn_id)))
|
||||
{
|
||||
E_Output *last;
|
||||
|
||||
last = container_of(dcomp->base.outputs.prev, E_Output, link);
|
||||
if (!wl_list_empty(&dcomp->base.outputs))
|
||||
x = last->x + last->current->w;
|
||||
else
|
||||
x = 0;
|
||||
y = 0;
|
||||
_output_create(dcomp, res, conn, x, y, drm_device);
|
||||
}
|
||||
drmModeFreeConnector(conn);
|
||||
}
|
||||
drmModeFreeResources(res);
|
||||
|
||||
if ((disconnects = dcomp->conn_alloc & ~connected))
|
||||
{
|
||||
wl_list_for_each_safe(doutput, next, &dcomp->base.outputs, base.link)
|
||||
{
|
||||
if ((xo != 0) || (yo != 0))
|
||||
e_output_move(&doutput->base, doutput->base.x - xo,
|
||||
doutput->base.y - yo);
|
||||
if (disconnects & (1 << doutput->conn_id))
|
||||
{
|
||||
disconnects &= ~(1 << doutput->conn_id);
|
||||
xo += doutput->base.current->w;
|
||||
e_drm_output_destroy(&doutput->base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dcomp->conn_alloc == 0)
|
||||
wl_display_terminate(dcomp->base.display);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_udev_event_is_hotplug(E_Drm_Compositor *dcomp, struct udev_device *dev)
|
||||
{
|
||||
const char *snum, *val;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
snum = udev_device_get_sysnum(dev);
|
||||
if ((!snum) || (atoi(snum) != dcomp->drm.id))
|
||||
return EINA_FALSE;
|
||||
|
||||
if (!(val = udev_device_get_property_value(dev, "HOTPLUG")))
|
||||
return EINA_FALSE;
|
||||
|
||||
if (!strcmp(val, "1")) return EINA_TRUE;
|
||||
|
||||
return EINA_FALSE;
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
#ifndef E_MOD_MAIN_H
|
||||
# define E_MOD_MAIN_H
|
||||
|
||||
# define DLOGFNS 1
|
||||
|
||||
# ifdef DLOGFNS
|
||||
# include <stdio.h>
|
||||
# define DLOGFN(fl, ln, fn) printf("-E-DRM: %25s: %5i - %s\n", fl, ln, fn);
|
||||
# else
|
||||
# define DLOGFN(fl, ln, fn)
|
||||
# endif
|
||||
|
||||
# include <libudev.h>
|
||||
# include <gbm.h>
|
||||
# include <xf86drm.h>
|
||||
# include <xf86drmMode.h>
|
||||
# include <drm_fourcc.h>
|
||||
# include <termios.h>
|
||||
# include <linux/kd.h>
|
||||
# include <linux/vt.h>
|
||||
# include <linux/major.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <wayland-server.h>
|
||||
# include <mtdev.h>
|
||||
|
||||
typedef void (*tty_vt_func_t)(E_Compositor *comp, int event);
|
||||
typedef struct _E_Tty E_Tty;
|
||||
typedef struct _E_Drm_Compositor E_Drm_Compositor;
|
||||
typedef struct _E_Sprite E_Sprite;
|
||||
typedef struct _E_Drm_Output_Mode E_Drm_Output_Mode;
|
||||
typedef struct _E_Drm_Output E_Drm_Output;
|
||||
typedef struct _E_Evdev_Input E_Evdev_Input;
|
||||
typedef struct _E_Evdev_Input_Device E_Evdev_Input_Device;
|
||||
|
||||
struct _E_Drm_Compositor
|
||||
{
|
||||
E_Compositor base;
|
||||
|
||||
struct udev *udev;
|
||||
struct wl_event_source *drm_source;
|
||||
struct udev_monitor *udev_monitor;
|
||||
struct wl_event_source *udev_drm_source;
|
||||
struct
|
||||
{
|
||||
int id, fd;
|
||||
} drm;
|
||||
struct gbm_device *gbm;
|
||||
unsigned int *crtcs;
|
||||
int num_crtcs;
|
||||
unsigned int crtc_alloc;
|
||||
unsigned int conn_alloc;
|
||||
|
||||
E_Tty *tty;
|
||||
|
||||
struct wl_list sprites;
|
||||
Eina_Bool sprites_broken;
|
||||
E_Compositor_State prev_state;
|
||||
};
|
||||
|
||||
struct _E_Tty
|
||||
{
|
||||
E_Compositor *comp;
|
||||
|
||||
int fd;
|
||||
struct termios term_attribs;
|
||||
struct wl_event_source *input_source;
|
||||
struct wl_event_source *vt_source;
|
||||
tty_vt_func_t vt_func;
|
||||
int vt, start_vt;
|
||||
Eina_Bool has_vt : 1;
|
||||
};
|
||||
|
||||
struct _E_Sprite
|
||||
{
|
||||
struct wl_list link;
|
||||
|
||||
unsigned int fb_id;
|
||||
unsigned int pending_fb_id;
|
||||
|
||||
E_Surface *surface, *pending_surface;
|
||||
E_Drm_Compositor *compositor;
|
||||
|
||||
struct wl_listener destroy_listener;
|
||||
struct wl_listener pending_destroy_listener;
|
||||
|
||||
unsigned int possible_crtcs;
|
||||
unsigned int plane_id;
|
||||
|
||||
int sx, sy;
|
||||
unsigned int sw, sh;
|
||||
unsigned int dx, dy, dw, dh;
|
||||
|
||||
unsigned int format_count;
|
||||
unsigned int formats[];
|
||||
};
|
||||
|
||||
struct _E_Drm_Output_Mode
|
||||
{
|
||||
E_Output_Mode base;
|
||||
drmModeModeInfo info;
|
||||
};
|
||||
|
||||
struct _E_Drm_Output
|
||||
{
|
||||
E_Output base;
|
||||
|
||||
unsigned int crtc_id;
|
||||
unsigned int conn_id;
|
||||
drmModeCrtcPtr orig_crtc;
|
||||
GLuint rbo[2];
|
||||
unsigned int fb_id[2];
|
||||
|
||||
EGLImageKHR image[2];
|
||||
struct gbm_bo *bo[2];
|
||||
|
||||
unsigned int current;
|
||||
unsigned int fs_surf_fb_id;
|
||||
unsigned int pending_fs_surf_fb_id;
|
||||
|
||||
struct wl_buffer *scanout_buffer, *pending_scanout_buffer;
|
||||
struct wl_listener scanout_buffer_destroy_listener;
|
||||
struct wl_listener pending_scanout_buffer_destroy_listener;
|
||||
|
||||
/* TODO: backlight */
|
||||
};
|
||||
|
||||
struct _E_Evdev_Input
|
||||
{
|
||||
E_Input_Device base;
|
||||
struct wl_list devices;
|
||||
struct udev_monitor *monitor;
|
||||
char *seat;
|
||||
};
|
||||
|
||||
struct _E_Evdev_Input_Device
|
||||
{
|
||||
E_Evdev_Input *master;
|
||||
struct wl_list link;
|
||||
struct wl_event_source *source;
|
||||
E_Output *output;
|
||||
char *devnode;
|
||||
int fd;
|
||||
struct
|
||||
{
|
||||
int min_x, max_x, min_y, max_y;
|
||||
int ox, oy, rx, ry;
|
||||
int x, y;
|
||||
} absolute;
|
||||
struct
|
||||
{
|
||||
int slot;
|
||||
int x[16], y[16];
|
||||
} mt;
|
||||
struct mtdev *mtdev;
|
||||
struct
|
||||
{
|
||||
int dx, dy;
|
||||
} rel;
|
||||
|
||||
int type;
|
||||
|
||||
Eina_Bool is_pad : 1;
|
||||
Eina_Bool is_mt : 1;
|
||||
};
|
||||
|
||||
extern E_Drm_Compositor *_comp;
|
||||
|
||||
EAPI extern E_Module_Api e_modapi;
|
||||
|
||||
EAPI void *e_modapi_init(E_Module *m);
|
||||
EAPI int e_modapi_shutdown(E_Module *m);
|
||||
EAPI int e_modapi_save(E_Module *m);
|
||||
|
||||
EINTERN E_Sprite *e_sprite_create(E_Drm_Compositor *dcomp, drmModePlane *plane);
|
||||
EINTERN Eina_Bool e_sprite_crtc_supported(E_Output *output, unsigned int supported);
|
||||
|
||||
EINTERN E_Tty *e_tty_create(E_Compositor *comp, tty_vt_func_t vt_func, int tty);
|
||||
EINTERN void e_tty_destroy(E_Tty *et);
|
||||
|
||||
EINTERN int e_drm_output_subpixel_convert(int value);
|
||||
EINTERN Eina_Bool e_drm_output_add_mode(E_Drm_Output *output, drmModeModeInfo *info);
|
||||
EINTERN void e_drm_output_set_modes(E_Drm_Compositor *dcomp);
|
||||
EINTERN void e_drm_output_scanout_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, unsigned int timestamp __UNUSED__);
|
||||
EINTERN void e_drm_output_pending_scanout_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, unsigned int timestamp __UNUSED__);
|
||||
EINTERN void e_drm_output_repaint(E_Output *base, pixman_region32_t *damage);
|
||||
EINTERN void e_drm_output_destroy(E_Output *base);
|
||||
EINTERN void e_drm_output_assign_planes(E_Output *base);
|
||||
EINTERN void e_drm_output_set_dpms(E_Output *base, E_Dpms_Level level);
|
||||
EINTERN Eina_Bool e_drm_output_prepare_scanout_surface(E_Drm_Output *output);
|
||||
EINTERN void e_drm_output_disable_sprites(E_Output *base);
|
||||
EINTERN drmModePropertyPtr e_drm_output_get_property(int fd, drmModeConnectorPtr conn, const char *name);
|
||||
EINTERN int e_drm_output_prepare_overlay_surface(E_Output *base, E_Surface *es, pixman_region32_t *overlap);
|
||||
EINTERN Eina_Bool e_drm_output_surface_transform_supported(E_Surface *es);
|
||||
EINTERN Eina_Bool e_drm_output_surface_overlap_supported(E_Output *base __UNUSED__, pixman_region32_t *overlap);
|
||||
EINTERN Eina_Bool e_drm_output_surface_format_supported(E_Sprite *s, unsigned int format);
|
||||
EINTERN void e_drm_output_set_cursor_region(E_Output *output, E_Input_Device *device, pixman_region32_t *overlap);
|
||||
EINTERN Eina_Bool e_drm_output_set_cursor(E_Output *output, E_Input_Device *device);
|
||||
|
||||
EINTERN void e_evdev_add_devices(struct udev *udev, E_Input_Device *base);
|
||||
EINTERN void e_evdev_remove_devices(E_Input_Device *base);
|
||||
EINTERN void e_evdev_input_create(E_Compositor *comp, struct udev *udev, const char *seat);
|
||||
EINTERN void e_evdev_input_destroy(E_Input_Device *base);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,88 @@
|
|||
#include "e.h"
|
||||
#include "e_mod_main.h"
|
||||
|
||||
/* local function prototypes */
|
||||
static void _e_sprite_cb_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, unsigned int timestamp __UNUSED__);
|
||||
static void _e_sprite_cb_pending_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, unsigned int timestamp __UNUSED__);
|
||||
|
||||
/* local variables */
|
||||
/* wayland interfaces */
|
||||
/* external variables */
|
||||
|
||||
EINTERN E_Sprite *
|
||||
e_sprite_create(E_Drm_Compositor *dcomp, drmModePlane *plane)
|
||||
{
|
||||
E_Sprite *es;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!plane) return NULL;
|
||||
|
||||
es = malloc(sizeof(E_Sprite) + ((sizeof(unsigned int)) * plane->count_formats));
|
||||
if (!es) return NULL;
|
||||
|
||||
memset(es, 0, sizeof(E_Sprite));
|
||||
|
||||
es->compositor = dcomp;
|
||||
es->possible_crtcs = plane->possible_crtcs;
|
||||
es->plane_id = plane->plane_id;
|
||||
es->surface = NULL;
|
||||
es->pending_surface = NULL;
|
||||
es->fb_id = 0;
|
||||
es->pending_fb_id = 0;
|
||||
es->destroy_listener.func = _e_sprite_cb_buffer_destroy;
|
||||
es->pending_destroy_listener.func = _e_sprite_cb_pending_buffer_destroy;
|
||||
es->format_count = plane->count_formats;
|
||||
memcpy(es->formats, plane->formats,
|
||||
plane->count_formats * sizeof(plane->formats[0]));
|
||||
|
||||
return es;
|
||||
}
|
||||
|
||||
EINTERN Eina_Bool
|
||||
e_sprite_crtc_supported(E_Output *output, unsigned int supported)
|
||||
{
|
||||
E_Compositor *comp;
|
||||
E_Drm_Compositor *dcomp;
|
||||
E_Drm_Output *doutput;
|
||||
int crtc = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
comp = output->compositor;
|
||||
dcomp = (E_Drm_Compositor *)comp;
|
||||
doutput = (E_Drm_Output *)output;
|
||||
|
||||
for (crtc = 0; crtc < dcomp->num_crtcs; crtc++)
|
||||
{
|
||||
if (dcomp->crtcs[crtc] != doutput->crtc_id)
|
||||
continue;
|
||||
if (supported & (1 << crtc))
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
static void
|
||||
_e_sprite_cb_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, unsigned int timestamp __UNUSED__)
|
||||
{
|
||||
E_Sprite *es;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
es = container_of(listener, E_Sprite, destroy_listener);
|
||||
es->surface = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_e_sprite_cb_pending_buffer_destroy(struct wl_listener *listener, struct wl_resource *resource __UNUSED__, unsigned int timestamp __UNUSED__)
|
||||
{
|
||||
E_Sprite *es;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
es = container_of(listener, E_Sprite, pending_destroy_listener);
|
||||
es->pending_surface = NULL;
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
#include "e.h"
|
||||
#include "e_mod_main.h"
|
||||
|
||||
/* local function prototypes */
|
||||
static int _e_tty_open_vt(E_Tty *et);
|
||||
static int _e_tty_cb_input(int fd __UNUSED__, uint32_t mask __UNUSED__, void *data);
|
||||
static int _e_tty_cb_handle(int sig __UNUSED__, void *data);
|
||||
|
||||
EINTERN E_Tty *
|
||||
e_tty_create(E_Compositor *comp, tty_vt_func_t vt_func, int tty)
|
||||
{
|
||||
E_Tty *et = NULL;
|
||||
struct stat buff;
|
||||
struct termios raw_attribs;
|
||||
struct wl_event_loop *loop;
|
||||
struct vt_mode mode;
|
||||
int ret = 0;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!(et = malloc(sizeof(E_Tty))))
|
||||
{
|
||||
e_error_message_show(_("Could not allocate space for E_Tty\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(et, 0, sizeof(E_Tty));
|
||||
|
||||
et->comp = comp;
|
||||
et->vt_func = vt_func;
|
||||
if (tty > 0)
|
||||
{
|
||||
char fname[16];
|
||||
|
||||
snprintf(fname, sizeof(fname), "/dev/tty%d", tty);
|
||||
printf("Using %s for tty\n", fname);
|
||||
et->fd = open(fname, O_RDWR | O_NOCTTY | O_CLOEXEC);
|
||||
}
|
||||
else if ((fstat(et->fd, &buff) == 0) &&
|
||||
(major(buff.st_rdev) == TTY_MAJOR) && (minor(buff.st_rdev) > 0))
|
||||
et->fd = fcntl(0, F_DUPFD_CLOEXEC, 0);
|
||||
else
|
||||
et->fd = _e_tty_open_vt(et);
|
||||
|
||||
if (et->fd <= 0)
|
||||
{
|
||||
e_error_message_show(_("Could not open a tty.\n"));
|
||||
free(et);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tcgetattr(et->fd, &et->term_attribs) < 0)
|
||||
{
|
||||
e_error_message_show(_("Could not get terminal attributes: %m\n"));
|
||||
free(et);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
raw_attribs = et->term_attribs;
|
||||
cfmakeraw(&raw_attribs);
|
||||
|
||||
raw_attribs.c_oflag |= (OPOST | OCRNL);
|
||||
if (tcsetattr(et->fd, TCSANOW, &raw_attribs) < 0)
|
||||
{
|
||||
e_error_message_show(_("Could not put terminal in raw mode: %m\n"));
|
||||
free(et);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
loop = wl_display_get_event_loop(comp->display);
|
||||
et->input_source =
|
||||
wl_event_loop_add_fd(loop, et->fd, WL_EVENT_READABLE, _e_tty_cb_input, et);
|
||||
|
||||
if ((ret = ioctl(et->fd, KDSETMODE, KD_GRAPHICS)))
|
||||
{
|
||||
e_error_message_show(_("Failed to set graphics mode on tty: %m\n"));
|
||||
free(et);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
et->has_vt = EINA_TRUE;
|
||||
mode.mode = VT_PROCESS;
|
||||
mode.relsig = SIGUSR1;
|
||||
mode.acqsig = SIGUSR1;
|
||||
if (ioctl(et->fd, VT_SETMODE, &mode) < 0)
|
||||
{
|
||||
e_error_message_show(_("Failed to take control of vt handling: %m\n"));
|
||||
free(et);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
et->vt_source =
|
||||
wl_event_loop_add_signal(loop, SIGUSR1, _e_tty_cb_handle, et);
|
||||
|
||||
return et;
|
||||
}
|
||||
|
||||
EINTERN void
|
||||
e_tty_destroy(E_Tty *et)
|
||||
{
|
||||
struct vt_mode mode;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if (!et) return;
|
||||
if (ioctl(et->fd, KDSETMODE, KD_TEXT))
|
||||
e_error_message_show(_("Failed to set KD_TEXT mode on tty: %m\n"));
|
||||
if (tcsetattr(et->fd, TCSANOW, &et->term_attribs) < 0)
|
||||
e_error_message_show(_("Could not restore terminal to canonical mode: %m\n"));
|
||||
mode.mode = VT_AUTO;
|
||||
if (ioctl(et->fd, VT_SETMODE, &mode) < 0)
|
||||
e_error_message_show(_("Could not reset vt handling: %m\n"));
|
||||
if ((et->has_vt) && (et->vt != et->start_vt))
|
||||
{
|
||||
ioctl(et->fd, VT_ACTIVATE, et->start_vt);
|
||||
ioctl(et->fd, VT_WAITACTIVE, et->start_vt);
|
||||
}
|
||||
close(et->fd);
|
||||
free(et);
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
static int
|
||||
_e_tty_open_vt(E_Tty *et)
|
||||
{
|
||||
int tty0, fd;
|
||||
char fname[16];
|
||||
struct vt_stat vts;
|
||||
|
||||
DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
if ((tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC)) < 0)
|
||||
{
|
||||
e_error_message_show(_("Failed to open tty0: %m\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ioctl(tty0, VT_OPENQRY, &et->vt) < 0) || (et->vt == -1))
|
||||
{
|
||||
e_error_message_show(_("Failed to open tty0: %m\n"));
|
||||
close(tty0);
|
||||
return -1;
|
||||
}
|
||||
close(tty0);
|
||||
|
||||
snprintf(fname, sizeof(fname), "/dev/tty%d", et->vt);
|
||||
printf("Compositor: Using new vt %s\n", fname);
|
||||
fd = open(fname, O_RDWR | O_NOCTTY | O_CLOEXEC);
|
||||
if (fd < 0) return fd;
|
||||
|
||||
if (ioctl(fd, VT_GETSTATE, &vts) == 0)
|
||||
et->start_vt = vts.v_active;
|
||||
else
|
||||
et->start_vt = et->vt;
|
||||
|
||||
if ((ioctl(fd, VT_ACTIVATE, et->vt) < 0) ||
|
||||
(ioctl(fd, VT_WAITACTIVE, et->vt) < 0))
|
||||
{
|
||||
e_error_message_show(_("Failed to switch to new vt: %m\n"));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
_e_tty_cb_input(int fd __UNUSED__, uint32_t mask __UNUSED__, void *data)
|
||||
{
|
||||
E_Tty *et;
|
||||
|
||||
// DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
et = data;
|
||||
tcflush(et->fd, TCIFLUSH);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_e_tty_cb_handle(int sig __UNUSED__, void *data)
|
||||
{
|
||||
E_Tty *et;
|
||||
|
||||
// DLOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
et = data;
|
||||
if (et->has_vt)
|
||||
{
|
||||
et->vt_func(et->comp, 1);
|
||||
et->has_vt = EINA_FALSE;
|
||||
ioctl(et->fd, VT_RELDISP, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioctl(et->fd, VT_RELDISP, VT_ACKACQ);
|
||||
et->vt_func(et->comp, 0);
|
||||
et->has_vt = EINA_TRUE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[Desktop Entry]
|
||||
Type=Link
|
||||
Name=Wayland Drm
|
||||
Icon=e-module-wl_drm
|
||||
Comment=Enlightenment DRM Composite Manager
|
||||
X-Enlightenment-ModuleType=look
|
|
@ -0,0 +1,33 @@
|
|||
MAINTAINERCLEANFILES = Makefile.in
|
||||
MODULE = wl_screenshot
|
||||
|
||||
# data files for the module
|
||||
filesdir = $(libdir)/enlightenment/modules/$(MODULE)
|
||||
files_DATA = \
|
||||
e-module-$(MODULE).edj module.desktop
|
||||
|
||||
EXTRA_DIST = $(files_DATA)
|
||||
|
||||
# the module .so file
|
||||
INCLUDES = -I. \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/src/modules/$(MODULE) \
|
||||
-I$(top_srcdir)/src/bin/e_wayland \
|
||||
-I$(top_builddir)/src/bin/e_wayland \
|
||||
-I$(top_srcdir)/src/modules \
|
||||
@e_wl_cflags@ @WAYLAND_SCREENSHOT_CFLAGS@
|
||||
|
||||
pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH)
|
||||
pkg_LTLIBRARIES = module.la
|
||||
|
||||
module_la_SOURCES = e_mod_main.c \
|
||||
e_mod_main.h \
|
||||
e_screenshooter_client_protocol.c \
|
||||
e_screenshooter_client_protocol.h
|
||||
|
||||
module_la_LIBADD = @e_wl_libs@ @dlopen_libs@ @WAYLAND_SCREENSHOT_LIBS@
|
||||
module_la_LDFLAGS = -module -avoid-version
|
||||
module_la_DEPENDENCIES = $(top_builddir)/config.h
|
||||
|
||||
uninstall:
|
||||
rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE)
|
Binary file not shown.
|
@ -0,0 +1,293 @@
|
|||
#include "e.h"
|
||||
#include "e_mod_main.h"
|
||||
|
||||
typedef struct _Instance Instance;
|
||||
struct _Instance
|
||||
{
|
||||
E_Gadcon_Client *gcc;
|
||||
Evas_Object *o_btn;
|
||||
};
|
||||
|
||||
static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style);
|
||||
static void _gc_shutdown(E_Gadcon_Client *gcc);
|
||||
static void _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient);
|
||||
static const char *_gc_label(E_Gadcon_Client_Class *cc);
|
||||
static Evas_Object *_gc_icon(E_Gadcon_Client_Class *cc, Evas *evas);
|
||||
static const char *_gc_id_new(E_Gadcon_Client_Class *cc);
|
||||
static void _cb_btn_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event);
|
||||
static void _cb_handle_global(struct wl_display *disp, unsigned int id, const char *interface, unsigned int version __UNUSED__, void *data);
|
||||
static struct wl_buffer *_create_shm_buffer(struct wl_shm *_shm, int width, int height, void **data_out);
|
||||
static void _cb_handle_geometry(void *data, struct wl_output *wl_output, int x, int y, int w, int h, int subpixel, const char *make, const char *model);
|
||||
static void _cb_handle_mode(void *data, struct wl_output *wl_output, unsigned int flags, int w, int h, int refresh);
|
||||
static void _save_png(int w, int h, void *data);
|
||||
static Eina_Bool _cb_timer(void *data __UNUSED__);
|
||||
|
||||
static const E_Gadcon_Client_Class _gc =
|
||||
{
|
||||
GADCON_CLIENT_CLASS_VERSION, "wl_screenshot",
|
||||
{
|
||||
_gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL,
|
||||
e_gadcon_site_is_not_toolbar
|
||||
},
|
||||
E_GADCON_CLIENT_STYLE_PLAIN
|
||||
};
|
||||
|
||||
static const struct wl_output_listener _output_listener =
|
||||
{
|
||||
_cb_handle_geometry,
|
||||
_cb_handle_mode
|
||||
};
|
||||
|
||||
static E_Module *_mod = NULL;
|
||||
static E_Screenshooter *_shooter = NULL;
|
||||
static struct wl_output *_output;
|
||||
static int ow = 0, oh = 0;
|
||||
static Ecore_Timer *_timer = NULL;
|
||||
|
||||
EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Screenshooter" };
|
||||
|
||||
EAPI void *
|
||||
e_modapi_init(E_Module *m)
|
||||
{
|
||||
struct wl_display *disp;
|
||||
|
||||
/* if (!ecore_wl_init(NULL)) return NULL; */
|
||||
|
||||
disp = ecore_wl_display_get();
|
||||
|
||||
_mod = m;
|
||||
e_gadcon_provider_register(&_gc);
|
||||
|
||||
/* e_module_delayed_set(m, 1); */
|
||||
/* e_module_priority_set(m, 1000); */
|
||||
|
||||
wl_display_add_global_listener(disp, _cb_handle_global, NULL);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
EAPI int
|
||||
e_modapi_shutdown(E_Module *m)
|
||||
{
|
||||
_mod = NULL;
|
||||
e_gadcon_provider_unregister(&_gc);
|
||||
/* ecore_wl_shutdown(); */
|
||||
return 1;
|
||||
}
|
||||
|
||||
EAPI int
|
||||
e_modapi_save(E_Module *m __UNUSED__)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static E_Gadcon_Client *
|
||||
_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
|
||||
{
|
||||
Evas_Object *o;
|
||||
E_Gadcon_Client *gcc;
|
||||
Instance *inst;
|
||||
char buff[PATH_MAX];
|
||||
|
||||
inst = E_NEW(Instance, 1);
|
||||
|
||||
snprintf(buff, sizeof(buff), "%s/e-module-wl_screenshot.edj", _mod->dir);
|
||||
|
||||
o = edje_object_add(gc->evas);
|
||||
if (!e_theme_edje_object_set(o, "base/theme/modules/wl_screenshot",
|
||||
"modules/wl_screenshot/main"))
|
||||
edje_object_file_set(o, buff, "modules/wl_screenshot/main");
|
||||
|
||||
gcc = e_gadcon_client_new(gc, name, id, style, o);
|
||||
gcc->data = inst;
|
||||
|
||||
inst->gcc = gcc;
|
||||
inst->o_btn = o;
|
||||
|
||||
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
|
||||
_cb_btn_down, inst);
|
||||
return gcc;
|
||||
}
|
||||
|
||||
static void
|
||||
_gc_shutdown(E_Gadcon_Client *gcc)
|
||||
{
|
||||
Instance *inst;
|
||||
|
||||
if (!(inst = gcc->data)) return;
|
||||
evas_object_del(inst->o_btn);
|
||||
free(inst);
|
||||
}
|
||||
|
||||
static void
|
||||
_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient)
|
||||
{
|
||||
Instance *inst;
|
||||
Evas_Coord mw, mh;
|
||||
|
||||
inst = gcc->data;
|
||||
mw = 0, mh = 0;
|
||||
edje_object_size_min_get(inst->o_btn, &mw, &mh);
|
||||
if ((mw < 1) || (mh < 1))
|
||||
edje_object_size_min_calc(inst->o_btn, &mw, &mh);
|
||||
if (mw < 4) mw = 4;
|
||||
if (mh < 4) mh = 4;
|
||||
e_gadcon_client_aspect_set(gcc, mw, mh);
|
||||
e_gadcon_client_min_size_set(gcc, mw, mh);
|
||||
}
|
||||
|
||||
static const char *
|
||||
_gc_label(E_Gadcon_Client_Class *cc)
|
||||
{
|
||||
return _("Screenshooter");
|
||||
}
|
||||
|
||||
static Evas_Object *
|
||||
_gc_icon(E_Gadcon_Client_Class *cc, Evas *evas)
|
||||
{
|
||||
Evas_Object *o;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
o = edje_object_add(evas);
|
||||
snprintf(buf, sizeof(buf), "%s/e-module-wl_screenshot.edj", _mod->dir);
|
||||
edje_object_file_set(o, buf, "icon");
|
||||
return o;
|
||||
}
|
||||
|
||||
static const char *
|
||||
_gc_id_new(E_Gadcon_Client_Class *cc)
|
||||
{
|
||||
return _gc.name;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_btn_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event)
|
||||
{
|
||||
Instance *inst;
|
||||
Evas_Event_Mouse_Down *ev;
|
||||
|
||||
inst = data;
|
||||
ev = event;
|
||||
if (ev->button == 1)
|
||||
{
|
||||
if (_timer) ecore_timer_del(_timer);
|
||||
_timer = ecore_timer_add(5.0, _cb_timer, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_handle_global(struct wl_display *disp, unsigned int id, const char *interface, unsigned int version __UNUSED__, void *data)
|
||||
{
|
||||
if (!strcmp(interface, "screenshooter"))
|
||||
_shooter = wl_display_bind(disp, id, &screenshooter_interface);
|
||||
else if (!strcmp(interface, "wl_output"))
|
||||
{
|
||||
_output = wl_display_bind(disp, id, &wl_output_interface);
|
||||
wl_output_add_listener(_output, &_output_listener, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static struct wl_buffer *
|
||||
_create_shm_buffer(struct wl_shm *_shm, int width, int height, void **data_out)
|
||||
{
|
||||
char filename[] = "/tmp/wayland-shm-XXXXXX";
|
||||
struct wl_buffer *buffer;
|
||||
int fd, size, stride;
|
||||
void *data;
|
||||
|
||||
fd = mkstemp(filename);
|
||||
if (fd < 0)
|
||||
{
|
||||
fprintf(stderr, "open %s failed: %m\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stride = width * 4;
|
||||
size = stride * height;
|
||||
if (ftruncate(fd, size) < 0)
|
||||
{
|
||||
fprintf(stderr, "ftruncate failed: %m\n");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
unlink(filename);
|
||||
|
||||
if (data == MAP_FAILED)
|
||||
{
|
||||
fprintf(stderr, "mmap failed: %m\n");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer = wl_shm_create_buffer(_shm, fd, width, height, stride,
|
||||
WL_SHM_FORMAT_ARGB8888);
|
||||
|
||||
close(fd);
|
||||
|
||||
*data_out = data;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_handle_geometry(void *data, struct wl_output *wl_output, int x, int y, int w, int h, int subpixel, const char *make, const char *model)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_handle_mode(void *data, struct wl_output *wl_output, unsigned int flags, int w, int h, int refresh)
|
||||
{
|
||||
if (ow == 0) ow = w;
|
||||
if (oh == 0) oh = h;
|
||||
}
|
||||
|
||||
static void
|
||||
_save_png(int w, int h, void *data)
|
||||
{
|
||||
Ecore_Evas *ee;
|
||||
Evas *evas;
|
||||
Evas_Object *img;
|
||||
char buff[1024];
|
||||
char fname[PATH_MAX];
|
||||
|
||||
ee = ecore_evas_buffer_new(w, h);
|
||||
evas = ecore_evas_get(ee);
|
||||
|
||||
img = evas_object_image_filled_add(evas);
|
||||
evas_object_image_fill_set(img, 0, 0, w, h);
|
||||
evas_object_image_size_set(img, w, h);
|
||||
evas_object_image_data_set(img, data);
|
||||
evas_object_show(img);
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s/screenshot.png", e_user_homedir_get());
|
||||
snprintf(buff, sizeof(buff), "quality=90 compress=9");
|
||||
if (!(evas_object_image_save(img, fname, NULL, buff)))
|
||||
{
|
||||
printf("Error saving shot\n");
|
||||
}
|
||||
|
||||
if (img) evas_object_del(img);
|
||||
if (ee) ecore_evas_free(ee);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_timer(void *data __UNUSED__)
|
||||
{
|
||||
struct wl_buffer *buffer;
|
||||
void *d = NULL;
|
||||
|
||||
if (!_shooter) return EINA_FALSE;
|
||||
|
||||
buffer = _create_shm_buffer(ecore_wl_shm_get(), ow, oh, &d);
|
||||
screenshooter_shoot(_shooter, _output, buffer);
|
||||
|
||||
ecore_wl_sync();
|
||||
|
||||
printf("Saving Png\n");
|
||||
_save_png(ow, oh, d);
|
||||
|
||||
return EINA_FALSE;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef E_MOD_MAIN_H
|
||||
# define E_MOD_MAIN_H
|
||||
|
||||
# include <wayland-client.h>
|
||||
# include "e_screenshooter_client_protocol.h"
|
||||
|
||||
EAPI extern E_Module_Api e_modapi;
|
||||
|
||||
EAPI void *e_modapi_init(E_Module *m);
|
||||
EAPI int e_modapi_shutdown(E_Module *m);
|
||||
EAPI int e_modapi_save(E_Module *m);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,22 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
extern const struct wl_interface wl_output_interface;
|
||||
extern const struct wl_interface wl_buffer_interface;
|
||||
|
||||
static const struct wl_interface *types[] = {
|
||||
&wl_output_interface,
|
||||
&wl_buffer_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message screenshooter_requests[] = {
|
||||
{ "shoot", "oo", types + 0 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface screenshooter_interface = {
|
||||
"screenshooter", 1,
|
||||
ARRAY_LENGTH(screenshooter_requests), screenshooter_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef E_SCREENSHOOTER_CLIENT_PROTOCOL_H
|
||||
#define E_SCREENSHOOTER_CLIENT_PROTOCOL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
struct wl_client;
|
||||
struct wl_resource;
|
||||
|
||||
extern const struct wl_interface screenshooter_interface;
|
||||
|
||||
#define SCREENSHOOTER_SHOOT 0
|
||||
|
||||
static inline void
|
||||
screenshooter_set_user_data(E_Screenshooter *screenshooter, void *user_data)
|
||||
{
|
||||
wl_proxy_set_user_data((struct wl_proxy *) screenshooter, user_data);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
screenshooter_get_user_data(E_Screenshooter *screenshooter)
|
||||
{
|
||||
return wl_proxy_get_user_data((struct wl_proxy *) screenshooter);
|
||||
}
|
||||
|
||||
static inline void
|
||||
screenshooter_destroy(E_Screenshooter *screenshooter)
|
||||
{
|
||||
wl_proxy_destroy((struct wl_proxy *) screenshooter);
|
||||
}
|
||||
|
||||
static inline void
|
||||
screenshooter_shoot(E_Screenshooter *screenshooter, struct wl_output *output, struct wl_buffer *buffer)
|
||||
{
|
||||
wl_proxy_marshal((struct wl_proxy *) screenshooter,
|
||||
SCREENSHOOTER_SHOOT, output, buffer);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
[Desktop Entry]
|
||||
Type=Link
|
||||
Name=Wayland Screenshot
|
||||
Icon=e-module-wl_screenshot.edj
|
||||
Comment=Enlightenment Wayland Screenshot Module
|
||||
X-Enlightenment-ModuleType=look
|
|
@ -0,0 +1,33 @@
|
|||
MAINTAINERCLEANFILES = Makefile.in
|
||||
MODULE = wl_shell
|
||||
|
||||
# data files for the module
|
||||
filesdir = $(libdir)/enlightenment/modules/$(MODULE)
|
||||
files_DATA = \
|
||||
e-module-$(MODULE).edj module.desktop
|
||||
|
||||
EXTRA_DIST = $(files_DATA)
|
||||
|
||||
# the module .so file
|
||||
INCLUDES = -I. \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/src/modules/$(MODULE) \
|
||||
-I$(top_srcdir)/src/bin/e_wayland \
|
||||
-I$(top_builddir)/src/bin/e_wayland \
|
||||
-I$(top_srcdir)/src/modules \
|
||||
@e_wl_cflags@ @WAYLAND_SHELL_CFLAGS@
|
||||
|
||||
pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH)
|
||||
pkg_LTLIBRARIES = module.la
|
||||
|
||||
module_la_SOURCES = e_mod_main.c \
|
||||
e_mod_main.h \
|
||||
e_desktop_shell_protocol.c \
|
||||
e_desktop_shell_protocol.h
|
||||
|
||||
module_la_LIBADD = @e_wl_libs@ @dlopen_libs@ @WAYLAND_SHELL_LIBS@
|
||||
module_la_LDFLAGS = -module -avoid-version
|
||||
module_la_DEPENDENCIES = $(top_builddir)/config.h
|
||||
|
||||
uninstall:
|
||||
rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE)
|
|
@ -0,0 +1,51 @@
|
|||
<protocol name="desktop">
|
||||
|
||||
<interface name="desktop_shell" version="1">
|
||||
<request name="set_background">
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
<arg name="surface" type="object" interface="wl_shell_surface"/>
|
||||
</request>
|
||||
|
||||
<request name="set_panel">
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
<arg name="surface" type="object" interface="wl_shell_surface"/>
|
||||
</request>
|
||||
|
||||
<request name="set_lock_surface">
|
||||
<arg name="surface" type="object" interface="wl_shell_surface"/>
|
||||
</request>
|
||||
|
||||
<request name="unlock"/>
|
||||
|
||||
<!-- We'll fold most of wl_shell into this interface and then
|
||||
they'll share the configure event. -->
|
||||
<event name="configure">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="edges" type="uint"/>
|
||||
<arg name="surface" type="object" interface="wl_shell_surface"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</event>
|
||||
|
||||
<!-- Tell the shell we want it to create and set the lock surface,
|
||||
which is a GUI asking the user to unlock the screen. The lock
|
||||
surface is announced with 'set_lock_surface'. Whether or not
|
||||
the shell actually implements locking, it MUST send 'unlock'
|
||||
request to let the normal desktop resume. -->
|
||||
<event name="prepare_lock_surface"/>
|
||||
</interface>
|
||||
|
||||
<!-- Only one client can bind this interface at a time. -->
|
||||
<interface name="screensaver" version="1">
|
||||
|
||||
<!-- Set the surface type as a screensaver for a particular output.
|
||||
A screensaver surface is normally hidden, and only visible after
|
||||
an idle timeout. -->
|
||||
<request name="set_surface">
|
||||
<arg name="surface" type="object" interface="wl_shell_surface"/>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</request>
|
||||
|
||||
</interface>
|
||||
|
||||
</protocol>
|
Binary file not shown.
|
@ -0,0 +1,56 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
extern const struct wl_interface wl_output_interface;
|
||||
extern const struct wl_interface wl_shell_surface_interface;
|
||||
extern const struct wl_interface wl_output_interface;
|
||||
extern const struct wl_interface wl_shell_surface_interface;
|
||||
extern const struct wl_interface wl_shell_surface_interface;
|
||||
extern const struct wl_interface wl_shell_surface_interface;
|
||||
extern const struct wl_interface wl_shell_surface_interface;
|
||||
extern const struct wl_interface wl_output_interface;
|
||||
|
||||
static const struct wl_interface *types[] = {
|
||||
&wl_output_interface,
|
||||
&wl_shell_surface_interface,
|
||||
&wl_output_interface,
|
||||
&wl_shell_surface_interface,
|
||||
&wl_shell_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_shell_surface_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_shell_surface_interface,
|
||||
&wl_output_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message desktop_shell_requests[] = {
|
||||
{ "set_background", "oo", types + 0 },
|
||||
{ "set_panel", "oo", types + 2 },
|
||||
{ "set_lock_surface", "o", types + 4 },
|
||||
{ "unlock", "", types + 0 },
|
||||
};
|
||||
|
||||
static const struct wl_message desktop_shell_events[] = {
|
||||
{ "configure", "uuoii", types + 5 },
|
||||
{ "prepare_lock_surface", "", types + 0 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface desktop_shell_interface = {
|
||||
"desktop_shell", 1,
|
||||
ARRAY_LENGTH(desktop_shell_requests), desktop_shell_requests,
|
||||
ARRAY_LENGTH(desktop_shell_events), desktop_shell_events,
|
||||
};
|
||||
|
||||
static const struct wl_message screensaver_requests[] = {
|
||||
{ "set_surface", "oo", types + 10 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface screensaver_interface = {
|
||||
"screensaver", 1,
|
||||
ARRAY_LENGTH(screensaver_requests), screensaver_requests,
|
||||
0, NULL,
|
||||
};
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
#ifndef DESKTOP_SERVER_PROTOCOL_H
|
||||
#define DESKTOP_SERVER_PROTOCOL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "wayland-util.h"
|
||||
|
||||
struct wl_client;
|
||||
struct wl_resource;
|
||||
|
||||
struct desktop_shell;
|
||||
struct screensaver;
|
||||
|
||||
extern const struct wl_interface desktop_shell_interface;
|
||||
extern const struct wl_interface screensaver_interface;
|
||||
|
||||
struct desktop_shell_interface {
|
||||
/**
|
||||
* set_background - (none)
|
||||
* @output: (none)
|
||||
* @surface: (none)
|
||||
*/
|
||||
void (*set_background)(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *output,
|
||||
struct wl_resource *surface);
|
||||
/**
|
||||
* set_panel - (none)
|
||||
* @output: (none)
|
||||
* @surface: (none)
|
||||
*/
|
||||
void (*set_panel)(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *output,
|
||||
struct wl_resource *surface);
|
||||
/**
|
||||
* set_lock_surface - (none)
|
||||
* @surface: (none)
|
||||
*/
|
||||
void (*set_lock_surface)(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *surface);
|
||||
/**
|
||||
* unlock - (none)
|
||||
*/
|
||||
void (*unlock)(struct wl_client *client,
|
||||
struct wl_resource *resource);
|
||||
};
|
||||
|
||||
#define DESKTOP_SHELL_CONFIGURE 0
|
||||
#define DESKTOP_SHELL_PREPARE_LOCK_SURFACE 1
|
||||
|
||||
static inline void
|
||||
desktop_shell_send_configure(struct wl_resource *resource_, uint32_t time, uint32_t edges, struct wl_resource *surface, int32_t width, int32_t height)
|
||||
{
|
||||
wl_resource_post_event(resource_, DESKTOP_SHELL_CONFIGURE, time, edges, surface, width, height);
|
||||
}
|
||||
|
||||
static inline void
|
||||
desktop_shell_send_prepare_lock_surface(struct wl_resource *resource_)
|
||||
{
|
||||
wl_resource_post_event(resource_, DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
|
||||
}
|
||||
|
||||
struct screensaver_interface {
|
||||
/**
|
||||
* set_surface - (none)
|
||||
* @surface: (none)
|
||||
* @output: (none)
|
||||
*/
|
||||
void (*set_surface)(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *surface,
|
||||
struct wl_resource *output);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,93 @@
|
|||
#ifndef E_MOD_MAIN_H
|
||||
# define E_MOD_MAIN_H
|
||||
|
||||
# define SLOGFNS 1
|
||||
|
||||
# ifdef SLOGFNS
|
||||
# include <stdio.h>
|
||||
# define SLOGFN(fl, ln, fn) printf("-E-SHELL: %25s: %5i - %s\n", fl, ln, fn);
|
||||
# else
|
||||
# define SLOGFN(fl, ln, fn)
|
||||
# endif
|
||||
|
||||
# include <wayland-server.h>
|
||||
# include "e_desktop_shell_protocol.h"
|
||||
|
||||
typedef enum _E_Shell_Surface_Type E_Shell_Surface_Type;
|
||||
typedef struct _E_Shell_Surface E_Shell_Surface;
|
||||
|
||||
struct wl_shell
|
||||
{
|
||||
E_Compositor *compositor;
|
||||
E_Shell shell;
|
||||
|
||||
E_Layer fullscreen_layer;
|
||||
E_Layer panel_layer;
|
||||
E_Layer toplevel_layer;
|
||||
E_Layer background_layer;
|
||||
E_Layer lock_layer;
|
||||
|
||||
Eina_Bool locked : 1;
|
||||
Eina_Bool prepare_event_sent : 1;
|
||||
|
||||
E_Shell_Surface *lock_surface;
|
||||
struct wl_listener lock_surface_listener;
|
||||
|
||||
struct wl_list backgrounds, panels;
|
||||
};
|
||||
|
||||
enum _E_Shell_Surface_Type
|
||||
{
|
||||
E_SHELL_SURFACE_NONE,
|
||||
E_SHELL_SURFACE_PANEL,
|
||||
E_SHELL_SURFACE_BACKGROUND,
|
||||
E_SHELL_SURFACE_LOCK,
|
||||
E_SHELL_SURFACE_SCREENSAVER,
|
||||
E_SHELL_SURFACE_TOPLEVEL,
|
||||
E_SHELL_SURFACE_TRANSIENT,
|
||||
E_SHELL_SURFACE_FULLSCREEN,
|
||||
E_SHELL_SURFACE_MAXIMIZED,
|
||||
E_SHELL_SURFACE_POPUP
|
||||
};
|
||||
|
||||
struct _E_Shell_Surface
|
||||
{
|
||||
struct wl_resource resource;
|
||||
E_Surface *surface;
|
||||
struct wl_listener surface_destroy_listener;
|
||||
E_Shell_Surface *parent;
|
||||
E_Shell_Surface_Type type;
|
||||
int sx, sy;
|
||||
Eina_Bool saved_pos_valid : 1;
|
||||
struct
|
||||
{
|
||||
E_Transform transform;
|
||||
E_Matrix rotation;
|
||||
} rotation;
|
||||
struct
|
||||
{
|
||||
struct wl_pointer_grab grab;
|
||||
unsigned int timestamp;
|
||||
int x, y;
|
||||
E_Transform parent_transform;
|
||||
Eina_Bool initial_up : 1;
|
||||
} popup;
|
||||
struct
|
||||
{
|
||||
enum wl_shell_surface_fullscreen_method type;
|
||||
E_Transform transform;
|
||||
unsigned int framerate;
|
||||
E_Surface *black_surface;
|
||||
} fullscreen;
|
||||
|
||||
E_Output *output, *fullscreen_output;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
EAPI extern E_Module_Api e_modapi;
|
||||
|
||||
EAPI void *e_modapi_init(E_Module *m);
|
||||
EAPI int e_modapi_shutdown(E_Module *m);
|
||||
EAPI int e_modapi_save(E_Module *m);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
[Desktop Entry]
|
||||
Type=Link
|
||||
Name=Wayland Shell
|
||||
Icon=e-module-wl_shell
|
||||
Comment=Enlightenment Wayland Shell
|
||||
X-Enlightenment-ModuleType=look
|
Loading…
Reference in New Issue