mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2026-04-15 08:21:47 -04:00
Add protocol for setting the pointer image
This commit is contained in:
parent
b036ad4a9a
commit
77fb167956
5 changed files with 110 additions and 82 deletions
11
TODO
11
TODO
|
|
@ -13,17 +13,6 @@ Core wayland protocol
|
||||||
or do X style (content mime-type negotiation, but data goes away
|
or do X style (content mime-type negotiation, but data goes away
|
||||||
when client quits).
|
when client quits).
|
||||||
|
|
||||||
- protocol for setting the cursor image
|
|
||||||
|
|
||||||
- should we have a mechanism to attach surface to cursor for
|
|
||||||
guaranteed non-laggy drag?
|
|
||||||
|
|
||||||
- drawing cursors, moving them, cursor themes, attaching surfaces
|
|
||||||
to cursors. How do you change cursors when you mouse over a
|
|
||||||
text field if you don't have subwindows? This is what we do: a
|
|
||||||
client can set a cursor for a surface and wayland will set that
|
|
||||||
on enter and revert to default on leave
|
|
||||||
|
|
||||||
- Discard buffer, as in "wayland discarded your buffer, it's no
|
- Discard buffer, as in "wayland discarded your buffer, it's no
|
||||||
longer visible, you can stop updating it now.", reattach, as in "oh
|
longer visible, you can stop updating it now.", reattach, as in "oh
|
||||||
hey, I'm about to show your buffer that I threw away, what was it
|
hey, I'm about to show your buffer that I threw away, what was it
|
||||||
|
|
|
||||||
153
compositor.c
153
compositor.c
|
|
@ -125,12 +125,24 @@ wlsc_matrix_transform(struct wlsc_matrix *matrix, struct wlsc_vector *v)
|
||||||
*v = t;
|
*v = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static struct wlsc_surface *
|
||||||
wlsc_surface_init(struct wlsc_surface *surface,
|
wlsc_surface_create(struct wlsc_compositor *compositor,
|
||||||
struct wlsc_compositor *compositor, struct wl_visual *visual,
|
struct wl_visual *visual,
|
||||||
int32_t x, int32_t y, int32_t width, int32_t height)
|
int32_t x, int32_t y, int32_t width, int32_t height)
|
||||||
{
|
{
|
||||||
|
struct wlsc_surface *surface;
|
||||||
|
|
||||||
|
surface = malloc(sizeof *surface);
|
||||||
|
if (surface == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
glGenTextures(1, &surface->texture);
|
glGenTextures(1, &surface->texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, surface->texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
surface->compositor = compositor;
|
surface->compositor = compositor;
|
||||||
surface->visual = visual;
|
surface->visual = visual;
|
||||||
wlsc_matrix_init(&surface->matrix);
|
wlsc_matrix_init(&surface->matrix);
|
||||||
|
|
@ -140,35 +152,8 @@ wlsc_surface_init(struct wlsc_surface *surface,
|
||||||
wlsc_matrix_init(&surface->matrix_inv);
|
wlsc_matrix_init(&surface->matrix_inv);
|
||||||
wlsc_matrix_translate(&surface->matrix_inv, -x, -y, 0);
|
wlsc_matrix_translate(&surface->matrix_inv, -x, -y, 0);
|
||||||
wlsc_matrix_scale(&surface->matrix_inv, 1.0 / width, 1.0 / height, 1);
|
wlsc_matrix_scale(&surface->matrix_inv, 1.0 / width, 1.0 / height, 1);
|
||||||
}
|
|
||||||
|
|
||||||
static struct wlsc_surface *
|
return surface;
|
||||||
wlsc_surface_create_from_cairo_surface(struct wlsc_compositor *ec,
|
|
||||||
cairo_surface_t *surface,
|
|
||||||
int x, int y, int width, int height)
|
|
||||||
{
|
|
||||||
struct wlsc_surface *es;
|
|
||||||
int stride;
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
stride = cairo_image_surface_get_stride(surface);
|
|
||||||
data = cairo_image_surface_get_data(surface);
|
|
||||||
|
|
||||||
es = malloc(sizeof *es);
|
|
||||||
if (es == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
wlsc_surface_init(es, ec, &ec->premultiplied_argb_visual,
|
|
||||||
x, y, width, height);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, es->texture);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE, data);
|
|
||||||
|
|
||||||
return es;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -213,6 +198,16 @@ pointer_create(struct wlsc_compositor *ec, int x, int y, int width, int height)
|
||||||
const int hotspot_x = 16, hotspot_y = 16;
|
const int hotspot_x = 16, hotspot_y = 16;
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
|
int stride;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
EGLint image_attribs[] = {
|
||||||
|
EGL_WIDTH, 0,
|
||||||
|
EGL_HEIGHT, 0,
|
||||||
|
EGL_IMAGE_FORMAT_MESA, EGL_IMAGE_FORMAT_ARGB8888_MESA,
|
||||||
|
EGL_IMAGE_USE_MESA, EGL_IMAGE_USE_SCANOUT_MESA,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
||||||
width, height);
|
width, height);
|
||||||
|
|
@ -231,17 +226,37 @@ pointer_create(struct wlsc_compositor *ec, int x, int y, int width, int height)
|
||||||
cairo_fill(cr);
|
cairo_fill(cr);
|
||||||
cairo_destroy(cr);
|
cairo_destroy(cr);
|
||||||
|
|
||||||
es = wlsc_surface_create_from_cairo_surface(ec,
|
es = wlsc_surface_create(ec, &ec->premultiplied_argb_visual,
|
||||||
surface,
|
x, y, width, height);
|
||||||
x - hotspot_x,
|
|
||||||
y - hotspot_y,
|
stride = cairo_image_surface_get_stride(surface);
|
||||||
width, height);
|
data = cairo_image_surface_get_data(surface);
|
||||||
|
|
||||||
|
image_attribs[1] = width;
|
||||||
|
image_attribs[3] = height;
|
||||||
|
ec->default_pointer_image =
|
||||||
|
eglCreateDRMImageMESA(ec->display, image_attribs);
|
||||||
|
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ec->default_pointer_image);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
|
||||||
cairo_surface_destroy(surface);
|
cairo_surface_destroy(surface);
|
||||||
|
|
||||||
return es;
|
return es;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wlsc_input_device_set_default_pointer_image(struct wlsc_input_device *device)
|
||||||
|
{
|
||||||
|
struct wlsc_compositor *ec = device->ec;
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, device->sprite->texture);
|
||||||
|
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, ec->default_pointer_image);
|
||||||
|
device->sprite->visual = &ec->premultiplied_argb_visual;
|
||||||
|
device->hotspot_x = 16;
|
||||||
|
device->hotspot_y = 16;
|
||||||
|
}
|
||||||
|
|
||||||
static struct wlsc_surface *
|
static struct wlsc_surface *
|
||||||
background_create(struct wlsc_output *output, const char *filename)
|
background_create(struct wlsc_output *output, const char *filename)
|
||||||
{
|
{
|
||||||
|
|
@ -251,12 +266,13 @@ background_create(struct wlsc_output *output, const char *filename)
|
||||||
void *data;
|
void *data;
|
||||||
GLenum format;
|
GLenum format;
|
||||||
|
|
||||||
background = malloc(sizeof *background);
|
background = wlsc_surface_create(output->compositor,
|
||||||
|
&output->compositor->rgb_visual,
|
||||||
|
output->x, output->y,
|
||||||
|
output->width, output->height);
|
||||||
if (background == NULL)
|
if (background == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
g_type_init();
|
|
||||||
|
|
||||||
pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
|
pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
|
||||||
output->width,
|
output->width,
|
||||||
output->height,
|
output->height,
|
||||||
|
|
@ -268,17 +284,7 @@ background_create(struct wlsc_output *output, const char *filename)
|
||||||
|
|
||||||
data = gdk_pixbuf_get_pixels(pixbuf);
|
data = gdk_pixbuf_get_pixels(pixbuf);
|
||||||
|
|
||||||
wlsc_surface_init(background, output->compositor,
|
if (gdk_pixbuf_get_has_alpha(pixbuf))
|
||||||
&output->compositor->rgb_visual,
|
|
||||||
output->x, output->y, output->width, output->height);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, background->texture);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
if (gdk_pixbuf_get_has_alpha(pixbuf))
|
|
||||||
format = GL_RGBA;
|
format = GL_RGBA;
|
||||||
else
|
else
|
||||||
format = GL_RGB;
|
format = GL_RGB;
|
||||||
|
|
@ -432,10 +438,6 @@ surface_attach(struct wl_client *client,
|
||||||
struct wlsc_buffer *buffer = (struct wlsc_buffer *) buffer_base;
|
struct wlsc_buffer *buffer = (struct wlsc_buffer *) buffer_base;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, es->texture);
|
glBindTexture(GL_TEXTURE_2D, es->texture);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image);
|
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image);
|
||||||
es->visual = buffer->visual;
|
es->visual = buffer->visual;
|
||||||
}
|
}
|
||||||
|
|
@ -520,7 +522,7 @@ compositor_create_surface(struct wl_client *client,
|
||||||
struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor;
|
struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor;
|
||||||
struct wlsc_surface *surface;
|
struct wlsc_surface *surface;
|
||||||
|
|
||||||
surface = malloc(sizeof *surface);
|
surface = wlsc_surface_create(ec, NULL, 0, 0, 0, 0);
|
||||||
if (surface == NULL) {
|
if (surface == NULL) {
|
||||||
wl_client_post_event(client,
|
wl_client_post_event(client,
|
||||||
(struct wl_object *) ec->wl_display,
|
(struct wl_object *) ec->wl_display,
|
||||||
|
|
@ -528,8 +530,6 @@ compositor_create_surface(struct wl_client *client,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlsc_surface_init(surface, ec, NULL, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
wl_list_insert(ec->surface_list.prev, &surface->link);
|
wl_list_insert(ec->surface_list.prev, &surface->link);
|
||||||
surface->base.base.destroy = destroy_surface;
|
surface->base.base.destroy = destroy_surface;
|
||||||
wl_client_add_surface(client, &surface->base,
|
wl_client_add_surface(client, &surface->base,
|
||||||
|
|
@ -609,6 +609,9 @@ wlsc_input_device_set_pointer_focus(struct wlsc_input_device *device,
|
||||||
time, &surface->base,
|
time, &surface->base,
|
||||||
x, y, sx, sy);
|
x, y, sx, sy);
|
||||||
|
|
||||||
|
if (!surface)
|
||||||
|
wlsc_input_device_set_default_pointer_image(device);
|
||||||
|
|
||||||
device->pointer_focus = surface;
|
device->pointer_focus = surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -640,7 +643,6 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y)
|
||||||
struct wlsc_surface *es;
|
struct wlsc_surface *es;
|
||||||
struct wlsc_compositor *ec = device->ec;
|
struct wlsc_compositor *ec = device->ec;
|
||||||
struct wlsc_output *output;
|
struct wlsc_output *output;
|
||||||
const int hotspot_x = 16, hotspot_y = 16;
|
|
||||||
int32_t sx, sy, width, height;
|
int32_t sx, sy, width, height;
|
||||||
|
|
||||||
/* FIXME: We need some multi head love here. */
|
/* FIXME: We need some multi head love here. */
|
||||||
|
|
@ -727,7 +729,7 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y)
|
||||||
wlsc_matrix_init(&device->sprite->matrix);
|
wlsc_matrix_init(&device->sprite->matrix);
|
||||||
wlsc_matrix_scale(&device->sprite->matrix, 64, 64, 1);
|
wlsc_matrix_scale(&device->sprite->matrix, 64, 64, 1);
|
||||||
wlsc_matrix_translate(&device->sprite->matrix,
|
wlsc_matrix_translate(&device->sprite->matrix,
|
||||||
x - hotspot_x, y - hotspot_y, 0);
|
x - device->hotspot_x, y - device->hotspot_y, 0);
|
||||||
|
|
||||||
wlsc_compositor_schedule_repaint(device->ec);
|
wlsc_compositor_schedule_repaint(device->ec);
|
||||||
}
|
}
|
||||||
|
|
@ -829,6 +831,30 @@ notify_key(struct wlsc_input_device *device,
|
||||||
WL_INPUT_DEVICE_KEY, time, key, state);
|
WL_INPUT_DEVICE_KEY, time, key, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
input_device_attach(struct wl_client *client,
|
||||||
|
struct wl_input_device *device_base,
|
||||||
|
struct wl_buffer *buffer_base, int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
struct wlsc_input_device *device =
|
||||||
|
(struct wlsc_input_device *) device_base;
|
||||||
|
struct wlsc_buffer *buffer = (struct wlsc_buffer *) buffer_base;
|
||||||
|
|
||||||
|
if (device->pointer_focus == NULL ||
|
||||||
|
device->pointer_focus->base.client != client)
|
||||||
|
return;
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, device->sprite->texture);
|
||||||
|
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image);
|
||||||
|
device->sprite->visual = buffer->visual;
|
||||||
|
device->hotspot_x = x;
|
||||||
|
device->hotspot_y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
const static struct wl_input_device_interface input_device_interface = {
|
||||||
|
input_device_attach,
|
||||||
|
};
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
get_time(void)
|
get_time(void)
|
||||||
{
|
{
|
||||||
|
|
@ -866,7 +892,8 @@ wlsc_input_device_init(struct wlsc_input_device *device,
|
||||||
struct wlsc_compositor *ec)
|
struct wlsc_compositor *ec)
|
||||||
{
|
{
|
||||||
device->base.interface = &wl_input_device_interface;
|
device->base.interface = &wl_input_device_interface;
|
||||||
device->base.implementation = NULL;
|
device->base.implementation =
|
||||||
|
(void (**)(void)) &input_device_interface;
|
||||||
wl_display_add_object(ec->wl_display, &device->base);
|
wl_display_add_object(ec->wl_display, &device->base);
|
||||||
wl_display_add_global(ec->wl_display, &device->base, NULL);
|
wl_display_add_global(ec->wl_display, &device->base, NULL);
|
||||||
|
|
||||||
|
|
@ -874,6 +901,8 @@ wlsc_input_device_init(struct wlsc_input_device *device,
|
||||||
device->y = 100;
|
device->y = 100;
|
||||||
device->ec = ec;
|
device->ec = ec;
|
||||||
device->sprite = pointer_create(ec, device->x, device->y, 64, 64);
|
device->sprite = pointer_create(ec, device->x, device->y, 64, 64);
|
||||||
|
device->hotspot_x = 16;
|
||||||
|
device->hotspot_y = 16;
|
||||||
|
|
||||||
device->listener.func = handle_surface_destroy;
|
device->listener.func = handle_surface_destroy;
|
||||||
wl_list_insert(ec->surface_destroy_listener_list.prev,
|
wl_list_insert(ec->surface_destroy_listener_list.prev,
|
||||||
|
|
@ -1092,6 +1121,8 @@ int main(int argc, char *argv[])
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GOptionContext *context;
|
GOptionContext *context;
|
||||||
|
|
||||||
|
g_type_init(); /* GdkPixbuf needs this, it seems. */
|
||||||
|
|
||||||
context = g_option_context_new(NULL);
|
context = g_option_context_new(NULL);
|
||||||
g_option_context_add_main_entries(context, option_entries, "Wayland");
|
g_option_context_add_main_entries(context, option_entries, "Wayland");
|
||||||
if (!g_option_context_parse(context, &argc, &argv, &error)) {
|
if (!g_option_context_parse(context, &argc, &argv, &error)) {
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ struct wlsc_input_device {
|
||||||
int32_t x, y;
|
int32_t x, y;
|
||||||
struct wlsc_compositor *ec;
|
struct wlsc_compositor *ec;
|
||||||
struct wlsc_surface *sprite;
|
struct wlsc_surface *sprite;
|
||||||
|
int32_t hotspot_x, hotspot_y;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
struct wlsc_surface *pointer_focus;
|
struct wlsc_surface *pointer_focus;
|
||||||
|
|
@ -118,6 +119,7 @@ struct wlsc_compositor {
|
||||||
EGLContext context;
|
EGLContext context;
|
||||||
GLuint fbo, vbo;
|
GLuint fbo, vbo;
|
||||||
GLuint proj_uniform, tex_uniform;
|
GLuint proj_uniform, tex_uniform;
|
||||||
|
EGLImageKHR default_pointer_image;
|
||||||
struct wl_display *wl_display;
|
struct wl_display *wl_display;
|
||||||
|
|
||||||
/* We implement the shell interface. */
|
/* We implement the shell interface. */
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,12 @@
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
<interface name="input_device" version="1">
|
<interface name="input_device" version="1">
|
||||||
|
<request name="attach">
|
||||||
|
<arg name="buffer" type="object" interface="buffer"/>
|
||||||
|
<arg name="hotspot_x" type="int"/>
|
||||||
|
<arg name="hotspot_y" type="int"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
<event name="motion">
|
<event name="motion">
|
||||||
<arg name="time" type="uint"/>
|
<arg name="time" type="uint"/>
|
||||||
<arg name="x" type="int"/>
|
<arg name="x" type="int"/>
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ delivered in both screen coordinates and surface local coordinates.
|
||||||
\hline
|
\hline
|
||||||
Interface \texttt{cache} \\ \hline
|
Interface \texttt{cache} \\ \hline
|
||||||
Requests \\ \hline
|
Requests \\ \hline
|
||||||
no requests \\ \hline
|
\texttt{attach(buffer, x, y)} \\
|
||||||
Events \\ \hline
|
Events \\ \hline
|
||||||
\texttt{motion(x, y, sx, sy)} \\
|
\texttt{motion(x, y, sx, sy)} \\
|
||||||
\texttt{button(button, state, x, y, sx, sy)} \\
|
\texttt{button(button, state, x, y, sx, sy)} \\
|
||||||
|
|
@ -179,14 +179,14 @@ Talk about:
|
||||||
A surface can change the pointer image when the surface is the pointer
|
A surface can change the pointer image when the surface is the pointer
|
||||||
focus of the input device. Wayland doesn't automatically change the
|
focus of the input device. Wayland doesn't automatically change the
|
||||||
pointer image when a pointer enters a surface, but expects the
|
pointer image when a pointer enters a surface, but expects the
|
||||||
application to set the cursor it wants in response the the motion
|
application to set the cursor it wants in response the the pointer
|
||||||
event. The rationale is that a client has to manage changing pointer
|
focus and motion events. The rationale is that a client has to manage
|
||||||
images for UI elements within the surface in response to motion events
|
changing pointer images for UI elements within the surface in response
|
||||||
anyway, so we'll make that the only mechanism for setting changing the
|
to motion events anyway, so we'll make that the only mechanism for
|
||||||
pointer image. If the server receives a request to set the pointer
|
setting changing the pointer image. If the server receives a request
|
||||||
image after the surface loses pointer focus, the request is ignored.
|
to set the pointer image after the surface loses pointer focus, the
|
||||||
To the client this will look like it successfully set the pointer
|
request is ignored. To the client this will look like it successfully
|
||||||
image.
|
set the pointer image.
|
||||||
|
|
||||||
The compositor will revert the pointer image back to a default image
|
The compositor will revert the pointer image back to a default image
|
||||||
when no surface has the pointer focus for that device. Clients can
|
when no surface has the pointer focus for that device. Clients can
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue