Skip to content
Commits on Source (36)
3.36.4
======
* Fix crash on area screenshots with fractional scaling [Sebastian; !1320]
* Do not paint textures of fully obscured windows [Robert; !1326]
* Turn off CRTCs as well when enabling DPMS [Michel; !1240]
* Improve selection support
[Robert, Carlos, Sebastian; !1330, !1193, !1253, !1255, !1293, !1350]
* Use a more appropriate combine function on opaque areas [Daniel; !1331]
* Fix remote desktop being broken without screencast session [Olivier; #1307]
* Fix popovers disappearing on wayland and HiDPI [Robert; #1312]
* Fixed crashes [Jonas Å.; !1317]
* Plugged memory leaks [Jonas Å.; !1283]
* Misc. bug fixes and cleanups
[Corentin, Sebastian, Jonas Å., Jonas D.; !1314, !1321, !1295, !1333]
Contributors:
Jonas Dreßler, Michel Dänzer, Olivier Fourdan, Carlos Garnacho,
Sebastian Keller, Robert Mader, Corentin Noël, Daniel van Vugt, Jonas Ådahl
3.36.3
======
* Broadcast clipboard/primary offers [Carlos; !1262]
......
......@@ -475,8 +475,10 @@ get_preferred_size_for_orientation (ClutterBoxLayout *self,
ClutterActor *child;
gint n_children = 0;
gfloat minimum, natural;
float largest_min_size, largest_nat_size;
minimum = natural = 0;
largest_min_size = largest_nat_size = 0;
clutter_actor_iter_init (&iter, container);
while (clutter_actor_iter_next (&iter, &child))
......@@ -491,8 +493,22 @@ get_preferred_size_for_orientation (ClutterBoxLayout *self,
get_child_size (child, priv->orientation,
for_size, &child_min, &child_nat);
minimum += child_min;
natural += child_nat;
if (priv->is_homogeneous)
{
largest_min_size = MAX (largest_min_size, child_min);
largest_nat_size = MAX (largest_nat_size, child_nat);
}
else
{
minimum += child_min;
natural += child_nat;
}
}
if (priv->is_homogeneous)
{
minimum = largest_min_size * n_children;
natural = largest_nat_size * n_children;
}
if (n_children > 1)
......@@ -623,6 +639,8 @@ get_preferred_size_for_opposite_orientation (ClutterBoxLayout *self,
}
else
{
size -= (nvis_children - 1) * priv->spacing;
/* Bring children up to size first */
if (isnormal (size) || size == 0)
{
......
......@@ -24,7 +24,7 @@ typedef enum _ClutterPaintFlag
{
CLUTTER_PAINT_FLAG_NONE = 0,
CLUTTER_PAINT_FLAG_NO_CURSORS = 1 << 0,
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL = 1 << 0,
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL = 1 << 1,
} ClutterPaintFlag;
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view,
......
......@@ -4526,8 +4526,8 @@ clutter_stage_paint_to_buffer (ClutterStage *stage,
CoglFramebuffer *framebuffer;
CoglBitmap *bitmap;
texture_width = (int) ceilf (rect->width * scale);
texture_height = (int) ceilf (rect->height * scale);
texture_width = (int) roundf (rect->width * scale);
texture_height = (int) roundf (rect->height * scale);
texture = cogl_texture_2d_new_with_size (cogl_context,
texture_width,
texture_height);
......
project('mutter', 'c',
version: '3.36.3',
version: '3.36.4',
meson_version: '>= 0.50.0',
license: 'GPLv2+'
)
......
......@@ -273,14 +273,6 @@ meta_remote_desktop_session_check_can_notify (MetaRemoteDesktopSession *session,
return FALSE;
}
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return FALSE;
}
return TRUE;
}
......@@ -591,6 +583,15 @@ handle_notify_pointer_motion_absolute (MetaDBusRemoteDesktopSession *skeleton,
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
if (!stream)
......@@ -628,6 +629,14 @@ handle_notify_touch_down (MetaDBusRemoteDesktopSession *skeleton,
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
if (!stream)
......@@ -666,6 +675,15 @@ handle_notify_touch_motion (MetaDBusRemoteDesktopSession *skeleton,
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
if (!stream)
......
......@@ -232,14 +232,28 @@ meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
uint64_t state,
MetaKmsUpdate *kms_update)
{
MetaGpu *gpu = META_GPU (gpu_kms);
GList *l;
for (l = meta_gpu_get_outputs (META_GPU (gpu_kms)); l; l = l->next)
for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
{
MetaOutput *output = l->data;
meta_output_kms_set_power_save_mode (output, state, kms_update);
}
if (state != META_POWER_SAVE_ON)
{
/* Turn off CRTCs for DPMS */
for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
{
MetaCrtc *crtc = META_CRTC (l->data);
meta_kms_update_mode_set (kms_update,
meta_crtc_kms_get_kms_crtc (crtc),
NULL, NULL);
}
}
}
gboolean
......
......@@ -2146,6 +2146,7 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
case META_RENDERER_NATIVE_MODE_GBM:
{
CoglFramebuffer *dmabuf_fb;
CoglDmaBufHandle *dmabuf_handle;
struct gbm_bo *new_bo;
int dmabuf_fd = -1;
......@@ -2182,8 +2183,11 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
if (!dmabuf_fb)
return NULL;
return cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo,
(GDestroyNotify) gbm_bo_destroy);
dmabuf_handle =
cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo,
(GDestroyNotify) gbm_bo_destroy);
cogl_object_unref (dmabuf_fb);
return dmabuf_handle;
}
break;
#ifdef HAVE_EGL_DEVICE
......
......@@ -843,12 +843,16 @@ meta_stage_x11_translate_event (MetaStageX11 *stage_x11,
g_debug ("Client message for stage, win:0x%x",
(unsigned int) xevent->xany.window);
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS)
{
event->any.type = CLUTTER_DELETE;
event->any.stage = stage;
res = TRUE;
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
{
event->any.type = CLUTTER_DELETE;
event->any.stage = stage;
res = TRUE;
}
}
break;
default:
......
......@@ -66,4 +66,7 @@ gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
int meta_shaped_texture_get_width (MetaShapedTexture *stex);
int meta_shaped_texture_get_height (MetaShapedTexture *stex);
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region);
#endif
......@@ -87,6 +87,9 @@ struct _MetaShapedTexture
/* The region containing only fully opaque pixels */
cairo_region_t *opaque_region;
/* MetaCullable regions, see that documentation for more details */
cairo_region_t *clip_region;
gboolean size_invalid;
MetaMonitorTransform transform;
gboolean has_viewport_src_rect;
......@@ -214,6 +217,15 @@ ensure_size_valid (MetaShapedTexture *stex)
update_size (stex);
}
void
meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region)
{
g_clear_pointer (&stex->clip_region, cairo_region_destroy);
if (clip_region)
stex->clip_region = cairo_region_reference (clip_region);
}
static void
meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex)
{
......@@ -239,6 +251,7 @@ meta_shaped_texture_dispose (GObject *object)
meta_shaped_texture_reset_pipelines (stex);
g_clear_pointer (&stex->opaque_region, cairo_region_destroy);
g_clear_pointer (&stex->clip_region, cairo_region_destroy);
g_clear_pointer (&stex->snippet, cogl_object_unref);
......@@ -390,17 +403,14 @@ get_unblended_pipeline (MetaShapedTexture *stex,
CoglContext *ctx)
{
CoglPipeline *pipeline;
CoglColor color;
if (stex->unblended_pipeline)
return stex->unblended_pipeline;
pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
cogl_pipeline_set_blend (pipeline,
"RGBA = ADD (SRC_COLOR, 0)",
NULL);
cogl_pipeline_set_color (pipeline, &color);
cogl_pipeline_set_layer_combine (pipeline, 0,
"RGBA = REPLACE (TEXTURE)",
NULL);
stex->unblended_pipeline = pipeline;
......@@ -585,12 +595,19 @@ do_paint_content (MetaShapedTexture *stex,
if (use_opaque_region)
{
blended_tex_region = cairo_region_create_rectangle (&content_rect);
if (stex->clip_region)
blended_tex_region = cairo_region_copy (stex->clip_region);
else
blended_tex_region = cairo_region_create_rectangle (&content_rect);
cairo_region_subtract (blended_tex_region, stex->opaque_region);
}
else
{
blended_tex_region = NULL;
if (stex->clip_region)
blended_tex_region = cairo_region_reference (stex->clip_region);
else
blended_tex_region = NULL;
}
/* Limit to how many separate rectangles we'll draw; beyond this just
......@@ -612,10 +629,21 @@ do_paint_content (MetaShapedTexture *stex,
/* First, paint the unblended parts, which are part of the opaque region. */
if (use_opaque_region)
{
cairo_region_t *region;
int n_rects;
int i;
if (!cairo_region_is_empty (stex->opaque_region))
if (stex->clip_region)
{
region = cairo_region_copy (stex->clip_region);
cairo_region_intersect (region, stex->opaque_region);
}
else
{
region = cairo_region_reference (stex->opaque_region);
}
if (!cairo_region_is_empty (region))
{
CoglPipeline *opaque_pipeline;
......@@ -623,16 +651,18 @@ do_paint_content (MetaShapedTexture *stex,
cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
n_rects = cairo_region_num_rectangles (stex->opaque_region);
n_rects = cairo_region_num_rectangles (region);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (stex->opaque_region, i, &rect);
cairo_region_get_rectangle (region, i, &rect);
paint_clipped_rectangle_node (stex, root_node,
opaque_pipeline,
&rect, alloc);
}
}
cairo_region_destroy (region);
}
/* Now, go ahead and paint the blended parts. */
......@@ -757,6 +787,9 @@ meta_shaped_texture_paint_content (ClutterContent *content,
CoglTexture *paint_tex = NULL;
uint8_t opacity;
if (stex->clip_region && cairo_region_is_empty (stex->clip_region))
return;
/* The GL EXT_texture_from_pixmap extension does allow for it to be
* used together with SGIS_generate_mipmap, however this is very
* rarely supported. Also, even when it is supported there
......
......@@ -34,7 +34,6 @@ typedef struct _MetaSurfaceActorPrivate
cairo_region_t *input_region;
/* MetaCullable regions, see that documentation for more details */
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
/* Freeze/thaw accounting */
......@@ -58,6 +57,12 @@ enum
static guint signals[LAST_SIGNAL];
typedef enum
{
IN_STAGE_PERSPECTIVE,
IN_ACTOR_PERSPECTIVE
} ScalePerspectiveType;
static cairo_region_t *
effective_unobscured_region (MetaSurfaceActor *surface_actor)
{
......@@ -79,18 +84,39 @@ effective_unobscured_region (MetaSurfaceActor *surface_actor)
}
static cairo_region_t*
get_scaled_region (MetaSurfaceActor *surface_actor,
cairo_region_t *region)
get_scaled_region (MetaSurfaceActor *surface_actor,
cairo_region_t *region,
ScalePerspectiveType scale_perspective)
{
MetaWindowActor *window_actor;
cairo_region_t *scaled_region;
int geometry_scale;
float x, y;
window_actor = meta_window_actor_from_actor (CLUTTER_ACTOR (surface_actor));
geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
return meta_region_scale_double (region,
1.0 / geometry_scale,
META_ROUNDING_STRATEGY_GROW);
clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y);
cairo_region_translate (region, x, y);
switch (scale_perspective)
{
case IN_STAGE_PERSPECTIVE:
scaled_region = meta_region_scale_double (region,
geometry_scale,
META_ROUNDING_STRATEGY_GROW);
break;
case IN_ACTOR_PERSPECTIVE:
scaled_region = meta_region_scale_double (region,
1.0 / geometry_scale,
META_ROUNDING_STRATEGY_GROW);
break;
}
cairo_region_translate (region, -x, -y);
cairo_region_translate (scaled_region, -x, -y);
return scaled_region;
}
static void
......@@ -120,8 +146,9 @@ set_unobscured_region (MetaSurfaceActor *surface_actor,
.height = height,
};
priv->unobscured_region =
get_scaled_region (surface_actor, unobscured_region);
priv->unobscured_region = get_scaled_region (surface_actor,
unobscured_region,
IN_ACTOR_PERSPECTIVE);
cairo_region_intersect_rectangle (priv->unobscured_region, &bounds);
}
......@@ -134,30 +161,23 @@ set_clip_region (MetaSurfaceActor *surface_actor,
{
MetaSurfaceActorPrivate *priv =
meta_surface_actor_get_instance_private (surface_actor);
MetaShapedTexture *stex = priv->texture;
g_clear_pointer (&priv->clip_region, cairo_region_destroy);
if (clip_region)
if (clip_region && !cairo_region_is_empty (clip_region))
{
if (cairo_region_is_empty (clip_region))
priv->clip_region = cairo_region_reference (clip_region);
else
priv->clip_region = get_scaled_region (surface_actor, clip_region);
}
}
cairo_region_t *region;
static void
meta_surface_actor_paint (ClutterActor *actor,
ClutterPaintContext *paint_context)
{
MetaSurfaceActor *surface_actor = META_SURFACE_ACTOR (actor);
MetaSurfaceActorPrivate *priv =
meta_surface_actor_get_instance_private (surface_actor);
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
region = get_scaled_region (surface_actor,
clip_region,
IN_ACTOR_PERSPECTIVE);
meta_shaped_texture_set_clip_region (stex, region);
CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->paint (actor,
paint_context);
cairo_region_destroy (region);
}
else
{
meta_shaped_texture_set_clip_region (stex, clip_region);
}
}
static void
......@@ -227,7 +247,6 @@ meta_surface_actor_dispose (GObject *object)
g_clear_object (&priv->texture);
set_unobscured_region (self, NULL);
set_clip_region (self, NULL);
G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object);
}
......@@ -239,7 +258,6 @@ meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
object_class->dispose = meta_surface_actor_dispose;
actor_class->paint = meta_surface_actor_paint;
actor_class->pick = meta_surface_actor_pick;
actor_class->get_paint_volume = meta_surface_actor_get_paint_volume;
......@@ -279,11 +297,8 @@ meta_surface_actor_cull_out (MetaCullable *cullable,
if (opacity == 0xff)
{
MetaWindowActor *window_actor;
cairo_region_t *scaled_opaque_region;
cairo_region_t *opaque_region;
int geometry_scale;
float x, y;
cairo_region_t *scaled_opaque_region;
opaque_region = meta_shaped_texture_get_opaque_region (priv->texture);
if (opaque_region)
......@@ -306,14 +321,9 @@ meta_surface_actor_cull_out (MetaCullable *cullable,
return;
}
window_actor = meta_window_actor_from_actor (CLUTTER_ACTOR (surface_actor));
geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y);
cairo_region_translate (opaque_region, x, y);
scaled_opaque_region = meta_region_scale (opaque_region, geometry_scale);
cairo_region_translate (scaled_opaque_region, -x, -y);
cairo_region_translate (opaque_region, -x, -y);
scaled_opaque_region = get_scaled_region (surface_actor,
opaque_region,
IN_STAGE_PERSPECTIVE);
if (unobscured_region)
cairo_region_subtract (unobscured_region, scaled_opaque_region);
......
......@@ -1630,8 +1630,8 @@ meta_window_actor_x11_init (MetaWindowActorX11 *self)
self->shadow_factory = meta_shadow_factory_get_default ();
self->shadow_factory_changed_handler_id =
g_signal_connect (self->shadow_factory,
"changed",
G_CALLBACK (invalidate_shadow),
self);
g_signal_connect_swapped (self->shadow_factory,
"changed",
G_CALLBACK (invalidate_shadow),
self);
}
......@@ -152,6 +152,7 @@ owner_changed_cb (MetaSelection *selection,
display->saved_clipboard);
g_set_object (&display->selection_source, new_owner);
meta_selection_set_owner (selection, selection_type, new_owner);
g_object_unref (new_owner);
}
}
......@@ -170,6 +171,7 @@ meta_clipboard_manager_shutdown (MetaDisplay *display)
{
MetaSelection *selection;
g_clear_object (&display->selection_source);
g_clear_pointer (&display->saved_clipboard, g_bytes_unref);
g_clear_pointer (&display->saved_clipboard_mimetype, g_free);
selection = meta_display_get_selection (display);
......
......@@ -495,7 +495,22 @@ if have_wayland
'wayland/meta-wayland-cursor-surface.h',
'wayland/meta-wayland-data-device.c',
'wayland/meta-wayland-data-device.h',
'wayland/meta-wayland-data-device-private.h',
'wayland/meta-wayland-data-device-primary.c',
'wayland/meta-wayland-data-device-primary.h',
'wayland/meta-wayland-data-device-primary-legacy.c',
'wayland/meta-wayland-data-device-primary-legacy.h',
'wayland/meta-wayland-data-offer.c',
'wayland/meta-wayland-data-offer.h',
'wayland/meta-wayland-data-offer-primary.c',
'wayland/meta-wayland-data-offer-primary.h',
'wayland/meta-wayland-data-offer-primary-legacy.c',
'wayland/meta-wayland-data-offer-primary-legacy.h',
'wayland/meta-wayland-data-source.c',
'wayland/meta-wayland-data-source.h',
'wayland/meta-wayland-data-source-primary.c',
'wayland/meta-wayland-data-source-primary.h',
'wayland/meta-wayland-data-source-primary-legacy.c',
'wayland/meta-wayland-data-source-primary-legacy.h',
'wayland/meta-wayland-dma-buf.c',
'wayland/meta-wayland-dma-buf.h',
'wayland/meta-wayland-dnd-surface.c',
......@@ -790,6 +805,7 @@ if have_wayland
['linux-dmabuf', 'unstable', 'v1', ],
['pointer-constraints', 'unstable', 'v1', ],
['pointer-gestures', 'unstable', 'v1', ],
['primary-selection', 'unstable', 'v1', ],
['relative-pointer', 'unstable', 'v1', ],
['tablet', 'unstable', 'v2', ],
['text-input', 'unstable', 'v3', ],
......
......@@ -26,7 +26,6 @@
#include "meta/meta-selection-source.h"
#include "wayland/meta-wayland-data-device.h"
#include "wayland/meta-wayland-data-device-private.h"
#define META_TYPE_SELECTION_SOURCE_WAYLAND (meta_selection_source_wayland_get_type ())
......
/*
* Copyright © 2011 Kristian Høgsberg
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/* The file is based on src/data-device.c from Weston */
#include "config.h"
#include "wayland/meta-wayland-data-device-primary-legacy.h"
#include "compositor/meta-dnd-actor-private.h"
#include "meta/meta-selection-source-memory.h"
#include "wayland/meta-selection-source-wayland-private.h"
#include "wayland/meta-wayland-data-offer-primary-legacy.h"
#include "wayland/meta-wayland-data-source-primary-legacy.h"
#include "wayland/meta-wayland-dnd-surface.h"
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-seat.h"
#include "gtk-primary-selection-server-protocol.h"
static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevicePrimaryLegacy *data_device,
struct wl_resource *target);
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
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
static void
default_destructor (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
set_selection_source (MetaWaylandDataDevicePrimaryLegacy *data_device,
MetaSelectionSource *selection_source)
{
MetaDisplay *display = meta_get_display ();
meta_selection_set_owner (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
selection_source);
g_set_object (&data_device->owner, selection_source);
}
static void
unset_selection_source (MetaWaylandDataDevicePrimaryLegacy *data_device)
{
MetaDisplay *display = meta_get_display ();
if (!data_device->owner)
return;
meta_selection_unset_owner (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
data_device->owner);
g_clear_object (&data_device->owner);
}
static void
primary_source_destroyed (gpointer data,
GObject *object_was_here)
{
MetaWaylandDataDevicePrimaryLegacy *data_device = data;
data_device->data_source = NULL;
unset_selection_source (data_device);
}
static void
meta_wayland_data_device_primary_legacy_set_selection (MetaWaylandDataDevicePrimaryLegacy *data_device,
MetaWaylandDataSource *source,
uint32_t serial)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
MetaSelectionSource *selection_source;
g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY_LEGACY (source));
if (data_device->data_source &&
data_device->serial - serial < UINT32_MAX / 2)
return;
if (data_device->data_source)
{
g_object_weak_unref (G_OBJECT (data_device->data_source),
primary_source_destroyed,
data_device);
}
data_device->data_source = source;
data_device->serial = serial;
if (source)
{
meta_wayland_data_source_set_seat (source, seat);
g_object_weak_ref (G_OBJECT (source),
primary_source_destroyed,
data_device);
selection_source = meta_selection_source_wayland_new (source);
}
else
{
selection_source = g_object_new (META_TYPE_SELECTION_SOURCE_MEMORY, NULL);
}
set_selection_source (data_device, selection_source);
g_object_unref (selection_source);
}
static void
primary_device_set_selection (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *source_resource,
uint32_t serial)
{
MetaWaylandDataDevicePrimaryLegacy *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
MetaWaylandDataSource *source = NULL;
if (source_resource)
source = wl_resource_get_user_data (source_resource);
if (wl_resource_get_client (resource) !=
meta_wayland_keyboard_get_focus_client (seat->keyboard))
return;
meta_wayland_data_device_primary_legacy_set_selection (data_device, source, serial);
}
static const struct gtk_primary_selection_device_interface primary_device_interface = {
primary_device_set_selection,
default_destructor,
};
static void
owner_changed_cb (MetaSelection *selection,
MetaSelectionType selection_type,
MetaSelectionSource *new_owner,
MetaWaylandDataDevicePrimaryLegacy *data_device)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWaylandSeat *seat = compositor->seat;
struct wl_resource *data_device_resource;
struct wl_client *focus_client;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (!focus_client)
return;
if (selection_type == META_SELECTION_PRIMARY)
{
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer = NULL;
if (new_owner)
{
offer = create_and_send_primary_offer (data_device,
data_device_resource);
}
gtk_primary_selection_device_send_selection (data_device_resource,
offer);
}
}
}
static void
ensure_owners_changed_handler_connected (MetaWaylandDataDevicePrimaryLegacy *data_device)
{
if (data_device->selection_owner_signal_id != 0)
return;
data_device->selection_owner_signal_id =
g_signal_connect (meta_display_get_selection (meta_get_display ()),
"owner-changed",
G_CALLBACK (owner_changed_cb), data_device);
}
static void
primary_device_manager_create_source (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id)
{
struct wl_resource *source_resource;
source_resource =
wl_resource_create (client, &gtk_primary_selection_source_interface,
wl_resource_get_version (manager_resource),
id);
meta_wayland_data_source_primary_legacy_new (source_resource);
}
static void
primary_device_manager_get_device (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id,
struct wl_resource *seat_resource)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
struct wl_resource *cr;
cr = wl_resource_create (client, &gtk_primary_selection_device_interface,
wl_resource_get_version (manager_resource), id);
wl_resource_set_implementation (cr, &primary_device_interface,
&seat->primary_legacy_data_device, unbind_resource);
wl_list_insert (&seat->primary_legacy_data_device.resource_list,
wl_resource_get_link (cr));
ensure_owners_changed_handler_connected (&seat->primary_legacy_data_device);
}
static const struct gtk_primary_selection_device_manager_interface primary_manager_interface = {
primary_device_manager_create_source,
primary_device_manager_get_device,
default_destructor,
};
static void
bind_primary_manager (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &gtk_primary_selection_device_manager_interface,
version, id);
wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
}
void
meta_wayland_data_device_primary_legacy_manager_init (MetaWaylandCompositor *compositor)
{
if (wl_global_create (compositor->wayland_display,
&gtk_primary_selection_device_manager_interface,
1, NULL, bind_primary_manager) == NULL)
g_error ("Could not create data_device");
}
void
meta_wayland_data_device_primary_legacy_init (MetaWaylandDataDevicePrimaryLegacy *data_device)
{
wl_list_init (&data_device->resource_list);
wl_list_init (&data_device->focus_resource_list);
}
static struct wl_resource *
create_and_send_primary_offer (MetaWaylandDataDevicePrimaryLegacy *data_device,
struct wl_resource *target)
{
MetaWaylandDataOffer *offer;
MetaDisplay *display = meta_get_display ();
struct wl_resource *resource;
GList *mimetypes, *l;
mimetypes = meta_selection_get_mimetypes (meta_display_get_selection (display),
META_SELECTION_PRIMARY);
if (!mimetypes)
return NULL;
offer = meta_wayland_data_offer_primary_legacy_new (target);
resource = meta_wayland_data_offer_get_resource (offer);
gtk_primary_selection_device_send_data_offer (target, resource);
for (l = mimetypes; l; l = l->next)
gtk_primary_selection_offer_send_offer (resource, l->data);
g_list_free_full (mimetypes, g_free);
return resource;
}
void
meta_wayland_data_device_primary_legacy_set_keyboard_focus (MetaWaylandDataDevicePrimaryLegacy *data_device)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
struct wl_client *focus_client;
struct wl_resource *data_device_resource;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (focus_client == data_device->focus_client)
return;
data_device->focus_client = focus_client;
move_resources (&data_device->resource_list,
&data_device->focus_resource_list);
if (!focus_client)
return;
move_resources_for_client (&data_device->focus_resource_list,
&data_device->resource_list,
focus_client);
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer;
offer = create_and_send_primary_offer (data_device, data_device_resource);
gtk_primary_selection_device_send_selection (data_device_resource, offer);
}
}
/*
* Copyright © 2008 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_DEVICE_PRIMARY_LEGACY_H
#define META_WAYLAND_DATA_DEVICE_PRIMARY_LEGACY_H
#include <glib-object.h>
#include <wayland-server.h>
#include "clutter/clutter.h"
#include "meta/meta-selection-source.h"
#include "wayland/meta-wayland-data-offer.h"
#include "wayland/meta-wayland-data-source.h"
#include "wayland/meta-wayland-types.h"
struct _MetaWaylandDataDevicePrimaryLegacy
{
uint32_t serial;
MetaWaylandDataSource *data_source;
struct wl_list resource_list;
struct wl_list focus_resource_list;
struct wl_client *focus_client;
guint selection_owner_signal_id;
MetaSelectionSource *owner;
};
void meta_wayland_data_device_primary_legacy_manager_init (MetaWaylandCompositor *compositor);
void meta_wayland_data_device_primary_legacy_init (MetaWaylandDataDevicePrimaryLegacy *data_device);
void meta_wayland_data_device_primary_legacy_set_keyboard_focus (MetaWaylandDataDevicePrimaryLegacy *data_device);
#endif /* META_WAYLAND_DATA_DEVICE_PRIMARY_LEGACY_H */
/*
* Copyright © 2011 Kristian Høgsberg
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/* The file is based on src/data-device.c from Weston */
#include "config.h"
#include "wayland/meta-wayland-data-device-primary.h"
#include "compositor/meta-dnd-actor-private.h"
#include "meta/meta-selection-source-memory.h"
#include "wayland/meta-selection-source-wayland-private.h"
#include "wayland/meta-wayland-data-offer-primary.h"
#include "wayland/meta-wayland-data-source-primary.h"
#include "wayland/meta-wayland-dnd-surface.h"
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-seat.h"
#include "primary-selection-unstable-v1-server-protocol.h"
static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevicePrimary *data_device,
struct wl_resource *target);
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
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
static void
default_destructor (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
set_selection_source (MetaWaylandDataDevicePrimary *data_device,
MetaSelectionSource *selection_source)
{
MetaDisplay *display = meta_get_display ();
meta_selection_set_owner (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
selection_source);
g_set_object (&data_device->owner, selection_source);
}
static void
unset_selection_source (MetaWaylandDataDevicePrimary *data_device)
{
MetaDisplay *display = meta_get_display ();
if (!data_device->owner)
return;
meta_selection_unset_owner (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
data_device->owner);
g_clear_object (&data_device->owner);
}
static void
primary_source_destroyed (gpointer data,
GObject *object_was_here)
{
MetaWaylandDataDevicePrimary *data_device = data;
data_device->data_source = NULL;
unset_selection_source (data_device);
}
static void
meta_wayland_data_device_primary_set_selection (MetaWaylandDataDevicePrimary *data_device,
MetaWaylandDataSource *source,
uint32_t serial)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_data_device);
MetaSelectionSource *selection_source;
g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY (source));
if (data_device->data_source &&
data_device->serial - serial < UINT32_MAX / 2)
return;
if (data_device->data_source)
{
g_object_weak_unref (G_OBJECT (data_device->data_source),
primary_source_destroyed,
data_device);
}
data_device->data_source = source;
data_device->serial = serial;
if (source)
{
meta_wayland_data_source_set_seat (source, seat);
g_object_weak_ref (G_OBJECT (source),
primary_source_destroyed,
data_device);
selection_source = meta_selection_source_wayland_new (source);
}
else
{
selection_source = g_object_new (META_TYPE_SELECTION_SOURCE_MEMORY, NULL);
}
set_selection_source (data_device, selection_source);
g_object_unref (selection_source);
}
static void
primary_device_set_selection (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *source_resource,
uint32_t serial)
{
MetaWaylandDataDevicePrimary *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_data_device);
MetaWaylandDataSource *source = NULL;
if (source_resource)
source = wl_resource_get_user_data (source_resource);
if (wl_resource_get_client (resource) !=
meta_wayland_keyboard_get_focus_client (seat->keyboard))
return;
meta_wayland_data_device_primary_set_selection (data_device, source, serial);
}
static const struct zwp_primary_selection_device_v1_interface primary_device_interface = {
primary_device_set_selection,
default_destructor,
};
static void
owner_changed_cb (MetaSelection *selection,
MetaSelectionType selection_type,
MetaSelectionSource *new_owner,
MetaWaylandDataDevicePrimary *data_device)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWaylandSeat *seat = compositor->seat;
struct wl_resource *data_device_resource;
struct wl_client *focus_client;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (!focus_client)
return;
if (selection_type == META_SELECTION_PRIMARY)
{
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer = NULL;
if (new_owner)
{
offer = create_and_send_primary_offer (data_device,
data_device_resource);
}
zwp_primary_selection_device_v1_send_selection (data_device_resource,
offer);
}
}
}
static void
ensure_owners_changed_handler_connected (MetaWaylandDataDevicePrimary *data_device)
{
if (data_device->selection_owner_signal_id != 0)
return;
data_device->selection_owner_signal_id =
g_signal_connect (meta_display_get_selection (meta_get_display ()),
"owner-changed",
G_CALLBACK (owner_changed_cb), data_device);
}
static void
primary_device_manager_create_source (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id)
{
struct wl_resource *source_resource;
source_resource =
wl_resource_create (client, &zwp_primary_selection_source_v1_interface,
wl_resource_get_version (manager_resource),
id);
meta_wayland_data_source_primary_new (source_resource);
}
static void
primary_device_manager_get_device (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id,
struct wl_resource *seat_resource)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
struct wl_resource *cr;
cr = wl_resource_create (client, &zwp_primary_selection_device_v1_interface,
wl_resource_get_version (manager_resource), id);
wl_resource_set_implementation (cr, &primary_device_interface,
&seat->primary_data_device, unbind_resource);
wl_list_insert (&seat->primary_data_device.resource_list, wl_resource_get_link (cr));
ensure_owners_changed_handler_connected (&seat->primary_data_device);
}
static const struct zwp_primary_selection_device_manager_v1_interface primary_manager_interface = {
primary_device_manager_create_source,
primary_device_manager_get_device,
default_destructor,
};
static void
bind_primary_manager (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_primary_selection_device_manager_v1_interface,
version, id);
wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
}
void
meta_wayland_data_device_primary_manager_init (MetaWaylandCompositor *compositor)
{
if (wl_global_create (compositor->wayland_display,
&zwp_primary_selection_device_manager_v1_interface,
1, NULL, bind_primary_manager) == NULL)
g_error ("Could not create data_device");
}
void
meta_wayland_data_device_primary_init (MetaWaylandDataDevicePrimary *data_device)
{
wl_list_init (&data_device->resource_list);
wl_list_init (&data_device->focus_resource_list);
}
static struct wl_resource *
create_and_send_primary_offer (MetaWaylandDataDevicePrimary *data_device,
struct wl_resource *target)
{
MetaWaylandDataOffer *offer;
MetaDisplay *display = meta_get_display ();
struct wl_resource *resource;
GList *mimetypes, *l;
mimetypes = meta_selection_get_mimetypes (meta_display_get_selection (display),
META_SELECTION_PRIMARY);
if (!mimetypes)
return NULL;
offer = meta_wayland_data_offer_primary_new (target);
resource = meta_wayland_data_offer_get_resource (offer);
zwp_primary_selection_device_v1_send_data_offer (target, resource);
for (l = mimetypes; l; l = l->next)
zwp_primary_selection_offer_v1_send_offer (resource, l->data);
g_list_free_full (mimetypes, g_free);
return resource;
}
void
meta_wayland_data_device_primary_set_keyboard_focus (MetaWaylandDataDevicePrimary *data_device)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_data_device);
struct wl_client *focus_client;
struct wl_resource *data_device_resource;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (focus_client == data_device->focus_client)
return;
data_device->focus_client = focus_client;
move_resources (&data_device->resource_list,
&data_device->focus_resource_list);
if (!focus_client)
return;
move_resources_for_client (&data_device->focus_resource_list,
&data_device->resource_list,
focus_client);
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer;
offer = create_and_send_primary_offer (data_device, data_device_resource);
zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
}
}
/*
* Copyright © 2008 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_DEVICE_PRIMARY_H
#define META_WAYLAND_DATA_DEVICE_PRIMARY_H
#include <glib-object.h>
#include <wayland-server.h>
#include "clutter/clutter.h"
#include "meta/meta-selection-source.h"
#include "wayland/meta-wayland-data-offer.h"
#include "wayland/meta-wayland-data-source.h"
#include "wayland/meta-wayland-types.h"
struct _MetaWaylandDataDevicePrimary
{
uint32_t serial;
MetaWaylandDataSource *data_source;
struct wl_list resource_list;
struct wl_list focus_resource_list;
struct wl_client *focus_client;
guint selection_owner_signal_id;
MetaSelectionSource *owner;
};
void meta_wayland_data_device_primary_manager_init (MetaWaylandCompositor *compositor);
void meta_wayland_data_device_primary_init (MetaWaylandDataDevicePrimary *data_device);
void meta_wayland_data_device_primary_set_keyboard_focus (MetaWaylandDataDevicePrimary *data_device);
#endif /* META_WAYLAND_DATA_DEVICE_PRIMARY_H */