diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 100b804597baf168d2917aee4af50a467c015835..c11bb4cb6656d6f7e24b7e0a3d32df8bf34de528 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -635,6 +635,7 @@ #include "clutter-interval.h" #include "clutter-main.h" #include "clutter-marshal.h" +#include "clutter-mutter.h" #include "clutter-paint-nodes.h" #include "clutter-paint-node-private.h" #include "clutter-paint-volume-private.h" @@ -16467,6 +16468,12 @@ clutter_actor_is_in_clone_paint (ClutterActor *self) return FALSE; } +gboolean +clutter_actor_has_damage (ClutterActor *actor) +{ + return actor->priv->is_dirty; +} + static gboolean set_direction_recursive (ClutterActor *actor, gpointer user_data) diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h index d5d0340ff74430f38586d200f9558369619d0ff3..788757140a62ef5b6f3e3ce6eca8c8cca92b0bb4 100644 --- a/clutter/clutter/clutter-mutter.h +++ b/clutter/clutter/clutter-mutter.h @@ -49,6 +49,9 @@ void clutter_stage_freeze_updates (ClutterStage *stage); CLUTTER_EXPORT void clutter_stage_thaw_updates (ClutterStage *stage); +CLUTTER_EXPORT +gboolean clutter_actor_has_damage (ClutterActor *actor); + #undef __CLUTTER_H_INSIDE__ #endif /* __CLUTTER_MUTTER_H__ */ diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c index 036c573a577c4eec089c1831d182ddcfd5991ae0..cb9823148ce95bd0c0c8db362dd944854332d6ba 100644 --- a/src/backends/meta-screen-cast-monitor-stream-src.c +++ b/src/backends/meta-screen-cast-monitor-stream-src.c @@ -344,64 +344,6 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src, return TRUE; } -static gboolean -draw_cursor_sprite_via_offscreen (MetaScreenCastMonitorStreamSrc *monitor_src, - CoglTexture *cursor_texture, - int bitmap_width, - int bitmap_height, - uint32_t *bitmap_data, - GError **error) -{ - MetaBackend *backend = get_backend (monitor_src); - ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); - CoglContext *cogl_context = - clutter_backend_get_cogl_context (clutter_backend); - CoglTexture2D *bitmap_texture; - CoglOffscreen *offscreen; - CoglFramebuffer *fb; - CoglPipeline *pipeline; - CoglColor clear_color; - - bitmap_texture = cogl_texture_2d_new_with_size (cogl_context, - bitmap_width, bitmap_height); - cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (bitmap_texture), - FALSE); - if (!cogl_texture_allocate (COGL_TEXTURE (bitmap_texture), error)) - { - cogl_object_unref (bitmap_texture); - return FALSE; - } - - offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (bitmap_texture)); - fb = COGL_FRAMEBUFFER (offscreen); - cogl_object_unref (bitmap_texture); - if (!cogl_framebuffer_allocate (fb, error)) - { - cogl_object_unref (fb); - return FALSE; - } - - pipeline = cogl_pipeline_new (cogl_context); - cogl_pipeline_set_layer_texture (pipeline, 0, cursor_texture); - cogl_pipeline_set_layer_filters (pipeline, 0, - COGL_PIPELINE_FILTER_LINEAR, - COGL_PIPELINE_FILTER_LINEAR); - cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); - cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color); - cogl_framebuffer_draw_rectangle (fb, pipeline, - -1, 1, 1, -1); - cogl_object_unref (pipeline); - - cogl_framebuffer_read_pixels (fb, - 0, 0, - bitmap_width, bitmap_height, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, - (uint8_t *) bitmap_data); - cogl_object_unref (fb); - - return TRUE; -} - static void meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, struct spa_meta_cursor *spa_meta_cursor) @@ -412,10 +354,7 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc MetaCursorRenderer *cursor_renderer = meta_backend_get_cursor_renderer (backend); MetaRenderer *renderer = meta_backend_get_renderer (backend); - MetaSpaType *spa_type = meta_screen_cast_stream_src_get_spa_type (src); - GError *error = NULL; MetaCursorSprite *cursor_sprite; - CoglTexture *cursor_texture; MetaMonitor *monitor; MetaLogicalMonitor *logical_monitor; MetaRectangle logical_monitor_layout; @@ -423,17 +362,14 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc MetaRendererView *view; float view_scale; ClutterPoint cursor_position; - struct spa_meta_bitmap *spa_meta_bitmap; + int x, y; cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); - if (cursor_sprite) - cursor_texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); - else - cursor_texture = NULL; if (!is_cursor_in_stream (monitor_src)) { - spa_meta_cursor->id = 0; + meta_screen_cast_stream_src_unset_cursor_metadata (src, + spa_meta_cursor); return; } @@ -456,86 +392,38 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc cursor_position.x *= view_scale; cursor_position.y *= view_scale; - spa_meta_cursor->id = 1; - spa_meta_cursor->position.x = (int32_t) roundf (cursor_position.x); - spa_meta_cursor->position.y = (int32_t) roundf (cursor_position.y); + x = (int) roundf (cursor_position.x); + y = (int) roundf (cursor_position.y); - if (!monitor_src->cursor_bitmap_invalid) + if (monitor_src->cursor_bitmap_invalid) { - spa_meta_cursor->hotspot.x = 0; - spa_meta_cursor->hotspot.y = 0; - spa_meta_cursor->bitmap_offset = 0; - return; - } - monitor_src->cursor_bitmap_invalid = FALSE; - - spa_meta_cursor->bitmap_offset = sizeof (struct spa_meta_cursor); - - spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor, - spa_meta_cursor->bitmap_offset, - struct spa_meta_bitmap); - spa_meta_bitmap->format = spa_type->video_format.RGBA; - spa_meta_bitmap->offset = sizeof (struct spa_meta_bitmap); - - if (cursor_texture) - { - float cursor_scale; - float bitmap_scale; - int hotspot_x, hotspot_y; - int texture_width, texture_height; - int bitmap_width, bitmap_height; - uint32_t *bitmap_data; - - cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); - bitmap_scale = view_scale * cursor_scale; - - meta_cursor_sprite_get_hotspot (cursor_sprite, &hotspot_x, &hotspot_y); - spa_meta_cursor->hotspot.x = (int32_t) roundf (hotspot_x * bitmap_scale); - spa_meta_cursor->hotspot.y = (int32_t) roundf (hotspot_y * bitmap_scale); - - texture_width = cogl_texture_get_width (cursor_texture); - texture_height = cogl_texture_get_height (cursor_texture); - bitmap_width = texture_width * bitmap_scale; - bitmap_height = texture_height * bitmap_scale; - - spa_meta_bitmap->size.width = bitmap_width; - spa_meta_bitmap->size.height = bitmap_height; - spa_meta_bitmap->stride = bitmap_width * 4; - - bitmap_data = SPA_MEMBER (spa_meta_bitmap, - spa_meta_bitmap->offset, - uint32_t); - - if (texture_width == bitmap_width && - texture_height == bitmap_height) + if (cursor_sprite) { - cogl_texture_get_data (cursor_texture, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, - texture_width * 4, - (uint8_t *) bitmap_data); + float cursor_scale; + float scale; + + cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); + scale = view_scale * cursor_scale; + meta_screen_cast_stream_src_set_cursor_sprite_metadata (src, + spa_meta_cursor, + cursor_sprite, + x, y, + scale); } else { - if (!draw_cursor_sprite_via_offscreen (monitor_src, - cursor_texture, - bitmap_width, - bitmap_height, - bitmap_data, - &error)) - { - g_warning ("Failed to draw cursor via offscreen: %s", - error->message); - g_error_free (error); - spa_meta_cursor->id = 0; - } + meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (src, + spa_meta_cursor, + x, y); } + + monitor_src->cursor_bitmap_invalid = FALSE; } else { - spa_meta_cursor->hotspot.x = 0; - spa_meta_cursor->hotspot.y = 0; - - *spa_meta_bitmap = (struct spa_meta_bitmap) { 0 }; + meta_screen_cast_stream_src_set_cursor_position_metadata (src, + spa_meta_cursor, + x, y); } } diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c index 130bd17c97293704e91bf480dacf735185bea781..a9b861e8df9ac3b90803597cf4a403e41e9034e8 100644 --- a/src/backends/meta-screen-cast-session.c +++ b/src/backends/meta-screen-cast-session.c @@ -383,6 +383,7 @@ handle_record_window (MetaDBusScreenCastSession *skeleton, GDBusInterfaceSkeleton *interface_skeleton; GDBusConnection *connection; MetaWindow *window; + MetaScreenCastCursorMode cursor_mode; GError *error = NULL; MetaDisplay *display; GVariant *window_id_variant = NULL; @@ -424,12 +425,28 @@ handle_record_window (MetaDBusScreenCastSession *skeleton, return TRUE; } + if (!g_variant_lookup (properties_variant, "cursor-mode", "u", &cursor_mode)) + { + cursor_mode = META_SCREEN_CAST_CURSOR_MODE_HIDDEN; + } + else + { + if (!is_valid_cursor_mode (cursor_mode)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "Unknown cursor mode"); + return TRUE; + } + } + interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton); connection = g_dbus_interface_skeleton_get_connection (interface_skeleton); window_stream = meta_screen_cast_window_stream_new (session, connection, window, + cursor_mode, &error); if (!window_stream) { diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c index 7e11bd067269702b808a72bd239e3277417280c0..82c5cba4362f662aea666e9ce892e5b5e31eb162 100644 --- a/src/backends/meta-screen-cast-stream-src.c +++ b/src/backends/meta-screen-cast-stream-src.c @@ -32,6 +32,7 @@ #include #include +#include "backends/meta-screen-cast-session.h" #include "backends/meta-screen-cast-stream.h" #include "clutter/clutter-mutter.h" #include "core/meta-fraction.h" @@ -61,6 +62,15 @@ enum static guint signals[N_SIGNALS]; +typedef struct _MetaSpaType +{ + struct spa_type_media_type media_type; + struct spa_type_media_subtype media_subtype; + struct spa_type_format_video format_video; + struct spa_type_video_format video_format; + uint32_t meta_cursor; +} MetaSpaType; + typedef struct _MetaPipeWireSource { GSource base; @@ -150,13 +160,222 @@ meta_screen_cast_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, klass->set_cursor_metadata (src, spa_meta_cursor); } -MetaSpaType * -meta_screen_cast_stream_src_get_spa_type (MetaScreenCastStreamSrc *src) +static gboolean +draw_cursor_sprite_via_offscreen (MetaScreenCastStreamSrc *src, + CoglTexture *cursor_texture, + int bitmap_width, + int bitmap_height, + uint8_t *bitmap_data, + GError **error) +{ + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream); + MetaScreenCast *screen_cast = + meta_screen_cast_session_get_screen_cast (session); + MetaBackend *backend = meta_screen_cast_get_backend (screen_cast); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + CoglContext *cogl_context = + clutter_backend_get_cogl_context (clutter_backend); + CoglTexture2D *bitmap_texture; + CoglOffscreen *offscreen; + CoglFramebuffer *fb; + CoglPipeline *pipeline; + CoglColor clear_color; + + bitmap_texture = cogl_texture_2d_new_with_size (cogl_context, + bitmap_width, bitmap_height); + cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (bitmap_texture), + FALSE); + if (!cogl_texture_allocate (COGL_TEXTURE (bitmap_texture), error)) + { + cogl_object_unref (bitmap_texture); + return FALSE; + } + + offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (bitmap_texture)); + fb = COGL_FRAMEBUFFER (offscreen); + cogl_object_unref (bitmap_texture); + if (!cogl_framebuffer_allocate (fb, error)) + { + cogl_object_unref (fb); + return FALSE; + } + + pipeline = cogl_pipeline_new (cogl_context); + cogl_pipeline_set_layer_texture (pipeline, 0, cursor_texture); + cogl_pipeline_set_layer_filters (pipeline, 0, + COGL_PIPELINE_FILTER_LINEAR, + COGL_PIPELINE_FILTER_LINEAR); + cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); + cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color); + cogl_framebuffer_draw_rectangle (fb, pipeline, + -1, 1, 1, -1); + cogl_object_unref (pipeline); + + cogl_framebuffer_read_pixels (fb, + 0, 0, + bitmap_width, bitmap_height, + COGL_PIXEL_FORMAT_RGBA_8888_PRE, + bitmap_data); + cogl_object_unref (fb); + + return TRUE; +} + +gboolean +meta_screen_cast_stream_src_draw_cursor_into (MetaScreenCastStreamSrc *src, + CoglTexture *cursor_texture, + float scale, + uint8_t *data, + GError **error) +{ + int texture_width, texture_height; + int width, height; + + texture_width = cogl_texture_get_width (cursor_texture); + texture_height = cogl_texture_get_height (cursor_texture); + width = texture_width * scale; + height = texture_height * scale; + + if (texture_width == width && + texture_height == height) + { + cogl_texture_get_data (cursor_texture, + COGL_PIXEL_FORMAT_RGBA_8888_PRE, + texture_width * 4, + data); + } + else + { + if (!draw_cursor_sprite_via_offscreen (src, + cursor_texture, + width, + height, + data, + error)) + return FALSE; + } + + return TRUE; +} + +void +meta_screen_cast_stream_src_unset_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +{ + spa_meta_cursor->id = 1; +} + +void +meta_screen_cast_stream_src_set_cursor_position_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor, + int x, + int y) +{ + spa_meta_cursor->id = 1; + spa_meta_cursor->position.x = x; + spa_meta_cursor->position.y = y; + spa_meta_cursor->hotspot.x = 0; + spa_meta_cursor->hotspot.y = 0; + spa_meta_cursor->bitmap_offset = 0; +} + +void +meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor, + int x, + int y) +{ + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); + MetaSpaType *spa_type = &priv->spa_type; + struct spa_meta_bitmap *spa_meta_bitmap; + + spa_meta_cursor->id = 1; + spa_meta_cursor->position.x = x; + spa_meta_cursor->position.y = y; + + spa_meta_cursor->bitmap_offset = sizeof (struct spa_meta_cursor); + + spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor, + spa_meta_cursor->bitmap_offset, + struct spa_meta_bitmap); + spa_meta_bitmap->format = spa_type->video_format.RGBA; + spa_meta_bitmap->offset = sizeof (struct spa_meta_bitmap); + + spa_meta_cursor->hotspot.x = 0; + spa_meta_cursor->hotspot.y = 0; + + *spa_meta_bitmap = (struct spa_meta_bitmap) { 0 }; +} + +void +meta_screen_cast_stream_src_set_cursor_sprite_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor, + MetaCursorSprite *cursor_sprite, + int x, + int y, + float scale) { MetaScreenCastStreamSrcPrivate *priv = meta_screen_cast_stream_src_get_instance_private (src); + MetaSpaType *spa_type = &priv->spa_type; + CoglTexture *cursor_texture; + struct spa_meta_bitmap *spa_meta_bitmap; + int hotspot_x, hotspot_y; + int texture_width, texture_height; + int bitmap_width, bitmap_height; + uint8_t *bitmap_data; + GError *error = NULL; + + cursor_texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); + if (!cursor_texture) + { + meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (src, + spa_meta_cursor, + x, y); + return; + } + + spa_meta_cursor->id = 1; + spa_meta_cursor->position.x = x; + spa_meta_cursor->position.y = y; - return &priv->spa_type; + spa_meta_cursor->bitmap_offset = sizeof (struct spa_meta_cursor); + + spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor, + spa_meta_cursor->bitmap_offset, + struct spa_meta_bitmap); + spa_meta_bitmap->format = spa_type->video_format.RGBA; + spa_meta_bitmap->offset = sizeof (struct spa_meta_bitmap); + + meta_cursor_sprite_get_hotspot (cursor_sprite, &hotspot_x, &hotspot_y); + spa_meta_cursor->hotspot.x = (int32_t) roundf (hotspot_x * scale); + spa_meta_cursor->hotspot.y = (int32_t) roundf (hotspot_y * scale); + + texture_width = cogl_texture_get_width (cursor_texture); + texture_height = cogl_texture_get_height (cursor_texture); + bitmap_width = texture_width * scale; + bitmap_height = texture_height * scale; + + spa_meta_bitmap->size.width = bitmap_width; + spa_meta_bitmap->size.height = bitmap_height; + spa_meta_bitmap->stride = bitmap_width * 4; + + bitmap_data = SPA_MEMBER (spa_meta_bitmap, + spa_meta_bitmap->offset, + uint8_t); + + if (!meta_screen_cast_stream_src_draw_cursor_into (src, + cursor_texture, + scale, + bitmap_data, + &error)) + { + g_warning ("Failed to draw cursor: %s", error->message); + g_error_free (error); + spa_meta_cursor->id = 0; + } } static void diff --git a/src/backends/meta-screen-cast-stream-src.h b/src/backends/meta-screen-cast-stream-src.h index f2f96f2130fbc71e864a415e611affe567c97ab3..fc0e5bc7714e81c6f51ac2372584faaead8b39a4 100644 --- a/src/backends/meta-screen-cast-stream-src.h +++ b/src/backends/meta-screen-cast-stream-src.h @@ -35,15 +35,6 @@ #include "cogl/cogl.h" #include "meta/boxes.h" -typedef struct _MetaSpaType -{ - struct spa_type_media_type media_type; - struct spa_type_media_subtype media_subtype; - struct spa_type_format_video format_video; - struct spa_type_video_format video_format; - uint32_t meta_cursor; -} MetaSpaType; - typedef struct _MetaScreenCastStream MetaScreenCastStream; #define META_TYPE_SCREEN_CAST_STREAM_SRC (meta_screen_cast_stream_src_get_type ()) @@ -74,6 +65,30 @@ void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *sr MetaScreenCastStream * meta_screen_cast_stream_src_get_stream (MetaScreenCastStreamSrc *src); -MetaSpaType * meta_screen_cast_stream_src_get_spa_type (MetaScreenCastStreamSrc *src); +gboolean meta_screen_cast_stream_src_draw_cursor_into (MetaScreenCastStreamSrc *src, + CoglTexture *cursor_texture, + float scale, + uint8_t *data, + GError **error); + +void meta_screen_cast_stream_src_unset_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor); + +void meta_screen_cast_stream_src_set_cursor_position_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor, + int x, + int y); + +void meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor, + int x, + int y); + +void meta_screen_cast_stream_src_set_cursor_sprite_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor, + MetaCursorSprite *cursor_sprite, + int x, + int y, + float scale); #endif /* META_SCREEN_CAST_STREAM_SRC_H */ diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c index 32df9f1275c3710c287bdbe4fc46e51c45cd42fc..dbf330420e87abc7e91cf8a7316343372771bc26 100644 --- a/src/backends/meta-screen-cast-window-stream-src.c +++ b/src/backends/meta-screen-cast-window-stream-src.c @@ -23,6 +23,7 @@ #include "backends/meta-screen-cast-window-stream-src.h" #include "backends/meta-backend-private.h" +#include "backends/meta-screen-cast-session.h" #include "backends/meta-screen-cast-window.h" #include "backends/meta-screen-cast-window-stream.h" #include "compositor/meta-window-actor-private.h" @@ -31,16 +32,34 @@ struct _MetaScreenCastWindowStreamSrc { MetaScreenCastStreamSrc parent; - MetaWindowActor *window_actor; + MetaScreenCastWindow *screen_cast_window; + + unsigned long screen_cast_window_before_paint_handler_id; + unsigned long screen_cast_window_after_paint_handler_id; + unsigned long screen_cast_window_destroyed_handler_id; + unsigned long cursor_moved_handler_id; + unsigned long cursor_changed_handler_id; - unsigned long actor_painted_handler_id; - unsigned long actor_destroyed_handler_id; + gboolean actor_was_dirty; + gboolean cursor_bitmap_invalid; }; G_DEFINE_TYPE (MetaScreenCastWindowStreamSrc, meta_screen_cast_window_stream_src, META_TYPE_SCREEN_CAST_STREAM_SRC) +static MetaBackend * +get_backend (MetaScreenCastWindowStreamSrc *window_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream); + MetaScreenCast *screen_cast = + meta_screen_cast_session_get_screen_cast (session); + + return meta_screen_cast_get_backend (screen_cast); +} + static MetaScreenCastWindowStream * get_window_stream (MetaScreenCastWindowStreamSrc *window_src) { @@ -83,20 +102,110 @@ get_stream_height (MetaScreenCastWindowStreamSrc *window_src) return meta_screen_cast_window_stream_get_height (window_stream); } +static void +maybe_draw_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src, + uint8_t *data, + MetaRectangle *stream_rect) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src); + MetaBackend *backend = get_backend (window_src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + MetaCursorSprite *cursor_sprite; + CoglTexture *cursor_texture; + MetaScreenCastWindow *screen_cast_window; + ClutterPoint cursor_position; + ClutterPoint relative_cursor_position; + cairo_surface_t *cursor_surface; + uint8_t *cursor_surface_data; + GError *error = NULL; + cairo_surface_t *stream_surface; + int width, height; + float scale; + int hotspot_x, hotspot_y; + cairo_t *cr; + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + if (!cursor_sprite) + return; + + cursor_texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); + if (!cursor_texture) + return; + + screen_cast_window = window_src->screen_cast_window; + cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + if (!meta_screen_cast_window_transform_cursor_position (screen_cast_window, + cursor_sprite, + &cursor_position, + &scale, + &relative_cursor_position)) + return; + + meta_cursor_sprite_get_hotspot (cursor_sprite, &hotspot_x, &hotspot_y); + + width = cogl_texture_get_width (cursor_texture) * scale; + height = cogl_texture_get_height (cursor_texture) * scale; + cursor_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + + cursor_surface_data = cairo_image_surface_get_data (cursor_surface); + if (!meta_screen_cast_stream_src_draw_cursor_into (src, + cursor_texture, + scale, + cursor_surface_data, + &error)) + { + g_warning ("Failed to draw cursor: %s", error->message); + g_error_free (error); + cairo_surface_destroy (cursor_surface); + return; + } + + stream_surface = + cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, + stream_rect->width, + stream_rect->height, + stream_rect->width * 4); + + cr = cairo_create (stream_surface); + cairo_surface_mark_dirty (cursor_surface); + cairo_surface_flush (cursor_surface); + cairo_set_source_surface (cr, cursor_surface, + relative_cursor_position.x - hotspot_x * scale, + relative_cursor_position.y - hotspot_y * scale); + cairo_paint (cr); + cairo_destroy (cr); + cairo_surface_destroy (stream_surface); + cairo_surface_destroy (cursor_surface); +} + static gboolean capture_into (MetaScreenCastWindowStreamSrc *window_src, uint8_t *data) { + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src); MetaRectangle stream_rect; - MetaScreenCastWindow *screen_cast_window; + MetaScreenCastStream *stream; stream_rect.x = 0; stream_rect.y = 0; stream_rect.width = get_stream_width (window_src); stream_rect.height = get_stream_height (window_src); - screen_cast_window = META_SCREEN_CAST_WINDOW (window_src->window_actor); - meta_screen_cast_window_capture_into (screen_cast_window, &stream_rect, data); + meta_screen_cast_window_capture_into (window_src->screen_cast_window, + &stream_rect, data); + + stream = meta_screen_cast_stream_src_get_stream (src); + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + maybe_draw_cursor_sprite (window_src, data, &stream_rect); + break; + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + break; + } return TRUE; } @@ -121,11 +230,10 @@ meta_screen_cast_window_stream_src_get_videocrop (MetaScreenCastStreamSrc *src, { MetaScreenCastWindowStreamSrc *window_src = META_SCREEN_CAST_WINDOW_STREAM_SRC (src); - MetaScreenCastWindow *screen_cast_window; MetaRectangle stream_rect; - screen_cast_window = META_SCREEN_CAST_WINDOW (window_src->window_actor); - meta_screen_cast_window_get_frame_bounds (screen_cast_window, crop_rect); + meta_screen_cast_window_get_frame_bounds (window_src->screen_cast_window, + crop_rect); stream_rect.x = 0; stream_rect.y = 0; @@ -141,35 +249,117 @@ static void meta_screen_cast_window_stream_src_stop (MetaScreenCastWindowStreamSrc *window_src) { - if (!window_src->window_actor) + MetaBackend *backend = get_backend (window_src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); + + if (!window_src->screen_cast_window) return; - if (window_src->actor_painted_handler_id) - g_signal_handler_disconnect (window_src->window_actor, - window_src->actor_painted_handler_id); - window_src->actor_painted_handler_id = 0; + if (window_src->screen_cast_window_before_paint_handler_id) + g_signal_handler_disconnect (window_src->screen_cast_window, + window_src->screen_cast_window_before_paint_handler_id); + window_src->screen_cast_window_before_paint_handler_id = 0; + + if (window_src->screen_cast_window_after_paint_handler_id) + g_signal_handler_disconnect (window_src->screen_cast_window, + window_src->screen_cast_window_after_paint_handler_id); + window_src->screen_cast_window_after_paint_handler_id = 0; + + if (window_src->screen_cast_window_destroyed_handler_id) + g_signal_handler_disconnect (window_src->screen_cast_window, + window_src->screen_cast_window_destroyed_handler_id); + window_src->screen_cast_window_destroyed_handler_id = 0; + + if (window_src->cursor_moved_handler_id) + g_signal_handler_disconnect (cursor_tracker, + window_src->cursor_moved_handler_id); + window_src->cursor_moved_handler_id = 0; + + if (window_src->cursor_changed_handler_id) + g_signal_handler_disconnect (cursor_tracker, + window_src->cursor_changed_handler_id); + window_src->cursor_changed_handler_id = 0; +} - if (window_src->actor_destroyed_handler_id) - g_signal_handler_disconnect (window_src->window_actor, - window_src->actor_destroyed_handler_id); - window_src->actor_destroyed_handler_id = 0; +static void +screen_cast_window_before_paint (MetaScreenCastWindow *screen_cast_window, + MetaScreenCastWindowStreamSrc *window_src) +{ + window_src->actor_was_dirty = + meta_screen_cast_window_has_damage (screen_cast_window); } static void -window_actor_painted (MetaWindowActor *actor, - MetaScreenCastWindowStreamSrc *window_src) +screen_cast_window_after_paint (MetaWindowActor *actor, + MetaScreenCastWindowStreamSrc *window_src) +{ + if (window_src->actor_was_dirty) + { + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src); + + meta_screen_cast_stream_src_maybe_record_frame (src); + } +} + +static void +screen_cast_window_destroyed (MetaWindowActor *actor, + MetaScreenCastWindowStreamSrc *window_src) +{ + meta_screen_cast_window_stream_src_stop (window_src); + window_src->screen_cast_window = NULL; +} + +static gboolean +is_cursor_in_stream (MetaScreenCastWindowStreamSrc *window_src) +{ + MetaBackend *backend = get_backend (window_src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + MetaCursorSprite *cursor_sprite; + ClutterPoint cursor_position; + MetaScreenCastWindow *screen_cast_window; + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + + cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + + screen_cast_window = window_src->screen_cast_window; + return meta_screen_cast_window_transform_cursor_position (screen_cast_window, + cursor_sprite, + &cursor_position, + NULL, + NULL); +} + +static void +sync_cursor_state (MetaScreenCastWindowStreamSrc *window_src) { MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src); + if (!is_cursor_in_stream (window_src)) + return; + + if (meta_screen_cast_window_has_damage (window_src->screen_cast_window)) + return; + meta_screen_cast_stream_src_maybe_record_frame (src); } static void -window_actor_destroyed (MetaWindowActor *actor, - MetaScreenCastWindowStreamSrc *window_src) +cursor_moved (MetaCursorTracker *cursor_tracker, + float x, + float y, + MetaScreenCastWindowStreamSrc *window_src) { - meta_screen_cast_window_stream_src_stop (window_src); - window_src->window_actor = NULL; + sync_cursor_state (window_src); +} + +static void +cursor_changed (MetaCursorTracker *cursor_tracker, + MetaScreenCastWindowStreamSrc *window_src) +{ + window_src->cursor_bitmap_invalid = TRUE; + sync_cursor_state (window_src); } static void @@ -177,25 +367,51 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src) { MetaScreenCastWindowStreamSrc *window_src = META_SCREEN_CAST_WINDOW_STREAM_SRC (src); + MetaBackend *backend = get_backend (window_src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); MetaWindowActor *window_actor; + MetaScreenCastStream *stream; window_actor = meta_window_actor_from_window (get_window (window_src)); if (!window_actor) return; - window_src->window_actor = window_actor; + window_src->screen_cast_window = META_SCREEN_CAST_WINDOW (window_actor); - window_src->actor_painted_handler_id = - g_signal_connect_after (window_src->window_actor, + window_src->screen_cast_window_before_paint_handler_id = + g_signal_connect (window_src->screen_cast_window, + "paint", + G_CALLBACK (screen_cast_window_before_paint), + window_src); + window_src->screen_cast_window_after_paint_handler_id = + g_signal_connect_after (window_src->screen_cast_window, "paint", - G_CALLBACK (window_actor_painted), + G_CALLBACK (screen_cast_window_after_paint), window_src); - window_src->actor_destroyed_handler_id = - g_signal_connect (window_src->window_actor, + window_src->screen_cast_window_destroyed_handler_id = + g_signal_connect (window_src->screen_cast_window, "destroy", - G_CALLBACK (window_actor_destroyed), + G_CALLBACK (screen_cast_window_destroyed), window_src); + + stream = meta_screen_cast_stream_src_get_stream (src); + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + window_src->cursor_moved_handler_id = + g_signal_connect_after (cursor_tracker, "cursor-moved", + G_CALLBACK (cursor_moved), + window_src); + window_src->cursor_changed_handler_id = + g_signal_connect_after (cursor_tracker, "cursor-changed", + G_CALLBACK (cursor_changed), + window_src); + break; + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + break; + } } static void @@ -219,6 +435,65 @@ meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src, return TRUE; } +static void +meta_screen_cast_window_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +{ + MetaScreenCastWindowStreamSrc *window_src = + META_SCREEN_CAST_WINDOW_STREAM_SRC (src); + MetaBackend *backend = get_backend (window_src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + MetaScreenCastWindow *screen_cast_window = window_src->screen_cast_window; + MetaCursorSprite *cursor_sprite; + ClutterPoint cursor_position; + float scale; + ClutterPoint relative_cursor_position; + int x, y; + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + + if (!meta_screen_cast_window_transform_cursor_position (screen_cast_window, + cursor_sprite, + &cursor_position, + &scale, + &relative_cursor_position)) + { + meta_screen_cast_stream_src_unset_cursor_metadata (src, + spa_meta_cursor); + return; + } + + x = (int) roundf (relative_cursor_position.x); + y = (int) roundf (relative_cursor_position.y); + + if (window_src->cursor_bitmap_invalid) + { + if (cursor_sprite) + { + meta_screen_cast_stream_src_set_cursor_sprite_metadata (src, + spa_meta_cursor, + cursor_sprite, + x, y, + scale); + } + else + { + meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (src, + spa_meta_cursor, + x, y); + } + window_src->cursor_bitmap_invalid = FALSE; + } + else + { + meta_screen_cast_stream_src_set_cursor_position_metadata (src, + spa_meta_cursor, + x, y); + } +} + MetaScreenCastWindowStreamSrc * meta_screen_cast_window_stream_src_new (MetaScreenCastWindowStream *window_stream, GError **error) @@ -231,6 +506,7 @@ meta_screen_cast_window_stream_src_new (MetaScreenCastWindowStream *window_stre static void meta_screen_cast_window_stream_src_init (MetaScreenCastWindowStreamSrc *window_src) { + window_src->cursor_bitmap_invalid = TRUE; } static void @@ -244,4 +520,5 @@ meta_screen_cast_window_stream_src_class_init (MetaScreenCastWindowStreamSrcClas src_class->disable = meta_screen_cast_window_stream_src_disable; src_class->record_frame = meta_screen_cast_window_stream_src_record_frame; src_class->get_videocrop = meta_screen_cast_window_stream_src_get_videocrop; + src_class->set_cursor_metadata = meta_screen_cast_window_stream_src_set_cursor_metadata; } diff --git a/src/backends/meta-screen-cast-window-stream.c b/src/backends/meta-screen-cast-window-stream.c index 4c92271164595c1bdabdeac787a1cbded35e0952..50d1806cde0c402864a0104ca286e3bcf930ccf4 100644 --- a/src/backends/meta-screen-cast-window-stream.c +++ b/src/backends/meta-screen-cast-window-stream.c @@ -44,13 +44,22 @@ struct _MetaScreenCastWindowStream int stream_width; int stream_height; + int logical_width; + int logical_height; unsigned long window_unmanaged_handler_id; }; -G_DEFINE_TYPE (MetaScreenCastWindowStream, - meta_screen_cast_window_stream, - META_TYPE_SCREEN_CAST_STREAM) +static GInitableIface *initable_parent_iface; + +static void +meta_screen_cast_window_stream_init_initable_iface (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaScreenCastWindowStream, + meta_screen_cast_window_stream, + META_TYPE_SCREEN_CAST_STREAM, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + meta_screen_cast_window_stream_init_initable_iface)) MetaWindow * meta_screen_cast_window_stream_get_window (MetaScreenCastWindowStream *window_stream) @@ -71,43 +80,20 @@ meta_screen_cast_window_stream_get_height (MetaScreenCastWindowStream *window_st } MetaScreenCastWindowStream * -meta_screen_cast_window_stream_new (MetaScreenCastSession *session, - GDBusConnection *connection, - MetaWindow *window, - GError **error) +meta_screen_cast_window_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaWindow *window, + MetaScreenCastCursorMode cursor_mode, + GError **error) { - MetaScreenCastWindowStream *window_stream; - MetaLogicalMonitor *logical_monitor; - int scale; - - logical_monitor = meta_window_get_main_logical_monitor (window); - if (!logical_monitor) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Main logical monitor not found"); - return NULL; - } - - window_stream = g_initable_new (META_TYPE_SCREEN_CAST_WINDOW_STREAM, - NULL, - error, - "session", session, - "connection", connection, - "window", window, - NULL); - if (!window_stream) - return NULL; - - window_stream->window = window; - /* We cannot set the stream size to the exact size of the window, because - * windows can be resized, whereas streams cannot. - * So we set a size equals to the size of the logical monitor for the window. - */ - scale = (int) ceil (meta_logical_monitor_get_scale (logical_monitor)); - window_stream->stream_width = logical_monitor->rect.width * scale; - window_stream->stream_height = logical_monitor->rect.height * scale; - - return window_stream; + return g_initable_new (META_TYPE_SCREEN_CAST_WINDOW_STREAM, + NULL, + error, + "session", session, + "connection", connection, + "cursor-mode", cursor_mode, + "window", window, + NULL); } static MetaScreenCastStreamSrc * @@ -132,22 +118,12 @@ meta_screen_cast_window_stream_set_parameters (MetaScreenCastStream *stream, { MetaScreenCastWindowStream *window_stream = META_SCREEN_CAST_WINDOW_STREAM (stream); - MetaScreenCastWindow *screen_cast_window = - META_SCREEN_CAST_WINDOW (meta_window_actor_from_window (window_stream->window)); - MetaRectangle bounds; - - meta_screen_cast_window_get_buffer_bounds (screen_cast_window, &bounds); - - g_variant_builder_add (parameters_builder, "{sv}", - "position", - g_variant_new ("(ii)", - bounds.x, bounds.y)); g_variant_builder_add (parameters_builder, "{sv}", "size", g_variant_new ("(ii)", - bounds.width, - bounds.height)); + window_stream->logical_width, + window_stream->logical_height)); } static void @@ -175,20 +151,6 @@ on_window_unmanaged (MetaScreenCastWindowStream *window_stream) meta_screen_cast_stream_close (META_SCREEN_CAST_STREAM (window_stream)); } -static void -meta_screen_cast_window_stream_constructed (GObject *object) -{ - MetaScreenCastWindowStream *window_stream = - META_SCREEN_CAST_WINDOW_STREAM (object); - - window_stream->window_unmanaged_handler_id = - g_signal_connect_swapped (window_stream->window, "unmanaged", - G_CALLBACK (on_window_unmanaged), - window_stream); - - G_OBJECT_CLASS (meta_screen_cast_window_stream_parent_class)->constructed (object); -} - static void meta_screen_cast_window_stream_set_property (GObject *object, guint prop_id, @@ -233,12 +195,58 @@ meta_screen_cast_window_stream_finalize (GObject *object) MetaScreenCastWindowStream *window_stream = META_SCREEN_CAST_WINDOW_STREAM (object); - g_signal_handler_disconnect (window_stream->window, - window_stream->window_unmanaged_handler_id); + if (window_stream->window_unmanaged_handler_id) + g_signal_handler_disconnect (window_stream->window, + window_stream->window_unmanaged_handler_id); G_OBJECT_CLASS (meta_screen_cast_window_stream_parent_class)->finalize (object); } +static gboolean +meta_screen_cast_window_stream_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + MetaScreenCastWindowStream *window_stream = + META_SCREEN_CAST_WINDOW_STREAM (initable); + MetaWindow *window = window_stream->window; + MetaLogicalMonitor *logical_monitor; + int scale; + + logical_monitor = meta_window_get_main_logical_monitor (window); + if (!logical_monitor) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Main logical monitor not found"); + return FALSE; + } + + window_stream->window_unmanaged_handler_id = + g_signal_connect_swapped (window, "unmanaged", + G_CALLBACK (on_window_unmanaged), + window_stream); + + /* We cannot set the stream size to the exact size of the window, because + * windows can be resized, whereas streams cannot. + * So we set a size equals to the size of the logical monitor for the window. + */ + scale = (int) ceil (meta_logical_monitor_get_scale (logical_monitor)); + window_stream->logical_width = logical_monitor->rect.width; + window_stream->logical_height = logical_monitor->rect.height; + window_stream->stream_width = logical_monitor->rect.width * scale; + window_stream->stream_height = logical_monitor->rect.height * scale; + + return initable_parent_iface->init (initable, cancellable, error); +} + +static void +meta_screen_cast_window_stream_init_initable_iface (GInitableIface *iface) +{ + initable_parent_iface = g_type_interface_peek_parent (iface); + + iface->init = meta_screen_cast_window_stream_initable_init; +} + static void meta_screen_cast_window_stream_init (MetaScreenCastWindowStream *window_stream) { @@ -251,7 +259,6 @@ meta_screen_cast_window_stream_class_init (MetaScreenCastWindowStreamClass *klas MetaScreenCastStreamClass *stream_class = META_SCREEN_CAST_STREAM_CLASS (klass); - object_class->constructed = meta_screen_cast_window_stream_constructed; object_class->set_property = meta_screen_cast_window_stream_set_property; object_class->get_property = meta_screen_cast_window_stream_get_property; object_class->finalize = meta_screen_cast_window_stream_finalize; diff --git a/src/backends/meta-screen-cast-window-stream.h b/src/backends/meta-screen-cast-window-stream.h index 3799be98a2cebf99301b510c56b7302b700a7239..6eae74f1cde2cadaa90aa93fe8437c161734c600 100644 --- a/src/backends/meta-screen-cast-window-stream.h +++ b/src/backends/meta-screen-cast-window-stream.h @@ -32,10 +32,11 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastWindowStream, META, SCREEN_CAST_WINDOW_STREAM, MetaScreenCastStream) -MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (MetaScreenCastSession *session, - GDBusConnection *connection, - MetaWindow *window, - GError **error); +MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaWindow *window, + MetaScreenCastCursorMode cursor_mode, + GError **error); MetaWindow * meta_screen_cast_window_stream_get_window (MetaScreenCastWindowStream *window_stream); int meta_screen_cast_window_stream_get_width (MetaScreenCastWindowStream *window_stream); diff --git a/src/backends/meta-screen-cast-window.c b/src/backends/meta-screen-cast-window.c index 21629a0cd55b07cf4acd63f3e3372ba1bba7b5c6..ce2bf82c9664a3b40cf435e9ad49b9dd9ec05f73 100644 --- a/src/backends/meta-screen-cast-window.c +++ b/src/backends/meta-screen-cast-window.c @@ -29,14 +29,6 @@ meta_screen_cast_window_default_init (MetaScreenCastWindowInterface *iface) { } -void -meta_screen_cast_window_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds) -{ - META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window)->get_buffer_bounds (screen_cast_window, - bounds); -} - void meta_screen_cast_window_get_frame_bounds (MetaScreenCastWindow *screen_cast_window, MetaRectangle *bounds) @@ -59,6 +51,22 @@ meta_screen_cast_window_transform_relative_position (MetaScreenCastWindow *scree y_out); } +gboolean +meta_screen_cast_window_transform_cursor_position (MetaScreenCastWindow *screen_cast_window, + MetaCursorSprite *cursor_sprite, + ClutterPoint *cursor_position, + float *out_cursor_scale, + ClutterPoint *out_relative_cursor_position) +{ + MetaScreenCastWindowInterface *iface = + META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window); + + return iface->transform_cursor_position (screen_cast_window, + cursor_sprite, + cursor_position, + out_cursor_scale, + out_relative_cursor_position); +} void meta_screen_cast_window_capture_into (MetaScreenCastWindow *screen_cast_window, @@ -69,3 +77,12 @@ meta_screen_cast_window_capture_into (MetaScreenCastWindow *screen_cast_window, bounds, data); } + +gboolean +meta_screen_cast_window_has_damage (MetaScreenCastWindow *screen_cast_window) +{ + MetaScreenCastWindowInterface *iface = + META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window); + + return iface->has_damage (screen_cast_window); +} diff --git a/src/backends/meta-screen-cast-window.h b/src/backends/meta-screen-cast-window.h index e023d3e174c69a93e913121c4c6f6a3a7bbb345d..badd8822484956b45e2061b7178d7ca6dba4fded 100644 --- a/src/backends/meta-screen-cast-window.h +++ b/src/backends/meta-screen-cast-window.h @@ -24,6 +24,7 @@ #include #include +#include "backends/meta-cursor.h" #include "meta/boxes.h" G_BEGIN_DECLS @@ -36,9 +37,6 @@ struct _MetaScreenCastWindowInterface { GTypeInterface parent_iface; - void (*get_buffer_bounds) (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds); - void (*get_frame_bounds) (MetaScreenCastWindow *screen_cast_window, MetaRectangle *bounds); @@ -48,13 +46,18 @@ struct _MetaScreenCastWindowInterface double *x_out, double *y_out); + gboolean (*transform_cursor_position) (MetaScreenCastWindow *screen_cast_window, + MetaCursorSprite *cursor_sprite, + ClutterPoint *cursor_position, + float *out_cursor_scale, + ClutterPoint *out_relative_cursor_position); + void (*capture_into) (MetaScreenCastWindow *screen_cast_window, MetaRectangle *bounds, uint8_t *data); -}; -void meta_screen_cast_window_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds); + gboolean (*has_damage) (MetaScreenCastWindow *screen_cast_window); +}; void meta_screen_cast_window_get_frame_bounds (MetaScreenCastWindow *screen_cast_window, MetaRectangle *bounds); @@ -65,10 +68,18 @@ void meta_screen_cast_window_transform_relative_position (MetaScreenCastWindow * double *x_out, double *y_out); +gboolean meta_screen_cast_window_transform_cursor_position (MetaScreenCastWindow *screen_cast_window, + MetaCursorSprite *cursor_sprite, + ClutterPoint *cursor_position, + float *out_cursor_scale, + ClutterPoint *out_relative_cursor_position); + void meta_screen_cast_window_capture_into (MetaScreenCastWindow *screen_cast_window, MetaRectangle *bounds, uint8_t *data); +gboolean meta_screen_cast_window_has_damage (MetaScreenCastWindow *screen_cast_window); + G_END_DECLS #endif /* META_SCREEN_CAST_WINDOW_H */ diff --git a/src/backends/meta-screen-cast.c b/src/backends/meta-screen-cast.c index ebf6c18b395183f19aeb19ad65076c58a08747ea..063fffd8ec2fe9b388fbf31259590190fa908072 100644 --- a/src/backends/meta-screen-cast.c +++ b/src/backends/meta-screen-cast.c @@ -32,7 +32,7 @@ #define META_SCREEN_CAST_DBUS_SERVICE "org.gnome.Mutter.ScreenCast" #define META_SCREEN_CAST_DBUS_PATH "/org/gnome/Mutter/ScreenCast" -#define META_SCREEN_CAST_API_VERSION 1 +#define META_SCREEN_CAST_API_VERSION 2 struct _MetaScreenCast { diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 20a22062fa977ace976f60e14e83247b7fb2e200..adcba898c509a3c4c871a1acf5a959bafd15d1ff 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -1850,20 +1850,6 @@ meta_window_actor_from_window (MetaWindow *window) return META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); } -static void -meta_window_actor_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window, - MetaRectangle *bounds) -{ - MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); - ClutterActor *clutter_actor; - - clutter_actor = CLUTTER_ACTOR (meta_window_actor_get_texture (window_actor)); - bounds->x = 0; - bounds->y = 0; - bounds->width = (int) clutter_actor_get_width (clutter_actor); - bounds->height = (int) clutter_actor_get_height (clutter_actor); -} - static void meta_window_actor_get_frame_bounds (MetaScreenCastWindow *screen_cast_window, MetaRectangle *bounds) @@ -1921,6 +1907,52 @@ meta_window_actor_transform_relative_position (MetaScreenCastWindow *screen_cast *y_out = (double) v2.y; } +static gboolean +meta_window_actor_transform_cursor_position (MetaScreenCastWindow *screen_cast_window, + MetaCursorSprite *cursor_sprite, + ClutterPoint *cursor_position, + float *out_cursor_scale, + ClutterPoint *out_relative_cursor_position) +{ + MetaWindowActor *window_actor = META_WINDOW_ACTOR (screen_cast_window); + MetaWindowActorPrivate *priv = + meta_window_actor_get_instance_private (window_actor); + MetaWindow *window; + + window = priv->window; + if (!meta_window_has_pointer (window)) + return FALSE; + + if (cursor_sprite && + meta_cursor_sprite_get_cogl_texture (cursor_sprite) && + out_cursor_scale) + { + MetaShapedTexture *stex; + double actor_scale; + float cursor_texture_scale; + + stex = meta_surface_actor_get_texture (priv->surface); + clutter_actor_get_scale (CLUTTER_ACTOR (stex), &actor_scale, NULL); + cursor_texture_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); + + *out_cursor_scale = actor_scale / cursor_texture_scale; + } + + if (out_relative_cursor_position) + { + MetaShapedTexture *stex; + + stex = meta_surface_actor_get_texture (priv->surface); + clutter_actor_transform_stage_point (CLUTTER_ACTOR (stex), + cursor_position->x, + cursor_position->y, + &out_relative_cursor_position->x, + &out_relative_cursor_position->y); + } + + return TRUE; +} + static void meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window, MetaRectangle *bounds, @@ -1975,11 +2007,18 @@ meta_window_actor_capture_into (MetaScreenCastWindow *screen_cast_window, cairo_surface_destroy (image); } +static gboolean +meta_window_actor_has_damage (MetaScreenCastWindow *screen_cast_window) +{ + return clutter_actor_has_damage (CLUTTER_ACTOR (screen_cast_window)); +} + static void screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface) { - iface->get_buffer_bounds = meta_window_actor_get_buffer_bounds; iface->get_frame_bounds = meta_window_actor_get_frame_bounds; iface->transform_relative_position = meta_window_actor_transform_relative_position; + iface->transform_cursor_position = meta_window_actor_transform_cursor_position; iface->capture_into = meta_window_actor_capture_into; + iface->has_damage = meta_window_actor_has_damage; } diff --git a/src/org.gnome.Mutter.ScreenCast.xml b/src/org.gnome.Mutter.ScreenCast.xml index 953809727e0a3d9bc9672cd238cf374c5df691cc..0e83747f53dd9fa87c4599aebaf29c770e83793d 100644 --- a/src/org.gnome.Mutter.ScreenCast.xml +++ b/src/org.gnome.Mutter.ScreenCast.xml @@ -74,6 +74,7 @@ Available @properties include: * "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below) + Available since API version 2. Available cursor mode values: @@ -92,11 +93,14 @@ @properties: Properties used determining what window to select @stream_path: Path to the new stream object + Supported since API version 2. + Record a single window. The cursor will not be included. Available @properties include: * "window-id" (t): Id of the window to record. + * "cursor-mode" (u): Cursor mode. Default: 'hidden' (see RecordMonitor). -->