commit c5c473b88d45a9591c0bd80712ef822ff2813682
parent e672b60aa376d3ca1878073af877ea483d179e91
Author: Michael Forney <mforney@mforney.org>
Date: Thu, 12 Sep 2013 20:00:27 -0700
Implement cursor surfaces
Diffstat:
8 files changed, 195 insertions(+), 3 deletions(-)
diff --git a/libswc/Makefile.am b/libswc/Makefile.am
@@ -12,6 +12,7 @@ libswc_la_SOURCES = \
plane.c plane.h \
surface.c surface.h \
compositor_surface.c compositor_surface.h \
+ cursor_surface.c cursor_surface.h \
region.c region.h \
renderer.c renderer.h \
input_focus.c input_focus.h \
diff --git a/libswc/compositor.c b/libswc/compositor.c
@@ -5,6 +5,7 @@
#include "compositor.h"
#include "compositor_surface.h"
+#include "cursor_surface.h"
#include "tty.h"
#include "output.h"
#include "surface.h"
@@ -300,6 +301,27 @@ static void handle_drm_event(struct wl_listener * listener, void * data)
}
}
+static void handle_pointer_event(struct wl_listener * listener, void * data)
+{
+ struct swc_event * event = data;
+ struct swc_pointer_event_data * event_data = event->data;
+ struct swc_compositor * compositor;
+
+ compositor = swc_container_of(listener, typeof(*compositor),
+ pointer_listener);
+
+ switch (event->type)
+ {
+ case SWC_POINTER_CURSOR_CHANGED:
+ if (event_data->old)
+ swc_surface_set_class(event_data->old, NULL);
+
+ if (event_data->new)
+ swc_surface_set_class(event_data->new, &compositor->cursor_class);
+ break;
+ }
+}
+
static void handle_terminate(uint32_t time, uint32_t value, void * data)
{
struct wl_display * display = data;
@@ -381,10 +403,13 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
compositor->display = display;
compositor->tty_listener.notify = &handle_tty_event;
compositor->drm_listener.notify = &handle_drm_event;
+ compositor->pointer_listener.notify = &handle_pointer_event;
compositor->scheduled_updates = 0;
compositor->pending_flips = 0;
compositor->compositor_class.interface
= &swc_compositor_class_implementation;
+ compositor->cursor_class.interface = &swc_cursor_class_implementation;
+
compositor->udev = udev_new();
@@ -415,6 +440,8 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
swc_seat_add_event_sources(&compositor->seat, event_loop);
compositor->seat.keyboard.handler = &keyboard_handler;
compositor->seat.pointer.handler = &pointer_handler;
+ wl_signal_add(&compositor->seat.pointer.event_signal,
+ &compositor->pointer_listener);
/* TODO: configurable seat */
if (!swc_drm_initialize(&compositor->drm, compositor->udev, default_seat))
diff --git a/libswc/compositor.h b/libswc/compositor.h
@@ -40,9 +40,11 @@ struct swc_compositor
};
struct swc_surface_class compositor_class;
+ struct swc_surface_class cursor_class;
struct wl_listener tty_listener;
struct wl_listener drm_listener;
+ struct wl_listener pointer_listener;
struct wl_signal destroy_signal;
};
diff --git a/libswc/cursor_surface.c b/libswc/cursor_surface.c
@@ -0,0 +1,112 @@
+/* swc: cursor_surface.c
+ *
+ * Copyright (c) 2013 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cursor_surface.h"
+#include "compositor.h"
+
+#include <string.h>
+#include <wld/wld.h>
+
+/* Cursor class */
+static const uint32_t cursor_buffer_size = 64 * 64 * 4;
+
+static void update_plane(struct swc_plane * plane, void * data)
+{
+ struct wld_drawable * drawable = swc_plane_get_buffer(plane);
+
+ wld_write(drawable, data, cursor_buffer_size);
+ swc_plane_flip(plane);
+}
+
+static void attach(struct swc_surface * surface,
+ struct wl_resource * resource)
+{
+ struct swc_compositor * compositor = swc_container_of
+ (surface->class, typeof(*compositor), cursor_class);
+
+ if (pixman_region32_not_empty(&surface->state.damage))
+ {
+ struct wl_shm_buffer * buffer = wl_shm_buffer_get(resource);
+ uint32_t width, height;
+
+ if (!buffer)
+ return;
+
+ width = wl_shm_buffer_get_width(buffer);
+ height = wl_shm_buffer_get_height(buffer);
+
+ if (width <= 64 && height <= 64)
+ {
+ struct swc_output * output;
+ char data[cursor_buffer_size];
+
+ memset(data, 0, sizeof data);
+ pixman_blt(wl_shm_buffer_get_data(buffer), (uint32_t *) data,
+ wl_shm_buffer_get_stride(buffer) >> 2, 64, 32, 32,
+ 0, 0, 0, 0, width, height);
+ wl_buffer_send_release(resource);
+ pixman_region32_clear(&surface->state.damage);
+
+ wl_list_for_each(output, &compositor->outputs, link)
+ {
+ if (swc_rectangle_overlap(&output->geometry,
+ &surface->geometry))
+ {
+ update_plane(&output->cursor_plane, data);
+ }
+ }
+ }
+ }
+}
+
+static void update(struct swc_surface * surface)
+{
+ swc_surface_send_frame_callbacks(surface, swc_time());
+}
+
+static void move(struct swc_surface * surface, int32_t x, int32_t y)
+{
+ struct swc_compositor * compositor = swc_container_of
+ (surface->class, typeof(*compositor), cursor_class);
+ struct swc_output * output;
+
+ surface->geometry.x = x;
+ surface->geometry.y = y;
+
+ wl_list_for_each(output, &compositor->outputs, link)
+ {
+ if (swc_rectangle_overlap(&output->geometry, &surface->geometry))
+ {
+ swc_plane_move(&output->cursor_plane,
+ surface->geometry.x - output->geometry.x,
+ surface->geometry.y - output->geometry.y);
+ }
+ }
+}
+
+const struct swc_surface_class_interface swc_cursor_class_implementation = {
+ .attach = &attach,
+ .update = &update,
+ .move = &move
+};
+
diff --git a/libswc/cursor_surface.h b/libswc/cursor_surface.h
@@ -0,0 +1,33 @@
+/* swc: cursor_surface.h
+ *
+ * Copyright (c) 2013 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef SWC_CURSOR_SURFACE_H
+#define SWC_CURSOR_SURFACE_H 1
+
+#include "surface.h"
+
+extern const struct swc_surface_class_interface
+ swc_cursor_class_implementation;
+
+#endif
+
diff --git a/libswc/pointer.c b/libswc/pointer.c
@@ -88,8 +88,9 @@ static void set_cursor(struct wl_client * client,
{
struct swc_pointer * pointer = wl_resource_get_user_data(resource);
struct swc_surface * surface;
+ struct swc_pointer_event_data data;
- printf("set_cursor\n");
+ data.old = pointer->cursor.surface;
if (pointer->cursor.surface)
wl_list_remove(&pointer->cursor.destroy_listener.link);
@@ -109,7 +110,9 @@ static void set_cursor(struct wl_client * client,
pointer->cursor.hotspot_x = hotspot_x;
pointer->cursor.hotspot_y = hotspot_y;
- swc_send_event(&pointer->event_signal, SWC_POINTER_CURSOR_CHANGED, pointer);
+ data.new = pointer->cursor.surface;
+
+ swc_send_event(&pointer->event_signal, SWC_POINTER_CURSOR_CHANGED, &data);
}
struct wl_pointer_interface pointer_implementation = {
diff --git a/libswc/pointer.h b/libswc/pointer.h
@@ -16,11 +16,16 @@ struct swc_pointer_handler
uint32_t button, uint32_t state);
};
-enum swc_pointer_event
+enum swc_pointer_event_type
{
SWC_POINTER_CURSOR_CHANGED
};
+struct swc_pointer_event_data
+{
+ struct swc_surface * old, * new;
+};
+
struct swc_pointer
{
struct swc_input_focus focus;
diff --git a/libswc/util.h b/libswc/util.h
@@ -2,6 +2,7 @@
#define SWC_UTIL_H 1
#include <stdbool.h>
+#include <sys/time.h>
#include <sys/param.h>
#include <wayland-server.h>
#include <pixman.h>
@@ -17,6 +18,14 @@
void swc_remove_resource(struct wl_resource * resource);
+static inline uint32_t swc_time()
+{
+ struct timeval timeval;
+
+ gettimeofday(&timeval, NULL);
+ return timeval.tv_sec * 1000 + timeval.tv_usec / 1000;
+}
+
static inline bool swc_rectangle_contains_point
(pixman_rectangle32_t * rectangle, int32_t x, int32_t y)
{