mutter/src/wayland/meta-wayland-tablet-tool.c

950 lines
30 KiB
C
Raw Normal View History

/*
* Wayland Support
*
* Copyright (C) 2015 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#include "config.h"
#include "wayland/meta-wayland-tablet-tool.h"
#include <glib.h>
#include <wayland-server.h>
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-tablet-cursor-surface.h"
#include "compositor/meta-surface-actor-wayland.h"
#include "wayland/meta-wayland-tablet.h"
#include "wayland/meta-wayland-tablet-seat.h"
#include "backends/meta-input-settings-private.h"
#include "backends/meta-logical-monitor.h"
#include "tablet-unstable-v2-server-protocol.h"
#define TABLET_AXIS_MAX 65535
static MetaBackend *
backend_from_tool (MetaWaylandTabletTool *tool)
{
MetaWaylandCompositor *compositor =
meta_wayland_seat_get_compositor (tool->seat->seat);
MetaContext *context = meta_wayland_compositor_get_context (compositor);
return meta_context_get_backend (context);
}
static MetaDisplay *
display_from_tool (MetaWaylandTabletTool *tool)
{
MetaWaylandCompositor *compositor =
meta_wayland_seat_get_compositor (tool->seat->seat);
MetaContext *context = meta_wayland_compositor_get_context (compositor);
return meta_context_get_display (context);
}
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
static void
move_resources (struct wl_list *destination,
struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
}
static void
meta_wayland_tablet_tool_update_cursor_surface (MetaWaylandTabletTool *tool)
{
MetaCursorSprite *cursor = NULL;
if (tool->cursor_renderer == NULL)
return;
if (tool->current && tool->current_tablet)
{
if (tool->cursor_surface &&
meta_wayland_surface_get_buffer (tool->cursor_surface))
{
MetaWaylandCursorSurface *cursor_surface =
META_WAYLAND_CURSOR_SURFACE (tool->cursor_surface->role);
cursor = meta_wayland_cursor_surface_get_sprite (cursor_surface);
}
else
cursor = NULL;
}
else if (tool->current_tablet)
cursor = META_CURSOR_SPRITE (tool->default_sprite);
else
cursor = NULL;
meta_cursor_renderer_set_cursor (tool->cursor_renderer, cursor);
}
static void
meta_wayland_tablet_tool_set_cursor_surface (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface)
{
if (tool->cursor_surface == surface)
return;
if (tool->cursor_surface)
{
MetaWaylandCursorSurface *cursor_surface;
cursor_surface = META_WAYLAND_CURSOR_SURFACE (tool->cursor_surface->role);
meta_wayland_cursor_surface_set_renderer (cursor_surface, NULL);
meta_wayland_surface_update_outputs (tool->cursor_surface);
wl_list_remove (&tool->cursor_surface_destroy_listener.link);
}
tool->cursor_surface = surface;
if (tool->cursor_surface)
{
meta_wayland_surface_update_outputs (tool->cursor_surface);
wl_resource_add_destroy_listener (tool->cursor_surface->resource,
&tool->cursor_surface_destroy_listener);
}
meta_wayland_tablet_tool_update_cursor_surface (tool);
}
static enum zwp_tablet_tool_v2_type
input_device_tool_get_type (ClutterInputDeviceTool *device_tool)
{
ClutterInputDeviceToolType tool_type;
tool_type = clutter_input_device_tool_get_tool_type (device_tool);
switch (tool_type)
{
case CLUTTER_INPUT_DEVICE_TOOL_NONE:
case CLUTTER_INPUT_DEVICE_TOOL_PEN:
return ZWP_TABLET_TOOL_V2_TYPE_PEN;
case CLUTTER_INPUT_DEVICE_TOOL_ERASER:
return ZWP_TABLET_TOOL_V2_TYPE_ERASER;
case CLUTTER_INPUT_DEVICE_TOOL_BRUSH:
return ZWP_TABLET_TOOL_V2_TYPE_BRUSH;
case CLUTTER_INPUT_DEVICE_TOOL_PENCIL:
return ZWP_TABLET_TOOL_V2_TYPE_PENCIL;
case CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH:
return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH;
case CLUTTER_INPUT_DEVICE_TOOL_MOUSE:
return ZWP_TABLET_TOOL_V2_TYPE_MOUSE;
case CLUTTER_INPUT_DEVICE_TOOL_LENS:
return ZWP_TABLET_TOOL_V2_TYPE_LENS;
}
g_assert_not_reached ();
return 0;
}
static void
meta_wayland_tablet_tool_notify_capabilities (MetaWaylandTabletTool *tool,
struct wl_resource *resource)
{
ClutterInputAxisFlags axes;
axes = clutter_input_device_tool_get_axes (tool->device_tool);
if (axes & CLUTTER_INPUT_AXIS_FLAG_PRESSURE)
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE);
if (axes & CLUTTER_INPUT_AXIS_FLAG_DISTANCE)
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE);
if (axes & (CLUTTER_INPUT_AXIS_FLAG_XTILT | CLUTTER_INPUT_AXIS_FLAG_YTILT))
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_TILT);
if (axes & CLUTTER_INPUT_AXIS_FLAG_ROTATION)
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION);
if (axes & CLUTTER_INPUT_AXIS_FLAG_SLIDER)
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER);
if (axes & CLUTTER_INPUT_AXIS_FLAG_WHEEL)
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL);
}
static void
meta_wayland_tablet_tool_notify_details (MetaWaylandTabletTool *tool,
struct wl_resource *resource)
{
guint64 serial, id;
zwp_tablet_tool_v2_send_type (resource,
input_device_tool_get_type (tool->device_tool));
serial = clutter_input_device_tool_get_serial (tool->device_tool);
zwp_tablet_tool_v2_send_hardware_serial (resource, (uint32_t) (serial >> 32),
(uint32_t) (serial & G_MAXUINT32));
id = clutter_input_device_tool_get_id (tool->device_tool);
zwp_tablet_tool_v2_send_hardware_id_wacom (resource, (uint32_t) (id >> 32),
(uint32_t) (id & G_MAXUINT32));
meta_wayland_tablet_tool_notify_capabilities (tool, resource);
zwp_tablet_tool_v2_send_done (resource);
}
static void
meta_wayland_tablet_tool_ensure_resource (MetaWaylandTabletTool *tool,
struct wl_client *client)
{
struct wl_resource *seat_resource, *tool_resource;
seat_resource = meta_wayland_tablet_seat_lookup_resource (tool->seat, client);
if (seat_resource &&
!meta_wayland_tablet_tool_lookup_resource (tool, client))
{
tool_resource = meta_wayland_tablet_tool_create_new_resource (tool, client,
seat_resource,
0);
meta_wayland_tablet_seat_notify_tool (tool->seat, tool, client);
meta_wayland_tablet_tool_notify_details (tool, tool_resource);
}
}
static void
broadcast_proximity_in (MetaWaylandTabletTool *tool)
{
struct wl_resource *resource, *tablet_resource;
struct wl_client *client;
client = wl_resource_get_client (tool->focus_surface->resource);
tablet_resource = meta_wayland_tablet_lookup_resource (tool->current_tablet,
client);
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_proximity_in (resource, tool->proximity_serial,
tablet_resource,
tool->focus_surface->resource);
}
}
static void
broadcast_proximity_out (MetaWaylandTabletTool *tool)
{
struct wl_resource *resource;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_proximity_out (resource);
}
}
static void
broadcast_frame (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
guint32 _time = event ? clutter_event_get_time (event) : CLUTTER_CURRENT_TIME;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_frame (resource, _time);
}
}
static void
meta_wayland_tablet_tool_set_focus (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
if (tool->focus_surface == surface)
return;
if (tool->focus_surface != NULL)
{
struct wl_list *l;
l = &tool->focus_resource_list;
if (!wl_list_empty (l))
{
broadcast_proximity_out (tool);
broadcast_frame (tool, event);
move_resources (&tool->resource_list, &tool->focus_resource_list);
}
wl_list_remove (&tool->focus_surface_destroy_listener.link);
tool->focus_surface = NULL;
}
if (surface != NULL && tool->current_tablet)
{
struct wl_client *client;
struct wl_list *l;
tool->focus_surface = surface;
client = wl_resource_get_client (tool->focus_surface->resource);
wl_resource_add_destroy_listener (tool->focus_surface->resource,
&tool->focus_surface_destroy_listener);
move_resources_for_client (&tool->focus_resource_list,
&tool->resource_list, client);
meta_wayland_tablet_tool_ensure_resource (tool, client);
l = &tool->focus_resource_list;
if (!wl_list_empty (l))
{
struct wl_client *client = wl_resource_get_client (tool->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
tool->proximity_serial = wl_display_next_serial (display);
broadcast_proximity_in (tool);
broadcast_frame (tool, event);
}
}
meta_wayland_tablet_tool_update_cursor_surface (tool);
}
static void
tablet_tool_handle_focus_surface_destroy (struct wl_listener *listener,
void *data)
{
MetaWaylandTabletTool *tool;
tool = wl_container_of (listener, tool, focus_surface_destroy_listener);
meta_wayland_tablet_tool_set_focus (tool, NULL, NULL);
}
static void
tablet_tool_handle_cursor_surface_destroy (struct wl_listener *listener,
void *data)
{
MetaWaylandTabletTool *tool;
tool = wl_container_of (listener, tool, cursor_surface_destroy_listener);
meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
}
static void
tool_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
float best_scale,
int x,
int y,
MetaWaylandTabletTool *tool)
{
MetaBackend *backend = backend_from_tool (tool);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaLogicalMonitor *logical_monitor;
logical_monitor =
meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
/* Reload the cursor texture if the scale has changed. */
if (logical_monitor)
{
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
float ceiled_scale;
ceiled_scale = ceilf (logical_monitor->scale);
meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
(int) ceiled_scale);
if (meta_backend_is_stage_views_scaled (backend))
meta_cursor_sprite_set_texture_scale (cursor_sprite,
1.0 / ceiled_scale);
else
meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0);
}
}
MetaWaylandTabletTool *
meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
ClutterInputDevice *device,
ClutterInputDeviceTool *device_tool)
{
MetaWaylandCompositor *compositor =
meta_wayland_seat_get_compositor (seat->seat);
MetaContext *context = meta_wayland_compositor_get_context (compositor);
MetaBackend *backend = meta_context_get_backend (context);
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
MetaWaylandTabletTool *tool;
tool = g_new0 (MetaWaylandTabletTool, 1);
tool->seat = seat;
tool->device = device;
tool->device_tool = device_tool;
wl_list_init (&tool->resource_list);
wl_list_init (&tool->focus_resource_list);
tool->focus_surface_destroy_listener.notify = tablet_tool_handle_focus_surface_destroy;
tool->cursor_surface_destroy_listener.notify = tablet_tool_handle_cursor_surface_destroy;
tool->default_sprite = meta_cursor_sprite_xcursor_new (META_CURSOR_DEFAULT,
cursor_tracker);
meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (tool->default_sprite),
(MetaCursorPrepareFunc) tool_cursor_prepare_at,
tool);
return tool;
}
void
meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool)
{
struct wl_resource *resource, *next;
meta_wayland_tablet_tool_set_focus (tool, NULL, NULL);
meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
g_clear_object (&tool->cursor_renderer);
wl_resource_for_each_safe (resource, next, &tool->resource_list)
{
zwp_tablet_tool_v2_send_removed (resource);
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (tool->default_sprite),
NULL, NULL);
g_object_unref (tool->default_sprite);
g_free (tool);
}
static void
tool_set_cursor (struct wl_client *client,
struct wl_resource *resource,
uint32_t serial,
struct wl_resource *surface_resource,
int32_t hotspot_x,
int32_t hotspot_y)
{
MetaWaylandTabletTool *tool = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface;
surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL);
if (tool->focus_surface == NULL)
return;
if (tool->cursor_renderer == NULL)
return;
if (wl_resource_get_client (tool->focus_surface->resource) != client)
return;
if (tool->proximity_serial - serial > G_MAXUINT32 / 2)
return;
if (surface &&
!meta_wayland_surface_assign_role (surface,
META_TYPE_WAYLAND_TABLET_CURSOR_SURFACE,
NULL))
{
wl_resource_post_error (resource, WL_POINTER_ERROR_ROLE,
"wl_surface@%d already has a different role",
wl_resource_get_id (surface_resource));
return;
}
if (surface)
{
MetaWaylandCursorSurface *cursor_surface;
cursor_surface = META_WAYLAND_CURSOR_SURFACE (surface->role);
meta_wayland_cursor_surface_set_renderer (cursor_surface,
tool->cursor_renderer);
meta_wayland_cursor_surface_set_hotspot (cursor_surface,
hotspot_x, hotspot_y);
}
meta_wayland_tablet_tool_set_cursor_surface (tool, surface);
}
static void
tool_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_tool_v2_interface tool_interface = {
tool_set_cursor,
tool_destroy
};
struct wl_resource *
meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_tool_v2_interface,
wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (resource, &tool_interface,
tool, unbind_resource);
wl_resource_set_user_data (resource, tool);
if (tool->focus_surface &&
wl_resource_get_client (tool->focus_surface->resource) == client)
{
wl_list_insert (&tool->focus_resource_list, wl_resource_get_link (resource));
}
else
{
wl_list_insert (&tool->resource_list, wl_resource_get_link (resource));
}
return resource;
}
struct wl_resource *
meta_wayland_tablet_tool_lookup_resource (MetaWaylandTabletTool *tool,
struct wl_client *client)
{
struct wl_resource *resource = NULL;
if (!wl_list_empty (&tool->resource_list))
resource = wl_resource_find_for_client (&tool->resource_list, client);
if (!wl_list_empty (&tool->focus_resource_list))
resource = wl_resource_find_for_client (&tool->focus_resource_list, client);
return resource;
}
static void
meta_wayland_tablet_tool_account_button (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
if (event->type == CLUTTER_BUTTON_PRESS)
{
tool->pressed_buttons |= 1 << (event->button.button - 1);
tool->button_count++;
}
else if (event->type == CLUTTER_BUTTON_RELEASE)
{
tool->pressed_buttons &= ~(1 << (event->button.button - 1));
tool->button_count--;
}
}
static void
sync_focus_surface (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
MetaDisplay *display = display_from_tool (tool);
MetaBackend *backend = backend_from_tool (tool);
ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
if (clutter_stage_get_grab_actor (stage))
{
meta_wayland_tablet_tool_set_focus (tool, NULL, event);
return;
}
switch (display->event_route)
{
case META_EVENT_ROUTE_WINDOW_OP:
case META_EVENT_ROUTE_FRAME_BUTTON:
/* The compositor has a grab, so remove our focus */
meta_wayland_tablet_tool_set_focus (tool, NULL, event);
break;
case META_EVENT_ROUTE_NORMAL:
case META_EVENT_ROUTE_WAYLAND_POPUP:
meta_wayland_tablet_tool_set_focus (tool, tool->current, event);
break;
default:
g_assert_not_reached ();
}
}
static void
repick_for_event (MetaWaylandTabletTool *tool,
const ClutterEvent *for_event)
{
ClutterActor *actor;
actor = clutter_stage_get_device_actor (clutter_event_get_stage (for_event),
clutter_event_get_device (for_event),
clutter_event_get_event_sequence (for_event));
if (META_IS_SURFACE_ACTOR_WAYLAND (actor))
tool->current = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor));
else
tool->current = NULL;
sync_focus_surface (tool, for_event);
meta_wayland_tablet_tool_update_cursor_surface (tool);
}
static void
meta_wayland_tablet_tool_get_relative_coordinates (MetaWaylandTabletTool *tool,
const ClutterEvent *event,
MetaWaylandSurface *surface,
wl_fixed_t *sx,
wl_fixed_t *sy)
{
float xf, yf;
clutter_event_get_coords (event, &xf, &yf);
meta_wayland_surface_get_relative_coordinates (surface, xf, yf, &xf, &yf);
*sx = wl_fixed_from_double (xf);
*sy = wl_fixed_from_double (yf);
}
static void
broadcast_motion (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
wl_fixed_t sx, sy;
meta_wayland_tablet_tool_get_relative_coordinates (tool, event,
tool->focus_surface,
&sx, &sy);
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_motion (resource, sx, sy);
}
}
static void
broadcast_down (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
tool->down_serial = wl_display_next_serial (tool->seat->manager->wl_display);
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_down (resource, tool->down_serial);
}
}
static void
broadcast_up (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_up (resource);
}
}
static void
broadcast_button (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
uint32_t button;
button = clutter_event_get_event_code (event);
tool->button_serial = wl_display_next_serial (tool->seat->manager->wl_display);
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_button (resource, tool->button_serial, button,
event->type == CLUTTER_BUTTON_PRESS ?
ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED :
ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED);
}
}
static void
broadcast_axis (MetaWaylandTabletTool *tool,
const ClutterEvent *event,
ClutterInputAxis axis)
{
struct wl_resource *resource;
uint32_t value;
double val;
val = event->motion.axes[axis];
value = val * TABLET_AXIS_MAX;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
switch (axis)
{
case CLUTTER_INPUT_AXIS_PRESSURE:
zwp_tablet_tool_v2_send_pressure (resource, value);
break;
case CLUTTER_INPUT_AXIS_DISTANCE:
zwp_tablet_tool_v2_send_distance (resource, value);
break;
case CLUTTER_INPUT_AXIS_SLIDER:
zwp_tablet_tool_v2_send_slider (resource, value);
break;
default:
break;
}
}
}
static void
broadcast_tilt (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
gdouble xtilt, ytilt;
xtilt = event->motion.axes[CLUTTER_INPUT_AXIS_XTILT];
ytilt = event->motion.axes[CLUTTER_INPUT_AXIS_YTILT];
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_tilt (resource,
wl_fixed_from_double (xtilt),
wl_fixed_from_double (ytilt));
}
}
static void
broadcast_rotation (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
gdouble rotation;
rotation = event->motion.axes[CLUTTER_INPUT_AXIS_ROTATION];
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_rotation (resource,
wl_fixed_from_double (rotation));
}
}
static void
broadcast_wheel (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
gdouble angle;
gint32 clicks = 0;
angle = event->motion.axes[CLUTTER_INPUT_AXIS_WHEEL];
/* FIXME: Perform proper angle-to-clicks accumulation elsewhere */
if (angle > 0.01)
clicks = 1;
else if (angle < -0.01)
clicks = -1;
else
return;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v2_send_wheel (resource,
wl_fixed_from_double (angle),
clicks);
}
}
static void
broadcast_axes (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
ClutterInputAxisFlags axes;
axes = clutter_input_device_tool_get_axes (tool->device_tool);
if (axes & CLUTTER_INPUT_AXIS_FLAG_PRESSURE)
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_PRESSURE);
if (axes & CLUTTER_INPUT_AXIS_FLAG_DISTANCE)
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_DISTANCE);
if (axes & (CLUTTER_INPUT_AXIS_FLAG_XTILT | CLUTTER_INPUT_AXIS_FLAG_YTILT))
broadcast_tilt (tool, event);
if (axes & CLUTTER_INPUT_AXIS_FLAG_ROTATION)
broadcast_rotation (tool, event);
if (axes & CLUTTER_INPUT_AXIS_FLAG_SLIDER)
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_SLIDER);
if (axes & CLUTTER_INPUT_AXIS_FLAG_WHEEL)
broadcast_wheel (tool, event);
}
static void
handle_motion_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
if (!tool->focus_surface)
return;
broadcast_motion (tool, event);
broadcast_axes (tool, event);
broadcast_frame (tool, event);
}
static void
handle_button_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
if (!tool->focus_surface)
return;
if (event->type == CLUTTER_BUTTON_PRESS && tool->button_count == 1)
clutter_event_get_coords (event, &tool->grab_x, &tool->grab_y);
if (event->type == CLUTTER_BUTTON_PRESS && event->button.button == 1)
broadcast_down (tool, event);
else if (event->type == CLUTTER_BUTTON_RELEASE && event->button.button == 1)
broadcast_up (tool, event);
else
broadcast_button (tool, event);
broadcast_frame (tool, event);
}
void
meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
switch (event->type)
{
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
meta_wayland_tablet_tool_account_button (tool, event);
break;
case CLUTTER_MOTION:
if (!tool->pressed_buttons)
repick_for_event (tool, event);
break;
case CLUTTER_PROXIMITY_IN:
if (!tool->cursor_renderer)
{
MetaCursorRenderer *renderer;
renderer =
meta_backend_get_cursor_renderer_for_device (backend_from_tool (tool),
clutter_event_get_source_device (event));
g_set_object (&tool->cursor_renderer, renderer);
}
tool->current_tablet =
meta_wayland_tablet_seat_lookup_tablet (tool->seat,
clutter_event_get_source_device (event));
break;
case CLUTTER_PROXIMITY_OUT:
tool->current_tablet = NULL;
meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
meta_wayland_tablet_tool_update_cursor_surface (tool);
g_clear_object (&tool->cursor_renderer);
break;
default:
break;
}
}
gboolean
meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
switch (event->type)
{
case CLUTTER_PROXIMITY_IN:
/* We don't have much info here to make anything useful out of it,
* wait until the first motion event so we have both coordinates
* and tool.
*/
break;
case CLUTTER_PROXIMITY_OUT:
meta_wayland_tablet_tool_set_focus (tool, NULL, event);
break;
case CLUTTER_MOTION:
handle_motion_event (tool, event);
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
handle_button_event (tool, event);
break;
default:
return CLUTTER_EVENT_PROPAGATE;
}
return CLUTTER_EVENT_STOP;
}
static gboolean
tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface)
{
MetaWaylandSurface *subsurface;
if (tool->focus_surface == surface)
return TRUE;
wayland/surface: Use transactions for all sub-surface hierarchy changes And keep track of the hierarchy separately for the Wayland protocol and for output. Protocol state is updated immediately as protocol requests are processed, output state only when the corresponding transaction is applied (which may be deferred until the next commit of the parent surface). v2: * Directly add placement ops to a transaction, instead of going via pending_state. * Use transaction entry for the sub-surface instead of that for its parent surface. v3: * Use transaction entry for the parent surface again, to ensure proper ordering of placement ops, and call meta_wayland_surface_notify_subsurface_state_changed only once per parent surface. * Drop all use of wl_resource_add_destroy_listener, transactions are keeping surfaces alive as long as needed. v4: * Rebase on https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2501 * Drop ClutterActor code from meta_wayland_surface_apply_placement_ops. (Robert Mader) v5: * Rename MetaWaylandSubSurfaceState to MetaWaylandSurfaceSubState, since the next commit adds not sub-surface specific state to it. v6: * Move include of meta-wayland-subsurface.h from meta-wayland-transaction.c to .h, since the latter references MetaWaylandSubsurfacePlacementOp. v7: * Drop superfluous !entry check from meta_wayland_transaction_apply. v8: * Rename output/protocol fields to output/protocol_state. (Jonas Ådahl) v9: * Use meta_wayland_surface_state_new in meta_wayland_transaction_add_placement_op. v10: * Fix a few style issues per check-style.py. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1880>
2021-07-23 10:01:37 -04:00
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state,
subsurface)
{
if (tablet_tool_can_grab_surface (tool, subsurface))
return TRUE;
}
return FALSE;
}
gboolean
meta_wayland_tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface,
uint32_t serial)
{
return ((tool->down_serial == serial || tool->button_serial == serial) &&
tablet_tool_can_grab_surface (tool, surface));
}
gboolean
meta_wayland_tablet_tool_can_popup (MetaWaylandTabletTool *tool,
uint32_t serial)
{
return tool->down_serial == serial || tool->button_serial == serial;
}