pepper: pointer cursor implementation 81/54581/1
authorJunghoon <jh13.son@samsung.com>
Sun, 18 Oct 2015 05:47:32 +0000 (14:47 +0900)
committer김태균 <tkq.kim@samsung.com>
Wed, 16 Dec 2015 08:20:50 +0000 (17:20 +0900)
    - implement wl_pointer::set_cursor
    - implement drm_cursor

Change-Id: I45aac2e96b176a8480307a4465782c255e4ca2be

src/lib/desktop-shell/desktop-shell-internal.h
src/lib/desktop-shell/shell-surface.c
src/lib/desktop-shell/shell.c
src/lib/drm/drm-common.c
src/lib/drm/drm-internal.h
src/lib/drm/drm-output.c
src/lib/pepper/pepper-internal.h
src/lib/pepper/pepper.h
src/lib/pepper/pointer.c
src/lib/pepper/surface.c

index cf46bea070ce382008713ea00e3196740a6c1331..bd5c9332cff1cd73ca2398ab47b8518697eb238a 100644 (file)
@@ -236,6 +236,9 @@ shell_surface_set_next_type(shell_surface_t *shsurf, shell_surface_type_t new_ty
 void
 shell_surface_set_parent(shell_surface_t *shsurf, pepper_surface_t *parent);
 
+void
+shell_surface_stack_top(shell_surface_t *shsurf, pepper_bool_t subtree);
+
 /* */
 shell_surface_t *
 get_shsurf_from_surface(pepper_surface_t *surface, desktop_shell_t *shell);
index 2a74783c5fea66bf70b90fb00b188cdf7cc3a979..2ad6d6ea29bcca81788469c0ef3e0dea94b41928 100644 (file)
@@ -721,6 +721,27 @@ shell_surface_set_position(shell_surface_t *shsurf, double x, double y)
 
 }
 
+void
+shell_surface_stack_top(shell_surface_t *shsurf, pepper_bool_t subtree)
+{
+    pepper_view_t      *cursor_view;
+    pepper_pointer_t   *pointer;
+    shell_seat_t       *shseat;
+
+    pepper_view_stack_top(shsurf->view, subtree);
+
+    pepper_list_for_each(shseat, &shsurf->shell->shseat_list, link)
+    {
+        pointer = pepper_seat_get_pointer(shseat->seat);
+        if (pointer)
+        {
+            cursor_view = pepper_pointer_get_cursor_view(pointer);
+            if (cursor_view)
+                pepper_view_stack_top(cursor_view, PEPPER_FALSE);
+        }
+    }
+}
+
 shell_surface_t *
 get_shsurf_from_surface(pepper_surface_t *surface, desktop_shell_t *shell)
 {
@@ -1073,7 +1094,7 @@ shell_surface_map_popup(shell_surface_t *shsurf)
 
     pepper_view_map(shsurf->view);
 
-    pepper_view_stack_top(shsurf->view, PEPPER_TRUE);
+    shell_surface_stack_top(shsurf, PEPPER_TRUE);
 
     shell_surface_add_popup_grab(shsurf);
 }
@@ -1112,7 +1133,7 @@ shell_surface_map_maximized(shell_surface_t *shsurf)
     pepper_view_map(shsurf->view);
 
     /* Set top of z-order */
-    pepper_view_stack_top(shsurf->view, PEPPER_TRUE /*FIXME:*/);
+    shell_surface_stack_top(shsurf, PEPPER_TRUE /*FIXME:*/);
 }
 
 static void
@@ -1215,7 +1236,7 @@ shell_surface_map_fullscreen(shell_surface_t *shsurf)
     shell_surface_place_fullscreen_surface(shsurf);
 
     pepper_view_map(shsurf->view);
-    pepper_view_stack_top(shsurf->view, PEPPER_TRUE /*FIXME*/ );
+    shell_surface_stack_top(shsurf, PEPPER_TRUE /*FIXME*/ );
 }
 
 void
index baedc2aed948b6009937db27923e45af7fe10fcb..b07cbc2e7bc4588bdf66062bf1731ffccf44c331 100644 (file)
@@ -163,7 +163,14 @@ default_pointer_grab_button(pepper_pointer_t *pointer, void *data,
         }
 
         if (pointer_focus)
-            pepper_view_stack_top(pointer_focus, PEPPER_FALSE);
+        {
+            shell_seat_t       *shseat = data;
+            desktop_shell_t    *shell = shseat->shell;
+            pepper_surface_t   *surface = pepper_view_get_surface(pointer_focus);
+            shell_surface_t    *shsurf = get_shsurf_from_surface(surface, shell);
+
+            shell_surface_stack_top(shsurf, PEPPER_FALSE);
+        }
     }
 
     pepper_pointer_send_button(pointer, pointer_focus, time, button, state);
@@ -195,7 +202,7 @@ pointer_add_callback(pepper_event_listener_t *listener, pepper_object_t *object,
                      void *info, void *data)
 {
     pepper_pointer_t *pointer = info;
-    pepper_pointer_set_grab(pointer, &default_pointer_grab, NULL);
+    pepper_pointer_set_grab(pointer, &default_pointer_grab, data);
 }
 
 static void
index 856878ce3329d5183afcee2270ff786ed966fe90..398e9acb61b2e98e41fcf3e7e929196743f667ee 100644 (file)
@@ -258,6 +258,12 @@ pepper_drm_create(pepper_compositor_t *compositor, struct udev *udev, const char
     drm->resources = drmModeGetResources(drm->fd);
     PEPPER_CHECK(drm->resources, goto error, "drmModeGetResources() failed.\n");
 
+    ret = drmGetCap(drm->fd, 0x8 /* DRM_CAP_CURSOR_WIDTH */, &cap);
+    drm->cursor_width = (ret == 0) ? cap : 64;
+
+    ret = drmGetCap(drm->fd, 0x9 /* DRM_CAP_CURSOR_HEIGHT */, &cap);
+    drm->cursor_height = (ret == 0) ? cap : 64;
+
     drm_init_planes(drm);
     drm_init_connectors(drm);
     udev_device_unref(udev_device);
index 4cea18147bb6aced7145e2565cc49ee56081f4b5..a0e6198f589f865b3e09df3b130f58a3f4e986b9 100644 (file)
@@ -84,6 +84,10 @@ struct pepper_drm
 #endif
     pepper_renderer_t          *pixman_renderer;
     pepper_renderer_t          *gl_renderer;
+
+    pepper_bool_t               cursor_broken;
+    int32_t                     cursor_width;
+    int32_t                     cursor_height;
 };
 
 struct drm_connector
@@ -159,6 +163,13 @@ struct drm_output
     pepper_bool_t           page_flip_pending;
     int                     vblank_pending_count;
 
+    pepper_view_t          *cursor_view;
+    pepper_buffer_t        *cursor_buffer;
+    struct gbm_bo          *cursor_bo[2];
+    int                     cursor_bo_index;
+    int                     cursor_x, cursor_y;
+    pepper_bool_t           need_set_cursor;
+
     pepper_plane_t         *cursor_plane;
     pepper_plane_t         *primary_plane;
     pepper_plane_t         *fb_plane;
index ba443b6bbe23e683876a0b1486fe57cedc698da9..0e75cfde7802319a4dea75613a3d70e2f42b9276 100644 (file)
@@ -137,8 +137,41 @@ drm_output_set_mode(void *o, const pepper_output_mode_t *mode)
 static pepper_plane_t *
 assign_cursor_plane(drm_output_t *output, pepper_view_t *view)
 {
-    /* TODO: */
-    return NULL;
+    int32_t             w, h;
+    pepper_surface_t   *surface;
+    pepper_buffer_t    *buffer;
+    struct wl_resource *resource;
+
+    if (output->cursor_view)
+        return NULL;
+
+    if (!output->drm->gbm_device)
+        return NULL;
+
+    if (output->drm->cursor_broken)
+        return NULL;
+
+    pepper_view_get_size(view, &w, &h);
+    if ((output->drm->cursor_width < w) || (output->drm->cursor_height < h))
+        return NULL;
+
+    surface = pepper_view_get_surface(view);
+    buffer = pepper_surface_get_buffer(surface);
+    if (!buffer)
+        return NULL;
+
+    resource = pepper_buffer_get_resource(buffer);
+    if (!resource || !wl_shm_buffer_get(resource))
+        return NULL;
+
+    output->cursor_view = view;
+    if (output->cursor_buffer != buffer)
+    {
+        output->cursor_buffer = buffer;
+        output->need_set_cursor = PEPPER_TRUE;
+    }
+
+    return output->cursor_plane;
 }
 
 static pepper_plane_t *
