wayland: Add focus management to MetaWaylandTabletTool
Tools can now switch between surfaces, which implies the emission of wl_tablet_tool.proximity_in/out events.
This commit is contained in:
parent
745cb67988
commit
edfb8fe19b
@ -30,6 +30,9 @@
|
|||||||
#include <wayland-server.h>
|
#include <wayland-server.h>
|
||||||
#include "tablet-unstable-v1-server-protocol.h"
|
#include "tablet-unstable-v1-server-protocol.h"
|
||||||
#include "meta-wayland-private.h"
|
#include "meta-wayland-private.h"
|
||||||
|
#include "meta-surface-actor-wayland.h"
|
||||||
|
#include "meta-wayland-tablet.h"
|
||||||
|
#include "meta-wayland-tablet-seat.h"
|
||||||
#include "meta-wayland-tablet-tool.h"
|
#include "meta-wayland-tablet-tool.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -38,6 +41,135 @@ unbind_resource (struct wl_resource *resource)
|
|||||||
wl_list_remove (wl_resource_get_link (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
|
||||||
|
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_v1_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_v1_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_v1_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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
MetaWaylandTabletTool *
|
MetaWaylandTabletTool *
|
||||||
meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
|
meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
|
||||||
ClutterInputDevice *device,
|
ClutterInputDevice *device,
|
||||||
@ -50,6 +182,9 @@ meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
|
|||||||
tool->device = device;
|
tool->device = device;
|
||||||
tool->device_tool = device_tool;
|
tool->device_tool = device_tool;
|
||||||
wl_list_init (&tool->resource_list);
|
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;
|
||||||
|
|
||||||
return tool;
|
return tool;
|
||||||
}
|
}
|
||||||
@ -59,6 +194,8 @@ meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool)
|
|||||||
{
|
{
|
||||||
struct wl_resource *resource, *next;
|
struct wl_resource *resource, *next;
|
||||||
|
|
||||||
|
meta_wayland_tablet_tool_set_focus (tool, NULL, NULL);
|
||||||
|
|
||||||
wl_resource_for_each_safe (resource, next, &tool->resource_list)
|
wl_resource_for_each_safe (resource, next, &tool->resource_list)
|
||||||
{
|
{
|
||||||
zwp_tablet_tool_v1_send_removed (resource);
|
zwp_tablet_tool_v1_send_removed (resource);
|
||||||
@ -89,6 +226,24 @@ static const struct zwp_tablet_tool_v1_interface tool_interface = {
|
|||||||
tool_destroy
|
tool_destroy
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
emit_proximity_in (MetaWaylandTabletTool *tool,
|
||||||
|
struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
struct wl_resource *tablet_resource;
|
||||||
|
struct wl_client *client;
|
||||||
|
|
||||||
|
if (!tool->focus_surface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
client = wl_resource_get_client (resource);
|
||||||
|
tablet_resource = meta_wayland_tablet_lookup_resource (tool->current_tablet,
|
||||||
|
client);
|
||||||
|
|
||||||
|
zwp_tablet_tool_v1_send_proximity_in (resource, tool->proximity_serial,
|
||||||
|
tablet_resource, tool->focus_surface->resource);
|
||||||
|
}
|
||||||
|
|
||||||
struct wl_resource *
|
struct wl_resource *
|
||||||
meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
|
meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
|
||||||
struct wl_client *client,
|
struct wl_client *client,
|
||||||
@ -102,7 +257,17 @@ meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
|
|||||||
wl_resource_set_implementation (resource, &tool_interface,
|
wl_resource_set_implementation (resource, &tool_interface,
|
||||||
tool, unbind_resource);
|
tool, unbind_resource);
|
||||||
wl_resource_set_user_data (resource, tool);
|
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));
|
||||||
|
emit_proximity_in (tool, resource);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
wl_list_insert (&tool->resource_list, wl_resource_get_link (resource));
|
wl_list_insert (&tool->resource_list, wl_resource_get_link (resource));
|
||||||
|
}
|
||||||
|
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
@ -111,21 +276,110 @@ struct wl_resource *
|
|||||||
meta_wayland_tablet_tool_lookup_resource (MetaWaylandTabletTool *tool,
|
meta_wayland_tablet_tool_lookup_resource (MetaWaylandTabletTool *tool,
|
||||||
struct wl_client *client)
|
struct wl_client *client)
|
||||||
{
|
{
|
||||||
if (wl_list_empty (&tool->resource_list))
|
struct wl_resource *resource = NULL;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return wl_resource_find_for_client (&tool->resource_list, client);
|
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);
|
||||||
|
else if (event->type == CLUTTER_BUTTON_RELEASE)
|
||||||
|
tool->pressed_buttons &= ~(1 << (event->button.button - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sync_focus_surface (MetaWaylandTabletTool *tool,
|
||||||
|
const ClutterEvent *event)
|
||||||
|
{
|
||||||
|
MetaDisplay *display = meta_get_display ();
|
||||||
|
|
||||||
|
switch (display->event_route)
|
||||||
|
{
|
||||||
|
case META_EVENT_ROUTE_WINDOW_OP:
|
||||||
|
case META_EVENT_ROUTE_COMPOSITOR_GRAB:
|
||||||
|
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 = NULL;
|
||||||
|
|
||||||
|
actor = clutter_event_get_source (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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool,
|
meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool,
|
||||||
const ClutterEvent *event)
|
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:
|
||||||
|
tool->current_tablet =
|
||||||
|
meta_wayland_tablet_seat_lookup_tablet (tool->seat,
|
||||||
|
clutter_event_get_source_device (event));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
|
meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
|
||||||
const ClutterEvent *event)
|
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;
|
||||||
|
default:
|
||||||
|
return CLUTTER_EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
return CLUTTER_EVENT_STOP;
|
return CLUTTER_EVENT_STOP;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,17 @@ struct _MetaWaylandTabletTool
|
|||||||
ClutterInputDevice *device;
|
ClutterInputDevice *device;
|
||||||
ClutterInputDeviceTool *device_tool;
|
ClutterInputDeviceTool *device_tool;
|
||||||
struct wl_list resource_list;
|
struct wl_list resource_list;
|
||||||
|
struct wl_list focus_resource_list;
|
||||||
|
|
||||||
|
MetaWaylandSurface *focus_surface;
|
||||||
|
struct wl_listener focus_surface_destroy_listener;
|
||||||
|
|
||||||
|
MetaWaylandSurface *current;
|
||||||
|
guint32 pressed_buttons;
|
||||||
|
|
||||||
|
guint32 proximity_serial;
|
||||||
|
|
||||||
|
MetaWaylandTablet *current_tablet;
|
||||||
};
|
};
|
||||||
|
|
||||||
MetaWaylandTabletTool * meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
|
MetaWaylandTabletTool * meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
|
||||||
|
Loading…
Reference in New Issue
Block a user