@@ -452,6 +485,79 @@ drm_output_start_repaint_loop(void *o)
     pepper_output_finish_frame(output->base, &ts);
 }
 
+static void
+drm_output_set_cursor(drm_output_t *output)
+{
+    pepper_drm_t       *drm = output->drm;
+    pepper_surface_t   *surface;
+    pepper_buffer_t    *buffer;
+
+    double              x, y;
+
+    if (!output->cursor_view)
+    {
+        drmModeSetCursor(drm->fd, output->crtc_id, 0, 0, 0);
+        return;
+    }
+
+    surface = pepper_view_get_surface(output->cursor_view);
+    buffer = pepper_surface_get_buffer(surface);
+
+    if (buffer && output->need_set_cursor)
+    {
+
+        int32_t                 i, w, h, stride;
+        uint8_t                *data;
+        uint32_t                buf[drm->cursor_width * drm->cursor_height];
+
+        struct gbm_bo          *bo;
+        struct wl_resource     *resource;
+        struct wl_shm_buffer   *shm_buffer;
+
+        resource = pepper_buffer_get_resource(buffer);
+
+        shm_buffer = wl_shm_buffer_get(resource);
+        stride = wl_shm_buffer_get_stride(shm_buffer);
+        data = wl_shm_buffer_get_data(shm_buffer);
+
+        pepper_view_get_size(output->cursor_view, &w, &h);
+
+        memset(buf, 0, sizeof(buf));
+        wl_shm_buffer_begin_access(shm_buffer);
+        for (i = 0; i < h; i++)
+            memcpy(buf + i * drm->cursor_width, data + i * stride, w * sizeof(uint32_t));
+        wl_shm_buffer_end_access(shm_buffer);
+
+        output->cursor_bo_index ^= 1;
+        bo = output->cursor_bo[output->cursor_bo_index];
+        gbm_bo_write(bo, buf, sizeof(buf));
+
+        if (drmModeSetCursor(drm->fd, output->crtc_id, gbm_bo_get_handle(bo).s32,
+                             drm->cursor_width, drm->cursor_height))
+        {
+            PEPPER_TRACE("failed to set cursor\n");
+            drm->cursor_broken = PEPPER_TRUE;
+        }
+
+        output->need_set_cursor = PEPPER_FALSE;
+    }
+
+    pepper_view_get_position(output->cursor_view, &x, &y);
+    if ((output->cursor_x != (int)x) || (output->cursor_y != (int)y))
+    {
+        if (drmModeMoveCursor(drm->fd, output->crtc_id, (int)x, (int)y))
+        {
+            PEPPER_TRACE("failed to move cursor\n");
+            drm->cursor_broken = PEPPER_TRUE;
+        }
+
+        output->cursor_x = (int)x;
+        output->cursor_y = (int)y;
+    }
+
+    output->cursor_view = NULL;
+}
+
 static void
 drm_output_repaint(void *o, const pepper_list_t *plane_list)
 {
@@ -480,6 +586,8 @@ drm_output_repaint(void *o, const pepper_list_t *plane_list)
         output->page_flip_pending = PEPPER_TRUE;
     }
 
+    drm_output_set_cursor(output);
+
     pepper_list_for_each(plane, &output->drm->plane_list, link)
     {
         drmVBlank vbl;
@@ -532,15 +640,26 @@ drm_output_flush_surface_damage(void *o, pepper_surface_t *surface, pepper_bool_
 
     pepper_renderer_flush_surface_damage(output->renderer, surface);
 
-    if (output->render_type == DRM_RENDER_TYPE_PIXMAN ||
-        (buffer && !wl_shm_buffer_get(pepper_buffer_get_resource(buffer))))
-    {
-        *keep_buffer = PEPPER_TRUE;
-    }
-    else
+    if (output->render_type == DRM_RENDER_TYPE_PIXMAN)
+        goto keep;
+
+    if (buffer)
     {
-        *keep_buffer = PEPPER_FALSE;
+        int w, h;
+
+        if (!wl_shm_buffer_get(pepper_buffer_get_resource(buffer)))
+            goto keep;
+
+        pepper_buffer_get_size(buffer, &w, &h);
+        if ((w <= output->drm->cursor_width) && (h <= output->drm->cursor_height))
+            goto keep;
     }
+
+    *keep_buffer = PEPPER_FALSE;
+    return;
+
+keep:
+    *keep_buffer = PEPPER_TRUE;
 }
 
 struct pepper_output_backend drm_output_backend =
@@ -776,6 +895,22 @@ drm_output_create(drm_connector_t *conn)
     if (use_overlay_env && strcmp(use_overlay_env, "1") == 0)
         output->use_overlay = PEPPER_TRUE;
 
+    if (drm->gbm_device)
+    {
+        int i;
+
+        for (i = 0; i < 2; i++)
+            output->cursor_bo[i] = gbm_bo_create(drm->gbm_device,
+                                                 drm->cursor_width, drm->cursor_height,
+                                                 GBM_FORMAT_ARGB8888,
+                                                 GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
+        if (!output->cursor_bo[0] || !output->cursor_bo[1])
+        {
+            PEPPER_TRACE("failed to create cursor bo\n");
+            drm->cursor_broken = PEPPER_TRUE;
+        }
+    }
+
     output->primary_plane = pepper_output_add_plane(output->base, NULL);
     PEPPER_CHECK(output->primary_plane, goto error, "pepper_output_add_plane() failed.\n");
 
@@ -817,6 +952,7 @@ error:
 void
 drm_output_destroy(void *o)
 {
+    int           i;
     drm_output_t *output = o;
     drm_plane_t  *plane;
 
@@ -826,6 +962,12 @@ drm_output_destroy(void *o)
         return;
     }
 
+    for (i = 0; i < 2; i++)
+    {
+        if (output->cursor_bo[i])
+            gbm_bo_destroy(output->cursor_bo[i]);
+    }
+
     if (output->render_type == DRM_RENDER_TYPE_PIXMAN)
         fini_pixman_renderer(output);
     else if (output->render_type == DRM_RENDER_TYPE_GL)
index 2255a839e30ca9b0ced6c6e0eb0fb38a7147fa5f..83c2917ead5a0646c5e51b22ed651aced6805716 100644 (file)
@@ -205,6 +205,7 @@ struct pepper_surface
     pixman_region32_t       damage_region;
     pixman_region32_t       opaque_region;
     pixman_region32_t       input_region;
+    pepper_bool_t           pickable;
 
     struct wl_list          frame_callback_list;
 
@@ -352,6 +353,10 @@ struct pepper_pointer
 
     double                          x_velocity;
     double                          y_velocity;
+
+    pepper_view_t                  *cursor_view;
+    int32_t                         hotspot_x;
+    int32_t                         hotspot_y;
 };
 
 pepper_pointer_t *
index f0389c59789bc0bfa27e4048bbea1cd991a039fb..bcaaf43083a42aa1a650862e875706b0c830cc7f 100644 (file)
@@ -1046,6 +1046,12 @@ pepper_pointer_get_grab(pepper_pointer_t *pointer);
 PEPPER_API void *
 pepper_pointer_get_grab_data(pepper_pointer_t *pointer);
 
+PEPPER_API pepper_view_t *
+pepper_pointer_get_cursor_view(pepper_pointer_t *pointer);
+
+PEPPER_API void
+pepper_pointer_set_hotspot(pepper_pointer_t *pointer, int32_t x, int32_t y);
+
 /* Keyboard. */
 struct pepper_keyboard_grab
 {
index f9621a30521b54b984dca532cfd70b6c4fbde6ec..fac1ed25ff34763adae6b4b0525c769ae4779e7b 100644 (file)
 #include "pepper-internal.h"
 #include <float.h>
 
+static pepper_view_t *
+get_cursor_view(pepper_pointer_t *pointer)
+{
+    if (pointer->cursor_view)
+        return pointer->cursor_view;
+
+    pointer->cursor_view = pepper_compositor_add_view(pointer->seat->compositor);
+
+    return pointer->cursor_view;
+}
+
 static void
 pointer_set_cursor(struct wl_client *client, struct wl_resource *resource, uint32_t serial,
                    struct wl_resource *surface_resource, int32_t x, int32_t y)
 {
-    /* TODO: */
+    pepper_pointer_t   *pointer = (pepper_pointer_t *)wl_resource_get_user_data(resource);
+    pepper_surface_t   *surface;
+    pepper_view_t      *cursor_view;
+
+    cursor_view = get_cursor_view(pointer);
+    PEPPER_CHECK(cursor_view, return, "failed to get cursor view\n");
+
+    if (!surface_resource)
+    {
+        pepper_view_set_surface(cursor_view, NULL);
+        return;
+    }
+
+    surface = (pepper_surface_t *)wl_resource_get_user_data(surface_resource);
+    if (!surface->role)
+        pepper_surface_set_role(surface, "wl_pointer-cursor");
+    else if (strcmp("wl_pointer-cursor", surface->role))
+        return;
+
+    if (surface != pepper_view_get_surface(cursor_view))
+    {
+        surface->pickable = PEPPER_FALSE;
+        pixman_region32_fini(&surface->input_region);
+        pixman_region32_init(&surface->input_region);
+        pepper_view_set_surface(cursor_view, surface);
+    }
+
+    pointer->hotspot_x = x;
+    pointer->hotspot_y = y;
+    pepper_view_set_position(cursor_view, pointer->x - x, pointer->y - y);
+    pepper_view_map(cursor_view);
 }
 
 static void
@@ -93,6 +134,10 @@ pointer_set_position(pepper_pointer_t *pointer, uint32_t time, double x, double
 
     pointer_clamp(pointer);
 
+    if (pointer->cursor_view)
+        pepper_view_set_position(pointer->cursor_view,
+                                 x - pointer->hotspot_x, y - pointer->hotspot_y);
+
     if (pointer->grab)
         pointer->grab->motion(pointer, pointer->data, time, pointer->x, pointer->y);
 
@@ -652,3 +697,16 @@ pepper_pointer_get_grab_data(pepper_pointer_t *pointer)
 {
     return pointer->data;
 }
+
+PEPPER_API pepper_view_t *
+pepper_pointer_get_cursor_view(pepper_pointer_t *pointer)
+{
+    return pointer->cursor_view;
+}
+
+PEPPER_API void
+pepper_pointer_set_hotspot(pepper_pointer_t *pointer, int32_t x, int32_t y)
+{
+    pointer->hotspot_x = x;
+    pointer->hotspot_y = y;
+}
index 9377acd4af619ce2c29158e39f2fe0704338e5bd..62b99599ddcf332162dfd86865c986003c1b6cc6 100644 (file)
@@ -327,6 +327,7 @@ pepper_surface_create(pepper_compositor_t *compositor,
     pixman_region32_init(&surface->damage_region);
     pixman_region32_init(&surface->opaque_region);
     pixman_region32_init_rect(&surface->input_region, INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX);
+    surface->pickable = PEPPER_TRUE;
 
     wl_list_init(&surface->frame_callback_list);
     pepper_list_init(&surface->view_list);
@@ -453,7 +454,9 @@ pepper_surface_commit_state(pepper_surface_t *surface, pepper_surface_state_t *s
 
     /* surface.set_opaque_region(), surface.set_input_region(). */
     pixman_region32_copy(&surface->opaque_region, &state->opaque_region);
-    pixman_region32_copy(&surface->input_region, &state->input_region);
+
+    if (surface->pickable)
+        pixman_region32_copy(&surface->input_region, &state->input_region);
 
     pepper_list_for_each(view, &surface->view_list, surface_link)
     {