Compare commits
82 Commits
pwood/fix-
...
wip/lantw/
Author | SHA1 | Date | |
---|---|---|---|
![]() |
af0478ae1e | ||
![]() |
aedf692e0c | ||
![]() |
5dfd86ebe7 | ||
![]() |
9e41f687a0 | ||
![]() |
61356caa06 | ||
![]() |
4300f1f91d | ||
![]() |
d26dc4ae44 | ||
![]() |
bd45a00fa3 | ||
![]() |
793a9d45e1 | ||
![]() |
43295bdcc4 | ||
![]() |
43e12dab7b | ||
![]() |
c4535fdf85 | ||
![]() |
d2c3272eb7 | ||
![]() |
90c4b6492f | ||
![]() |
b7bf42e778 | ||
![]() |
e849667be6 | ||
![]() |
424016d66c | ||
![]() |
a4f55d4986 | ||
![]() |
1b33a5a3a7 | ||
![]() |
36111270aa | ||
![]() |
6e0cfd3e55 | ||
![]() |
5671f0a284 | ||
![]() |
a7e63bea6c | ||
![]() |
94b3c334e5 | ||
![]() |
efb0addb62 | ||
![]() |
988da215c8 | ||
![]() |
551a57ed7f | ||
![]() |
b7366b5b53 | ||
![]() |
5e8d8b9ade | ||
![]() |
4726f3d5d3 | ||
![]() |
91ef7515de | ||
![]() |
317f6c0910 | ||
![]() |
6a3d521466 | ||
![]() |
1363246d44 | ||
![]() |
0b6560fac4 | ||
![]() |
d4c3870286 | ||
![]() |
4bdf9a1e70 | ||
![]() |
1909977a67 | ||
![]() |
655a783891 | ||
![]() |
a4596becc4 | ||
![]() |
7015bb3efd | ||
![]() |
d2c762cc66 | ||
![]() |
04d429b743 | ||
![]() |
0b21dcfe08 | ||
![]() |
7c939d78c2 | ||
![]() |
8a2b82897d | ||
![]() |
e95c365cf0 | ||
![]() |
a32cb7133b | ||
![]() |
967966cdee | ||
![]() |
06d67b6abf | ||
![]() |
f15ce01e2b | ||
![]() |
e48516679c | ||
![]() |
65a6c4c361 | ||
![]() |
b51c468c0f | ||
![]() |
2e7d02f1ce | ||
![]() |
dc4fe780f7 | ||
![]() |
d682cdb078 | ||
![]() |
ff7a42b8bc | ||
![]() |
4b1805c306 | ||
![]() |
03c00e4944 | ||
![]() |
cb05b16414 | ||
![]() |
b9fe9c736a | ||
![]() |
3dd8861fbf | ||
![]() |
753066598f | ||
![]() |
3da8c1bfdc | ||
![]() |
f8ee974628 | ||
![]() |
f36120757f | ||
![]() |
bc178b711f | ||
![]() |
5dad87cfb9 | ||
![]() |
0f8f607e4c | ||
![]() |
282aada13a | ||
![]() |
47002bf0cd | ||
![]() |
3d47c7edc1 | ||
![]() |
bc350f37f5 | ||
![]() |
b55e2e1df9 | ||
![]() |
43baf643d4 | ||
![]() |
21b8ae10b8 | ||
![]() |
425a10de11 | ||
![]() |
d0ef660ff6 | ||
![]() |
506e06589b | ||
![]() |
1d75d5aa2f | ||
![]() |
645d596f9d |
33
NEWS
33
NEWS
@@ -1,3 +1,36 @@
|
||||
3.37.1
|
||||
======
|
||||
* Fix screencasting non-maximized windows [Jonas Å.; !1174]
|
||||
* Make window-aliveness checks less aggressive [Jonas Å.; !1182]
|
||||
* Fix stylus coordinates when using screen rotation [Jonas T.; #1118]
|
||||
* Preserve keyboard state on VT switch [Olivier; !1185]
|
||||
* Remove Clutter's drag and drop actions [Jonas D.; !789]
|
||||
* Cancel clicks/gestures actions on disable [Georges; !1188]
|
||||
* Fix various clipboard issues [Carlos; !1186, !1198, !1203, !1204, !1206]
|
||||
* Fix trackball button scrolling [Phillip; #1120]
|
||||
* Fix tiled monitor support [Jonas; !1199]
|
||||
* Support unredirecting fullscreen wayland surfaces [Jonas Å.; !798]
|
||||
* Support area screencasts [Jonas Å.; !1207]
|
||||
* Synchronize shadows to server-side decorations [Olivier; !1214]
|
||||
* Allow inhibiting remote access [Jonas Å.; !1212]
|
||||
* Fix overview key on X11 when using multiple keyboard layouts [Olivier; !1219]
|
||||
* Fixed crashes [Jonas, D., Carlos; !1173, !1183, !1012]
|
||||
* Misc. bug fixes and cleanups [Andre, Georges, Christian, Jonas Å., Andre,
|
||||
Simon, Florian, Carlos, Adam, Marco, Thomas, Elias, Pekka, Jonas D.,
|
||||
Laurent; !1169, !1168, !1166, !1170, !1167, !1172, !1175, !1176, !1184,
|
||||
!1126, !1187, !1191, !1195, !1179, !1200, !1193, !1209, !1213, !1208,
|
||||
#1074, !1223]
|
||||
|
||||
Contributors:
|
||||
Marco Trevisan (Treviño), Elias Aebi, Thomas Hindoe Paaboel Andersen,
|
||||
Laurent Bigonville, Jonas Dreßler, Olivier Fourdan, Carlos Garnacho,
|
||||
Adam Jackson, Andre Moreira Magalhaes, Simon McVittie, Florian Müllner,
|
||||
Georges Basile Stavracas Neto, Pekka Paalanen, Christian Rauch, Jonas Troeger,
|
||||
Phillip Wood, Jonas Ådahl
|
||||
|
||||
Translators:
|
||||
Dušan Kazik [sk], Christian Kirbach [de]
|
||||
|
||||
3.36.0
|
||||
======
|
||||
* Fix placement of popup windows in multi-monitor setups [Jonas; !1110]
|
||||
|
@@ -19960,6 +19960,23 @@ clutter_actor_get_transition (ClutterActor *self,
|
||||
return clos->transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_has_transitions: (skip)
|
||||
*/
|
||||
gboolean
|
||||
clutter_actor_has_transitions (ClutterActor *self)
|
||||
{
|
||||
const ClutterAnimationInfo *info;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
||||
|
||||
info = _clutter_actor_get_animation_info_or_defaults (self);
|
||||
if (info->transitions == NULL)
|
||||
return FALSE;
|
||||
|
||||
return g_hash_table_size (info->transitions) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_save_easing_state:
|
||||
* @self: a #ClutterActor
|
||||
|
@@ -9,7 +9,13 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@CLUTTER_CONFIG_DEFINES@
|
||||
#mesondefine CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
|
||||
#mesondefine CLUTTER_WINDOWING_X11
|
||||
#mesondefine CLUTTER_INPUT_X11
|
||||
#mesondefine CLUTTER_WINDOWING_GLX
|
||||
#mesondefine CLUTTER_WINDOWING_EGL
|
||||
#mesondefine CLUTTER_INPUT_EVDEV
|
||||
#mesondefine CLUTTER_INPUT_NULL
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@@ -36,6 +36,9 @@
|
||||
#include "cogl/clutter-stage-cogl.h"
|
||||
#include "clutter/x11/clutter-backend-x11.h"
|
||||
|
||||
CLUTTER_EXPORT
|
||||
GList * clutter_stage_peek_stage_views (ClutterStage *stage);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_set_custom_backend_func (ClutterBackend *(* func) (void));
|
||||
|
||||
@@ -48,6 +51,23 @@ void clutter_stage_capture_into (ClutterStage *stage,
|
||||
cairo_rectangle_int_t *rect,
|
||||
uint8_t *data);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_paint_to_framebuffer (ClutterStage *stage,
|
||||
CoglFramebuffer *framebuffer,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
float scale,
|
||||
ClutterPaintFlag paint_flags);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_stage_paint_to_buffer (ClutterStage *stage,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
float scale,
|
||||
uint8_t *data,
|
||||
int stride,
|
||||
CoglPixelFormat format,
|
||||
ClutterPaintFlag paint_flags,
|
||||
GError **error);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_freeze_updates (ClutterStage *stage);
|
||||
|
||||
@@ -57,9 +77,16 @@ void clutter_stage_thaw_updates (ClutterStage *stage);
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_update_resource_scales (ClutterStage *stage);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view,
|
||||
CoglScanout *scanout);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_actor_has_damage (ClutterActor *actor);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_actor_has_transitions (ClutterActor *actor);
|
||||
|
||||
#undef __CLUTTER_H_INSIDE__
|
||||
|
||||
#endif /* __CLUTTER_MUTTER_H__ */
|
||||
|
@@ -21,7 +21,8 @@
|
||||
#include "clutter-paint-context.h"
|
||||
|
||||
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip);
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags);
|
||||
|
||||
gboolean clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context);
|
||||
|
||||
|
@@ -23,6 +23,8 @@ struct _ClutterPaintContext
|
||||
{
|
||||
grefcount ref_count;
|
||||
|
||||
ClutterPaintFlag paint_flags;
|
||||
|
||||
GList *framebuffers;
|
||||
|
||||
ClutterStageView *view;
|
||||
@@ -36,7 +38,8 @@ G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
|
||||
|
||||
ClutterPaintContext *
|
||||
clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
const cairo_region_t *redraw_clip)
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags)
|
||||
{
|
||||
ClutterPaintContext *paint_context;
|
||||
CoglFramebuffer *framebuffer;
|
||||
@@ -45,6 +48,7 @@ clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
g_ref_count_init (&paint_context->ref_count);
|
||||
paint_context->view = view;
|
||||
paint_context->redraw_clip = cairo_region_copy (redraw_clip);
|
||||
paint_context->paint_flags = paint_flags;
|
||||
|
||||
framebuffer = clutter_stage_view_get_framebuffer (view);
|
||||
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
|
||||
@@ -56,12 +60,16 @@ clutter_paint_context_new_for_view (ClutterStageView *view,
|
||||
* clutter_paint_context_new_for_framebuffer: (skip)
|
||||
*/
|
||||
ClutterPaintContext *
|
||||
clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer)
|
||||
clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer,
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags)
|
||||
{
|
||||
ClutterPaintContext *paint_context;
|
||||
|
||||
paint_context = g_new0 (ClutterPaintContext, 1);
|
||||
g_ref_count_init (&paint_context->ref_count);
|
||||
paint_context->redraw_clip = cairo_region_copy (redraw_clip);
|
||||
paint_context->paint_flags = paint_flags;
|
||||
|
||||
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
|
||||
|
||||
@@ -170,3 +178,12 @@ clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context)
|
||||
|
||||
return !paint_context->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_paint_context_get_paint_flags: (skip)
|
||||
*/
|
||||
ClutterPaintFlag
|
||||
clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context)
|
||||
{
|
||||
return paint_context->paint_flags;
|
||||
}
|
||||
|
@@ -29,13 +29,21 @@
|
||||
|
||||
typedef struct _ClutterPaintContext ClutterPaintContext;
|
||||
|
||||
typedef enum _ClutterPaintFlag
|
||||
{
|
||||
CLUTTER_PAINT_FLAG_NONE = 0,
|
||||
CLUTTER_PAINT_FLAG_NO_CURSORS = 1 << 0,
|
||||
} ClutterPaintFlag;
|
||||
|
||||
#define CLUTTER_TYPE_PAINT_CONTEXT (clutter_paint_context_get_type ())
|
||||
|
||||
CLUTTER_EXPORT
|
||||
GType clutter_paint_context_get_type (void);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterPaintContext * clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer);
|
||||
ClutterPaintContext * clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer,
|
||||
const cairo_region_t *redraw_clip,
|
||||
ClutterPaintFlag paint_flags);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterPaintContext * clutter_paint_context_ref (ClutterPaintContext *paint_context);
|
||||
@@ -62,4 +70,7 @@ void clutter_paint_context_pop_framebuffer (ClutterPaintContext *paint_context);
|
||||
CLUTTER_EXPORT
|
||||
const cairo_region_t * clutter_paint_context_get_redraw_clip (ClutterPaintContext *paint_context);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterPaintFlag clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context);
|
||||
|
||||
#endif /* CLUTTER_PAINT_CONTEXT_H */
|
||||
|
@@ -139,8 +139,6 @@ void _clutter_stage_presented (ClutterStage *stag
|
||||
CoglFrameEvent frame_event,
|
||||
ClutterFrameInfo *frame_info);
|
||||
|
||||
GList * _clutter_stage_peek_stage_views (ClutterStage *stage);
|
||||
|
||||
void clutter_stage_queue_actor_relayout (ClutterStage *stage,
|
||||
ClutterActor *actor);
|
||||
|
||||
|
@@ -43,4 +43,6 @@ const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *vi
|
||||
|
||||
cairo_region_t * clutter_stage_view_take_redraw_clip (ClutterStageView *view);
|
||||
|
||||
CoglScanout * clutter_stage_view_take_scanout (ClutterStageView *view);
|
||||
|
||||
#endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */
|
||||
|
@@ -24,6 +24,8 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "clutter/clutter-private.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "cogl/cogl.h"
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -52,6 +54,8 @@ typedef struct _ClutterStageViewPrivate
|
||||
CoglOffscreen *shadowfb;
|
||||
CoglPipeline *shadowfb_pipeline;
|
||||
|
||||
CoglScanout *next_scanout;
|
||||
|
||||
gboolean has_redraw_clip;
|
||||
cairo_region_t *redraw_clip;
|
||||
|
||||
@@ -407,6 +411,25 @@ clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *vie
|
||||
cogl_matrix_init_identity (matrix);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_view_assign_next_scanout (ClutterStageView *view,
|
||||
CoglScanout *scanout)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
g_set_object (&priv->next_scanout, scanout);
|
||||
}
|
||||
|
||||
CoglScanout *
|
||||
clutter_stage_view_take_scanout (ClutterStageView *view)
|
||||
{
|
||||
ClutterStageViewPrivate *priv =
|
||||
clutter_stage_view_get_instance_private (view);
|
||||
|
||||
return g_steal_pointer (&priv->next_scanout);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
|
@@ -552,7 +552,7 @@ clutter_stage_add_redraw_clip (ClutterStage *stage,
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = _clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
|
||||
@@ -924,7 +924,8 @@ clutter_stage_do_paint_view (ClutterStage *stage,
|
||||
ClutterPaintContext *paint_context;
|
||||
cairo_rectangle_int_t clip_rect;
|
||||
|
||||
paint_context = clutter_paint_context_new_for_view (view, redraw_clip);
|
||||
paint_context = clutter_paint_context_new_for_view (view, redraw_clip,
|
||||
CLUTTER_PAINT_FLAG_NONE);
|
||||
|
||||
cairo_region_get_extents (redraw_clip, &clip_rect);
|
||||
setup_view_for_pick_or_paint (stage, view, &clip_rect);
|
||||
@@ -1572,7 +1573,7 @@ is_full_stage_redraw_queued (ClutterStage *stage)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = _clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
|
||||
@@ -4163,6 +4164,97 @@ clutter_stage_get_capture_final_size (ClutterStage *stage,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_paint_to_framebuffer (ClutterStage *stage,
|
||||
CoglFramebuffer *framebuffer,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
float scale,
|
||||
ClutterPaintFlag paint_flags)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
ClutterPaintContext *paint_context;
|
||||
cairo_region_t *redraw_clip;
|
||||
|
||||
redraw_clip = cairo_region_create_rectangle (rect);
|
||||
paint_context =
|
||||
clutter_paint_context_new_for_framebuffer (framebuffer,
|
||||
redraw_clip,
|
||||
paint_flags);
|
||||
cairo_region_destroy (redraw_clip);
|
||||
|
||||
cogl_framebuffer_push_matrix (framebuffer);
|
||||
cogl_framebuffer_set_projection_matrix (framebuffer, &priv->projection);
|
||||
cogl_framebuffer_set_viewport (framebuffer,
|
||||
-(rect->x * scale),
|
||||
-(rect->y * scale),
|
||||
priv->viewport[2] * scale,
|
||||
priv->viewport[3] * scale);
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage), paint_context);
|
||||
cogl_framebuffer_pop_matrix (framebuffer);
|
||||
|
||||
clutter_paint_context_destroy (paint_context);
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_stage_paint_to_buffer (ClutterStage *stage,
|
||||
const cairo_rectangle_int_t *rect,
|
||||
float scale,
|
||||
uint8_t *data,
|
||||
int stride,
|
||||
CoglPixelFormat format,
|
||||
ClutterPaintFlag paint_flags,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
||||
CoglContext *cogl_context =
|
||||
clutter_backend_get_cogl_context (clutter_backend);
|
||||
int texture_width, texture_height;
|
||||
CoglTexture2D *texture;
|
||||
CoglOffscreen *offscreen;
|
||||
CoglFramebuffer *framebuffer;
|
||||
CoglBitmap *bitmap;
|
||||
|
||||
texture_width = (int) ceilf (rect->width * scale);
|
||||
texture_height = (int) ceilf (rect->height * scale);
|
||||
texture = cogl_texture_2d_new_with_size (cogl_context,
|
||||
texture_width,
|
||||
texture_height);
|
||||
if (!texture)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Failed to create %dx%d texture",
|
||||
texture_width, texture_height);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture));
|
||||
framebuffer = COGL_FRAMEBUFFER (offscreen);
|
||||
|
||||
cogl_object_unref (texture);
|
||||
|
||||
if (!cogl_framebuffer_allocate (framebuffer, error))
|
||||
return FALSE;
|
||||
|
||||
clutter_stage_paint_to_framebuffer (stage, framebuffer,
|
||||
rect, scale, paint_flags);
|
||||
|
||||
bitmap = cogl_bitmap_new_for_data (cogl_context,
|
||||
texture_width, texture_height,
|
||||
format,
|
||||
stride,
|
||||
data);
|
||||
|
||||
cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
|
||||
0, 0,
|
||||
COGL_READ_PIXELS_COLOR_BUFFER,
|
||||
bitmap);
|
||||
|
||||
cogl_object_unref (bitmap);
|
||||
cogl_object_unref (framebuffer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
capture_view_into (ClutterStage *stage,
|
||||
gboolean paint,
|
||||
@@ -4310,8 +4402,11 @@ clutter_stage_thaw_updates (ClutterStage *stage)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_peek_stage_views: (skip)
|
||||
*/
|
||||
GList *
|
||||
_clutter_stage_peek_stage_views (ClutterStage *stage)
|
||||
clutter_stage_peek_stage_views (ClutterStage *stage)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
|
||||
|
@@ -375,15 +375,11 @@ static gboolean
|
||||
swap_framebuffer (ClutterStageWindow *stage_window,
|
||||
ClutterStageView *view,
|
||||
cairo_region_t *swap_region,
|
||||
gboolean swap_with_damage,
|
||||
cairo_region_t *queued_redraw_clip)
|
||||
gboolean swap_with_damage)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
|
||||
int *damage, n_rects, i;
|
||||
|
||||
if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION)))
|
||||
paint_damage_region (stage_window, view, swap_region, queued_redraw_clip);
|
||||
|
||||
n_rects = cairo_region_num_rectangles (swap_region);
|
||||
damage = g_newa (int, n_rects * 4);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
@@ -620,7 +616,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
gboolean swap_with_damage;
|
||||
ClutterActor *wrapper;
|
||||
cairo_region_t *redraw_clip;
|
||||
cairo_region_t *queued_redraw_clip;
|
||||
cairo_region_t *queued_redraw_clip = NULL;
|
||||
cairo_region_t *fb_clip_region;
|
||||
cairo_region_t *swap_region;
|
||||
cairo_rectangle_int_t redraw_rect;
|
||||
@@ -644,6 +640,8 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
has_buffer_age = cogl_is_onscreen (fb) && is_buffer_age_enabled ();
|
||||
|
||||
redraw_clip = clutter_stage_view_take_redraw_clip (view);
|
||||
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION))
|
||||
queued_redraw_clip = cairo_region_copy (redraw_clip);
|
||||
|
||||
/* NB: a NULL redraw clip == full stage redraw */
|
||||
if (!redraw_clip)
|
||||
@@ -711,8 +709,6 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
redraw_clip = cairo_region_create_rectangle (&view_rect);
|
||||
}
|
||||
|
||||
queued_redraw_clip = cairo_region_copy (redraw_clip);
|
||||
|
||||
if (may_use_clipped_redraw &&
|
||||
G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
|
||||
use_clipped_redraw = TRUE;
|
||||
@@ -922,7 +918,6 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
}
|
||||
|
||||
g_clear_pointer (&redraw_clip, cairo_region_destroy);
|
||||
g_clear_pointer (&queued_redraw_clip, cairo_region_destroy);
|
||||
g_clear_pointer (&fb_clip_region, cairo_region_destroy);
|
||||
|
||||
if (do_swap_buffer)
|
||||
@@ -943,11 +938,17 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
swap_region = transformed_swap_region;
|
||||
}
|
||||
|
||||
if (queued_redraw_clip)
|
||||
{
|
||||
paint_damage_region (stage_window, view,
|
||||
swap_region, queued_redraw_clip);
|
||||
cairo_region_destroy (queued_redraw_clip);
|
||||
}
|
||||
|
||||
res = swap_framebuffer (stage_window,
|
||||
view,
|
||||
swap_region,
|
||||
swap_with_damage,
|
||||
queued_redraw_clip);
|
||||
swap_with_damage);
|
||||
|
||||
cairo_region_destroy (swap_region);
|
||||
|
||||
@@ -955,10 +956,25 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_pointer (&queued_redraw_clip, cairo_region_destroy);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
|
||||
ClutterStageView *view,
|
||||
CoglScanout *scanout)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
|
||||
CoglOnscreen *onscreen;
|
||||
|
||||
g_return_if_fail (cogl_is_onscreen (framebuffer));
|
||||
|
||||
onscreen = COGL_ONSCREEN (framebuffer);
|
||||
cogl_onscreen_direct_scanout (onscreen, scanout);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
{
|
||||
@@ -971,11 +987,23 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *view = l->data;
|
||||
g_autoptr (CoglScanout) scanout = NULL;
|
||||
|
||||
if (!clutter_stage_view_has_redraw_clip (view))
|
||||
continue;
|
||||
|
||||
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
|
||||
scanout = clutter_stage_view_take_scanout (view);
|
||||
if (scanout)
|
||||
{
|
||||
clutter_stage_cogl_scanout_view (stage_cogl,
|
||||
view,
|
||||
scanout);
|
||||
swap_event = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
|
||||
}
|
||||
}
|
||||
|
||||
_clutter_stage_emit_after_paint (stage_cogl->wrapper);
|
||||
|
@@ -337,35 +337,20 @@ clutter_build_config_h = configure_file(
|
||||
)
|
||||
clutter_built_private_headers += clutter_build_config_h
|
||||
|
||||
clutter_config_defines = []
|
||||
cdata = configuration_data()
|
||||
if have_wayland
|
||||
clutter_config_defines += [
|
||||
'#define CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT 1',
|
||||
]
|
||||
cdata.set10('CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT', true)
|
||||
endif
|
||||
if have_x11
|
||||
clutter_config_defines += [
|
||||
'#define CLUTTER_WINDOWING_X11 "x11"',
|
||||
'#define CLUTTER_INPUT_X11 "x11"',
|
||||
'#define CLUTTER_WINDOWING_GLX "glx"',
|
||||
]
|
||||
cdata.set_quoted('CLUTTER_WINDOWING_X11', 'x11')
|
||||
cdata.set_quoted('CLUTTER_INPUT_X11', 'x11')
|
||||
cdata.set_quoted('CLUTTER_WINDOWING_GLX', 'glx')
|
||||
endif
|
||||
if have_native_backend
|
||||
clutter_config_defines += [
|
||||
'#define CLUTTER_WINDOWING_EGL "eglnative"',
|
||||
'#define CLUTTER_INPUT_EVDEV "evdev"',
|
||||
]
|
||||
cdata.set_quoted('CLUTTER_WINDOWING_EGL', 'eglnative')
|
||||
cdata.set_quoted('CLUTTER_INPUT_EVDEV', 'evdev')
|
||||
endif
|
||||
clutter_config_defines += [
|
||||
'#define CLUTTER_INPUT_NULL "null"',
|
||||
]
|
||||
clutter_config_defines_string = ''
|
||||
foreach clutter_config_define : clutter_config_defines
|
||||
clutter_config_defines_string += clutter_config_define + '\n'
|
||||
endforeach
|
||||
|
||||
cdata = configuration_data()
|
||||
cdata.set('CLUTTER_CONFIG_DEFINES', clutter_config_defines_string)
|
||||
cdata.set_quoted('CLUTTER_INPUT_NULL', 'null')
|
||||
|
||||
clutter_config_h = configure_file(
|
||||
input: 'clutter-config.h.in',
|
||||
|
@@ -74,7 +74,7 @@ PangoFontMap *
|
||||
cogl_pango_font_map_new (void)
|
||||
{
|
||||
PangoFontMap *fm = pango_cairo_font_map_new ();
|
||||
CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
|
||||
g_autofree CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
|
||||
|
||||
_COGL_GET_CONTEXT (context, NULL);
|
||||
|
||||
@@ -85,7 +85,7 @@ cogl_pango_font_map_new (void)
|
||||
* for now. */
|
||||
g_object_set_qdata_full (G_OBJECT (fm),
|
||||
cogl_pango_font_map_get_priv_key (),
|
||||
priv,
|
||||
g_steal_pointer (&priv),
|
||||
free_priv);
|
||||
|
||||
return fm;
|
||||
|
@@ -93,10 +93,12 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
|
||||
CoglOnscreen *
|
||||
_cogl_onscreen_new (void)
|
||||
{
|
||||
CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1);
|
||||
g_autofree CoglOnscreen *onscreen_ptr = g_new0 (CoglOnscreen, 1);
|
||||
CoglOnscreen *onscreen;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
onscreen = g_steal_pointer (&onscreen_ptr);
|
||||
_cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
|
||||
ctx,
|
||||
COGL_FRAMEBUFFER_TYPE_ONSCREEN,
|
||||
@@ -403,6 +405,27 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen)
|
||||
return winsys->onscreen_get_buffer_age (onscreen);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
|
||||
CoglScanout *scanout)
|
||||
{
|
||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||
const CoglWinsysVtable *winsys;
|
||||
CoglFrameInfo *info;
|
||||
|
||||
g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
|
||||
g_return_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT));
|
||||
|
||||
info = _cogl_frame_info_new ();
|
||||
info->frame_counter = onscreen->frame_counter;
|
||||
g_queue_push_tail (&onscreen->pending_frame_infos, info);
|
||||
|
||||
winsys = _cogl_framebuffer_get_winsys (framebuffer);
|
||||
winsys->onscreen_direct_scanout (onscreen, scanout);
|
||||
|
||||
onscreen->frame_counter++;
|
||||
}
|
||||
|
||||
#ifdef COGL_HAS_X11_SUPPORT
|
||||
uint32_t
|
||||
cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen)
|
||||
|
@@ -50,6 +50,8 @@ G_BEGIN_DECLS
|
||||
typedef struct _CoglOnscreen CoglOnscreen;
|
||||
#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
|
||||
|
||||
typedef struct _CoglScanout CoglScanout;
|
||||
|
||||
/**
|
||||
* cogl_onscreen_get_gtype:
|
||||
*
|
||||
@@ -284,6 +286,13 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||
const int *rectangles,
|
||||
int n_rectangles);
|
||||
|
||||
/**
|
||||
* cogl_onscreen_direct_scanout: (skip)
|
||||
*/
|
||||
COGL_EXPORT void
|
||||
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
|
||||
CoglScanout *scanout);
|
||||
|
||||
/**
|
||||
* cogl_onscreen_swap_region:
|
||||
* @onscreen: A #CoglOnscreen framebuffer
|
||||
|
@@ -50,7 +50,7 @@ struct _CoglPipelineCache
|
||||
CoglPipelineCache *
|
||||
_cogl_pipeline_cache_new (void)
|
||||
{
|
||||
CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
|
||||
g_autofree CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
|
||||
unsigned long vertex_state;
|
||||
unsigned long layer_vertex_state;
|
||||
unsigned int fragment_state;
|
||||
@@ -80,7 +80,7 @@ _cogl_pipeline_cache_new (void)
|
||||
layer_vertex_state | layer_fragment_state,
|
||||
"programs");
|
||||
|
||||
return cache;
|
||||
return g_steal_pointer (&cache);
|
||||
}
|
||||
|
||||
void
|
||||
|
27
cogl/cogl/cogl-scanout.c
Normal file
27
cogl/cogl/cogl-scanout.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cogl-config.h"
|
||||
|
||||
#include "cogl-scanout.h"
|
||||
|
||||
G_DEFINE_INTERFACE (CoglScanout, cogl_scanout, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
cogl_scanout_default_init (CoglScanoutInterface *iface)
|
||||
{
|
||||
}
|
35
cogl/cogl/cogl-scanout.h
Normal file
35
cogl/cogl/cogl-scanout.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef COGL_SCANOUT_H
|
||||
#define COGL_SCANOUT_H
|
||||
|
||||
#include "cogl/cogl-types.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define COGL_TYPE_SCANOUT (cogl_scanout_get_type ())
|
||||
COGL_EXPORT
|
||||
G_DECLARE_INTERFACE (CoglScanout, cogl_scanout,
|
||||
COGL, SCANOUT, GObject)
|
||||
|
||||
struct _CoglScanoutInterface
|
||||
{
|
||||
GTypeInterface parent_iface;
|
||||
};
|
||||
|
||||
#endif /* COGL_SCANOUT_H */
|
@@ -122,6 +122,7 @@
|
||||
#include <cogl/cogl-fence.h>
|
||||
#include <cogl/cogl-glib-source.h>
|
||||
#include <cogl/cogl-trace.h>
|
||||
#include <cogl/cogl-scanout.h>
|
||||
/* XXX: This will definitly go away once all the Clutter winsys
|
||||
* code has been migrated down into Cogl! */
|
||||
#include <cogl/deprecated/cogl-clutter.h>
|
||||
|
@@ -122,6 +122,7 @@ cogl_nonintrospected_headers = [
|
||||
'cogl-version.h',
|
||||
'cogl-gtype-private.h',
|
||||
'cogl-glib-source.h',
|
||||
'cogl-scanout.h',
|
||||
]
|
||||
|
||||
cogl_nodist_headers = [
|
||||
@@ -347,6 +348,7 @@ cogl_sources = [
|
||||
'cogl-closure-list.c',
|
||||
'cogl-fence.c',
|
||||
'cogl-fence-private.h',
|
||||
'cogl-scanout.c',
|
||||
'deprecated/cogl-material-compat.c',
|
||||
'deprecated/cogl-program.c',
|
||||
'deprecated/cogl-program-private.h',
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "cogl-renderer.h"
|
||||
#include "cogl-onscreen.h"
|
||||
#include "cogl-scanout.h"
|
||||
|
||||
#ifdef COGL_HAS_XLIB_SUPPORT
|
||||
#include "cogl-texture-pixmap-x11-private.h"
|
||||
@@ -117,6 +118,10 @@ typedef struct _CoglWinsysVtable
|
||||
const int *rectangles,
|
||||
int n_rectangles);
|
||||
|
||||
void
|
||||
(*onscreen_direct_scanout) (CoglOnscreen *onscreen,
|
||||
CoglScanout *scanout);
|
||||
|
||||
void
|
||||
(*onscreen_set_visibility) (CoglOnscreen *onscreen,
|
||||
gboolean visibility);
|
||||
|
@@ -70,3 +70,12 @@
|
||||
|
||||
/* Whether Xwayland has -initfd option */
|
||||
#mesondefine HAVE_XWAYLAND_INITFD
|
||||
|
||||
/* Whether the mkostemp function exists */
|
||||
#mesondefine HAVE_MKOSTEMP
|
||||
|
||||
/* Whether the posix_fallocate function exists */
|
||||
#mesondefine HAVE_POSIX_FALLOCATE
|
||||
|
||||
/* Whether the memfd_create function exists */
|
||||
#mesondefine HAVE_MEMFD_CREATE
|
||||
|
16
meson.build
16
meson.build
@@ -1,5 +1,5 @@
|
||||
project('mutter', 'c',
|
||||
version: '3.37.0',
|
||||
version: '3.37.1',
|
||||
meson_version: '>= 0.50.0',
|
||||
license: 'GPLv2+'
|
||||
)
|
||||
@@ -408,6 +408,20 @@ if have_wayland
|
||||
endif
|
||||
endif
|
||||
|
||||
optional_functions = [
|
||||
'mkostemp',
|
||||
'posix_fallocate',
|
||||
'memfd_create',
|
||||
]
|
||||
|
||||
foreach function : optional_functions
|
||||
if cc.has_function(function)
|
||||
cdata.set('HAVE_' + function.to_upper(), 1)
|
||||
else
|
||||
message('Optional function ' + function + ' missing')
|
||||
endif
|
||||
endforeach
|
||||
|
||||
xwayland_grab_default_access_rules = get_option('xwayland_grab_default_access_rules')
|
||||
cdata.set_quoted('XWAYLAND_GRAB_DEFAULT_ACCESS_RULES',
|
||||
xwayland_grab_default_access_rules)
|
||||
|
85
po/de.po
85
po/de.po
@@ -13,8 +13,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mutter master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
|
||||
"POT-Creation-Date: 2019-08-06 00:49+0000\n"
|
||||
"PO-Revision-Date: 2019-09-05 23:42+0200\n"
|
||||
"POT-Creation-Date: 2020-03-30 20:11+0000\n"
|
||||
"PO-Revision-Date: 2020-04-06 23:13+0200\n"
|
||||
"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
|
||||
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
|
||||
"Language: de\n"
|
||||
@@ -22,7 +22,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 2.2.1\n"
|
||||
"X-Generator: Poedit 2.3\n"
|
||||
|
||||
#: data/50-mutter-navigation.xml:6
|
||||
msgid "Navigation"
|
||||
@@ -435,20 +435,33 @@ msgstr "Zusatztaste zum Finden des Zeigers"
|
||||
msgid "This key will initiate the “locate pointer” action."
|
||||
msgstr "Diese Taste wird die Aktion »Zeiger finden« auslösen."
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:155
|
||||
#: data/org.gnome.mutter.gschema.xml.in:142
|
||||
msgid "Timeout for check-alive ping"
|
||||
msgstr "Reaktionsschwellwert bei Kontaktkontrolle"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:143
|
||||
msgid ""
|
||||
"Number of milliseconds a client has to respond to a ping request in order to "
|
||||
"not be detected as frozen. Using 0 will disable the alive check completely."
|
||||
msgstr ""
|
||||
"Zeit in Millisekunden, innerhalb welcher ein Client auf eine "
|
||||
"Kontaktkontrolle antworten muss, um nicht als abgestürzt zu gelten. »0« "
|
||||
"bedeutet, dass die Kontaktkontrolle ausgeschaltet wird."
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:165
|
||||
msgid "Select window from tab popup"
|
||||
msgstr "Fenster aus Tab-Anzeige auswählen"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:160
|
||||
#: data/org.gnome.mutter.gschema.xml.in:170
|
||||
msgid "Cancel tab popup"
|
||||
msgstr "Tab-Anzeige abbrechen"
|
||||
|
||||
#: data/org.gnome.mutter.gschema.xml.in:165
|
||||
#: data/org.gnome.mutter.gschema.xml.in:175
|
||||
msgid "Switch monitor configurations"
|
||||
msgstr "Bildschirmkonfigurationen wechseln"
|
||||
|
||||
# Ich denke nicht, dass »rotate« hier die Bildschirmdrehung meint, sondern eher eine Liste aus Konfigurationen rotiert (d.h. umgewälzt) wird.
|
||||
#: data/org.gnome.mutter.gschema.xml.in:170
|
||||
#: data/org.gnome.mutter.gschema.xml.in:180
|
||||
msgid "Rotates the built-in monitor configuration"
|
||||
msgstr "Wechselt die Konfiguration des eingebauten Bildschirms"
|
||||
|
||||
@@ -569,7 +582,7 @@ msgstr ""
|
||||
#. TRANSLATORS: This string refers to a button that switches between
|
||||
#. * different modes.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2531
|
||||
#: src/backends/meta-input-settings.c:2631
|
||||
#, c-format
|
||||
msgid "Mode Switch (Group %d)"
|
||||
msgstr "Moduswechsel (Gruppe %d)"
|
||||
@@ -577,34 +590,34 @@ msgstr "Moduswechsel (Gruppe %d)"
|
||||
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
|
||||
#. * mapping through the available outputs.
|
||||
#.
|
||||
#: src/backends/meta-input-settings.c:2554
|
||||
#: src/backends/meta-input-settings.c:2654
|
||||
msgid "Switch monitor"
|
||||
msgstr "Bildschirm wechseln"
|
||||
|
||||
#: src/backends/meta-input-settings.c:2556
|
||||
#: src/backends/meta-input-settings.c:2656
|
||||
msgid "Show on-screen help"
|
||||
msgstr "Bildschirmhilfe anzeigen"
|
||||
|
||||
#: src/backends/meta-monitor.c:223
|
||||
#: src/backends/meta-monitor.c:226
|
||||
msgid "Built-in display"
|
||||
msgstr "Eingebaute Anzeige"
|
||||
|
||||
#: src/backends/meta-monitor.c:252
|
||||
#: src/backends/meta-monitor.c:255
|
||||
msgid "Unknown"
|
||||
msgstr "Unbekannt"
|
||||
|
||||
#: src/backends/meta-monitor.c:254
|
||||
#: src/backends/meta-monitor.c:257
|
||||
msgid "Unknown Display"
|
||||
msgstr "Unbekannte Anzeige"
|
||||
|
||||
#: src/backends/meta-monitor.c:262
|
||||
#: src/backends/meta-monitor.c:265
|
||||
#, c-format
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
|
||||
msgid "%s %s"
|
||||
msgstr "%s %s"
|
||||
|
||||
#: src/backends/meta-monitor.c:270
|
||||
#: src/backends/meta-monitor.c:273
|
||||
#, c-format
|
||||
msgctxt ""
|
||||
"This is a monitor vendor name followed by product/model name where size in "
|
||||
@@ -614,13 +627,13 @@ msgstr "%s %s"
|
||||
|
||||
# https://de.wikipedia.org/wiki/Composition-Manager
|
||||
#. Translators: this string will appear in Sysprof
|
||||
#: src/backends/meta-profiler.c:82
|
||||
#: src/backends/meta-profiler.c:79
|
||||
msgid "Compositor"
|
||||
msgstr "Compositor"
|
||||
|
||||
#. This probably means that a non-WM compositor like xcompmgr is running;
|
||||
#. * we have no way to get it to exit
|
||||
#: src/compositor/compositor.c:510
|
||||
#: src/compositor/compositor.c:533
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Another compositing manager is already running on screen %i on display “%s”."
|
||||
@@ -632,47 +645,47 @@ msgstr ""
|
||||
msgid "Bell event"
|
||||
msgstr "Klangereignis"
|
||||
|
||||
#: src/core/main.c:185
|
||||
#: src/core/main.c:190
|
||||
msgid "Disable connection to session manager"
|
||||
msgstr "Verbindung zur Sitzungsverwaltung deaktivieren"
|
||||
|
||||
#: src/core/main.c:191
|
||||
#: src/core/main.c:196
|
||||
msgid "Replace the running window manager"
|
||||
msgstr "Den aktuellen Fensterverwalter ersetzen"
|
||||
|
||||
#: src/core/main.c:197
|
||||
#: src/core/main.c:202
|
||||
msgid "Specify session management ID"
|
||||
msgstr "Kennung der Sitzungsverwaltung angeben"
|
||||
|
||||
#: src/core/main.c:202
|
||||
#: src/core/main.c:207
|
||||
msgid "X Display to use"
|
||||
msgstr "Zu verwendende X-Anzeige"
|
||||
|
||||
#: src/core/main.c:208
|
||||
#: src/core/main.c:213
|
||||
msgid "Initialize session from savefile"
|
||||
msgstr "Sitzung anhand gespeicherter Datei starten"
|
||||
|
||||
#: src/core/main.c:214
|
||||
#: src/core/main.c:219
|
||||
msgid "Make X calls synchronous"
|
||||
msgstr "X-Aufrufe abgleichen"
|
||||
|
||||
#: src/core/main.c:221
|
||||
#: src/core/main.c:226
|
||||
msgid "Run as a wayland compositor"
|
||||
msgstr "Als Wayland-Compositor ausführen"
|
||||
|
||||
#: src/core/main.c:227
|
||||
#: src/core/main.c:232
|
||||
msgid "Run as a nested compositor"
|
||||
msgstr "Als eingebetteten Compositor ausführen"
|
||||
|
||||
#: src/core/main.c:233
|
||||
#: src/core/main.c:238
|
||||
msgid "Run wayland compositor without starting Xwayland"
|
||||
msgstr "Wayland-Compositor ausführen, ohne Xwayland zu starten"
|
||||
|
||||
#: src/core/main.c:241
|
||||
#: src/core/main.c:246
|
||||
msgid "Run as a full display server, rather than nested"
|
||||
msgstr "Als vollwertigen Display-Server verwenden (nicht eingebettet)"
|
||||
|
||||
#: src/core/main.c:247
|
||||
#: src/core/main.c:252
|
||||
msgid "Run with X11 backend"
|
||||
msgstr "Mit X11-Backend ausführen"
|
||||
|
||||
@@ -728,21 +741,21 @@ msgstr "Version ausgeben"
|
||||
msgid "Mutter plugin to use"
|
||||
msgstr "Zu benutzendes Mutter-Plugin"
|
||||
|
||||
#: src/core/prefs.c:1849
|
||||
#: src/core/prefs.c:1911
|
||||
#, c-format
|
||||
msgid "Workspace %d"
|
||||
msgstr "Arbeitsfläche %d"
|
||||
|
||||
#: src/core/util.c:121
|
||||
#: src/core/util.c:122
|
||||
msgid "Mutter was compiled without support for verbose mode\n"
|
||||
msgstr "Mutter wurde ohne Unterstützung für den redseligen Modus kompiliert\n"
|
||||
|
||||
#: src/wayland/meta-wayland-tablet-pad.c:567
|
||||
#: src/wayland/meta-wayland-tablet-pad.c:568
|
||||
#, c-format
|
||||
msgid "Mode Switch: Mode %d"
|
||||
msgstr "Moduswechsel: Modus %d"
|
||||
|
||||
#: src/x11/meta-x11-display.c:671
|
||||
#: src/x11/meta-x11-display.c:676
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Display “%s” already has a window manager; try using the --replace option to "
|
||||
@@ -751,21 +764,21 @@ msgstr ""
|
||||
"Bildschirm »%s« hat bereits einen Fensterverwalter. Versuchen Sie die Option "
|
||||
"»--replace«, um den aktuellen Fensterverwalter zu ersetzen."
|
||||
|
||||
#: src/x11/meta-x11-display.c:1032
|
||||
#: src/x11/meta-x11-display.c:1089
|
||||
msgid "Failed to initialize GDK\n"
|
||||
msgstr "GDK konnte nicht initialisiert werden\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1056
|
||||
#: src/x11/meta-x11-display.c:1113
|
||||
#, c-format
|
||||
msgid "Failed to open X Window System display “%s”\n"
|
||||
msgstr "X-Window-Systemanzeige »%s« konnte nicht geöffnet werden\n"
|
||||
|
||||
#: src/x11/meta-x11-display.c:1140
|
||||
#: src/x11/meta-x11-display.c:1196
|
||||
#, c-format
|
||||
msgid "Screen %d on display “%s” is invalid\n"
|
||||
msgstr "Bildschirm %d auf Anzeige »%s« ist ungültig\n"
|
||||
|
||||
#: src/x11/meta-x11-selection-input-stream.c:445
|
||||
#: src/x11/meta-x11-selection-input-stream.c:460
|
||||
#, c-format
|
||||
msgid "Format %s not supported"
|
||||
msgstr "Format %s wird nicht unterstützt"
|
||||
|
@@ -49,6 +49,7 @@ typedef struct _MetaTileInfo MetaTileInfo;
|
||||
typedef struct _MetaRenderer MetaRenderer;
|
||||
typedef struct _MetaRendererView MetaRendererView;
|
||||
|
||||
typedef struct _MetaRemoteDesktop MetaRemoteDesktop;
|
||||
typedef struct _MetaScreenCast MetaScreenCast;
|
||||
typedef struct _MetaScreenCastSession MetaScreenCastSession;
|
||||
typedef struct _MetaScreenCastStream MetaScreenCastStream;
|
||||
|
@@ -552,12 +552,12 @@ meta_backend_real_post_init (MetaBackend *backend)
|
||||
}
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
priv->remote_access_controller =
|
||||
g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL);
|
||||
priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL);
|
||||
priv->screen_cast = meta_screen_cast_new (backend,
|
||||
priv->dbus_session_watcher);
|
||||
priv->remote_desktop = meta_remote_desktop_new (priv->dbus_session_watcher);
|
||||
priv->remote_access_controller =
|
||||
meta_remote_access_controller_new (priv->remote_desktop, priv->screen_cast);
|
||||
#endif /* HAVE_REMOTE_DESKTOP */
|
||||
|
||||
if (!meta_monitor_manager_is_headless (priv->monitor_manager))
|
||||
@@ -809,9 +809,6 @@ static MetaMonitorManager *
|
||||
meta_backend_create_monitor_manager (MetaBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
if (g_getenv ("META_DUMMY_MONITORS"))
|
||||
return g_object_new (META_TYPE_MONITOR_MANAGER_DUMMY, NULL);
|
||||
|
||||
return META_BACKEND_GET_CLASS (backend)->create_monitor_manager (backend,
|
||||
error);
|
||||
}
|
||||
|
@@ -54,8 +54,8 @@ meta_input_device_init (MetaInputDevice *input_device)
|
||||
static void
|
||||
meta_input_device_constructed (GObject *object)
|
||||
{
|
||||
MetaInputDevice *input_device = META_INPUT_DEVICE (object);
|
||||
#ifdef HAVE_LIBWACOM
|
||||
MetaInputDevice *input_device;
|
||||
WacomDeviceDatabase *wacom_db;
|
||||
MetaInputDevicePrivate *priv;
|
||||
const char *node;
|
||||
@@ -64,6 +64,7 @@ meta_input_device_constructed (GObject *object)
|
||||
G_OBJECT_CLASS (meta_input_device_parent_class)->constructed (object);
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
input_device = META_INPUT_DEVICE (object);
|
||||
priv = meta_input_device_get_instance_private (input_device);
|
||||
wacom_db = meta_backend_get_wacom_database (meta_get_backend ());
|
||||
node = clutter_input_device_get_device_node (CLUTTER_INPUT_DEVICE (input_device));
|
||||
|
@@ -172,6 +172,7 @@ assign_monitor_crtc (MetaMonitor *monitor,
|
||||
MetaCrtc *crtc;
|
||||
MetaMonitorTransform transform;
|
||||
MetaMonitorTransform crtc_transform;
|
||||
MetaMonitorTransform crtc_hw_transform;
|
||||
int crtc_x, crtc_y;
|
||||
float x_offset, y_offset;
|
||||
float scale = 0.0;
|
||||
@@ -200,10 +201,12 @@ assign_monitor_crtc (MetaMonitor *monitor,
|
||||
|
||||
transform = data->logical_monitor_config->transform;
|
||||
crtc_transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
|
||||
if (!meta_monitor_manager_is_transform_handled (data->monitor_manager,
|
||||
crtc,
|
||||
crtc_transform))
|
||||
crtc_transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
if (meta_monitor_manager_is_transform_handled (data->monitor_manager,
|
||||
crtc,
|
||||
crtc_transform))
|
||||
crtc_hw_transform = crtc_transform;
|
||||
else
|
||||
crtc_hw_transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
|
||||
meta_monitor_calculate_crtc_pos (monitor, mode, output, crtc_transform,
|
||||
&crtc_x, &crtc_y);
|
||||
@@ -244,7 +247,7 @@ assign_monitor_crtc (MetaMonitor *monitor,
|
||||
.crtc = crtc,
|
||||
.mode = crtc_mode,
|
||||
.layout = crtc_layout,
|
||||
.transform = crtc_transform,
|
||||
.transform = crtc_hw_transform,
|
||||
.outputs = g_ptr_array_new ()
|
||||
};
|
||||
g_ptr_array_add (crtc_info->outputs, output);
|
||||
@@ -443,23 +446,35 @@ MetaMonitorsConfigKey *
|
||||
meta_create_monitors_config_key_for_current_state (MetaMonitorManager *monitor_manager)
|
||||
{
|
||||
MetaMonitorsConfigKey *config_key;
|
||||
MetaMonitorSpec *laptop_monitor_spec;
|
||||
GList *l;
|
||||
GList *monitor_specs;
|
||||
|
||||
laptop_monitor_spec = NULL;
|
||||
monitor_specs = NULL;
|
||||
for (l = monitor_manager->monitors; l; l = l->next)
|
||||
{
|
||||
MetaMonitor *monitor = l->data;
|
||||
MetaMonitorSpec *monitor_spec;
|
||||
|
||||
if (meta_monitor_is_laptop_panel (monitor) &&
|
||||
is_lid_closed (monitor_manager))
|
||||
continue;
|
||||
if (meta_monitor_is_laptop_panel (monitor))
|
||||
{
|
||||
laptop_monitor_spec = meta_monitor_get_spec (monitor);
|
||||
|
||||
if (is_lid_closed (monitor_manager))
|
||||
continue;
|
||||
}
|
||||
|
||||
monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
|
||||
monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
|
||||
}
|
||||
|
||||
if (!monitor_specs && laptop_monitor_spec)
|
||||
{
|
||||
monitor_specs =
|
||||
g_list_prepend (NULL, meta_monitor_spec_clone (laptop_monitor_spec));
|
||||
}
|
||||
|
||||
if (!monitor_specs)
|
||||
return NULL;
|
||||
|
||||
|
@@ -817,19 +817,19 @@ calculate_tile_coordinate (MetaMonitor *monitor,
|
||||
case META_MONITOR_TRANSFORM_270:
|
||||
case META_MONITOR_TRANSFORM_FLIPPED_270:
|
||||
if (other_output->tile_info.loc_v_tile == output->tile_info.loc_v_tile &&
|
||||
other_output->tile_info.loc_h_tile < output->tile_info.loc_h_tile)
|
||||
other_output->tile_info.loc_h_tile > output->tile_info.loc_h_tile)
|
||||
y += other_output->tile_info.tile_w;
|
||||
if (other_output->tile_info.loc_h_tile == output->tile_info.loc_h_tile &&
|
||||
other_output->tile_info.loc_v_tile < output->tile_info.loc_v_tile)
|
||||
other_output->tile_info.loc_v_tile > output->tile_info.loc_v_tile)
|
||||
x += other_output->tile_info.tile_h;
|
||||
break;
|
||||
case META_MONITOR_TRANSFORM_90:
|
||||
case META_MONITOR_TRANSFORM_FLIPPED_90:
|
||||
if (other_output->tile_info.loc_v_tile == output->tile_info.loc_v_tile &&
|
||||
other_output->tile_info.loc_h_tile > output->tile_info.loc_h_tile)
|
||||
other_output->tile_info.loc_h_tile < output->tile_info.loc_h_tile)
|
||||
y += other_output->tile_info.tile_w;
|
||||
if (other_output->tile_info.loc_h_tile == output->tile_info.loc_h_tile &&
|
||||
other_output->tile_info.loc_v_tile > output->tile_info.loc_v_tile)
|
||||
other_output->tile_info.loc_v_tile < output->tile_info.loc_v_tile)
|
||||
x += other_output->tile_info.tile_h;
|
||||
break;
|
||||
}
|
||||
|
@@ -21,8 +21,12 @@
|
||||
#ifndef META_REMOTE_ACCESS_CONTROLLER_PRIVATE_H
|
||||
#define META_REMOTE_ACCESS_CONTROLLER_PRIVATE_H
|
||||
|
||||
#include "backends/meta-backend-types.h"
|
||||
#include "meta/meta-remote-access-controller.h"
|
||||
|
||||
MetaRemoteAccessController * meta_remote_access_controller_new (MetaRemoteDesktop *remote_desktop,
|
||||
MetaScreenCast *screen_cast);
|
||||
|
||||
void meta_remote_access_controller_notify_new_handle (MetaRemoteAccessController *controller,
|
||||
MetaRemoteAccessHandle *handle);
|
||||
|
||||
|
@@ -22,6 +22,11 @@
|
||||
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
#include "backends/meta-remote-desktop.h"
|
||||
#include "backends/meta-screen-cast.h"
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
HANDLE_STOPPED,
|
||||
@@ -54,6 +59,9 @@ G_DEFINE_TYPE_WITH_PRIVATE (MetaRemoteAccessHandle,
|
||||
struct _MetaRemoteAccessController
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
MetaRemoteDesktop *remote_desktop;
|
||||
MetaScreenCast *screen_cast;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaRemoteAccessController,
|
||||
@@ -122,6 +130,53 @@ meta_remote_access_controller_notify_new_handle (MetaRemoteAccessController *con
|
||||
handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_remote_access_controller_inhibit_remote_access:
|
||||
* @controller: a #MetaRemoteAccessController
|
||||
*
|
||||
* Inhibits remote access sessions from being created and running. Any active
|
||||
* remote access session will be terminated.
|
||||
*/
|
||||
void
|
||||
meta_remote_access_controller_inhibit_remote_access (MetaRemoteAccessController *controller)
|
||||
{
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
meta_remote_desktop_inhibit (controller->remote_desktop);
|
||||
meta_screen_cast_inhibit (controller->screen_cast);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_remote_access_controller_uninhibit_remote_access:
|
||||
* @controller: a #MetaRemoteAccessController
|
||||
*
|
||||
* Uninhibits remote access sessions from being created and running. If this was
|
||||
* the last inhibitation that was inhibited, new remote access sessions can now
|
||||
* be created.
|
||||
*/
|
||||
void
|
||||
meta_remote_access_controller_uninhibit_remote_access (MetaRemoteAccessController *controller)
|
||||
{
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
meta_screen_cast_uninhibit (controller->screen_cast);
|
||||
meta_remote_desktop_uninhibit (controller->remote_desktop);
|
||||
#endif
|
||||
}
|
||||
|
||||
MetaRemoteAccessController *
|
||||
meta_remote_access_controller_new (MetaRemoteDesktop *remote_desktop,
|
||||
MetaScreenCast *screen_cast)
|
||||
{
|
||||
MetaRemoteAccessController *remote_access_controller;
|
||||
|
||||
remote_access_controller = g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER,
|
||||
NULL);
|
||||
remote_access_controller->remote_desktop = remote_desktop;
|
||||
remote_access_controller->screen_cast = screen_cast;
|
||||
|
||||
return remote_access_controller;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_access_handle_init (MetaRemoteAccessHandle *handle)
|
||||
{
|
||||
|
@@ -56,6 +56,8 @@ struct _MetaRemoteDesktop
|
||||
|
||||
int dbus_name_id;
|
||||
|
||||
int inhibit_count;
|
||||
|
||||
GHashTable *sessions;
|
||||
|
||||
MetaDbusSessionWatcher *session_watcher;
|
||||
@@ -70,6 +72,34 @@ G_DEFINE_TYPE_WITH_CODE (MetaRemoteDesktop,
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_REMOTE_DESKTOP,
|
||||
meta_remote_desktop_init_iface));
|
||||
|
||||
void
|
||||
meta_remote_desktop_inhibit (MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
remote_desktop->inhibit_count++;
|
||||
if (remote_desktop->inhibit_count == 1)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, remote_desktop->sessions);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
MetaRemoteDesktopSession *session = value;
|
||||
|
||||
g_hash_table_iter_steal (&iter);
|
||||
meta_remote_desktop_session_close (session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_remote_desktop_uninhibit (MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
g_return_if_fail (remote_desktop->inhibit_count > 0);
|
||||
|
||||
remote_desktop->inhibit_count--;
|
||||
}
|
||||
|
||||
GDBusConnection *
|
||||
meta_remote_desktop_get_connection (MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
@@ -108,6 +138,15 @@ handle_create_session (MetaDBusRemoteDesktop *skeleton,
|
||||
char *session_path;
|
||||
const char *client_dbus_name;
|
||||
|
||||
if (remote_desktop->inhibit_count > 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_ACCESS_DENIED,
|
||||
"Session creation inhibited");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
peer_name = g_dbus_method_invocation_get_sender (invocation);
|
||||
session = meta_remote_desktop_session_new (remote_desktop,
|
||||
peer_name,
|
||||
|
@@ -36,6 +36,10 @@ G_DECLARE_FINAL_TYPE (MetaRemoteDesktop, meta_remote_desktop,
|
||||
META, REMOTE_DESKTOP,
|
||||
MetaDBusRemoteDesktopSkeleton)
|
||||
|
||||
void meta_remote_desktop_inhibit (MetaRemoteDesktop *remote_desktop);
|
||||
|
||||
void meta_remote_desktop_uninhibit (MetaRemoteDesktop *remote_desktop);
|
||||
|
||||
MetaRemoteDesktopSession * meta_remote_desktop_get_session (MetaRemoteDesktop *remote_desktop,
|
||||
const char *session_id);
|
||||
|
||||
|
570
src/backends/meta-screen-cast-area-stream-src.c
Normal file
570
src/backends/meta-screen-cast-area-stream-src.c
Normal file
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/meta-screen-cast-area-stream-src.h"
|
||||
|
||||
#include <spa/buffer/meta.h>
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "backends/meta-screen-cast-area-stream.h"
|
||||
#include "backends/meta-screen-cast-session.h"
|
||||
#include "backends/meta-stage-private.h"
|
||||
#include "clutter/clutter.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "core/boxes-private.h"
|
||||
|
||||
struct _MetaScreenCastAreaStreamSrc
|
||||
{
|
||||
MetaScreenCastStreamSrc parent;
|
||||
|
||||
gboolean cursor_bitmap_invalid;
|
||||
gboolean hw_cursor_inhibited;
|
||||
|
||||
GList *watches;
|
||||
|
||||
gulong cursor_moved_handler_id;
|
||||
gulong cursor_changed_handler_id;
|
||||
|
||||
guint maybe_record_idle_id;
|
||||
};
|
||||
|
||||
static void
|
||||
hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaScreenCastAreaStreamSrc,
|
||||
meta_screen_cast_area_stream_src,
|
||||
META_TYPE_SCREEN_CAST_STREAM_SRC,
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_HW_CURSOR_INHIBITOR,
|
||||
hw_cursor_inhibitor_iface_init))
|
||||
|
||||
static ClutterStage *
|
||||
get_stage (MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src;
|
||||
MetaScreenCastStream *stream;
|
||||
MetaScreenCastAreaStream *area_stream;
|
||||
|
||||
src = META_SCREEN_CAST_STREAM_SRC (area_src);
|
||||
stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
|
||||
return meta_screen_cast_area_stream_get_stage (area_stream);
|
||||
}
|
||||
|
||||
static MetaBackend *
|
||||
get_backend (MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_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 MetaCursorRenderer *
|
||||
get_cursor_renderer (MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_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);
|
||||
MetaBackend *backend = meta_screen_cast_get_backend (screen_cast);
|
||||
|
||||
return meta_backend_get_cursor_renderer (backend);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_src_get_specs (MetaScreenCastStreamSrc *src,
|
||||
int *width,
|
||||
int *height,
|
||||
float *frame_rate)
|
||||
{
|
||||
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
MetaScreenCastAreaStream *area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
MetaRectangle *area;
|
||||
float scale;
|
||||
|
||||
area = meta_screen_cast_area_stream_get_area (area_stream);
|
||||
scale = meta_screen_cast_area_stream_get_scale (area_stream);
|
||||
|
||||
*width = (int) roundf (area->width * scale);
|
||||
*height = (int) roundf (area->height * scale);
|
||||
*frame_rate = 60.0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_cursor_in_stream (MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_src);
|
||||
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
MetaScreenCastAreaStream *area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
MetaBackend *backend = get_backend (area_src);
|
||||
MetaCursorRenderer *cursor_renderer =
|
||||
meta_backend_get_cursor_renderer (backend);
|
||||
MetaRectangle *area;
|
||||
graphene_rect_t area_rect;
|
||||
MetaCursorSprite *cursor_sprite;
|
||||
|
||||
area = meta_screen_cast_area_stream_get_area (area_stream);
|
||||
area_rect = meta_rectangle_to_graphene_rect (area);
|
||||
|
||||
cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
|
||||
if (cursor_sprite)
|
||||
{
|
||||
graphene_rect_t cursor_rect;
|
||||
|
||||
cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
|
||||
cursor_sprite);
|
||||
return graphene_rect_intersection (&cursor_rect, &area_rect, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
graphene_point_t cursor_position;
|
||||
|
||||
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
|
||||
return graphene_rect_contains_point (&area_rect, &cursor_position);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sync_cursor_state (MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_src);
|
||||
ClutterStage *stage = get_stage (area_src);
|
||||
|
||||
if (!is_cursor_in_stream (area_src))
|
||||
return;
|
||||
|
||||
if (clutter_stage_is_redraw_queued (stage))
|
||||
return;
|
||||
|
||||
meta_screen_cast_stream_src_maybe_record_frame (src);
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_moved (MetaCursorTracker *cursor_tracker,
|
||||
float x,
|
||||
float y,
|
||||
MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
sync_cursor_state (area_src);
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_changed (MetaCursorTracker *cursor_tracker,
|
||||
MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
area_src->cursor_bitmap_invalid = TRUE;
|
||||
sync_cursor_state (area_src);
|
||||
}
|
||||
|
||||
static void
|
||||
inhibit_hw_cursor (MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
MetaCursorRenderer *cursor_renderer;
|
||||
MetaHwCursorInhibitor *inhibitor;
|
||||
|
||||
g_return_if_fail (!area_src->hw_cursor_inhibited);
|
||||
|
||||
cursor_renderer = get_cursor_renderer (area_src);
|
||||
inhibitor = META_HW_CURSOR_INHIBITOR (area_src);
|
||||
meta_cursor_renderer_add_hw_cursor_inhibitor (cursor_renderer, inhibitor);
|
||||
|
||||
area_src->hw_cursor_inhibited = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
uninhibit_hw_cursor (MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
MetaCursorRenderer *cursor_renderer;
|
||||
MetaHwCursorInhibitor *inhibitor;
|
||||
|
||||
g_return_if_fail (area_src->hw_cursor_inhibited);
|
||||
|
||||
cursor_renderer = get_cursor_renderer (area_src);
|
||||
inhibitor = META_HW_CURSOR_INHIBITOR (area_src);
|
||||
meta_cursor_renderer_remove_hw_cursor_inhibitor (cursor_renderer, inhibitor);
|
||||
|
||||
area_src->hw_cursor_inhibited = FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
maybe_record_frame_on_idle (gpointer user_data)
|
||||
{
|
||||
MetaScreenCastAreaStreamSrc *area_src =
|
||||
META_SCREEN_CAST_AREA_STREAM_SRC (user_data);
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_src);
|
||||
|
||||
area_src->maybe_record_idle_id = 0;
|
||||
|
||||
meta_screen_cast_stream_src_maybe_record_frame (src);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
stage_painted (MetaStage *stage,
|
||||
ClutterStageView *view,
|
||||
ClutterPaintContext *paint_context,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaScreenCastAreaStreamSrc *area_src =
|
||||
META_SCREEN_CAST_AREA_STREAM_SRC (user_data);
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_src);
|
||||
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
MetaScreenCastAreaStream *area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
const cairo_region_t *redraw_clip;
|
||||
MetaRectangle *area;
|
||||
|
||||
if (area_src->maybe_record_idle_id)
|
||||
return;
|
||||
|
||||
area = meta_screen_cast_area_stream_get_area (area_stream);
|
||||
redraw_clip = clutter_paint_context_get_redraw_clip (paint_context);
|
||||
|
||||
if (redraw_clip)
|
||||
{
|
||||
switch (cairo_region_contains_rectangle (redraw_clip, area))
|
||||
{
|
||||
case CAIRO_REGION_OVERLAP_IN:
|
||||
case CAIRO_REGION_OVERLAP_PART:
|
||||
break;
|
||||
case CAIRO_REGION_OVERLAP_OUT:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
area_src->maybe_record_idle_id = g_idle_add (maybe_record_frame_on_idle, src);
|
||||
}
|
||||
|
||||
static void
|
||||
add_view_painted_watches (MetaScreenCastAreaStreamSrc *area_src,
|
||||
MetaStageWatchPhase watch_phase)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_src);
|
||||
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
MetaScreenCastAreaStream *area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
MetaBackend *backend = get_backend (area_src);
|
||||
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
||||
ClutterStage *stage;
|
||||
MetaStage *meta_stage;
|
||||
MetaRectangle *area;
|
||||
GList *l;
|
||||
|
||||
stage = get_stage (area_src);
|
||||
meta_stage = META_STAGE (stage);
|
||||
area = meta_screen_cast_area_stream_get_area (area_stream);
|
||||
|
||||
for (l = meta_renderer_get_views (renderer); l; l = l->next)
|
||||
{
|
||||
MetaRendererView *view = l->data;
|
||||
MetaRectangle view_layout;
|
||||
|
||||
clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view), &view_layout);
|
||||
if (meta_rectangle_overlap (area, &view_layout))
|
||||
{
|
||||
MetaStageWatch *watch;
|
||||
|
||||
watch = meta_stage_watch_view (meta_stage,
|
||||
CLUTTER_STAGE_VIEW (view),
|
||||
watch_phase,
|
||||
stage_painted,
|
||||
area_src);
|
||||
|
||||
area_src->watches = g_list_prepend (area_src->watches, watch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_src_enable (MetaScreenCastStreamSrc *src)
|
||||
{
|
||||
MetaScreenCastAreaStreamSrc *area_src =
|
||||
META_SCREEN_CAST_AREA_STREAM_SRC (src);
|
||||
MetaBackend *backend = get_backend (area_src);
|
||||
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
|
||||
ClutterStage *stage;
|
||||
MetaScreenCastStream *stream;
|
||||
|
||||
stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
stage = get_stage (area_src);
|
||||
|
||||
switch (meta_screen_cast_stream_get_cursor_mode (stream))
|
||||
{
|
||||
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
|
||||
area_src->cursor_moved_handler_id =
|
||||
g_signal_connect_after (cursor_tracker, "cursor-moved",
|
||||
G_CALLBACK (cursor_moved),
|
||||
area_src);
|
||||
area_src->cursor_changed_handler_id =
|
||||
g_signal_connect_after (cursor_tracker, "cursor-changed",
|
||||
G_CALLBACK (cursor_changed),
|
||||
area_src);
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
|
||||
add_view_painted_watches (area_src,
|
||||
META_STAGE_WATCH_AFTER_ACTOR_PAINT);
|
||||
break;
|
||||
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
|
||||
inhibit_hw_cursor (area_src);
|
||||
add_view_painted_watches (area_src,
|
||||
META_STAGE_WATCH_AFTER_ACTOR_PAINT);
|
||||
break;
|
||||
}
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_src_disable (MetaScreenCastStreamSrc *src)
|
||||
{
|
||||
MetaScreenCastAreaStreamSrc *area_src =
|
||||
META_SCREEN_CAST_AREA_STREAM_SRC (src);
|
||||
MetaBackend *backend = get_backend (area_src);
|
||||
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
|
||||
ClutterStage *stage;
|
||||
MetaStage *meta_stage;
|
||||
GList *l;
|
||||
|
||||
stage = get_stage (area_src);
|
||||
meta_stage = META_STAGE (stage);
|
||||
|
||||
for (l = area_src->watches; l; l = l->next)
|
||||
{
|
||||
MetaStageWatch *watch = l->data;
|
||||
|
||||
meta_stage_remove_watch (meta_stage, watch);
|
||||
}
|
||||
g_clear_pointer (&area_src->watches, g_list_free);
|
||||
|
||||
if (area_src->hw_cursor_inhibited)
|
||||
uninhibit_hw_cursor (area_src);
|
||||
|
||||
g_clear_signal_handler (&area_src->cursor_moved_handler_id,
|
||||
cursor_tracker);
|
||||
g_clear_signal_handler (&area_src->cursor_changed_handler_id,
|
||||
cursor_tracker);
|
||||
|
||||
g_clear_handle_id (&area_src->maybe_record_idle_id, g_source_remove);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_screen_cast_area_stream_src_record_frame (MetaScreenCastStreamSrc *src,
|
||||
uint8_t *data)
|
||||
{
|
||||
MetaScreenCastAreaStreamSrc *area_src =
|
||||
META_SCREEN_CAST_AREA_STREAM_SRC (src);
|
||||
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
MetaScreenCastAreaStream *area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
ClutterStage *stage;
|
||||
MetaRectangle *area;
|
||||
float scale;
|
||||
int stride;
|
||||
ClutterPaintFlag paint_flags = CLUTTER_PAINT_FLAG_NONE;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
stage = get_stage (area_src);
|
||||
area = meta_screen_cast_area_stream_get_area (area_stream);
|
||||
scale = meta_screen_cast_area_stream_get_scale (area_stream);
|
||||
stride = meta_screen_cast_stream_src_get_stride (src);
|
||||
|
||||
switch (meta_screen_cast_stream_get_cursor_mode (stream))
|
||||
{
|
||||
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
|
||||
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
|
||||
paint_flags |= CLUTTER_PAINT_FLAG_NO_CURSORS;
|
||||
break;
|
||||
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!clutter_stage_paint_to_buffer (stage, area, scale,
|
||||
data,
|
||||
stride,
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
paint_flags,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Failed to record area: %s", error->message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_screen_cast_area_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src,
|
||||
CoglFramebuffer *framebuffer)
|
||||
{
|
||||
MetaScreenCastAreaStreamSrc *area_src =
|
||||
META_SCREEN_CAST_AREA_STREAM_SRC (src);
|
||||
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
MetaScreenCastAreaStream *area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
MetaBackend *backend = get_backend (area_src);
|
||||
ClutterStage *stage;
|
||||
MetaRectangle *area;
|
||||
float scale;
|
||||
ClutterPaintFlag paint_flags = CLUTTER_PAINT_FLAG_NONE;
|
||||
|
||||
stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
|
||||
area = meta_screen_cast_area_stream_get_area (area_stream);
|
||||
scale = meta_screen_cast_area_stream_get_scale (area_stream);
|
||||
|
||||
switch (meta_screen_cast_stream_get_cursor_mode (stream))
|
||||
{
|
||||
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
|
||||
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
|
||||
paint_flags |= CLUTTER_PAINT_FLAG_NO_CURSORS;
|
||||
break;
|
||||
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
|
||||
break;
|
||||
}
|
||||
clutter_stage_paint_to_framebuffer (stage, framebuffer,
|
||||
area, scale,
|
||||
paint_flags);
|
||||
|
||||
cogl_framebuffer_finish (framebuffer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
|
||||
struct spa_meta_cursor *spa_meta_cursor)
|
||||
{
|
||||
MetaScreenCastAreaStreamSrc *area_src =
|
||||
META_SCREEN_CAST_AREA_STREAM_SRC (src);
|
||||
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
MetaScreenCastAreaStream *area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
MetaBackend *backend = get_backend (area_src);
|
||||
MetaCursorRenderer *cursor_renderer =
|
||||
meta_backend_get_cursor_renderer (backend);
|
||||
MetaCursorSprite *cursor_sprite;
|
||||
MetaRectangle *area;
|
||||
float scale;
|
||||
graphene_point_t cursor_position;
|
||||
int x, y;
|
||||
|
||||
cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
|
||||
|
||||
if (!is_cursor_in_stream (area_src))
|
||||
{
|
||||
meta_screen_cast_stream_src_unset_cursor_metadata (src,
|
||||
spa_meta_cursor);
|
||||
return;
|
||||
}
|
||||
|
||||
area = meta_screen_cast_area_stream_get_area (area_stream);
|
||||
scale = meta_screen_cast_area_stream_get_scale (area_stream);
|
||||
|
||||
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
|
||||
cursor_position.x -= area->x;
|
||||
cursor_position.y -= area->y;
|
||||
cursor_position.x *= scale;
|
||||
cursor_position.y *= scale;
|
||||
|
||||
x = (int) roundf (cursor_position.x);
|
||||
y = (int) roundf (cursor_position.y);
|
||||
|
||||
if (area_src->cursor_bitmap_invalid)
|
||||
{
|
||||
if (cursor_sprite)
|
||||
{
|
||||
float cursor_scale;
|
||||
float metadata_scale;
|
||||
|
||||
cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite);
|
||||
metadata_scale = scale * cursor_scale;
|
||||
meta_screen_cast_stream_src_set_cursor_sprite_metadata (src,
|
||||
spa_meta_cursor,
|
||||
cursor_sprite,
|
||||
x, y,
|
||||
metadata_scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (src,
|
||||
spa_meta_cursor,
|
||||
x, y);
|
||||
}
|
||||
|
||||
area_src->cursor_bitmap_invalid = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_screen_cast_stream_src_set_cursor_position_metadata (src,
|
||||
spa_meta_cursor,
|
||||
x, y);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_screen_cast_area_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
MetaScreenCastAreaStreamSrc *area_src =
|
||||
META_SCREEN_CAST_AREA_STREAM_SRC (inhibitor);
|
||||
|
||||
return is_cursor_in_stream (area_src);
|
||||
}
|
||||
|
||||
static void
|
||||
hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface)
|
||||
{
|
||||
iface->is_cursor_sprite_inhibited =
|
||||
meta_screen_cast_area_stream_src_is_cursor_sprite_inhibited;
|
||||
}
|
||||
|
||||
MetaScreenCastAreaStreamSrc *
|
||||
meta_screen_cast_area_stream_src_new (MetaScreenCastAreaStream *area_stream,
|
||||
GError **error)
|
||||
{
|
||||
return g_initable_new (META_TYPE_SCREEN_CAST_AREA_STREAM_SRC, NULL, error,
|
||||
"stream", area_stream,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_src_init (MetaScreenCastAreaStreamSrc *area_src)
|
||||
{
|
||||
area_src->cursor_bitmap_invalid = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_src_class_init (MetaScreenCastAreaStreamSrcClass *klass)
|
||||
{
|
||||
MetaScreenCastStreamSrcClass *src_class =
|
||||
META_SCREEN_CAST_STREAM_SRC_CLASS (klass);
|
||||
|
||||
src_class->get_specs = meta_screen_cast_area_stream_src_get_specs;
|
||||
src_class->enable = meta_screen_cast_area_stream_src_enable;
|
||||
src_class->disable = meta_screen_cast_area_stream_src_disable;
|
||||
src_class->record_frame = meta_screen_cast_area_stream_src_record_frame;
|
||||
src_class->blit_to_framebuffer =
|
||||
meta_screen_cast_area_stream_src_blit_to_framebuffer;
|
||||
src_class->set_cursor_metadata =
|
||||
meta_screen_cast_area_stream_src_set_cursor_metadata;
|
||||
}
|
37
src/backends/meta-screen-cast-area-stream-src.h
Normal file
37
src/backends/meta-screen-cast-area-stream-src.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef META_SCREEN_CAST_AREA_STREAM_SRC_H
|
||||
#define META_SCREEN_CAST_AREA_STREAM_SRC_H
|
||||
|
||||
#include "backends/meta-screen-cast-stream-src.h"
|
||||
|
||||
typedef struct _MetaScreenCastAreaStream MetaScreenCastAreaStream;
|
||||
|
||||
#define META_TYPE_SCREEN_CAST_AREA_STREAM_SRC (meta_screen_cast_area_stream_src_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaScreenCastAreaStreamSrc,
|
||||
meta_screen_cast_area_stream_src,
|
||||
META, SCREEN_CAST_AREA_STREAM_SRC,
|
||||
MetaScreenCastStreamSrc)
|
||||
|
||||
MetaScreenCastAreaStreamSrc * meta_screen_cast_area_stream_src_new (MetaScreenCastAreaStream *area_stream,
|
||||
GError **error);
|
||||
|
||||
#endif /* META_SCREEN_CAST_AREA_STREAM_SRC_H */
|
177
src/backends/meta-screen-cast-area-stream.c
Normal file
177
src/backends/meta-screen-cast-area-stream.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/meta-screen-cast-area-stream.h"
|
||||
|
||||
#include "backends/meta-screen-cast-area-stream-src.h"
|
||||
|
||||
struct _MetaScreenCastAreaStream
|
||||
{
|
||||
MetaScreenCastStream parent;
|
||||
|
||||
ClutterStage *stage;
|
||||
|
||||
MetaRectangle area;
|
||||
float scale;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaScreenCastAreaStream,
|
||||
meta_screen_cast_area_stream,
|
||||
META_TYPE_SCREEN_CAST_STREAM)
|
||||
|
||||
ClutterStage *
|
||||
meta_screen_cast_area_stream_get_stage (MetaScreenCastAreaStream *area_stream)
|
||||
{
|
||||
return area_stream->stage;
|
||||
}
|
||||
|
||||
MetaRectangle *
|
||||
meta_screen_cast_area_stream_get_area (MetaScreenCastAreaStream *area_stream)
|
||||
{
|
||||
return &area_stream->area;
|
||||
}
|
||||
|
||||
float
|
||||
meta_screen_cast_area_stream_get_scale (MetaScreenCastAreaStream *area_stream)
|
||||
{
|
||||
return area_stream->scale;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
calculate_scale (ClutterStage *stage,
|
||||
MetaRectangle *area,
|
||||
float *out_scale)
|
||||
{
|
||||
GList *l;
|
||||
float scale = 0.0;
|
||||
|
||||
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *stage_view = l->data;
|
||||
MetaRectangle view_layout;
|
||||
|
||||
clutter_stage_view_get_layout (stage_view, &view_layout);
|
||||
if (meta_rectangle_overlap (area, &view_layout))
|
||||
scale = MAX (clutter_stage_view_get_scale (stage_view), scale);
|
||||
}
|
||||
|
||||
if (scale == 0.0)
|
||||
return FALSE;
|
||||
|
||||
*out_scale = scale;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaScreenCastAreaStream *
|
||||
meta_screen_cast_area_stream_new (MetaScreenCastSession *session,
|
||||
GDBusConnection *connection,
|
||||
MetaRectangle *area,
|
||||
ClutterStage *stage,
|
||||
MetaScreenCastCursorMode cursor_mode,
|
||||
GError **error)
|
||||
{
|
||||
MetaScreenCastAreaStream *area_stream;
|
||||
float scale;
|
||||
|
||||
if (!calculate_scale (stage, area, &scale))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Area is off-screen");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
area_stream = g_initable_new (META_TYPE_SCREEN_CAST_AREA_STREAM,
|
||||
NULL,
|
||||
error,
|
||||
"session", session,
|
||||
"connection", connection,
|
||||
"cursor-mode", cursor_mode,
|
||||
NULL);
|
||||
if (!area_stream)
|
||||
return NULL;
|
||||
|
||||
area_stream->area = *area;
|
||||
area_stream->scale = scale;
|
||||
area_stream->stage = stage;
|
||||
|
||||
return area_stream;
|
||||
}
|
||||
|
||||
static MetaScreenCastStreamSrc *
|
||||
meta_screen_cast_area_stream_create_src (MetaScreenCastStream *stream,
|
||||
GError **error)
|
||||
{
|
||||
MetaScreenCastAreaStream *area_stream =
|
||||
META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
MetaScreenCastAreaStreamSrc *area_stream_src;
|
||||
|
||||
area_stream_src = meta_screen_cast_area_stream_src_new (area_stream,
|
||||
error);
|
||||
if (!area_stream_src)
|
||||
return NULL;
|
||||
|
||||
return META_SCREEN_CAST_STREAM_SRC (area_stream_src);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_set_parameters (MetaScreenCastStream *stream,
|
||||
GVariantBuilder *parameters_builder)
|
||||
{
|
||||
MetaScreenCastAreaStream *area_stream =
|
||||
META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
|
||||
g_variant_builder_add (parameters_builder, "{sv}",
|
||||
"size",
|
||||
g_variant_new ("(ii)",
|
||||
area_stream->area.width,
|
||||
area_stream->area.height));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_transform_position (MetaScreenCastStream *stream,
|
||||
double stream_x,
|
||||
double stream_y,
|
||||
double *x,
|
||||
double *y)
|
||||
{
|
||||
MetaScreenCastAreaStream *area_stream =
|
||||
META_SCREEN_CAST_AREA_STREAM (stream);
|
||||
|
||||
*x = area_stream->area.x + (int) roundf (stream_x / area_stream->scale);
|
||||
*y = area_stream->area.y + (int) roundf (stream_y / area_stream->scale);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_init (MetaScreenCastAreaStream *area_stream)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_area_stream_class_init (MetaScreenCastAreaStreamClass *klass)
|
||||
{
|
||||
MetaScreenCastStreamClass *stream_class =
|
||||
META_SCREEN_CAST_STREAM_CLASS (klass);
|
||||
|
||||
stream_class->create_src = meta_screen_cast_area_stream_create_src;
|
||||
stream_class->set_parameters = meta_screen_cast_area_stream_set_parameters;
|
||||
stream_class->transform_position = meta_screen_cast_area_stream_transform_position;
|
||||
}
|
48
src/backends/meta-screen-cast-area-stream.h
Normal file
48
src/backends/meta-screen-cast-area-stream.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef META_SCREEN_CAST_AREA_STREAM_H
|
||||
#define META_SCREEN_CAST_AREA_STREAM_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "backends/meta-screen-cast-stream.h"
|
||||
#include "backends/meta-screen-cast.h"
|
||||
|
||||
#define META_TYPE_SCREEN_CAST_AREA_STREAM (meta_screen_cast_area_stream_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaScreenCastAreaStream,
|
||||
meta_screen_cast_area_stream,
|
||||
META, SCREEN_CAST_AREA_STREAM,
|
||||
MetaScreenCastStream)
|
||||
|
||||
MetaScreenCastAreaStream * meta_screen_cast_area_stream_new (MetaScreenCastSession *session,
|
||||
GDBusConnection *connection,
|
||||
MetaRectangle *area,
|
||||
ClutterStage *stage,
|
||||
MetaScreenCastCursorMode cursor_mode,
|
||||
GError **error);
|
||||
|
||||
ClutterStage * meta_screen_cast_area_stream_get_stage (MetaScreenCastAreaStream *area_stream);
|
||||
|
||||
MetaRectangle * meta_screen_cast_area_stream_get_area (MetaScreenCastAreaStream *area_stream);
|
||||
|
||||
float meta_screen_cast_area_stream_get_scale (MetaScreenCastAreaStream *area_stream);
|
||||
|
||||
#endif /* META_SCREEN_CAST_AREA_STREAM_H */
|
@@ -115,9 +115,10 @@ meta_screen_cast_monitor_stream_src_get_specs (MetaScreenCastStreamSrc *src,
|
||||
}
|
||||
|
||||
static void
|
||||
stage_painted (MetaStage *stage,
|
||||
ClutterStageView *view,
|
||||
gpointer user_data)
|
||||
stage_painted (MetaStage *stage,
|
||||
ClutterStageView *view,
|
||||
ClutterPaintContext *paint_context,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (user_data);
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
#include "backends/meta-screen-cast-area-stream.h"
|
||||
#include "backends/meta-screen-cast-monitor-stream.h"
|
||||
#include "backends/meta-screen-cast-stream.h"
|
||||
#include "backends/meta-screen-cast-window-stream.h"
|
||||
@@ -485,6 +486,90 @@ handle_record_window (MetaDBusScreenCastSession *skeleton,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_record_area (MetaDBusScreenCastSession *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
GVariant *properties_variant)
|
||||
{
|
||||
MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (skeleton);
|
||||
GDBusInterfaceSkeleton *interface_skeleton;
|
||||
GDBusConnection *connection;
|
||||
MetaBackend *backend;
|
||||
ClutterStage *stage;
|
||||
MetaScreenCastCursorMode cursor_mode;
|
||||
g_autoptr (GError) error = NULL;
|
||||
MetaRectangle rect;
|
||||
MetaScreenCastAreaStream *area_stream;
|
||||
MetaScreenCastStream *stream;
|
||||
char *stream_path;
|
||||
|
||||
if (!check_permission (session, invocation))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_ACCESS_DENIED,
|
||||
"Permission denied");
|
||||
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);
|
||||
backend = meta_screen_cast_get_backend (session->screen_cast);
|
||||
stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
|
||||
|
||||
rect = (MetaRectangle) {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height
|
||||
};
|
||||
area_stream = meta_screen_cast_area_stream_new (session,
|
||||
connection,
|
||||
&rect,
|
||||
stage,
|
||||
cursor_mode,
|
||||
&error);
|
||||
if (!area_stream)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Failed to record area: %s",
|
||||
error->message);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
stream = META_SCREEN_CAST_STREAM (area_stream);
|
||||
stream_path = meta_screen_cast_stream_get_object_path (stream);
|
||||
|
||||
session->streams = g_list_append (session->streams, stream);
|
||||
|
||||
g_signal_connect (stream, "closed", G_CALLBACK (on_stream_closed), session);
|
||||
|
||||
meta_dbus_screen_cast_session_complete_record_area (skeleton,
|
||||
invocation,
|
||||
stream_path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_session_init_iface (MetaDBusScreenCastSessionIface *iface)
|
||||
{
|
||||
@@ -492,6 +577,7 @@ meta_screen_cast_session_init_iface (MetaDBusScreenCastSessionIface *iface)
|
||||
iface->handle_stop = handle_stop;
|
||||
iface->handle_record_monitor = handle_record_monitor;
|
||||
iface->handle_record_window = handle_record_window;
|
||||
iface->handle_record_area = handle_record_area;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -956,6 +956,15 @@ meta_screen_cast_stream_src_init_initable_iface (GInitableIface *iface)
|
||||
iface->init = meta_screen_cast_stream_src_initable_init;
|
||||
}
|
||||
|
||||
int
|
||||
meta_screen_cast_stream_src_get_stride (MetaScreenCastStreamSrc *src)
|
||||
{
|
||||
MetaScreenCastStreamSrcPrivate *priv =
|
||||
meta_screen_cast_stream_src_get_instance_private (src);
|
||||
|
||||
return priv->video_stride;
|
||||
}
|
||||
|
||||
MetaScreenCastStream *
|
||||
meta_screen_cast_stream_src_get_stream (MetaScreenCastStreamSrc *src)
|
||||
{
|
||||
|
@@ -65,6 +65,8 @@ struct _MetaScreenCastStreamSrcClass
|
||||
|
||||
void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src);
|
||||
|
||||
int meta_screen_cast_stream_src_get_stride (MetaScreenCastStreamSrc *src);
|
||||
|
||||
MetaScreenCastStream * meta_screen_cast_stream_src_get_stream (MetaScreenCastStreamSrc *src);
|
||||
|
||||
gboolean meta_screen_cast_stream_src_draw_cursor_into (MetaScreenCastStreamSrc *src,
|
||||
|
@@ -40,6 +40,8 @@ struct _MetaScreenCast
|
||||
|
||||
int dbus_name_id;
|
||||
|
||||
int inhibit_count;
|
||||
|
||||
GList *sessions;
|
||||
|
||||
MetaDbusSessionWatcher *session_watcher;
|
||||
@@ -54,6 +56,29 @@ G_DEFINE_TYPE_WITH_CODE (MetaScreenCast, meta_screen_cast,
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_SCREEN_CAST,
|
||||
meta_screen_cast_init_iface))
|
||||
|
||||
void
|
||||
meta_screen_cast_inhibit (MetaScreenCast *screen_cast)
|
||||
{
|
||||
screen_cast->inhibit_count++;
|
||||
if (screen_cast->inhibit_count == 1)
|
||||
{
|
||||
while (screen_cast->sessions)
|
||||
{
|
||||
MetaScreenCastSession *session = screen_cast->sessions->data;
|
||||
|
||||
meta_screen_cast_session_close (session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_cast_uninhibit (MetaScreenCast *screen_cast)
|
||||
{
|
||||
g_return_if_fail (screen_cast->inhibit_count > 0);
|
||||
|
||||
screen_cast->inhibit_count--;
|
||||
}
|
||||
|
||||
GDBusConnection *
|
||||
meta_screen_cast_get_connection (MetaScreenCast *screen_cast)
|
||||
{
|
||||
@@ -119,6 +144,15 @@ handle_create_session (MetaDBusScreenCast *skeleton,
|
||||
gboolean disable_animations;
|
||||
MetaScreenCastSessionType session_type;
|
||||
|
||||
if (screen_cast->inhibit_count > 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_ACCESS_DENIED,
|
||||
"Session creation inhibited");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_variant_lookup (properties, "remote-desktop-session-id", "s",
|
||||
&remote_desktop_session_id);
|
||||
|
||||
|
@@ -42,6 +42,10 @@ G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast,
|
||||
META, SCREEN_CAST,
|
||||
MetaDBusScreenCastSkeleton)
|
||||
|
||||
void meta_screen_cast_inhibit (MetaScreenCast *screen_cast);
|
||||
|
||||
void meta_screen_cast_uninhibit (MetaScreenCast *screen_cast);
|
||||
|
||||
GDBusConnection * meta_screen_cast_get_connection (MetaScreenCast *screen_cast);
|
||||
|
||||
MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast);
|
||||
|
@@ -38,9 +38,10 @@ typedef enum
|
||||
META_STAGE_WATCH_AFTER_PAINT,
|
||||
} MetaStageWatchPhase;
|
||||
|
||||
typedef void (* MetaStageWatchFunc) (MetaStage *stage,
|
||||
ClutterStageView *view,
|
||||
gpointer user_data);
|
||||
typedef void (* MetaStageWatchFunc) (MetaStage *stage,
|
||||
ClutterStageView *view,
|
||||
ClutterPaintContext *paint_context,
|
||||
gpointer user_data);
|
||||
|
||||
ClutterActor *meta_stage_new (MetaBackend *backend);
|
||||
|
||||
|
@@ -65,7 +65,6 @@ struct _MetaStage
|
||||
ClutterStage parent;
|
||||
|
||||
GPtrArray *watchers[N_WATCH_MODES];
|
||||
ClutterStageView *current_view;
|
||||
|
||||
GList *overlays;
|
||||
gboolean is_active;
|
||||
@@ -169,6 +168,7 @@ meta_stage_finalize (GObject *object)
|
||||
static void
|
||||
notify_watchers_for_mode (MetaStage *stage,
|
||||
ClutterStageView *view,
|
||||
ClutterPaintContext *paint_context,
|
||||
MetaStageWatchPhase watch_phase)
|
||||
{
|
||||
GPtrArray *watchers;
|
||||
@@ -183,7 +183,7 @@ notify_watchers_for_mode (MetaStage *stage,
|
||||
if (watch->view && view != watch->view)
|
||||
continue;
|
||||
|
||||
watch->callback (stage, view, watch->user_data);
|
||||
watch->callback (stage, view, paint_context, watch->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,20 +192,32 @@ meta_stage_paint (ClutterActor *actor,
|
||||
ClutterPaintContext *paint_context)
|
||||
{
|
||||
MetaStage *stage = META_STAGE (actor);
|
||||
ClutterStageView *view;
|
||||
GList *l;
|
||||
|
||||
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor, paint_context);
|
||||
|
||||
notify_watchers_for_mode (stage, stage->current_view,
|
||||
META_STAGE_WATCH_AFTER_ACTOR_PAINT);
|
||||
view = clutter_paint_context_get_stage_view (paint_context);
|
||||
if (view)
|
||||
{
|
||||
notify_watchers_for_mode (stage, view, paint_context,
|
||||
META_STAGE_WATCH_AFTER_ACTOR_PAINT);
|
||||
}
|
||||
|
||||
g_signal_emit (stage, signals[ACTORS_PAINTED], 0);
|
||||
|
||||
for (l = stage->overlays; l; l = l->next)
|
||||
meta_overlay_paint (l->data, paint_context);
|
||||
if (!(clutter_paint_context_get_paint_flags (paint_context) &
|
||||
CLUTTER_PAINT_FLAG_NO_CURSORS))
|
||||
{
|
||||
for (l = stage->overlays; l; l = l->next)
|
||||
meta_overlay_paint (l->data, paint_context);
|
||||
}
|
||||
|
||||
notify_watchers_for_mode (stage, stage->current_view,
|
||||
META_STAGE_WATCH_AFTER_OVERLAY_PAINT);
|
||||
if (view)
|
||||
{
|
||||
notify_watchers_for_mode (stage, view, paint_context,
|
||||
META_STAGE_WATCH_AFTER_OVERLAY_PAINT);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -215,13 +227,14 @@ meta_stage_paint_view (ClutterStage *stage,
|
||||
{
|
||||
MetaStage *meta_stage = META_STAGE (stage);
|
||||
|
||||
notify_watchers_for_mode (meta_stage, view, META_STAGE_WATCH_BEFORE_PAINT);
|
||||
notify_watchers_for_mode (meta_stage, view, NULL,
|
||||
META_STAGE_WATCH_BEFORE_PAINT);
|
||||
|
||||
meta_stage->current_view = view;
|
||||
CLUTTER_STAGE_CLASS (meta_stage_parent_class)->paint_view (stage, view,
|
||||
redraw_clip);
|
||||
|
||||
notify_watchers_for_mode (meta_stage, view, META_STAGE_WATCH_AFTER_PAINT);
|
||||
notify_watchers_for_mode (meta_stage, view, NULL,
|
||||
META_STAGE_WATCH_AFTER_PAINT);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -407,13 +407,14 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
|
||||
else
|
||||
scale = 1.0;
|
||||
|
||||
meta_monitor_calculate_crtc_pos (monitor, monitor_mode,
|
||||
monitor_crtc_mode->output,
|
||||
META_MONITOR_TRANSFORM_NORMAL,
|
||||
&crtc_x, &crtc_y);
|
||||
|
||||
transform = meta_logical_monitor_get_transform (data->in_logical_monitor);
|
||||
transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
|
||||
|
||||
meta_monitor_calculate_crtc_pos (monitor, monitor_mode,
|
||||
monitor_crtc_mode->output,
|
||||
transform,
|
||||
&crtc_x, &crtc_y);
|
||||
|
||||
if (meta_monitor_transform_is_rotated (transform))
|
||||
{
|
||||
crtc_width = monitor_crtc_mode->crtc_mode->height;
|
||||
|
@@ -44,7 +44,12 @@ struct _MetaDrmBufferGbm
|
||||
uint32_t fb_id;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaDrmBufferGbm, meta_drm_buffer_gbm, META_TYPE_DRM_BUFFER)
|
||||
static void
|
||||
cogl_scanout_iface_init (CoglScanoutInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaDrmBufferGbm, meta_drm_buffer_gbm, META_TYPE_DRM_BUFFER,
|
||||
G_IMPLEMENT_INTERFACE (COGL_TYPE_SCANOUT,
|
||||
cogl_scanout_iface_init))
|
||||
|
||||
struct gbm_bo *
|
||||
meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm)
|
||||
@@ -53,22 +58,12 @@ meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
acquire_swapped_buffer (MetaDrmBufferGbm *buffer_gbm,
|
||||
gboolean use_modifiers,
|
||||
GError **error)
|
||||
init_fb_id (MetaDrmBufferGbm *buffer_gbm,
|
||||
struct gbm_bo *bo,
|
||||
gboolean use_modifiers,
|
||||
GError **error)
|
||||
{
|
||||
MetaGpuKmsFBArgs fb_args = { 0, };
|
||||
struct gbm_bo *bo;
|
||||
|
||||
bo = gbm_surface_lock_front_buffer (buffer_gbm->surface);
|
||||
if (!bo)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"gbm_surface_lock_front_buffer failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gbm_bo_get_handle_for_plane (bo, 0).s32 == -1)
|
||||
{
|
||||
@@ -99,21 +94,34 @@ acquire_swapped_buffer (MetaDrmBufferGbm *buffer_gbm,
|
||||
use_modifiers,
|
||||
&fb_args,
|
||||
&buffer_gbm->fb_id, error))
|
||||
{
|
||||
gbm_surface_release_buffer (buffer_gbm->surface, bo);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
buffer_gbm->bo = bo;
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
lock_front_buffer (MetaDrmBufferGbm *buffer_gbm,
|
||||
gboolean use_modifiers,
|
||||
GError **error)
|
||||
{
|
||||
buffer_gbm->bo = gbm_surface_lock_front_buffer (buffer_gbm->surface);
|
||||
if (!buffer_gbm->bo)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"gbm_surface_lock_front_buffer failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return init_fb_id (buffer_gbm, buffer_gbm->bo, use_modifiers, error);
|
||||
}
|
||||
|
||||
MetaDrmBufferGbm *
|
||||
meta_drm_buffer_gbm_new (MetaGpuKms *gpu_kms,
|
||||
struct gbm_surface *gbm_surface,
|
||||
gboolean use_modifiers,
|
||||
GError **error)
|
||||
meta_drm_buffer_gbm_new_lock_front (MetaGpuKms *gpu_kms,
|
||||
struct gbm_surface *gbm_surface,
|
||||
gboolean use_modifiers,
|
||||
GError **error)
|
||||
{
|
||||
MetaDrmBufferGbm *buffer_gbm;
|
||||
|
||||
@@ -121,7 +129,7 @@ meta_drm_buffer_gbm_new (MetaGpuKms *gpu_kms,
|
||||
buffer_gbm->gpu_kms = gpu_kms;
|
||||
buffer_gbm->surface = gbm_surface;
|
||||
|
||||
if (!acquire_swapped_buffer (buffer_gbm, use_modifiers, error))
|
||||
if (!lock_front_buffer (buffer_gbm, use_modifiers, error))
|
||||
{
|
||||
g_object_unref (buffer_gbm);
|
||||
return NULL;
|
||||
@@ -130,12 +138,39 @@ meta_drm_buffer_gbm_new (MetaGpuKms *gpu_kms,
|
||||
return buffer_gbm;
|
||||
}
|
||||
|
||||
MetaDrmBufferGbm *
|
||||
meta_drm_buffer_gbm_new_take (MetaGpuKms *gpu_kms,
|
||||
struct gbm_bo *bo,
|
||||
gboolean use_modifiers,
|
||||
GError **error)
|
||||
{
|
||||
MetaDrmBufferGbm *buffer_gbm;
|
||||
|
||||
buffer_gbm = g_object_new (META_TYPE_DRM_BUFFER_GBM, NULL);
|
||||
buffer_gbm->gpu_kms = gpu_kms;
|
||||
|
||||
if (!init_fb_id (buffer_gbm, bo, use_modifiers, error))
|
||||
{
|
||||
g_object_unref (buffer_gbm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer_gbm->bo = bo;
|
||||
|
||||
return buffer_gbm;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
meta_drm_buffer_gbm_get_fb_id (MetaDrmBuffer *buffer)
|
||||
{
|
||||
return META_DRM_BUFFER_GBM (buffer)->fb_id;
|
||||
}
|
||||
|
||||
static void
|
||||
cogl_scanout_iface_init (CoglScanoutInterface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_drm_buffer_gbm_finalize (GObject *object)
|
||||
{
|
||||
@@ -150,7 +185,12 @@ meta_drm_buffer_gbm_finalize (GObject *object)
|
||||
}
|
||||
|
||||
if (buffer_gbm->bo)
|
||||
gbm_surface_release_buffer (buffer_gbm->surface, buffer_gbm->bo);
|
||||
{
|
||||
if (buffer_gbm->surface)
|
||||
gbm_surface_release_buffer (buffer_gbm->surface, buffer_gbm->bo);
|
||||
else
|
||||
gbm_bo_destroy (buffer_gbm->bo);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (meta_drm_buffer_gbm_parent_class)->finalize (object);
|
||||
}
|
||||
|
@@ -33,10 +33,16 @@ G_DECLARE_FINAL_TYPE (MetaDrmBufferGbm,
|
||||
META, DRM_BUFFER_GBM,
|
||||
MetaDrmBuffer)
|
||||
|
||||
MetaDrmBufferGbm * meta_drm_buffer_gbm_new (MetaGpuKms *gpu_kms,
|
||||
struct gbm_surface *gbm_surface,
|
||||
gboolean use_modifiers,
|
||||
GError **error);
|
||||
MetaDrmBufferGbm * meta_drm_buffer_gbm_new_lock_front (MetaGpuKms *gpu_kms,
|
||||
struct gbm_surface *gbm_surface,
|
||||
gboolean use_modifiers,
|
||||
GError **error);
|
||||
|
||||
|
||||
MetaDrmBufferGbm * meta_drm_buffer_gbm_new_take (MetaGpuKms *gpu_kms,
|
||||
struct gbm_bo *gbm_bo,
|
||||
gboolean use_modifiers,
|
||||
GError **error);
|
||||
|
||||
struct gbm_bo * meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm);
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Red Hat
|
||||
* Copyright (C) 2019 DisplayLink (UK) Ltd.
|
||||
* Copyright (C) 2019-2020 DisplayLink (UK) Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -660,6 +660,9 @@ process_page_flip (MetaKmsImpl *impl,
|
||||
meta_kms_page_flip_data_ref (page_flip_data));
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
meta_kms_page_flip_data_unref (page_flip_data);
|
||||
|
||||
if (ret == -EBUSY)
|
||||
{
|
||||
CachedModeSet *cached_mode_set;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat
|
||||
* Copyright 2020 DisplayLink (UK) Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -383,6 +384,7 @@ meta_kms_add_source_in_impl (MetaKms *kms,
|
||||
simple_impl_source->kms = kms;
|
||||
|
||||
g_source_set_callback (source, func, user_data, user_data_destroy);
|
||||
g_source_set_ready_time (source, 0);
|
||||
g_source_attach (source, g_main_context_get_thread_default ());
|
||||
|
||||
return source;
|
||||
|
@@ -313,6 +313,12 @@ meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms)
|
||||
return renderer_gpu_data->gbm.device;
|
||||
}
|
||||
|
||||
MetaGpuKms *
|
||||
meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native)
|
||||
{
|
||||
return renderer_native->primary_gpu_kms;
|
||||
}
|
||||
|
||||
static MetaRendererNativeGpuData *
|
||||
meta_create_renderer_native_gpu_data (MetaGpuKms *gpu_kms)
|
||||
{
|
||||
@@ -1621,13 +1627,14 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_gbm = meta_drm_buffer_gbm_new (secondary_gpu_state->gpu_kms,
|
||||
buffer_gbm =
|
||||
meta_drm_buffer_gbm_new_lock_front (secondary_gpu_state->gpu_kms,
|
||||
secondary_gpu_state->gbm.surface,
|
||||
renderer_native->use_modifiers,
|
||||
&error);
|
||||
if (!buffer_gbm)
|
||||
{
|
||||
g_warning ("meta_drm_buffer_gbm_new failed: %s",
|
||||
g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
@@ -2012,6 +2019,34 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_crtc_modes (CoglOnscreen *onscreen,
|
||||
MetaKmsUpdate *kms_update)
|
||||
{
|
||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
||||
CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context;
|
||||
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
||||
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
||||
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
||||
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
||||
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
||||
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_backend_get_monitor_manager (backend);
|
||||
MetaPowerSave power_save_mode;
|
||||
|
||||
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
||||
if (onscreen_native->pending_set_crtc &&
|
||||
power_save_mode == META_POWER_SAVE_ON)
|
||||
{
|
||||
meta_onscreen_native_set_crtc_mode (onscreen,
|
||||
renderer_gpu_data,
|
||||
kms_update);
|
||||
onscreen_native->pending_set_crtc = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||
const int *rectangles,
|
||||
@@ -2025,8 +2060,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
||||
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
||||
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_backend_get_monitor_manager (backend);
|
||||
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
||||
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||
@@ -2035,7 +2068,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||
CoglFrameInfo *frame_info;
|
||||
gboolean egl_context_changed = FALSE;
|
||||
MetaKmsUpdate *kms_update;
|
||||
MetaPowerSave power_save_mode;
|
||||
g_autoptr (GError) error = NULL;
|
||||
MetaDrmBufferGbm *buffer_gbm;
|
||||
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
|
||||
@@ -2071,13 +2103,14 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||
g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
|
||||
g_clear_object (&onscreen_native->gbm.next_fb);
|
||||
|
||||
buffer_gbm = meta_drm_buffer_gbm_new (render_gpu,
|
||||
buffer_gbm =
|
||||
meta_drm_buffer_gbm_new_lock_front (render_gpu,
|
||||
onscreen_native->gbm.surface,
|
||||
renderer_native->use_modifiers,
|
||||
&error);
|
||||
if (!buffer_gbm)
|
||||
{
|
||||
g_warning ("meta_drm_buffer_gbm_new failed: %s",
|
||||
g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s",
|
||||
error->message);
|
||||
return;
|
||||
}
|
||||
@@ -2093,18 +2126,7 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||
|
||||
update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
|
||||
|
||||
/* If this is the first framebuffer to be presented then we now setup the
|
||||
* crtc modes, else we flip from the previous buffer */
|
||||
|
||||
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
||||
if (onscreen_native->pending_set_crtc &&
|
||||
power_save_mode == META_POWER_SAVE_ON)
|
||||
{
|
||||
meta_onscreen_native_set_crtc_mode (onscreen,
|
||||
renderer_gpu_data,
|
||||
kms_update);
|
||||
onscreen_native->pending_set_crtc = FALSE;
|
||||
}
|
||||
ensure_crtc_modes (onscreen, kms_update);
|
||||
|
||||
onscreen_native->pending_queue_swap_notify_frame_count = renderer_native->frame_counter;
|
||||
meta_onscreen_native_flip_crtcs (onscreen, kms_update);
|
||||
@@ -2198,6 +2220,92 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
|
||||
uint32_t drm_format,
|
||||
uint64_t drm_modifier,
|
||||
uint32_t stride)
|
||||
{
|
||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
||||
MetaDrmBuffer *fb;
|
||||
struct gbm_bo *gbm_bo;
|
||||
|
||||
if (onscreen_native->crtc->config->transform != META_MONITOR_TRANSFORM_NORMAL)
|
||||
return FALSE;
|
||||
|
||||
if (onscreen_native->secondary_gpu_state)
|
||||
return FALSE;
|
||||
|
||||
if (!onscreen_native->gbm.surface)
|
||||
return FALSE;
|
||||
|
||||
fb = onscreen_native->gbm.current_fb ? onscreen_native->gbm.current_fb
|
||||
: onscreen_native->gbm.next_fb;
|
||||
if (!fb)
|
||||
return FALSE;
|
||||
|
||||
if (!META_IS_DRM_BUFFER_GBM (fb))
|
||||
return FALSE;
|
||||
|
||||
gbm_bo = meta_drm_buffer_gbm_get_bo (META_DRM_BUFFER_GBM (fb));
|
||||
|
||||
if (gbm_bo_get_format (gbm_bo) != drm_format)
|
||||
return FALSE;
|
||||
|
||||
if (gbm_bo_get_modifier (gbm_bo) != drm_modifier)
|
||||
return FALSE;
|
||||
|
||||
if (gbm_bo_get_stride (gbm_bo) != stride)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
|
||||
CoglScanout *scanout)
|
||||
{
|
||||
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
||||
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
||||
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
|
||||
CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context;
|
||||
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
||||
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
||||
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
||||
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
||||
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
||||
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
||||
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
||||
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
||||
CoglFrameInfo *frame_info;
|
||||
MetaKmsUpdate *kms_update;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
kms_update = meta_kms_ensure_pending_update (kms);
|
||||
|
||||
wait_for_pending_flips (onscreen);
|
||||
|
||||
frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos);
|
||||
frame_info->global_frame_counter = renderer_native->frame_counter;
|
||||
|
||||
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
||||
render_gpu);
|
||||
|
||||
g_return_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM);
|
||||
|
||||
g_warn_if_fail (!onscreen_native->gbm.next_fb);
|
||||
g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout));
|
||||
|
||||
ensure_crtc_modes (onscreen, kms_update);
|
||||
|
||||
onscreen_native->pending_queue_swap_notify_frame_count =
|
||||
renderer_native->frame_counter;
|
||||
meta_onscreen_native_flip_crtcs (onscreen, kms_update);
|
||||
|
||||
meta_kms_post_pending_update_sync (kms);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_renderer_native_init_egl_context (CoglContext *cogl_context,
|
||||
GError **error)
|
||||
@@ -2921,6 +3029,7 @@ get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer)
|
||||
vtable.onscreen_swap_region = NULL;
|
||||
vtable.onscreen_swap_buffers_with_damage =
|
||||
meta_onscreen_native_swap_buffers_with_damage;
|
||||
vtable.onscreen_direct_scanout = meta_onscreen_native_direct_scanout;
|
||||
|
||||
vtable.context_get_clock_time = meta_renderer_native_get_clock_time;
|
||||
|
||||
@@ -3037,6 +3146,7 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
|
||||
float scale;
|
||||
int onscreen_width;
|
||||
int onscreen_height;
|
||||
MetaRectangle view_layout;
|
||||
MetaRendererView *view;
|
||||
GError *error = NULL;
|
||||
|
||||
@@ -3108,8 +3218,11 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
|
||||
else
|
||||
scale = 1.0;
|
||||
|
||||
meta_rectangle_from_graphene_rect (&crtc->config->layout,
|
||||
META_ROUNDING_STRATEGY_ROUND,
|
||||
&view_layout);
|
||||
view = g_object_new (META_TYPE_RENDERER_VIEW,
|
||||
"layout", &logical_monitor->rect,
|
||||
"layout", &view_layout,
|
||||
"scale", scale,
|
||||
"framebuffer", onscreen,
|
||||
"offscreen", offscreen,
|
||||
|
@@ -51,8 +51,15 @@ MetaRendererNative * meta_renderer_native_new (MetaBackendNative *backend_nativ
|
||||
|
||||
struct gbm_device * meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms);
|
||||
|
||||
MetaGpuKms * meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native);
|
||||
|
||||
void meta_renderer_native_finish_frame (MetaRendererNative *renderer_native);
|
||||
|
||||
int64_t meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native);
|
||||
|
||||
gboolean meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
|
||||
uint32_t drm_format,
|
||||
uint64_t drm_modifier,
|
||||
uint32_t stride);
|
||||
|
||||
#endif /* META_RENDERER_NATIVE_H */
|
||||
|
@@ -14,11 +14,14 @@
|
||||
/* Wait 2ms after vblank before starting to draw next frame */
|
||||
#define META_SYNC_DELAY 2
|
||||
|
||||
typedef struct _MetaLaters MetaLaters;
|
||||
|
||||
struct _MetaCompositorClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* manage) (MetaCompositor *compositor);
|
||||
gboolean (* manage) (MetaCompositor *compositor,
|
||||
GError **error);
|
||||
void (* unmanage) (MetaCompositor *compositor);
|
||||
void (* pre_paint) (MetaCompositor *compositor);
|
||||
void (* post_paint) (MetaCompositor *compositor);
|
||||
@@ -26,6 +29,9 @@ struct _MetaCompositorClass
|
||||
MetaWindow *window);
|
||||
};
|
||||
|
||||
gboolean meta_compositor_do_manage (MetaCompositor *compositor,
|
||||
GError **error);
|
||||
|
||||
void meta_compositor_remove_window_actor (MetaCompositor *compositor,
|
||||
MetaWindowActor *window_actor);
|
||||
|
||||
@@ -67,4 +73,6 @@ ClutterStage * meta_compositor_get_stage (MetaCompositor *compositor);
|
||||
|
||||
gboolean meta_compositor_is_switching_workspace (MetaCompositor *compositor);
|
||||
|
||||
MetaLaters * meta_compositor_get_laters (MetaCompositor *compositor);
|
||||
|
||||
#endif /* META_COMPOSITOR_PRIVATE_H */
|
||||
|
@@ -62,8 +62,8 @@
|
||||
#include "backends/x11/meta-stage-x11.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
#include "cogl/cogl.h"
|
||||
#include "compositor/meta-later-private.h"
|
||||
#include "compositor/meta-window-actor-x11.h"
|
||||
#include "compositor/meta-window-actor-wayland.h"
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
#include "compositor/meta-window-group-private.h"
|
||||
#include "core/display-private.h"
|
||||
@@ -82,6 +82,7 @@
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "compositor/meta-window-actor-wayland.h"
|
||||
#include "wayland/meta-wayland-private.h"
|
||||
#endif
|
||||
|
||||
@@ -96,6 +97,15 @@ enum
|
||||
|
||||
static GParamSpec *obj_props[N_PROPS] = { NULL, };
|
||||
|
||||
enum
|
||||
{
|
||||
PRE_PAINT,
|
||||
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS];
|
||||
|
||||
typedef struct _MetaCompositorPrivate
|
||||
{
|
||||
GObject parent;
|
||||
@@ -131,6 +141,8 @@ typedef struct _MetaCompositorPrivate
|
||||
int switch_workspace_in_progress;
|
||||
|
||||
MetaPluginManager *plugin_mgr;
|
||||
|
||||
MetaLaters *laters;
|
||||
} MetaCompositorPrivate;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaCompositor, meta_compositor,
|
||||
@@ -550,8 +562,9 @@ meta_compositor_redirect_x11_windows (MetaCompositor *compositor)
|
||||
redirect_windows (display->x11_display);
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_manage (MetaCompositor *compositor)
|
||||
gboolean
|
||||
meta_compositor_do_manage (MetaCompositor *compositor,
|
||||
GError **error)
|
||||
{
|
||||
MetaCompositorPrivate *priv =
|
||||
meta_compositor_get_instance_private (compositor);
|
||||
@@ -587,9 +600,21 @@ meta_compositor_manage (MetaCompositor *compositor)
|
||||
clutter_actor_add_child (priv->stage, priv->top_window_group);
|
||||
clutter_actor_add_child (priv->stage, priv->feedback_group);
|
||||
|
||||
META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor);
|
||||
if (!META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor, error))
|
||||
return FALSE;
|
||||
|
||||
priv->plugin_mgr = meta_plugin_manager_new (compositor);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_manage (MetaCompositor *compositor)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!meta_compositor_do_manage (compositor, &error))
|
||||
g_error ("Compositor failed to manage display: %s", error->message);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1108,7 +1133,8 @@ meta_compositor_pre_paint (MetaCompositor *compositor)
|
||||
{
|
||||
COGL_TRACE_BEGIN_SCOPED (MetaCompositorPrePaint,
|
||||
"Compositor (pre-paint)");
|
||||
META_COMPOSITOR_GET_CLASS (compositor)->pre_paint (compositor);
|
||||
|
||||
g_signal_emit (compositor, signals[PRE_PAINT], 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1230,6 +1256,8 @@ meta_compositor_init (MetaCompositor *compositor)
|
||||
meta_post_paint_func,
|
||||
compositor,
|
||||
NULL);
|
||||
|
||||
priv->laters = meta_laters_new (compositor);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1239,6 +1267,8 @@ meta_compositor_dispose (GObject *object)
|
||||
MetaCompositorPrivate *priv =
|
||||
meta_compositor_get_instance_private (compositor);
|
||||
|
||||
g_clear_pointer (&priv->laters, meta_laters_free);
|
||||
|
||||
g_clear_signal_handler (&priv->stage_after_paint_id, priv->stage);
|
||||
g_clear_signal_handler (&priv->stage_presented_id, priv->stage);
|
||||
|
||||
@@ -1280,6 +1310,14 @@ meta_compositor_class_init (MetaCompositorClass *klass)
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
||||
|
||||
signals[PRE_PAINT] =
|
||||
g_signal_new ("pre-paint",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (MetaCompositorClass, pre_paint),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1597,3 +1635,12 @@ meta_compositor_is_switching_workspace (MetaCompositor *compositor)
|
||||
|
||||
return priv->switch_workspace_in_progress > 0;
|
||||
}
|
||||
|
||||
MetaLaters *
|
||||
meta_compositor_get_laters (MetaCompositor *compositor)
|
||||
{
|
||||
MetaCompositorPrivate *priv =
|
||||
meta_compositor_get_instance_private (compositor);
|
||||
|
||||
return priv->laters;
|
||||
}
|
||||
|
148
src/compositor/meta-compositor-native.c
Normal file
148
src/compositor/meta-compositor-native.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "compositor/meta-compositor-native.h"
|
||||
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "compositor/meta-surface-actor-wayland.h"
|
||||
|
||||
struct _MetaCompositorNative
|
||||
{
|
||||
MetaCompositorServer parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaCompositorNative, meta_compositor_native,
|
||||
META_TYPE_COMPOSITOR_SERVER)
|
||||
|
||||
static MetaRendererView *
|
||||
get_window_view (MetaRenderer *renderer,
|
||||
MetaWindow *window)
|
||||
{
|
||||
GList *l;
|
||||
MetaRendererView *view_found = NULL;
|
||||
|
||||
for (l = meta_renderer_get_views (renderer); l; l = l->next)
|
||||
{
|
||||
ClutterStageView *stage_view = l->data;
|
||||
MetaRectangle view_layout;
|
||||
|
||||
clutter_stage_view_get_layout (stage_view, &view_layout);
|
||||
|
||||
if (meta_rectangle_equal (&window->buffer_rect,
|
||||
&view_layout))
|
||||
{
|
||||
if (view_found)
|
||||
return NULL;
|
||||
view_found = META_RENDERER_VIEW (stage_view);
|
||||
}
|
||||
}
|
||||
|
||||
return view_found;
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_assign_primary_plane (MetaCompositor *compositor)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
||||
MetaWindowActor *window_actor;
|
||||
MetaWindow *window;
|
||||
MetaRendererView *view;
|
||||
CoglFramebuffer *framebuffer;
|
||||
CoglOnscreen *onscreen;
|
||||
MetaSurfaceActor *surface_actor;
|
||||
MetaSurfaceActorWayland *surface_actor_wayland;
|
||||
g_autoptr (CoglScanout) scanout = NULL;
|
||||
|
||||
if (meta_compositor_is_unredirect_inhibited (compositor))
|
||||
return;
|
||||
|
||||
window_actor = meta_compositor_get_top_window_actor (compositor);
|
||||
if (!window_actor)
|
||||
return;
|
||||
|
||||
if (meta_window_actor_effect_in_progress (window_actor))
|
||||
return;
|
||||
|
||||
if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor)))
|
||||
return;
|
||||
|
||||
if (clutter_actor_get_n_children (CLUTTER_ACTOR (window_actor)) != 1)
|
||||
return;
|
||||
|
||||
window = meta_window_actor_get_meta_window (window_actor);
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
view = get_window_view (renderer, window);
|
||||
if (!view)
|
||||
return;
|
||||
|
||||
framebuffer = clutter_stage_view_get_framebuffer (CLUTTER_STAGE_VIEW (view));
|
||||
if (!cogl_is_onscreen (framebuffer))
|
||||
return;
|
||||
|
||||
surface_actor = meta_window_actor_get_surface (window_actor);
|
||||
if (!META_IS_SURFACE_ACTOR_WAYLAND (surface_actor))
|
||||
return;
|
||||
|
||||
surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (surface_actor);
|
||||
onscreen = COGL_ONSCREEN (framebuffer);
|
||||
scanout = meta_surface_actor_wayland_try_acquire_scanout (surface_actor_wayland,
|
||||
onscreen);
|
||||
if (!scanout)
|
||||
return;
|
||||
|
||||
clutter_stage_view_assign_next_scanout (CLUTTER_STAGE_VIEW (view), scanout);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_compositor_native_pre_paint (MetaCompositor *compositor)
|
||||
{
|
||||
MetaCompositorClass *parent_class;
|
||||
|
||||
maybe_assign_primary_plane (compositor);
|
||||
|
||||
parent_class = META_COMPOSITOR_CLASS (meta_compositor_native_parent_class);
|
||||
parent_class->pre_paint (compositor);
|
||||
}
|
||||
|
||||
MetaCompositorNative *
|
||||
meta_compositor_native_new (MetaDisplay *display)
|
||||
{
|
||||
return g_object_new (META_TYPE_COMPOSITOR_NATIVE,
|
||||
"display", display,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_compositor_native_init (MetaCompositorNative *compositor_native)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_compositor_native_class_init (MetaCompositorNativeClass *klass)
|
||||
{
|
||||
MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass);
|
||||
|
||||
compositor_class->pre_paint = meta_compositor_native_pre_paint;
|
||||
}
|
@@ -1,7 +1,5 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat
|
||||
* Copyright (C) 2019 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -18,17 +16,17 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by:
|
||||
* Jonas Ådahl <jadahl@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef META_WAYLAND_DATA_DEVICE_PRIVATE_H
|
||||
#define META_WAYLAND_DATA_DEVICE_PRIVATE_H
|
||||
#ifndef META_COMPOSITOR_NATIVE_H
|
||||
#define META_COMPOSITOR_NATIVE_H
|
||||
|
||||
#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY (meta_wayland_data_source_primary_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimary,
|
||||
meta_wayland_data_source_primary,
|
||||
META, WAYLAND_DATA_SOURCE_PRIMARY,
|
||||
MetaWaylandDataSource);
|
||||
#include "compositor/meta-compositor-server.h"
|
||||
|
||||
#endif /* META_WAYLAND_DATA_DEVICE_PRIVATE_H */
|
||||
#define META_TYPE_COMPOSITOR_NATIVE (meta_compositor_native_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaCompositorNative, meta_compositor_native,
|
||||
META, COMPOSITOR_NATIVE, MetaCompositor)
|
||||
|
||||
MetaCompositorNative * meta_compositor_native_new (MetaDisplay *display);
|
||||
|
||||
#endif /* META_COMPOSITOR_NATIVE_H */
|
@@ -22,16 +22,13 @@
|
||||
|
||||
#include "compositor/meta-compositor-server.h"
|
||||
|
||||
struct _MetaCompositorServer
|
||||
{
|
||||
MetaCompositor parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaCompositorServer, meta_compositor_server, META_TYPE_COMPOSITOR)
|
||||
|
||||
static void
|
||||
meta_compositor_server_manage (MetaCompositor *compositor)
|
||||
static gboolean
|
||||
meta_compositor_server_manage (MetaCompositor *compositor,
|
||||
GError **error)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -24,8 +24,13 @@
|
||||
#include "compositor/compositor-private.h"
|
||||
|
||||
#define META_TYPE_COMPOSITOR_SERVER (meta_compositor_server_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaCompositorServer, meta_compositor_server,
|
||||
META, COMPOSITOR_SERVER, MetaCompositor)
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaCompositorServer, meta_compositor_server,
|
||||
META, COMPOSITOR_SERVER, MetaCompositor)
|
||||
|
||||
struct _MetaCompositorServerClass
|
||||
{
|
||||
MetaCompositorClass parent_class;
|
||||
};
|
||||
|
||||
MetaCompositorServer * meta_compositor_server_new (MetaDisplay *display);
|
||||
|
||||
|
@@ -100,15 +100,39 @@ meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11,
|
||||
meta_x11_handle_event (xevent);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_compositor_x11_manage (MetaCompositor *compositor)
|
||||
static gboolean
|
||||
meta_compositor_x11_manage (MetaCompositor *compositor,
|
||||
GError **error)
|
||||
{
|
||||
MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor);
|
||||
MetaDisplay *display = meta_compositor_get_display (compositor);
|
||||
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
||||
MetaX11Display *x11_display = display->x11_display;
|
||||
Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
|
||||
int composite_version;
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
Window xwindow;
|
||||
|
||||
if (!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ||
|
||||
!META_X11_DISPLAY_HAS_DAMAGE (x11_display))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Missing required extension %s",
|
||||
!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ?
|
||||
"composite" : "damage");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
composite_version = ((x11_display->composite_major_version * 10) +
|
||||
x11_display->composite_minor_version);
|
||||
if (composite_version < 3)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"COMPOSITE extension 3.0 required (found %d.%d)",
|
||||
x11_display->composite_major_version,
|
||||
x11_display->composite_minor_version);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
meta_x11_display_set_cm_selection (display->x11_display);
|
||||
|
||||
compositor_x11->output = display->x11_display->composite_overlay_window;
|
||||
@@ -139,6 +163,8 @@ meta_compositor_x11_manage (MetaCompositor *compositor)
|
||||
compositor_x11->have_x11_sync_object = meta_sync_ring_init (xdisplay);
|
||||
|
||||
meta_compositor_redirect_x11_windows (META_COMPOSITOR (compositor));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
28
src/compositor/meta-later-private.h
Normal file
28
src/compositor/meta-later-private.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_LATER_PRIVATE_H
|
||||
#define META_LATER_PRIVATE_H
|
||||
|
||||
typedef struct _MetaLaters MetaLaters;
|
||||
typedef struct _MetaCompositor MetaCompositor;
|
||||
|
||||
MetaLaters * meta_laters_new (MetaCompositor *compositor);
|
||||
|
||||
void meta_laters_free (MetaLaters *laters);
|
||||
|
||||
#endif /* META_LATER_PRIVATE_H */
|
349
src/compositor/meta-later.c
Normal file
349
src/compositor/meta-later.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2005 Elijah Newren
|
||||
* Copyright (C) 2020 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "compositor/meta-later-private.h"
|
||||
|
||||
#include "cogl/cogl.h"
|
||||
#include "compositor/compositor-private.h"
|
||||
#include "core/display-private.h"
|
||||
#include "meta/meta-later.h"
|
||||
|
||||
typedef struct _MetaLater
|
||||
{
|
||||
unsigned int id;
|
||||
unsigned int ref_count;
|
||||
MetaLaterType when;
|
||||
|
||||
GSourceFunc func;
|
||||
gpointer user_data;
|
||||
GDestroyNotify destroy_notify;
|
||||
|
||||
guint source_id;
|
||||
gboolean run_once;
|
||||
} MetaLater;
|
||||
|
||||
#define META_LATER_N_TYPES (META_LATER_IDLE + 1)
|
||||
|
||||
struct _MetaLaters
|
||||
{
|
||||
MetaCompositor *compositor;
|
||||
|
||||
unsigned int last_later_id;
|
||||
|
||||
GSList *laters[META_LATER_N_TYPES];
|
||||
|
||||
ClutterTimeline *timeline;
|
||||
gulong pre_paint_handler_id;
|
||||
};
|
||||
|
||||
static MetaLater *
|
||||
meta_later_ref (MetaLater *later)
|
||||
{
|
||||
later->ref_count++;
|
||||
return later;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_later_unref (MetaLater *later)
|
||||
{
|
||||
if (--later->ref_count == 0)
|
||||
{
|
||||
if (later->destroy_notify)
|
||||
{
|
||||
later->destroy_notify (later->user_data);
|
||||
later->destroy_notify = NULL;
|
||||
}
|
||||
|
||||
g_slice_free (MetaLater, later);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_later_destroy (MetaLater *later)
|
||||
{
|
||||
g_clear_handle_id (&later->source_id, g_source_remove);
|
||||
later->func = NULL;
|
||||
meta_later_unref (later);
|
||||
}
|
||||
|
||||
#ifdef COGL_HAS_TRACING
|
||||
static const char *
|
||||
later_type_to_string (MetaLaterType when)
|
||||
{
|
||||
switch (when)
|
||||
{
|
||||
case META_LATER_RESIZE:
|
||||
return "Later (resize)";
|
||||
case META_LATER_CALC_SHOWING:
|
||||
return "Later (calc-showing)";
|
||||
case META_LATER_CHECK_FULLSCREEN:
|
||||
return "Later (check-fullscreen)";
|
||||
case META_LATER_SYNC_STACK:
|
||||
return "Later (sync-stack)";
|
||||
case META_LATER_BEFORE_REDRAW:
|
||||
return "Later (before-redraw)";
|
||||
case META_LATER_IDLE:
|
||||
return "Later (idle)";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
meta_later_invoke (MetaLater *later)
|
||||
{
|
||||
COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when));
|
||||
return later->func (later->user_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
remove_later_from_list (unsigned int later_id,
|
||||
GSList **laters_list)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = *laters_list; l; l = l->next)
|
||||
{
|
||||
MetaLater *later = l->data;
|
||||
|
||||
if (later->id == later_id)
|
||||
{
|
||||
*laters_list = g_slist_delete_link (*laters_list, l);
|
||||
meta_later_destroy (later);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
run_repaint_laters (GSList **laters_list)
|
||||
{
|
||||
g_autoptr (GSList) laters_copy = NULL;
|
||||
GSList *l;
|
||||
|
||||
for (l = *laters_list; l; l = l->next)
|
||||
{
|
||||
MetaLater *later = l->data;
|
||||
|
||||
if (!later->source_id ||
|
||||
(later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
|
||||
laters_copy = g_slist_prepend (laters_copy, meta_later_ref (later));
|
||||
}
|
||||
laters_copy = g_slist_reverse (laters_copy);
|
||||
|
||||
for (l = laters_copy; l; l = l->next)
|
||||
{
|
||||
MetaLater *later = l->data;
|
||||
|
||||
if (!later->func)
|
||||
remove_later_from_list (later->id, laters_list);
|
||||
else if (!meta_later_invoke (later))
|
||||
remove_later_from_list (later->id, laters_list);
|
||||
|
||||
meta_later_unref (later);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_pre_paint (MetaCompositor *compositor,
|
||||
MetaLaters *laters)
|
||||
{
|
||||
unsigned int i;
|
||||
GSList *l;
|
||||
gboolean keep_timeline_running = FALSE;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
|
||||
run_repaint_laters (&laters->laters[i]);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
|
||||
{
|
||||
for (l = laters->laters[i]; l; l = l->next)
|
||||
{
|
||||
MetaLater *later = l->data;
|
||||
|
||||
if (!later->source_id)
|
||||
keep_timeline_running = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keep_timeline_running)
|
||||
clutter_timeline_stop (laters->timeline);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_timeline_running (MetaLaters *laters)
|
||||
{
|
||||
clutter_timeline_start (laters->timeline);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
invoke_later_idle (gpointer data)
|
||||
{
|
||||
MetaLater *later = data;
|
||||
|
||||
if (!later->func (later->user_data))
|
||||
{
|
||||
meta_later_remove (later->id);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
later->run_once = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
meta_laters_add (MetaLaters *laters,
|
||||
MetaLaterType when,
|
||||
GSourceFunc func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaLater *later = g_slice_new0 (MetaLater);
|
||||
|
||||
later->id = ++laters->last_later_id;
|
||||
later->ref_count = 1;
|
||||
later->when = when;
|
||||
later->func = func;
|
||||
later->user_data = user_data;
|
||||
later->destroy_notify = notify;
|
||||
|
||||
laters->laters[when] = g_slist_prepend (laters->laters[when], later);
|
||||
|
||||
switch (when)
|
||||
{
|
||||
case META_LATER_RESIZE:
|
||||
later->source_id = g_idle_add_full (META_PRIORITY_RESIZE,
|
||||
invoke_later_idle,
|
||||
later, NULL);
|
||||
g_source_set_name_by_id (later->source_id, "[mutter] invoke_later_idle");
|
||||
ensure_timeline_running (laters);
|
||||
break;
|
||||
case META_LATER_CALC_SHOWING:
|
||||
case META_LATER_CHECK_FULLSCREEN:
|
||||
case META_LATER_SYNC_STACK:
|
||||
case META_LATER_BEFORE_REDRAW:
|
||||
ensure_timeline_running (laters);
|
||||
break;
|
||||
case META_LATER_IDLE:
|
||||
later->source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
|
||||
invoke_later_idle,
|
||||
later, NULL);
|
||||
g_source_set_name_by_id (later->source_id, "[mutter] invoke_later_idle");
|
||||
break;
|
||||
}
|
||||
|
||||
return later->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_later_add:
|
||||
* @when: enumeration value determining the phase at which to run the callback
|
||||
* @func: callback to run later
|
||||
* @data: data to pass to the callback
|
||||
* @notify: function to call to destroy @data when it is no longer in use, or %NULL
|
||||
*
|
||||
* Sets up a callback to be called at some later time. @when determines the
|
||||
* particular later occasion at which it is called. This is much like g_idle_add(),
|
||||
* except that the functions interact properly with clutter event handling.
|
||||
* If a "later" function is added from a clutter event handler, and is supposed
|
||||
* to be run before the stage is redrawn, it will be run before that redraw
|
||||
* of the stage, not the next one.
|
||||
*
|
||||
* Return value: an integer ID (guaranteed to be non-zero) that can be used
|
||||
* to cancel the callback and prevent it from being run.
|
||||
*/
|
||||
unsigned int
|
||||
meta_later_add (MetaLaterType when,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
|
||||
return meta_laters_add (meta_compositor_get_laters (compositor),
|
||||
when, func, data, notify);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_laters_remove (MetaLaters *laters,
|
||||
unsigned int later_id)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
|
||||
{
|
||||
if (remove_later_from_list (later_id, &laters->laters[i]))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_later_remove:
|
||||
* @later_id: the integer ID returned from meta_later_add()
|
||||
*
|
||||
* Removes a callback added with meta_later_add()
|
||||
*/
|
||||
void
|
||||
meta_later_remove (unsigned int later_id)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaCompositor *compositor = display->compositor;
|
||||
|
||||
if (!compositor)
|
||||
return;
|
||||
|
||||
meta_laters_remove (meta_compositor_get_laters (compositor), later_id);
|
||||
}
|
||||
|
||||
MetaLaters *
|
||||
meta_laters_new (MetaCompositor *compositor)
|
||||
{
|
||||
MetaLaters *laters;
|
||||
|
||||
laters = g_new0 (MetaLaters, 1);
|
||||
laters->compositor = compositor;
|
||||
laters->timeline = clutter_timeline_new (G_MAXUINT);
|
||||
|
||||
laters->pre_paint_handler_id = g_signal_connect (compositor, "pre-paint",
|
||||
G_CALLBACK (on_pre_paint),
|
||||
laters);
|
||||
|
||||
return laters;
|
||||
}
|
||||
|
||||
void
|
||||
meta_laters_free (MetaLaters *laters)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (laters->laters); i++)
|
||||
g_slist_free_full (laters->laters[i], (GDestroyNotify) meta_later_unref);
|
||||
|
||||
g_clear_object (&laters->timeline);
|
||||
g_clear_signal_handler (&laters->pre_paint_handler_id, laters->compositor);
|
||||
g_free (laters);
|
||||
}
|
@@ -1270,7 +1270,9 @@ get_image_via_offscreen (MetaShapedTexture *stex,
|
||||
root_node = clutter_root_node_new (fb, &clear_color, COGL_BUFFER_BIT_COLOR);
|
||||
clutter_paint_node_set_static_name (root_node, "MetaShapedTexture.offscreen");
|
||||
|
||||
paint_context = clutter_paint_context_new_for_framebuffer (fb);
|
||||
paint_context =
|
||||
clutter_paint_context_new_for_framebuffer (fb, NULL,
|
||||
CLUTTER_PAINT_FLAG_NONE);
|
||||
|
||||
do_paint_content (stex, root_node, paint_context,
|
||||
stex->texture,
|
||||
|
@@ -79,6 +79,40 @@ meta_surface_actor_wayland_is_opaque (MetaSurfaceActor *actor)
|
||||
return meta_shaped_texture_is_opaque (stex);
|
||||
}
|
||||
|
||||
static void
|
||||
queue_frame_callbacks (MetaSurfaceActorWayland *self)
|
||||
{
|
||||
MetaWaylandCompositor *wayland_compositor;
|
||||
|
||||
if (!self->surface)
|
||||
return;
|
||||
|
||||
if (meta_surface_actor_is_obscured (META_SURFACE_ACTOR (self)))
|
||||
return;
|
||||
|
||||
wayland_compositor = self->surface->compositor;
|
||||
wl_list_insert_list (&wayland_compositor->frame_callbacks,
|
||||
&self->frame_callback_list);
|
||||
wl_list_init (&self->frame_callback_list);
|
||||
}
|
||||
|
||||
CoglScanout *
|
||||
meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self,
|
||||
CoglOnscreen *onscreen)
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
CoglScanout *scanout;
|
||||
|
||||
surface = meta_surface_actor_wayland_get_surface (self);
|
||||
scanout = meta_wayland_surface_try_acquire_scanout (surface, onscreen);
|
||||
if (!scanout)
|
||||
return NULL;
|
||||
|
||||
queue_frame_callbacks (self);
|
||||
|
||||
return scanout;
|
||||
}
|
||||
|
||||
void
|
||||
meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self,
|
||||
struct wl_list *frame_callbacks)
|
||||
@@ -92,14 +126,7 @@ meta_surface_actor_wayland_paint (ClutterActor *actor,
|
||||
{
|
||||
MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor);
|
||||
|
||||
if (self->surface &&
|
||||
!meta_surface_actor_is_obscured (META_SURFACE_ACTOR (actor)))
|
||||
{
|
||||
MetaWaylandCompositor *compositor = self->surface->compositor;
|
||||
|
||||
wl_list_insert_list (&compositor->frame_callbacks, &self->frame_callback_list);
|
||||
wl_list_init (&self->frame_callback_list);
|
||||
}
|
||||
queue_frame_callbacks (self);
|
||||
|
||||
CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor,
|
||||
paint_context);
|
||||
|
@@ -52,6 +52,9 @@ void meta_surface_actor_wayland_get_subsurface_rect (MetaSurfaceActorWayland *se
|
||||
void meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self,
|
||||
struct wl_list *frame_callbacks);
|
||||
|
||||
CoglScanout * meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self,
|
||||
CoglOnscreen *onscreen);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */
|
||||
|
@@ -260,33 +260,14 @@ meta_surface_actor_x11_is_opaque (MetaSurfaceActor *actor)
|
||||
gboolean
|
||||
meta_surface_actor_x11_should_unredirect (MetaSurfaceActorX11 *self)
|
||||
{
|
||||
MetaWindow *window = self->window;
|
||||
|
||||
if (meta_window_requested_dont_bypass_compositor (window))
|
||||
return FALSE;
|
||||
|
||||
if (window->opacity != 0xFF)
|
||||
return FALSE;
|
||||
|
||||
if (window->shape_region != NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!meta_window_is_monitor_sized (window))
|
||||
return FALSE;
|
||||
|
||||
if (meta_window_requested_bypass_compositor (window))
|
||||
return TRUE;
|
||||
|
||||
if (!meta_surface_actor_x11_is_opaque (META_SURFACE_ACTOR (self)))
|
||||
return FALSE;
|
||||
|
||||
if (meta_window_is_override_redirect (window))
|
||||
return TRUE;
|
||||
if (!self->does_full_damage &&
|
||||
!meta_window_is_override_redirect (self->window))
|
||||
return FALSE;
|
||||
|
||||
if (self->does_full_damage)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include "meta/meta-window-actor.h"
|
||||
#include "meta/meta-x11-errors.h"
|
||||
#include "meta/window.h"
|
||||
#include "x11/window-x11.h"
|
||||
#include "x11/meta-x11-display-private.h"
|
||||
#include "x11/window-x11.h"
|
||||
|
||||
@@ -85,6 +86,8 @@ struct _MetaWindowActorX11
|
||||
cairo_region_t *shape_region;
|
||||
/* The region we should clip to when painting the shadow */
|
||||
cairo_region_t *shadow_clip;
|
||||
/* The frame region */
|
||||
cairo_region_t *frame_bounds;
|
||||
|
||||
/* Extracted size-invariant shape used for shadows */
|
||||
MetaWindowShape *shadow_shape;
|
||||
@@ -540,12 +543,18 @@ has_shadow (MetaWindowActorX11 *actor_x11)
|
||||
gboolean
|
||||
meta_window_actor_x11_should_unredirect (MetaWindowActorX11 *actor_x11)
|
||||
{
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
|
||||
MetaSurfaceActor *surface;
|
||||
MetaSurfaceActorX11 *surface_x11;
|
||||
|
||||
if (meta_window_actor_is_destroyed (META_WINDOW_ACTOR (actor_x11)))
|
||||
return FALSE;
|
||||
|
||||
if (!meta_window_x11_can_unredirect (window_x11))
|
||||
return FALSE;
|
||||
|
||||
surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor_x11));
|
||||
if (!surface)
|
||||
return FALSE;
|
||||
@@ -702,11 +711,8 @@ set_clip_region_beneath (MetaWindowActorX11 *actor_x11,
|
||||
|
||||
if (clip_shadow_under_window (actor_x11))
|
||||
{
|
||||
cairo_region_t *frame_bounds;
|
||||
|
||||
frame_bounds = meta_window_get_frame_bounds (window);
|
||||
if (frame_bounds)
|
||||
cairo_region_subtract (actor_x11->shadow_clip, frame_bounds);
|
||||
if (actor_x11->frame_bounds)
|
||||
cairo_region_subtract (actor_x11->shadow_clip, actor_x11->frame_bounds);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1126,6 +1132,17 @@ update_opaque_region (MetaWindowActorX11 *actor_x11)
|
||||
cairo_region_destroy (opaque_region);
|
||||
}
|
||||
|
||||
static void
|
||||
update_frame_bounds (MetaWindowActorX11 *actor_x11)
|
||||
{
|
||||
MetaWindow *window =
|
||||
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
|
||||
|
||||
g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy);
|
||||
actor_x11->frame_bounds =
|
||||
cairo_region_copy (meta_window_get_frame_bounds (window));
|
||||
}
|
||||
|
||||
static void
|
||||
update_regions (MetaWindowActorX11 *actor_x11)
|
||||
{
|
||||
@@ -1197,6 +1214,7 @@ handle_updates (MetaWindowActorX11 *actor_x11)
|
||||
if (!meta_surface_actor_is_visible (surface))
|
||||
return;
|
||||
|
||||
update_frame_bounds (actor_x11);
|
||||
check_needs_reshape (actor_x11);
|
||||
check_needs_shadow (actor_x11);
|
||||
}
|
||||
@@ -1250,15 +1268,13 @@ meta_window_actor_x11_paint (ClutterActor *actor,
|
||||
*/
|
||||
if (!clip && clip_shadow_under_window (actor_x11))
|
||||
{
|
||||
cairo_region_t *frame_bounds;
|
||||
cairo_rectangle_int_t bounds;
|
||||
|
||||
get_shadow_bounds (actor_x11, appears_focused, &bounds);
|
||||
clip = cairo_region_create_rectangle (&bounds);
|
||||
|
||||
frame_bounds = meta_window_get_frame_bounds (window);
|
||||
if (frame_bounds)
|
||||
cairo_region_subtract (clip, frame_bounds);
|
||||
if (actor_x11->frame_bounds)
|
||||
cairo_region_subtract (clip, actor_x11->frame_bounds);
|
||||
}
|
||||
|
||||
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
|
||||
@@ -1545,6 +1561,7 @@ meta_window_actor_x11_dispose (GObject *object)
|
||||
|
||||
g_clear_pointer (&actor_x11->shape_region, cairo_region_destroy);
|
||||
g_clear_pointer (&actor_x11->shadow_clip, cairo_region_destroy);
|
||||
g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy);
|
||||
|
||||
g_clear_pointer (&actor_x11->shadow_class, g_free);
|
||||
g_clear_pointer (&actor_x11->focused_shadow, meta_shadow_unref);
|
||||
|
@@ -1321,7 +1321,9 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window,
|
||||
cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1);
|
||||
cogl_framebuffer_translate (framebuffer, -x, -y, 0);
|
||||
|
||||
paint_context = clutter_paint_context_new_for_framebuffer (framebuffer);
|
||||
paint_context =
|
||||
clutter_paint_context_new_for_framebuffer (framebuffer, NULL,
|
||||
CLUTTER_PAINT_FLAG_NONE);
|
||||
clutter_actor_paint (actor, paint_context);
|
||||
clutter_paint_context_destroy (paint_context);
|
||||
|
||||
@@ -1479,7 +1481,9 @@ meta_window_actor_get_image (MetaWindowActor *self,
|
||||
cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1);
|
||||
cogl_framebuffer_translate (framebuffer, -x, -y, 0);
|
||||
|
||||
paint_context = clutter_paint_context_new_for_framebuffer (framebuffer);
|
||||
paint_context =
|
||||
clutter_paint_context_new_for_framebuffer (framebuffer, NULL,
|
||||
CLUTTER_PAINT_FLAG_NONE);
|
||||
clutter_actor_paint (actor, paint_context);
|
||||
clutter_paint_context_destroy (paint_context);
|
||||
|
||||
|
@@ -51,6 +51,7 @@
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "backends/x11/meta-event-x11.h"
|
||||
#include "backends/x11/cm/meta-backend-x11-cm.h"
|
||||
#include "backends/x11/nested/meta-backend-x11-nested.h"
|
||||
#include "clutter/x11/clutter-x11.h"
|
||||
#include "compositor/compositor-private.h"
|
||||
#include "compositor/meta-compositor-x11.h"
|
||||
@@ -81,6 +82,7 @@
|
||||
#include "x11/xprops.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "compositor/meta-compositor-native.h"
|
||||
#include "compositor/meta-compositor-server.h"
|
||||
#include "wayland/meta-xwayland-private.h"
|
||||
#include "wayland/meta-wayland-tablet-seat.h"
|
||||
@@ -572,44 +574,16 @@ static MetaCompositor *
|
||||
create_compositor (MetaDisplay *display)
|
||||
{
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (meta_is_wayland_compositor ())
|
||||
return META_COMPOSITOR (meta_compositor_server_new (display));
|
||||
else
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
if (META_IS_BACKEND_NATIVE (backend))
|
||||
return META_COMPOSITOR (meta_compositor_native_new (display));
|
||||
#endif
|
||||
return META_COMPOSITOR (meta_compositor_x11_new (display));
|
||||
}
|
||||
|
||||
static void
|
||||
enable_compositor (MetaDisplay *display)
|
||||
{
|
||||
MetaX11Display *x11_display = display->x11_display;
|
||||
|
||||
if (x11_display)
|
||||
{
|
||||
if (!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ||
|
||||
!META_X11_DISPLAY_HAS_DAMAGE (x11_display))
|
||||
{
|
||||
meta_fatal ("Missing %s extension required for compositing",
|
||||
!META_X11_DISPLAY_HAS_COMPOSITE (x11_display) ?
|
||||
"composite" : "damage");
|
||||
return;
|
||||
}
|
||||
|
||||
int version = (x11_display->composite_major_version * 10) +
|
||||
x11_display->composite_minor_version;
|
||||
if (version < 3)
|
||||
{
|
||||
meta_fatal ("Your version of COMPOSITE (%d.%d) is too old. Version 3.0 or later required.",
|
||||
x11_display->composite_major_version,
|
||||
x11_display->composite_minor_version);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!display->compositor)
|
||||
display->compositor = create_compositor (display);
|
||||
|
||||
meta_compositor_manage (display->compositor);
|
||||
if (META_IS_BACKEND_X11_NESTED (backend))
|
||||
return META_COMPOSITOR (meta_compositor_server_new (display));
|
||||
#endif
|
||||
return META_COMPOSITOR (meta_compositor_x11_new (display));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -885,6 +859,8 @@ meta_display_open (void)
|
||||
g_signal_connect (settings, "ui-scaling-factor-changed",
|
||||
G_CALLBACK (on_ui_scaling_factor_changed), display);
|
||||
|
||||
display->compositor = create_compositor (display);
|
||||
|
||||
meta_display_set_cursor (display, META_CURSOR_DEFAULT);
|
||||
|
||||
display->stack = meta_stack_new (display);
|
||||
@@ -922,7 +898,6 @@ meta_display_open (void)
|
||||
|
||||
display->last_focus_time = timestamp;
|
||||
display->last_user_time = timestamp;
|
||||
display->compositor = NULL;
|
||||
|
||||
if (!meta_is_wayland_compositor ())
|
||||
meta_prop_get_window (display->x11_display,
|
||||
@@ -930,7 +905,11 @@ meta_display_open (void)
|
||||
display->x11_display->atom__NET_ACTIVE_WINDOW,
|
||||
&old_active_xwindow);
|
||||
|
||||
enable_compositor (display);
|
||||
if (!meta_compositor_do_manage (display->compositor, &error))
|
||||
{
|
||||
g_error ("Compositor failed to manage display: %s",
|
||||
error->message);
|
||||
}
|
||||
|
||||
if (display->x11_display)
|
||||
{
|
||||
|
@@ -2129,7 +2129,7 @@ process_special_modifier_key (MetaDisplay *display,
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->type == CLUTTER_KEY_PRESS &&
|
||||
(event->modifier_state & ~(IGNORED_MODIFIERS)) == 0 &&
|
||||
((event->modifier_state & ~(IGNORED_MODIFIERS)) & CLUTTER_MODIFIER_MASK) == 0 &&
|
||||
resolved_key_combo_has_keycode (resolved_key_combo,
|
||||
event->hardware_keycode))
|
||||
{
|
||||
|
368
src/core/meta-anonymous-file.c
Normal file
368
src/core/meta-anonymous-file.c
Normal file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Sebastian Wick
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Sebastian Wick <sebastian@sebastianwick.net>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "core/meta-anonymous-file.h"
|
||||
|
||||
struct _MetaAnonymousFile
|
||||
{
|
||||
int fd;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
#define READONLY_SEALS (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
|
||||
|
||||
static int
|
||||
create_tmpfile_cloexec (char *tmpname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#if defined(HAVE_MKOSTEMP)
|
||||
fd = mkostemp (tmpname, O_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
unlink (tmpname);
|
||||
#else
|
||||
fd = mkstemp (tmpname);
|
||||
if (fd >= 0)
|
||||
{
|
||||
long flags;
|
||||
|
||||
unlink (tmpname);
|
||||
|
||||
flags = fcntl (fd, F_GETFD);
|
||||
if (flags == -1 ||
|
||||
fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
||||
{
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new, unique, anonymous file of the given size, and
|
||||
* return the file descriptor for it. The file descriptor is set
|
||||
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
||||
* the given size at offset zero.
|
||||
*
|
||||
* The file should not have a permanent backing store like a disk,
|
||||
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
||||
*
|
||||
* The file name is deleted from the file system.
|
||||
*
|
||||
* The file is suitable for buffer sharing between processes by
|
||||
* transmitting the file descriptor over Unix sockets using the
|
||||
* SCM_RIGHTS methods.
|
||||
*
|
||||
* If the C library implements posix_fallocate(), it is used to
|
||||
* guarantee that disk space is available for the file at the
|
||||
* given size. If disk space is insufficient, errno is set to ENOSPC.
|
||||
* If posix_fallocate() is not supported, program may receive
|
||||
* SIGBUS on accessing mmap()'ed file contents instead.
|
||||
*
|
||||
* If the C library implements memfd_create(), it is used to create the
|
||||
* file purely in memory, without any backing file name on the file
|
||||
* system, and then sealing off the possibility of shrinking it. This
|
||||
* can then be checked before accessing mmap()'ed file contents, to make
|
||||
* sure SIGBUS can't happen. It also avoids requiring XDG_RUNTIME_DIR.
|
||||
*/
|
||||
static int
|
||||
create_anonymous_file (off_t size)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
#if defined(HAVE_MEMFD_CREATE)
|
||||
fd = memfd_create ("mutter-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
if (fd >= 0)
|
||||
{
|
||||
/* We can add this seal before calling posix_fallocate(), as
|
||||
* the file is currently zero-sized anyway.
|
||||
*
|
||||
* There is also no need to check for the return value, we
|
||||
* couldn't do anything with it anyway.
|
||||
*/
|
||||
fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
static const char template[] = "/mutter-shared-XXXXXX";
|
||||
const char *path;
|
||||
char *name;
|
||||
|
||||
path = getenv ("XDG_RUNTIME_DIR");
|
||||
if (!path)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = g_malloc (strlen (path) + sizeof (template));
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
strcpy (name, path);
|
||||
strcat (name, template);
|
||||
|
||||
fd = create_tmpfile_cloexec (name);
|
||||
|
||||
g_free (name);
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_POSIX_FALLOCATE)
|
||||
do
|
||||
{
|
||||
ret = posix_fallocate (fd, 0, size);
|
||||
}
|
||||
while (ret == EINTR);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
close (fd);
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
do
|
||||
{
|
||||
ret = ftruncate (fd, size);
|
||||
}
|
||||
while (ret < 0 && errno == EINTR);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_anonymous_file_new: (skip)
|
||||
* @size: The size of @data
|
||||
* @data: The data of the file with the size @size
|
||||
*
|
||||
* Create a new anonymous read-only file of the given size and the given data
|
||||
* The intended use-case is for sending mid-sized data from the compositor
|
||||
* to clients.
|
||||
*
|
||||
* When done, free the data using meta_anonymous_file_free().
|
||||
*
|
||||
* If this function fails errno is set.
|
||||
*
|
||||
* Returns: The newly created #MetaAnonymousFile, or NULL on failure. Use
|
||||
* meta_anonymous_file_free() to free the resources when done.
|
||||
*/
|
||||
MetaAnonymousFile *
|
||||
meta_anonymous_file_new (size_t size,
|
||||
const uint8_t *data)
|
||||
{
|
||||
MetaAnonymousFile *file;
|
||||
void *map;
|
||||
|
||||
file = g_malloc0 (sizeof *file);
|
||||
if (!file)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file->size = size;
|
||||
file->fd = create_anonymous_file (size);
|
||||
if (file->fd == -1)
|
||||
goto err_free;
|
||||
|
||||
map = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, file->fd, 0);
|
||||
if (map == MAP_FAILED)
|
||||
goto err_close;
|
||||
|
||||
memcpy (map, data, size);
|
||||
|
||||
munmap (map, size);
|
||||
|
||||
#if defined(HAVE_MEMFD_CREATE)
|
||||
/* try to put seals on the file to make it read-only so that we can
|
||||
* return the fd later directly when MAPMODE_SHARED is not set.
|
||||
* meta_anonymous_file_open_fd can handle the fd even if it is not
|
||||
* sealed read-only and will instead create a new anonymous file on
|
||||
* each invocation.
|
||||
*/
|
||||
fcntl (file->fd, F_ADD_SEALS, READONLY_SEALS);
|
||||
#endif
|
||||
|
||||
return file;
|
||||
|
||||
err_close:
|
||||
close (file->fd);
|
||||
err_free:
|
||||
g_free (file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* meta_anonymous_file_free: (skip)
|
||||
* @file: the #MetaAnonymousFile
|
||||
*
|
||||
* Free the resources used by an anonymous read-only file.
|
||||
*/
|
||||
void
|
||||
meta_anonymous_file_free (MetaAnonymousFile *file)
|
||||
{
|
||||
close (file->fd);
|
||||
g_free (file);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_anonymous_file_size: (skip)
|
||||
* @file: the #MetaAnonymousFile
|
||||
*
|
||||
* Get the size of an anonymous read-only file.
|
||||
*
|
||||
* Returns: The size of the anonymous read-only file.
|
||||
*/
|
||||
size_t
|
||||
meta_anonymous_file_size (MetaAnonymousFile *file)
|
||||
{
|
||||
return file->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_anonymous_file_open_fd: (skip)
|
||||
* @file: the #MetaAnonymousFile to get a file descriptor for
|
||||
* @mapmode: describes the ways in which the returned file descriptor can
|
||||
* be used with mmap
|
||||
*
|
||||
* Returns a file descriptor for the given file, ready to be sent to a client.
|
||||
* The returned file descriptor must not be shared between multiple clients.
|
||||
* If @mapmode is %META_ANONYMOUS_FILE_MAPMODE_PRIVATE the file descriptor is
|
||||
* only guaranteed to be mmapable with MAP_PRIVATE. If @mapmode is
|
||||
* %META_ANONYMOUS_FILE_MAPMODE_SHARED the file descriptor can be mmaped with
|
||||
* either MAP_PRIVATE or MAP_SHARED.
|
||||
*
|
||||
* In case %META_ANONYMOUS_FILE_MAPMODE_PRIVATE is used, it is important to
|
||||
* only read the returned fd using mmap() since using read() will move the
|
||||
* read cursor of the fd and thus may cause read() calls on other returned
|
||||
* fds to fail.
|
||||
*
|
||||
* When done using the fd, it is required to call meta_anonymous_file_close_fd()
|
||||
* instead of close().
|
||||
*
|
||||
* If this function fails errno is set.
|
||||
*
|
||||
* Returns: A file descriptor for the given file that can be sent to a client
|
||||
* or -1 on failure. Use meta_anonymous_file_close_fd() to release the fd
|
||||
* when done.
|
||||
*/
|
||||
int
|
||||
meta_anonymous_file_open_fd (MetaAnonymousFile *file,
|
||||
MetaAnonymousFileMapmode mapmode)
|
||||
{
|
||||
void *src, *dst;
|
||||
int fd;
|
||||
|
||||
#if defined(HAVE_MEMFD_CREATE)
|
||||
int seals;
|
||||
|
||||
seals = fcntl (file->fd, F_GET_SEALS);
|
||||
|
||||
/* file was sealed for read-only and we don't have to support MAP_SHARED
|
||||
* so we can simply pass the memfd fd
|
||||
*/
|
||||
if (seals != -1 && mapmode == META_ANONYMOUS_FILE_MAPMODE_PRIVATE &&
|
||||
(seals & READONLY_SEALS) == READONLY_SEALS)
|
||||
return file->fd;
|
||||
#endif
|
||||
|
||||
/* for all other cases we create a new anonymous file that can be mapped
|
||||
* with MAP_SHARED and copy the contents to it and return that instead
|
||||
*/
|
||||
fd = create_anonymous_file (file->size);
|
||||
if (fd == -1)
|
||||
return fd;
|
||||
|
||||
src = mmap (NULL, file->size, PROT_READ, MAP_PRIVATE, file->fd, 0);
|
||||
if (src == MAP_FAILED)
|
||||
{
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dst = mmap (NULL, file->size, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (dst == MAP_FAILED)
|
||||
{
|
||||
close (fd);
|
||||
munmap (src, file->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (dst, src, file->size);
|
||||
munmap (src, file->size);
|
||||
munmap (dst, file->size);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_anonymous_file_close_fd: (skip)
|
||||
* @fd: A file descriptor obtained using meta_anonymous_file_open_fd()
|
||||
*
|
||||
* Release a file descriptor returned by meta_anonymous_file_open_fd().
|
||||
* This function must be called for every file descriptor created with
|
||||
* meta_anonymous_file_open_fd() to not leak any resources.
|
||||
*
|
||||
* If this function fails errno is set.
|
||||
*/
|
||||
void
|
||||
meta_anonymous_file_close_fd (int fd)
|
||||
{
|
||||
#if defined(HAVE_MEMFD_CREATE)
|
||||
int seals;
|
||||
|
||||
seals = fcntl (fd, F_GET_SEALS);
|
||||
if (seals == -1 && errno != EINVAL)
|
||||
{
|
||||
g_warning ("Reading seals of anonymous file %d failed", fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The only case in which we do NOT have to close the file is when the file
|
||||
* was sealed for read-only
|
||||
*/
|
||||
if (seals != -1 && (seals & READONLY_SEALS) == READONLY_SEALS)
|
||||
return;
|
||||
#endif
|
||||
|
||||
close (fd);
|
||||
}
|
53
src/core/meta-anonymous-file.h
Normal file
53
src/core/meta-anonymous-file.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Sebastian Wick
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Author: Sebastian Wick <sebastian@sebastianwick.net>
|
||||
*/
|
||||
|
||||
#ifndef META_ANONYMOUS_FILE_H
|
||||
#define META_ANONYMOUS_FILE_H
|
||||
|
||||
#include "meta/common.h"
|
||||
#include "core/util-private.h"
|
||||
|
||||
typedef struct _MetaAnonymousFile MetaAnonymousFile;
|
||||
|
||||
typedef enum _MetaAnonymousFileMapmode
|
||||
{
|
||||
META_ANONYMOUS_FILE_MAPMODE_PRIVATE,
|
||||
META_ANONYMOUS_FILE_MAPMODE_SHARED,
|
||||
} MetaAnonymousFileMapmode;
|
||||
|
||||
META_EXPORT_TEST
|
||||
MetaAnonymousFile * meta_anonymous_file_new (size_t size,
|
||||
const uint8_t *data);
|
||||
|
||||
META_EXPORT_TEST
|
||||
void meta_anonymous_file_free (MetaAnonymousFile *file);
|
||||
|
||||
META_EXPORT_TEST
|
||||
size_t meta_anonymous_file_size (MetaAnonymousFile *file);
|
||||
|
||||
META_EXPORT_TEST
|
||||
int meta_anonymous_file_open_fd (MetaAnonymousFile *file,
|
||||
MetaAnonymousFileMapmode mapmode);
|
||||
|
||||
META_EXPORT_TEST
|
||||
void meta_anonymous_file_close_fd (int fd);
|
||||
|
||||
#endif /* META_ANONYMOUS_FILE_H */
|
@@ -51,6 +51,9 @@ static guint signals[N_SIGNALS] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE (MetaSelection, meta_selection, G_TYPE_OBJECT)
|
||||
|
||||
static void read_selection_source_async (GTask *task,
|
||||
TransferRequest *request);
|
||||
|
||||
static void
|
||||
meta_selection_dispose (GObject *object)
|
||||
{
|
||||
@@ -217,6 +220,7 @@ write_cb (GOutputStream *stream,
|
||||
GAsyncResult *result,
|
||||
GTask *task)
|
||||
{
|
||||
TransferRequest *request;
|
||||
GError *error = NULL;
|
||||
|
||||
g_output_stream_write_bytes_finish (stream, result, &error);
|
||||
@@ -227,8 +231,17 @@ write_cb (GOutputStream *stream,
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
request = g_task_get_task_data (task);
|
||||
|
||||
if (request->len > 0)
|
||||
{
|
||||
read_selection_source_async (task, request);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -247,8 +260,26 @@ read_cb (GInputStream *stream,
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
else if (g_bytes_get_size (bytes) == 0)
|
||||
{
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
request = g_task_get_task_data (task);
|
||||
|
||||
if (request->len < g_bytes_get_size (bytes))
|
||||
{
|
||||
GBytes *copy;
|
||||
|
||||
/* Trim content */
|
||||
copy = g_bytes_new_from_bytes (bytes, 0, request->len);
|
||||
g_bytes_unref (bytes);
|
||||
bytes = copy;
|
||||
}
|
||||
|
||||
request->len -= g_bytes_get_size (bytes);
|
||||
g_output_stream_write_bytes_async (request->ostream,
|
||||
bytes,
|
||||
G_PRIORITY_DEFAULT,
|
||||
@@ -258,6 +289,18 @@ read_cb (GInputStream *stream,
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
|
||||
static void
|
||||
read_selection_source_async (GTask *task,
|
||||
TransferRequest *request)
|
||||
{
|
||||
g_input_stream_read_bytes_async (request->istream,
|
||||
(gsize) request->len,
|
||||
G_PRIORITY_DEFAULT,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) read_cb,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
source_read_cb (MetaSelectionSource *source,
|
||||
GAsyncResult *result,
|
||||
@@ -291,12 +334,7 @@ source_read_cb (MetaSelectionSource *source,
|
||||
}
|
||||
else
|
||||
{
|
||||
g_input_stream_read_bytes_async (request->istream,
|
||||
(gsize) request->len,
|
||||
G_PRIORITY_DEFAULT,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) read_cb,
|
||||
task);
|
||||
read_selection_source_async (task, request);
|
||||
}
|
||||
}
|
||||
|
||||
|
285
src/core/util.c
285
src/core/util.c
@@ -50,9 +50,6 @@ meta_topic_real_valist (MetaDebugTopic topic,
|
||||
va_list args) G_GNUC_PRINTF(2, 0);
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
meta_later_remove_from_list (guint later_id, GSList **laters_list);
|
||||
|
||||
static gint verbose_topics = 0;
|
||||
static gboolean is_debugging = FALSE;
|
||||
static gboolean replace_current = FALSE;
|
||||
@@ -715,288 +712,6 @@ meta_show_dialog (const char *type,
|
||||
return child_pid;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Later functions: like idles but integrated with the Clutter repaint loop
|
||||
***************************************************************************/
|
||||
|
||||
static guint last_later_id = 0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint id;
|
||||
guint ref_count;
|
||||
MetaLaterType when;
|
||||
GSourceFunc func;
|
||||
gpointer data;
|
||||
GDestroyNotify notify;
|
||||
int source;
|
||||
gboolean run_once;
|
||||
} MetaLater;
|
||||
|
||||
static GSList *laters[] = {
|
||||
NULL, /* META_LATER_RESIZE */
|
||||
NULL, /* META_LATER_CALC_SHOWING */
|
||||
NULL, /* META_LATER_CHECK_FULLSCREEN */
|
||||
NULL, /* META_LATER_SYNC_STACK */
|
||||
NULL, /* META_LATER_BEFORE_REDRAW */
|
||||
NULL, /* META_LATER_IDLE */
|
||||
};
|
||||
/* This is a dummy timeline used to get the Clutter master clock running */
|
||||
static ClutterTimeline *later_timeline;
|
||||
static guint later_repaint_func = 0;
|
||||
|
||||
static void ensure_later_repaint_func (void);
|
||||
|
||||
static void
|
||||
unref_later (MetaLater *later)
|
||||
{
|
||||
if (--later->ref_count == 0)
|
||||
{
|
||||
if (later->notify)
|
||||
{
|
||||
later->notify (later->data);
|
||||
later->notify = NULL;
|
||||
}
|
||||
g_slice_free (MetaLater, later);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_later (MetaLater *later)
|
||||
{
|
||||
g_clear_handle_id (&later->source, g_source_remove);
|
||||
later->func = NULL;
|
||||
unref_later (later);
|
||||
}
|
||||
|
||||
#ifdef COGL_HAS_TRACING
|
||||
static const char *
|
||||
later_type_to_string (MetaLaterType when)
|
||||
{
|
||||
switch (when)
|
||||
{
|
||||
case META_LATER_RESIZE:
|
||||
return "Later (resize)";
|
||||
case META_LATER_CALC_SHOWING:
|
||||
return "Later (calc-showing)";
|
||||
case META_LATER_CHECK_FULLSCREEN:
|
||||
return "Later (check-fullscreen)";
|
||||
case META_LATER_SYNC_STACK:
|
||||
return "Later (sync-stack)";
|
||||
case META_LATER_BEFORE_REDRAW:
|
||||
return "Later (before-redraw)";
|
||||
case META_LATER_IDLE:
|
||||
return "Later (idle)";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
call_later_func (MetaLater *later)
|
||||
{
|
||||
COGL_TRACE_BEGIN_SCOPED (later, later_type_to_string (later->when));
|
||||
return later->func (later->data);
|
||||
}
|
||||
|
||||
static void
|
||||
run_repaint_laters (GSList **laters_list)
|
||||
{
|
||||
GSList *laters_copy;
|
||||
GSList *l;
|
||||
|
||||
laters_copy = NULL;
|
||||
for (l = *laters_list; l; l = l->next)
|
||||
{
|
||||
MetaLater *later = l->data;
|
||||
if (later->source == 0 ||
|
||||
(later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
|
||||
{
|
||||
later->ref_count++;
|
||||
laters_copy = g_slist_prepend (laters_copy, later);
|
||||
}
|
||||
}
|
||||
laters_copy = g_slist_reverse (laters_copy);
|
||||
|
||||
for (l = laters_copy; l; l = l->next)
|
||||
{
|
||||
MetaLater *later = l->data;
|
||||
|
||||
if (!later->func || !call_later_func (later))
|
||||
meta_later_remove_from_list (later->id, laters_list);
|
||||
unref_later (later);
|
||||
}
|
||||
|
||||
g_slist_free (laters_copy);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
run_all_repaint_laters (gpointer data)
|
||||
{
|
||||
guint i;
|
||||
GSList *l;
|
||||
gboolean keep_timeline_running = FALSE;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (laters); i++)
|
||||
{
|
||||
run_repaint_laters (&laters[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (laters); i++)
|
||||
{
|
||||
for (l = laters[i]; l; l = l->next)
|
||||
{
|
||||
MetaLater *later = l->data;
|
||||
|
||||
if (later->source == 0)
|
||||
keep_timeline_running = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keep_timeline_running)
|
||||
clutter_timeline_stop (later_timeline);
|
||||
|
||||
/* Just keep the repaint func around - it's cheap if the lists are empty */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_later_repaint_func (void)
|
||||
{
|
||||
if (!later_timeline)
|
||||
later_timeline = clutter_timeline_new (G_MAXUINT);
|
||||
|
||||
if (later_repaint_func == 0)
|
||||
later_repaint_func = clutter_threads_add_repaint_func (run_all_repaint_laters,
|
||||
NULL, NULL);
|
||||
|
||||
/* Make sure the repaint function gets run */
|
||||
clutter_timeline_start (later_timeline);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
call_idle_later (gpointer data)
|
||||
{
|
||||
MetaLater *later = data;
|
||||
|
||||
if (!later->func (later->data))
|
||||
{
|
||||
meta_later_remove (later->id);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
later->run_once = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_later_add:
|
||||
* @when: enumeration value determining the phase at which to run the callback
|
||||
* @func: callback to run later
|
||||
* @data: data to pass to the callback
|
||||
* @notify: function to call to destroy @data when it is no longer in use, or %NULL
|
||||
*
|
||||
* Sets up a callback to be called at some later time. @when determines the
|
||||
* particular later occasion at which it is called. This is much like g_idle_add(),
|
||||
* except that the functions interact properly with clutter event handling.
|
||||
* If a "later" function is added from a clutter event handler, and is supposed
|
||||
* to be run before the stage is redrawn, it will be run before that redraw
|
||||
* of the stage, not the next one.
|
||||
*
|
||||
* Return value: an integer ID (guaranteed to be non-zero) that can be used
|
||||
* to cancel the callback and prevent it from being run.
|
||||
*/
|
||||
guint
|
||||
meta_later_add (MetaLaterType when,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaLater *later = g_slice_new0 (MetaLater);
|
||||
|
||||
later->id = ++last_later_id;
|
||||
later->ref_count = 1;
|
||||
later->when = when;
|
||||
later->func = func;
|
||||
later->data = data;
|
||||
later->notify = notify;
|
||||
|
||||
laters[when] = g_slist_prepend (laters[when], later);
|
||||
|
||||
switch (when)
|
||||
{
|
||||
case META_LATER_RESIZE:
|
||||
/* We add this one two ways - as a high-priority idle and as a
|
||||
* repaint func. If we are in a clutter event callback, the repaint
|
||||
* handler will get hit first, and we'll take care of this function
|
||||
* there so it gets called before the stage is redrawn, even if
|
||||
* we haven't gotten back to the main loop. Otherwise, the idle
|
||||
* handler will get hit first and we want to call this function
|
||||
* there so it will happen before GTK+ repaints.
|
||||
*/
|
||||
later->source = g_idle_add_full (META_PRIORITY_RESIZE, call_idle_later, later, NULL);
|
||||
g_source_set_name_by_id (later->source, "[mutter] call_idle_later");
|
||||
ensure_later_repaint_func ();
|
||||
break;
|
||||
case META_LATER_CALC_SHOWING:
|
||||
case META_LATER_CHECK_FULLSCREEN:
|
||||
case META_LATER_SYNC_STACK:
|
||||
case META_LATER_BEFORE_REDRAW:
|
||||
ensure_later_repaint_func ();
|
||||
break;
|
||||
case META_LATER_IDLE:
|
||||
later->source = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, call_idle_later, later, NULL);
|
||||
g_source_set_name_by_id (later->source, "[mutter] call_idle_later");
|
||||
break;
|
||||
}
|
||||
|
||||
return later->id;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_later_remove_from_list (guint later_id, GSList **laters_list)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = *laters_list; l; l = l->next)
|
||||
{
|
||||
MetaLater *later = l->data;
|
||||
|
||||
if (later->id == later_id)
|
||||
{
|
||||
*laters_list = g_slist_delete_link (*laters_list, l);
|
||||
/* If this was a "repaint func" later, we just let the
|
||||
* repaint func run and get removed
|
||||
*/
|
||||
destroy_later (later);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_later_remove:
|
||||
* @later_id: the integer ID returned from meta_later_add()
|
||||
*
|
||||
* Removes a callback added with meta_later_add()
|
||||
*/
|
||||
void
|
||||
meta_later_remove (guint later_id)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (laters); i++)
|
||||
{
|
||||
if (meta_later_remove_from_list (later_id, &laters[i]))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MetaLocaleDirection
|
||||
meta_get_locale_direction (void)
|
||||
{
|
||||
|
@@ -65,13 +65,6 @@ typedef enum
|
||||
|
||||
#define NUMBER_OF_QUEUES 3
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_NET_WM_BYPASS_COMPOSITOR_HINT_AUTO = 0,
|
||||
_NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1,
|
||||
_NET_WM_BYPASS_COMPOSITOR_HINT_OFF = 2,
|
||||
} MetaBypassCompositorHintValue;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_MOVE_RESIZE_CONFIGURE_REQUEST = 1 << 0,
|
||||
@@ -539,9 +532,6 @@ struct _MetaWindow
|
||||
/* The currently complementary tiled window, if any */
|
||||
MetaWindow *tile_match;
|
||||
|
||||
/* Bypass compositor hints */
|
||||
guint bypass_compositor;
|
||||
|
||||
struct {
|
||||
MetaPlacementRule *rule;
|
||||
MetaPlacementState state;
|
||||
|
@@ -3018,30 +3018,6 @@ meta_window_is_on_primary_monitor (MetaWindow *window)
|
||||
return window->monitor->is_primary;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_window_requested_bypass_compositor:
|
||||
* @window: a #MetaWindow
|
||||
*
|
||||
* Return value: %TRUE if the window requested to bypass the compositor
|
||||
*/
|
||||
gboolean
|
||||
meta_window_requested_bypass_compositor (MetaWindow *window)
|
||||
{
|
||||
return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_ON;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_window_requested_dont_bypass_compositor:
|
||||
* @window: a #MetaWindow
|
||||
*
|
||||
* Return value: %TRUE if the window requested to opt out of unredirecting
|
||||
*/
|
||||
gboolean
|
||||
meta_window_requested_dont_bypass_compositor (MetaWindow *window)
|
||||
{
|
||||
return window->bypass_compositor == _NET_WM_BYPASS_COMPOSITOR_HINT_OFF;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_window_get_tile_fraction (MetaWindow *window,
|
||||
MetaTileMode tile_mode,
|
||||
|
@@ -291,6 +291,8 @@ mutter_sources = [
|
||||
'compositor/meta-background-group.c',
|
||||
'compositor/meta-background-image.c',
|
||||
'compositor/meta-background-private.h',
|
||||
'compositor/meta-compositor-server.c',
|
||||
'compositor/meta-compositor-server.h',
|
||||
'compositor/meta-compositor-x11.c',
|
||||
'compositor/meta-compositor-x11.h',
|
||||
'compositor/meta-cullable.c',
|
||||
@@ -300,6 +302,7 @@ mutter_sources = [
|
||||
'compositor/meta-dnd.c',
|
||||
'compositor/meta-feedback-actor.c',
|
||||
'compositor/meta-feedback-actor-private.h',
|
||||
'compositor/meta-later.c',
|
||||
'compositor/meta-module.c',
|
||||
'compositor/meta-module.h',
|
||||
'compositor/meta-plugin.c',
|
||||
@@ -346,6 +349,8 @@ mutter_sources = [
|
||||
'core/main-private.h',
|
||||
'core/meta-accel-parse.c',
|
||||
'core/meta-accel-parse.h',
|
||||
'core/meta-anonymous-file.c',
|
||||
'core/meta-anonymous-file.h',
|
||||
'core/meta-border.c',
|
||||
'core/meta-border.h',
|
||||
'core/meta-clipboard-manager.c',
|
||||
@@ -453,6 +458,10 @@ if have_remote_desktop
|
||||
'backends/meta-remote-desktop-session.h',
|
||||
'backends/meta-screen-cast.c',
|
||||
'backends/meta-screen-cast.h',
|
||||
'backends/meta-screen-cast-area-stream.c',
|
||||
'backends/meta-screen-cast-area-stream.h',
|
||||
'backends/meta-screen-cast-area-stream-src.c',
|
||||
'backends/meta-screen-cast-area-stream-src.h',
|
||||
'backends/meta-screen-cast-monitor-stream.c',
|
||||
'backends/meta-screen-cast-monitor-stream.h',
|
||||
'backends/meta-screen-cast-monitor-stream-src.c',
|
||||
@@ -476,8 +485,6 @@ if have_wayland
|
||||
'compositor/meta-surface-actor-wayland.h',
|
||||
'compositor/meta-window-actor-wayland.c',
|
||||
'compositor/meta-window-actor-wayland.h',
|
||||
'compositor/meta-compositor-server.c',
|
||||
'compositor/meta-compositor-server.h',
|
||||
'wayland/meta-cursor-sprite-wayland.c',
|
||||
'wayland/meta-cursor-sprite-wayland.h',
|
||||
'wayland/meta-pointer-confinement-wayland.c',
|
||||
@@ -495,7 +502,16 @@ 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-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-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-dma-buf.c',
|
||||
'wayland/meta-wayland-dma-buf.h',
|
||||
'wayland/meta-wayland-dnd-surface.c',
|
||||
@@ -675,6 +691,8 @@ if have_native_backend
|
||||
'backends/native/meta-virtual-input-device-native.h',
|
||||
'backends/native/meta-xkb-utils.c',
|
||||
'backends/native/meta-xkb-utils.h',
|
||||
'compositor/meta-compositor-native.c',
|
||||
'compositor/meta-compositor-native.h',
|
||||
]
|
||||
endif
|
||||
|
||||
|
@@ -19,6 +19,7 @@ mutter_public_headers = [
|
||||
'meta-idle-monitor.h',
|
||||
'meta-inhibit-shortcuts-dialog.h',
|
||||
'meta-launch-context.h',
|
||||
'meta-later.h',
|
||||
'meta-monitor-manager.h',
|
||||
'meta-plugin.h',
|
||||
'meta-remote-access-controller.h',
|
||||
|
53
src/meta/meta-later.h
Normal file
53
src/meta/meta-later.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
* Copyright (C) 2005 Elijah Newren
|
||||
* Copyright (C) 2020 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_LATER_H
|
||||
#define META_LATER_H
|
||||
|
||||
/**
|
||||
* MetaLaterType:
|
||||
* @META_LATER_RESIZE: call in a resize processing phase that is done
|
||||
* before GTK+ repainting (including window borders) is done.
|
||||
* @META_LATER_CALC_SHOWING: used by Mutter to compute which windows should be mapped
|
||||
* @META_LATER_CHECK_FULLSCREEN: used by Mutter to see if there's a fullscreen window
|
||||
* @META_LATER_SYNC_STACK: used by Mutter to send it's idea of the stacking order to the server
|
||||
* @META_LATER_BEFORE_REDRAW: call before the stage is redrawn
|
||||
* @META_LATER_IDLE: call at a very low priority (can be blocked
|
||||
* by running animations or redrawing applications)
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
META_LATER_RESIZE,
|
||||
META_LATER_CALC_SHOWING,
|
||||
META_LATER_CHECK_FULLSCREEN,
|
||||
META_LATER_SYNC_STACK,
|
||||
META_LATER_BEFORE_REDRAW,
|
||||
META_LATER_IDLE
|
||||
} MetaLaterType;
|
||||
|
||||
META_EXPORT
|
||||
guint meta_later_add (MetaLaterType when,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
META_EXPORT
|
||||
void meta_later_remove (guint later_id);
|
||||
|
||||
#endif /* META_LATER_H */
|
@@ -54,4 +54,10 @@ G_DECLARE_FINAL_TYPE (MetaRemoteAccessController,
|
||||
META, REMOTE_ACCESS_CONTROLLER,
|
||||
GObject)
|
||||
|
||||
META_EXPORT
|
||||
void meta_remote_access_controller_inhibit_remote_access (MetaRemoteAccessController *controller);
|
||||
|
||||
META_EXPORT
|
||||
void meta_remote_access_controller_uninhibit_remote_access (MetaRemoteAccessController *controller);
|
||||
|
||||
#endif /* META_REMOTE_ACCESS_CONTROLLER_H */
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <meta/common.h>
|
||||
#include <meta/meta-later.h>
|
||||
|
||||
META_EXPORT
|
||||
gboolean meta_is_verbose (void);
|
||||
@@ -185,36 +186,6 @@ GPid meta_show_dialog (const char *type,
|
||||
|
||||
#endif /* !WITH_VERBOSE_MODE */
|
||||
|
||||
/**
|
||||
* MetaLaterType:
|
||||
* @META_LATER_RESIZE: call in a resize processing phase that is done
|
||||
* before GTK+ repainting (including window borders) is done.
|
||||
* @META_LATER_CALC_SHOWING: used by Mutter to compute which windows should be mapped
|
||||
* @META_LATER_CHECK_FULLSCREEN: used by Mutter to see if there's a fullscreen window
|
||||
* @META_LATER_SYNC_STACK: used by Mutter to send it's idea of the stacking order to the server
|
||||
* @META_LATER_BEFORE_REDRAW: call before the stage is redrawn
|
||||
* @META_LATER_IDLE: call at a very low priority (can be blocked
|
||||
* by running animations or redrawing applications)
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
META_LATER_RESIZE,
|
||||
META_LATER_CALC_SHOWING,
|
||||
META_LATER_CHECK_FULLSCREEN,
|
||||
META_LATER_SYNC_STACK,
|
||||
META_LATER_BEFORE_REDRAW,
|
||||
META_LATER_IDLE
|
||||
} MetaLaterType;
|
||||
|
||||
META_EXPORT
|
||||
guint meta_later_add (MetaLaterType when,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
META_EXPORT
|
||||
void meta_later_remove (guint later_id);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_LOCALE_DIRECTION_LTR,
|
||||
|
@@ -283,12 +283,6 @@ gboolean meta_window_is_monitor_sized (MetaWindow *window);
|
||||
META_EXPORT
|
||||
gboolean meta_window_is_on_primary_monitor (MetaWindow *window);
|
||||
|
||||
META_EXPORT
|
||||
gboolean meta_window_requested_bypass_compositor (MetaWindow *window);
|
||||
|
||||
META_EXPORT
|
||||
gboolean meta_window_requested_dont_bypass_compositor (MetaWindow *window);
|
||||
|
||||
META_EXPORT
|
||||
gboolean meta_window_get_icon_geometry (MetaWindow *window,
|
||||
MetaRectangle *rect);
|
||||
|
@@ -111,6 +111,39 @@
|
||||
<arg name="properties" type="a{sv}" direction="in" />
|
||||
<arg name="stream_path" type="o" direction="out" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
RecordArea:
|
||||
@x: X position of the recorded area
|
||||
@y: Y position of the recorded area
|
||||
@width: width of the recorded area
|
||||
@height: height of the recorded area
|
||||
@properties: Properties
|
||||
@stream_path: Path to the new stream object
|
||||
|
||||
Record an area of the stage. The coordinates are in stage coordinates.
|
||||
The size of the stream does not necessarily match the size of the
|
||||
recorded area, and will depend on DPI scale of the affected monitors.
|
||||
|
||||
Available @properties include:
|
||||
|
||||
* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below)
|
||||
Available since API version 2.
|
||||
|
||||
Available cursor mode values:
|
||||
|
||||
0: hidden - cursor is not included in the stream
|
||||
1: embedded - cursor is included in the framebuffer
|
||||
2: metadata - cursor is included as metadata in the PipeWire stream
|
||||
-->
|
||||
<method name="RecordArea">
|
||||
<arg name="x" type="i" direction="in" />
|
||||
<arg name="y" type="i" direction="in" />
|
||||
<arg name="width" type="i" direction="in" />
|
||||
<arg name="height" type="i" direction="in" />
|
||||
<arg name="properties" type="a{sv}" direction="in" />
|
||||
<arg name="stream_path" type="o" direction="out" />
|
||||
</method>
|
||||
</interface>
|
||||
|
||||
<!--
|
||||
|
@@ -112,7 +112,7 @@ test_cogl_multitexture_main (int argc, char *argv[])
|
||||
GError *error = NULL;
|
||||
ClutterActor *stage;
|
||||
ClutterColor stage_color = { 0x61, 0x56, 0x56, 0xff };
|
||||
TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1);
|
||||
g_autofree TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1);
|
||||
gfloat stage_w, stage_h;
|
||||
gchar **files;
|
||||
gfloat tex_coords[] =
|
||||
|
23
src/tests/monitor-configs/lid-scale.xml
Normal file
23
src/tests/monitor-configs/lid-scale.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<monitors version="2">
|
||||
<configuration>
|
||||
<logicalmonitor>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<primary>yes</primary>
|
||||
<scale>2</scale>
|
||||
<monitor>
|
||||
<monitorspec>
|
||||
<connector>eDP-1</connector>
|
||||
<vendor>MetaProduct's Inc.</vendor>
|
||||
<product>MetaMonitor</product>
|
||||
<serial>0x123456</serial>
|
||||
</monitorspec>
|
||||
<mode>
|
||||
<width>1920</width>
|
||||
<height>1080</height>
|
||||
<rate>60.000495910644531</rate>
|
||||
</mode>
|
||||
</monitor>
|
||||
</logicalmonitor>
|
||||
</configuration>
|
||||
</monitors>
|
@@ -2868,6 +2868,116 @@ meta_test_monitor_lid_closed_with_hotplugged_external (void)
|
||||
check_monitor_configuration (&test_case);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_monitor_lid_scaled_closed_opened (void)
|
||||
{
|
||||
MonitorTestCase test_case = {
|
||||
.setup = {
|
||||
.modes = {
|
||||
{
|
||||
.width = 1920,
|
||||
.height = 1080,
|
||||
.refresh_rate = 60.000495910644531
|
||||
}
|
||||
},
|
||||
.n_modes = 1,
|
||||
.outputs = {
|
||||
{
|
||||
.crtc = 0,
|
||||
.modes = { 0 },
|
||||
.n_modes = 1,
|
||||
.preferred_mode = 0,
|
||||
.possible_crtcs = { 0 },
|
||||
.n_possible_crtcs = 1,
|
||||
.width_mm = 222,
|
||||
.height_mm = 125,
|
||||
.is_laptop_panel = TRUE
|
||||
},
|
||||
},
|
||||
.n_outputs = 1,
|
||||
.crtcs = {
|
||||
{
|
||||
.current_mode = 0
|
||||
},
|
||||
},
|
||||
.n_crtcs = 1
|
||||
},
|
||||
|
||||
.expect = {
|
||||
.monitors = {
|
||||
{
|
||||
.outputs = { 0 },
|
||||
.n_outputs = 1,
|
||||
.modes = {
|
||||
{
|
||||
.width = 1920,
|
||||
.height = 1080,
|
||||
.refresh_rate = 60.000495910644531,
|
||||
.crtc_modes = {
|
||||
{
|
||||
.output = 0,
|
||||
.crtc_mode = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.n_modes = 1,
|
||||
.current_mode = 0,
|
||||
.width_mm = 222,
|
||||
.height_mm = 125,
|
||||
}
|
||||
},
|
||||
.n_monitors = 1,
|
||||
.logical_monitors = {
|
||||
{
|
||||
.monitors = { 0 },
|
||||
.n_monitors = 1,
|
||||
.layout = { .x = 0, .y = 0, .width = 960, .height = 540 },
|
||||
.scale = 2
|
||||
}
|
||||
},
|
||||
.n_logical_monitors = 1,
|
||||
.primary_logical_monitor = 0,
|
||||
.n_outputs = 1,
|
||||
.crtcs = {
|
||||
{
|
||||
.current_mode = 0,
|
||||
}
|
||||
},
|
||||
.n_crtcs = 1,
|
||||
.n_tiled_monitors = 0,
|
||||
.screen_width = 960,
|
||||
.screen_height = 540
|
||||
}
|
||||
};
|
||||
MetaMonitorTestSetup *test_setup;
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_backend_get_monitor_manager (backend);
|
||||
|
||||
if (!meta_is_stage_views_enabled ())
|
||||
{
|
||||
g_test_skip ("Not using stage views");
|
||||
return;
|
||||
}
|
||||
|
||||
test_setup = create_monitor_test_setup (&test_case,
|
||||
MONITOR_TEST_FLAG_NONE);
|
||||
set_custom_monitor_config ("lid-scale.xml");
|
||||
emulate_hotplug (test_setup);
|
||||
check_monitor_configuration (&test_case);
|
||||
|
||||
meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), TRUE);
|
||||
meta_monitor_manager_lid_is_closed_changed (monitor_manager);
|
||||
|
||||
check_monitor_configuration (&test_case);
|
||||
|
||||
meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), FALSE);
|
||||
meta_monitor_manager_lid_is_closed_changed (monitor_manager);
|
||||
|
||||
check_monitor_configuration (&test_case);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_monitor_no_outputs (void)
|
||||
{
|
||||
@@ -4828,12 +4938,13 @@ meta_test_monitor_custom_second_rotated_tiled_config (void)
|
||||
.current_mode = 1,
|
||||
.transform = META_MONITOR_TRANSFORM_90,
|
||||
.x = 1024,
|
||||
.y = 400,
|
||||
.y = 0,
|
||||
},
|
||||
{
|
||||
.current_mode = 1,
|
||||
.transform = META_MONITOR_TRANSFORM_90,
|
||||
.x = 1024,
|
||||
.y = 400,
|
||||
}
|
||||
},
|
||||
.n_crtcs = 3,
|
||||
@@ -4859,6 +4970,198 @@ meta_test_monitor_custom_second_rotated_tiled_config (void)
|
||||
check_monitor_configuration (&test_case);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_monitor_custom_second_rotated_nonnative_tiled_config (void)
|
||||
{
|
||||
MonitorTestCase test_case = {
|
||||
.setup = {
|
||||
.modes = {
|
||||
{
|
||||
.width = 1024,
|
||||
.height = 768,
|
||||
.refresh_rate = 60.000495910644531
|
||||
},
|
||||
{
|
||||
.width = 400,
|
||||
.height = 600,
|
||||
.refresh_rate = 60.000495910644531
|
||||
}
|
||||
},
|
||||
.n_modes = 2,
|
||||
.outputs = {
|
||||
{
|
||||
.crtc = 0,
|
||||
.modes = { 0 },
|
||||
.n_modes = 1,
|
||||
.preferred_mode = 0,
|
||||
.possible_crtcs = { 0 },
|
||||
.n_possible_crtcs = 1,
|
||||
.width_mm = 222,
|
||||
.height_mm = 125,
|
||||
},
|
||||
{
|
||||
.crtc = -1,
|
||||
.modes = { 1 },
|
||||
.n_modes = 1,
|
||||
.preferred_mode = 1,
|
||||
.possible_crtcs = { 1, 2 },
|
||||
.n_possible_crtcs = 2,
|
||||
.width_mm = 222,
|
||||
.height_mm = 125,
|
||||
.tile_info = {
|
||||
.group_id = 1,
|
||||
.max_h_tiles = 2,
|
||||
.max_v_tiles = 1,
|
||||
.loc_h_tile = 0,
|
||||
.loc_v_tile = 0,
|
||||
.tile_w = 400,
|
||||
.tile_h = 600
|
||||
}
|
||||
},
|
||||
{
|
||||
.crtc = -1,
|
||||
.modes = { 1 },
|
||||
.n_modes = 1,
|
||||
.preferred_mode = 1,
|
||||
.possible_crtcs = { 1, 2 },
|
||||
.n_possible_crtcs = 2,
|
||||
.width_mm = 222,
|
||||
.height_mm = 125,
|
||||
.tile_info = {
|
||||
.group_id = 1,
|
||||
.max_h_tiles = 2,
|
||||
.max_v_tiles = 1,
|
||||
.loc_h_tile = 1,
|
||||
.loc_v_tile = 0,
|
||||
.tile_w = 400,
|
||||
.tile_h = 600
|
||||
}
|
||||
}
|
||||
},
|
||||
.n_outputs = 3,
|
||||
.crtcs = {
|
||||
{
|
||||
.current_mode = -1
|
||||
},
|
||||
{
|
||||
.current_mode = -1
|
||||
},
|
||||
{
|
||||
.current_mode = -1
|
||||
}
|
||||
},
|
||||
.n_crtcs = 3
|
||||
},
|
||||
|
||||
.expect = {
|
||||
.monitors = {
|
||||
{
|
||||
.outputs = { 0 },
|
||||
.n_outputs = 1,
|
||||
.modes = {
|
||||
{
|
||||
.width = 1024,
|
||||
.height = 768,
|
||||
.refresh_rate = 60.000495910644531,
|
||||
.crtc_modes = {
|
||||
{
|
||||
.output = 0,
|
||||
.crtc_mode = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.n_modes = 1,
|
||||
.current_mode = 0,
|
||||
.width_mm = 222,
|
||||
.height_mm = 125,
|
||||
},
|
||||
{
|
||||
.outputs = { 1, 2 },
|
||||
.n_outputs = 2,
|
||||
.modes = {
|
||||
{
|
||||
.width = 800,
|
||||
.height = 600,
|
||||
.refresh_rate = 60.000495910644531,
|
||||
.crtc_modes = {
|
||||
{
|
||||
.output = 1,
|
||||
.crtc_mode = 1,
|
||||
},
|
||||
{
|
||||
.output = 2,
|
||||
.crtc_mode = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.n_modes = 1,
|
||||
.current_mode = 0,
|
||||
.width_mm = 222,
|
||||
.height_mm = 125,
|
||||
}
|
||||
},
|
||||
.n_monitors = 2,
|
||||
.logical_monitors = {
|
||||
{
|
||||
.monitors = { 0 },
|
||||
.n_monitors = 1,
|
||||
.layout = { .x = 0, .y = 256, .width = 1024, .height = 768 },
|
||||
.scale = 1
|
||||
},
|
||||
{
|
||||
.monitors = { 1 },
|
||||
.n_monitors = 1,
|
||||
.layout = { .x = 1024, .y = 0, .width = 600, .height = 800 },
|
||||
.scale = 1,
|
||||
.transform = META_MONITOR_TRANSFORM_90
|
||||
}
|
||||
},
|
||||
.n_logical_monitors = 2,
|
||||
.primary_logical_monitor = 0,
|
||||
.n_outputs = 3,
|
||||
.crtcs = {
|
||||
{
|
||||
.current_mode = 0,
|
||||
.y = 256,
|
||||
},
|
||||
{
|
||||
.current_mode = 1,
|
||||
.transform = META_MONITOR_TRANSFORM_NORMAL,
|
||||
.x = 1024,
|
||||
.y = 0,
|
||||
},
|
||||
{
|
||||
.current_mode = 1,
|
||||
.transform = META_MONITOR_TRANSFORM_NORMAL,
|
||||
.x = 1024,
|
||||
.y = 400,
|
||||
}
|
||||
},
|
||||
.n_crtcs = 3,
|
||||
.n_tiled_monitors = 1,
|
||||
.screen_width = 1024 + 600,
|
||||
.screen_height = 1024
|
||||
}
|
||||
};
|
||||
MetaMonitorTestSetup *test_setup;
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_backend_get_monitor_manager (backend);
|
||||
MetaMonitorManagerTest *monitor_manager_test =
|
||||
META_MONITOR_MANAGER_TEST (monitor_manager);
|
||||
|
||||
meta_monitor_manager_test_set_handles_transforms (monitor_manager_test,
|
||||
FALSE);
|
||||
|
||||
test_setup = create_monitor_test_setup (&test_case,
|
||||
MONITOR_TEST_FLAG_NONE);
|
||||
set_custom_monitor_config ("second-rotated-tiled.xml");
|
||||
emulate_hotplug (test_setup);
|
||||
check_monitor_configuration (&test_case);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_test_monitor_custom_second_rotated_nonnative_config (void)
|
||||
{
|
||||
@@ -6058,6 +6361,8 @@ init_monitor_tests (void)
|
||||
meta_test_monitor_lid_closed_no_external);
|
||||
add_monitor_test ("/backends/monitor/lid-closed-with-hotplugged-external",
|
||||
meta_test_monitor_lid_closed_with_hotplugged_external);
|
||||
add_monitor_test ("/backends/monitor/lid-scaled-closed-opened",
|
||||
meta_test_monitor_lid_scaled_closed_opened);
|
||||
add_monitor_test ("/backends/monitor/no-outputs",
|
||||
meta_test_monitor_no_outputs);
|
||||
add_monitor_test ("/backends/monitor/underscanning-config",
|
||||
@@ -6093,6 +6398,8 @@ init_monitor_tests (void)
|
||||
meta_test_monitor_custom_second_rotated_config);
|
||||
add_monitor_test ("/backends/monitor/custom/second-rotated-tiled-config",
|
||||
meta_test_monitor_custom_second_rotated_tiled_config);
|
||||
add_monitor_test ("/backends/monitor/custom/second-rotated-nonnative-tiled-config",
|
||||
meta_test_monitor_custom_second_rotated_nonnative_tiled_config);
|
||||
add_monitor_test ("/backends/monitor/custom/second-rotated-nonnative-config",
|
||||
meta_test_monitor_custom_second_rotated_nonnative_config);
|
||||
add_monitor_test ("/backends/monitor/custom/interlaced-config",
|
||||
|
@@ -427,7 +427,7 @@ test_client_new (const char *id,
|
||||
MetaWindowClientType type,
|
||||
GError **error)
|
||||
{
|
||||
TestClient *client = g_new0 (TestClient, 1);
|
||||
TestClient *client;
|
||||
GSubprocessLauncher *launcher;
|
||||
GSubprocess *subprocess;
|
||||
MetaWaylandCompositor *compositor;
|
||||
@@ -462,6 +462,7 @@ test_client_new (const char *id,
|
||||
if (!subprocess)
|
||||
return NULL;
|
||||
|
||||
client = g_new0 (TestClient, 1);
|
||||
client->type = type;
|
||||
client->id = g_strdup (id);
|
||||
client->cancellable = g_cancellable_new ();
|
||||
|
@@ -59,3 +59,19 @@ executable('subsurface-remap-toplevel',
|
||||
install: have_installed_tests,
|
||||
install_dir: wayland_test_client_installed_tests_libexecdir,
|
||||
)
|
||||
|
||||
executable('meta-anonymous-file',
|
||||
sources: [
|
||||
'meta-anonymous-file.c',
|
||||
common_sources,
|
||||
],
|
||||
include_directories: tests_includepath,
|
||||
c_args: tests_c_args,
|
||||
dependencies: [
|
||||
glib_dep,
|
||||
wayland_client_dep,
|
||||
libmutter_dep,
|
||||
],
|
||||
install: have_installed_tests,
|
||||
install_dir: wayland_test_client_installed_tests_libexecdir,
|
||||
)
|
||||
|
278
src/tests/wayland-test-clients/meta-anonymous-file.c
Normal file
278
src/tests/wayland-test-clients/meta-anonymous-file.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Jonas Dreßler.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <core/meta-anonymous-file.h>
|
||||
|
||||
#include "wayland-test-client-utils.h"
|
||||
|
||||
#define READONLY_SEALS (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
|
||||
|
||||
static const char *teststring = "test string 1234567890";
|
||||
|
||||
static int
|
||||
test_read_fd_mmap (int fd,
|
||||
const char *expected_string)
|
||||
{
|
||||
void *mem;
|
||||
int string_size;
|
||||
|
||||
string_size = strlen (expected_string) + 1;
|
||||
|
||||
mem = mmap (NULL, string_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
g_assert (mem != MAP_FAILED);
|
||||
|
||||
if (strcmp (expected_string, mem) != 0)
|
||||
{
|
||||
munmap (mem, string_size);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
munmap (mem, string_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
test_write_fd (int fd,
|
||||
const char *string)
|
||||
{
|
||||
int written_size, string_size;
|
||||
|
||||
string_size = strlen (string) + 1;
|
||||
written_size = write (fd, string, string_size);
|
||||
if (written_size != string_size)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
test_readonly_seals (int fd)
|
||||
{
|
||||
unsigned int seals;
|
||||
|
||||
seals = fcntl (fd, F_GET_SEALS);
|
||||
if (seals == -1)
|
||||
return FALSE;
|
||||
|
||||
if (seals != READONLY_SEALS)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
test_write_read (int fd)
|
||||
{
|
||||
g_autofree char *new_string = g_uuid_string_random ();
|
||||
|
||||
if (!test_write_fd (fd, new_string))
|
||||
return FALSE;
|
||||
|
||||
if (!test_read_fd_mmap (fd, new_string))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if defined(HAVE_MEMFD_CREATE)
|
||||
static int
|
||||
test_open_write_read (const char *path)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open (path, O_RDWR);
|
||||
g_assert (fd != -1);
|
||||
|
||||
if (!test_write_read (fd))
|
||||
{
|
||||
close (fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
MetaAnonymousFile *file;
|
||||
int fd = -1, other_fd = -1;
|
||||
g_autofree char *fd_path = NULL;
|
||||
|
||||
file = meta_anonymous_file_new (strlen (teststring) + 1,
|
||||
(const uint8_t *) teststring);
|
||||
if (!file)
|
||||
{
|
||||
g_critical ("%s: Creating file failed", __func__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#if defined(HAVE_MEMFD_CREATE)
|
||||
fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_PRIVATE);
|
||||
g_assert (fd != -1);
|
||||
other_fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_PRIVATE);
|
||||
g_assert (other_fd != -1);
|
||||
|
||||
/* When MAPMODE_PRIVATE was used, meta_anonymous_file_open_fd() should always
|
||||
* return the same fd. */
|
||||
if (other_fd != fd)
|
||||
goto fail;
|
||||
|
||||
/* If memfd_create was used and we request a MAPMODE_PRIVATE file, all the
|
||||
* readonly seals should be set. */
|
||||
if (!test_readonly_seals (fd))
|
||||
goto fail;
|
||||
|
||||
if (!test_read_fd_mmap (fd, teststring))
|
||||
goto fail;
|
||||
|
||||
/* Writing and reading the written data should fail */
|
||||
if (test_write_read (fd))
|
||||
goto fail;
|
||||
|
||||
/* Instead we should still be reading the teststring */
|
||||
if (!test_read_fd_mmap (fd, teststring))
|
||||
goto fail;
|
||||
|
||||
/* Opening the fd manually in RW mode and writing to it should fail */
|
||||
fd_path = g_strdup_printf ("/proc/%d/fd/%d", getpid (), fd);
|
||||
if (test_open_write_read (fd_path))
|
||||
goto fail;
|
||||
|
||||
/* Instead we should still be reading the teststring */
|
||||
if (!test_read_fd_mmap (fd, teststring))
|
||||
goto fail;
|
||||
|
||||
/* Just to be sure test the other fd, too */
|
||||
if (!test_read_fd_mmap (other_fd, teststring))
|
||||
goto fail;
|
||||
|
||||
meta_anonymous_file_close_fd (fd);
|
||||
meta_anonymous_file_close_fd (fd);
|
||||
|
||||
|
||||
fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_SHARED);
|
||||
g_assert (fd != -1);
|
||||
other_fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_SHARED);
|
||||
g_assert (other_fd != -1);
|
||||
|
||||
/* The MAPMODE_SHARED fd should not have readonly seals applied */
|
||||
if (test_readonly_seals (fd))
|
||||
goto fail;
|
||||
|
||||
if (!test_read_fd_mmap (fd, teststring))
|
||||
goto fail;
|
||||
|
||||
if (!test_read_fd_mmap (other_fd, teststring))
|
||||
goto fail;
|
||||
|
||||
/* Writing and reading the written data should succeed */
|
||||
if (!test_write_read (fd))
|
||||
goto fail;
|
||||
|
||||
/* The other fd should still read the teststring though */
|
||||
if (!test_read_fd_mmap (other_fd, teststring))
|
||||
goto fail;
|
||||
|
||||
meta_anonymous_file_close_fd (fd);
|
||||
meta_anonymous_file_close_fd (other_fd);
|
||||
|
||||
|
||||
/* Test an artificial out-of-space situation by setting the maximium file
|
||||
* size this process may create to 2 bytes, if memfd_create with
|
||||
* MAPMODE_PRIVATE is used, everything should still work (the existing FD
|
||||
* should be used). */
|
||||
struct rlimit limit = {2, 2};
|
||||
if (setrlimit (RLIMIT_FSIZE, &limit) == -1)
|
||||
goto fail;
|
||||
|
||||
fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_PRIVATE);
|
||||
g_assert (fd != -1);
|
||||
|
||||
if (!test_read_fd_mmap (fd, teststring))
|
||||
goto fail;
|
||||
|
||||
meta_anonymous_file_close_fd (fd);
|
||||
#else
|
||||
fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_PRIVATE);
|
||||
g_assert (fd != -1);
|
||||
other_fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_PRIVATE);
|
||||
g_assert (other_fd != -1);
|
||||
|
||||
if (test_readonly_seals (fd))
|
||||
goto fail;
|
||||
|
||||
/* Writing and reading the written data should succeed */
|
||||
if (!test_write_read (fd))
|
||||
goto fail;
|
||||
|
||||
/* The other fd should still read the teststring though */
|
||||
if (!test_read_fd_mmap (other_fd, teststring))
|
||||
goto fail;
|
||||
|
||||
meta_anonymous_file_close_fd (fd);
|
||||
meta_anonymous_file_close_fd (other_fd);
|
||||
|
||||
|
||||
fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_SHARED);
|
||||
g_assert (fd != -1);
|
||||
other_fd = meta_anonymous_file_open_fd (file, META_ANONYMOUS_FILE_MAPMODE_SHARED);
|
||||
g_assert (other_fd != -1);
|
||||
|
||||
if (test_readonly_seals (fd))
|
||||
goto fail;
|
||||
|
||||
if (!test_read_fd_mmap (fd, teststring))
|
||||
goto fail;
|
||||
|
||||
if (!test_read_fd_mmap (other_fd, teststring))
|
||||
goto fail;
|
||||
|
||||
/* Writing and reading the written data should succeed */
|
||||
if (!test_write_read (fd))
|
||||
goto fail;
|
||||
|
||||
/* The other fd should still read the teststring though */
|
||||
if (!test_read_fd_mmap (other_fd, teststring))
|
||||
goto fail;
|
||||
|
||||
meta_anonymous_file_close_fd (fd);
|
||||
meta_anonymous_file_close_fd (other_fd);
|
||||
#endif
|
||||
|
||||
meta_anonymous_file_free (file);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
fail:
|
||||
if (fd > 0)
|
||||
meta_anonymous_file_close_fd (fd);
|
||||
if (other_fd > 0)
|
||||
meta_anonymous_file_close_fd (other_fd);
|
||||
meta_anonymous_file_free (file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
@@ -417,7 +417,7 @@ meta_ui_frame_calc_geometry (MetaUIFrame *frame,
|
||||
MetaFrameType type;
|
||||
MetaButtonLayout button_layout;
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (frame->meta_window);
|
||||
MetaWindowX11Private *priv = window_x11->priv;
|
||||
MetaRectangle client_rect;
|
||||
|
||||
flags = meta_frame_get_flags (frame->meta_window->frame);
|
||||
type = meta_window_get_frame_type (frame->meta_window);
|
||||
@@ -426,13 +426,15 @@ meta_ui_frame_calc_geometry (MetaUIFrame *frame,
|
||||
|
||||
meta_prefs_get_button_layout (&button_layout);
|
||||
|
||||
client_rect = meta_window_x11_get_client_rect (window_x11);
|
||||
|
||||
meta_theme_calc_geometry (meta_theme_get_default (),
|
||||
frame->style_info,
|
||||
type,
|
||||
frame->text_height,
|
||||
flags,
|
||||
priv->client_rect.width,
|
||||
priv->client_rect.height,
|
||||
client_rect.width,
|
||||
client_rect.height,
|
||||
&button_layout,
|
||||
fgeom);
|
||||
}
|
||||
@@ -1520,7 +1522,7 @@ meta_ui_frame_paint (MetaUIFrame *frame,
|
||||
int button_type = -1;
|
||||
MetaButtonLayout button_layout;
|
||||
MetaWindowX11 *window_x11 = META_WINDOW_X11 (frame->meta_window);
|
||||
MetaWindowX11Private *priv = window_x11->priv;
|
||||
MetaRectangle client_rect;
|
||||
|
||||
for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
|
||||
button_states[i] = META_BUTTON_STATE_NORMAL;
|
||||
@@ -1558,13 +1560,15 @@ meta_ui_frame_paint (MetaUIFrame *frame,
|
||||
|
||||
meta_prefs_get_button_layout (&button_layout);
|
||||
|
||||
client_rect = meta_window_x11_get_client_rect (window_x11);
|
||||
|
||||
meta_theme_draw_frame (meta_theme_get_default (),
|
||||
frame->style_info,
|
||||
cr,
|
||||
type,
|
||||
flags,
|
||||
priv->client_rect.width,
|
||||
priv->client_rect.height,
|
||||
client_rect.width,
|
||||
client_rect.height,
|
||||
frame->text_layout,
|
||||
frame->text_height,
|
||||
&button_layout,
|
||||
|
@@ -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 ())
|
||||
|
||||
|
@@ -156,7 +156,7 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor
|
||||
surface_actor = priv->actor;
|
||||
stex = meta_surface_actor_get_texture (surface_actor);
|
||||
|
||||
buffer = surface->buffer_ref.buffer;
|
||||
buffer = surface->buffer_ref->buffer;
|
||||
if (buffer)
|
||||
{
|
||||
CoglSnippet *snippet;
|
||||
|
@@ -58,6 +58,11 @@
|
||||
#include "meta/util.h"
|
||||
#include "wayland/meta-wayland-dma-buf.h"
|
||||
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
#include "backends/native/meta-drm-buffer-gbm.h"
|
||||
#include "backends/native/meta-renderer-native.h"
|
||||
#endif
|
||||
|
||||
#ifndef DRM_FORMAT_MOD_INVALID
|
||||
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
|
||||
#endif
|
||||
@@ -577,6 +582,93 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
static CoglScanout *
|
||||
try_acquire_egl_image_scanout (MetaWaylandBuffer *buffer,
|
||||
CoglOnscreen *onscreen)
|
||||
{
|
||||
#ifdef HAVE_NATIVE_BACKEND
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
||||
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
|
||||
MetaGpuKms *gpu_kms;
|
||||
struct gbm_device *gbm_device;
|
||||
struct gbm_bo *gbm_bo;
|
||||
uint32_t drm_format;
|
||||
uint64_t drm_modifier;
|
||||
uint32_t stride;
|
||||
MetaDrmBufferGbm *fb;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
|
||||
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
|
||||
|
||||
gbm_bo = gbm_bo_import (gbm_device,
|
||||
GBM_BO_IMPORT_WL_BUFFER, buffer->resource,
|
||||
GBM_BO_USE_SCANOUT);
|
||||
if (!gbm_bo)
|
||||
return NULL;
|
||||
|
||||
drm_format = gbm_bo_get_format (gbm_bo);
|
||||
drm_modifier = gbm_bo_get_modifier (gbm_bo);
|
||||
stride = gbm_bo_get_stride (gbm_bo);
|
||||
if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen,
|
||||
drm_format,
|
||||
drm_modifier,
|
||||
stride))
|
||||
{
|
||||
gbm_bo_destroy (gbm_bo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo,
|
||||
drm_modifier != DRM_FORMAT_MOD_INVALID,
|
||||
&error);
|
||||
if (!fb)
|
||||
{
|
||||
g_debug ("Failed to create scanout buffer: %s", error->message);
|
||||
gbm_bo_destroy (gbm_bo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return COGL_SCANOUT (fb);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
CoglScanout *
|
||||
meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
|
||||
CoglOnscreen *onscreen)
|
||||
{
|
||||
switch (buffer->type)
|
||||
{
|
||||
case META_WAYLAND_BUFFER_TYPE_SHM:
|
||||
return NULL;
|
||||
case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
|
||||
return try_acquire_egl_image_scanout (buffer, onscreen);
|
||||
#ifdef HAVE_WAYLAND_EGLSTREAM
|
||||
case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
|
||||
return NULL;
|
||||
#endif
|
||||
case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
|
||||
{
|
||||
MetaWaylandDmaBufBuffer *dma_buf;
|
||||
|
||||
dma_buf = meta_wayland_dma_buf_from_buffer (buffer);
|
||||
if (!dma_buf)
|
||||
return NULL;
|
||||
|
||||
return meta_wayland_dma_buf_try_acquire_scanout (dma_buf, onscreen);
|
||||
}
|
||||
case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
|
||||
g_warn_if_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_buffer_finalize (GObject *object)
|
||||
{
|
||||
|
@@ -88,5 +88,7 @@ gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuff
|
||||
void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
|
||||
CoglTexture *texture,
|
||||
cairo_region_t *region);
|
||||
CoglScanout * meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
|
||||
CoglOnscreen *onscreen);
|
||||
|
||||
#endif /* META_WAYLAND_BUFFER_H */
|
||||
|
326
src/wayland/meta-wayland-data-device-primary.c
Normal file
326
src/wayland/meta-wayland-data-device-primary.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* 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 "gtk-primary-selection-server-protocol.h"
|
||||
|
||||
static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevicePrimary *data_device,
|
||||
struct wl_resource *target);
|
||||
|
||||
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 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,
|
||||
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)
|
||||
{
|
||||
data_device_resource =
|
||||
wl_resource_find_for_client (&data_device->resource_list,
|
||||
focus_client);
|
||||
if (data_device_resource)
|
||||
{
|
||||
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 (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, >k_primary_selection_source_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, >k_primary_selection_device_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 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, >k_primary_selection_device_manager_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,
|
||||
>k_primary_selection_device_manager_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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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_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;
|
||||
|
||||
if (!focus_client)
|
||||
return;
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
|
||||
if (data_device_resource)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
54
src/wayland/meta-wayland-data-device-primary.h
Normal file
54
src/wayland/meta-wayland-data-device-primary.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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_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 */
|
File diff suppressed because it is too large
Load Diff
@@ -28,42 +28,19 @@
|
||||
|
||||
#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"
|
||||
|
||||
typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab;
|
||||
typedef struct _MetaWaylandDataSourceFuncs MetaWaylandDataSourceFuncs;
|
||||
|
||||
#define META_TYPE_WAYLAND_DATA_SOURCE (meta_wayland_data_source_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaWaylandDataSource, meta_wayland_data_source,
|
||||
META, WAYLAND_DATA_SOURCE, GObject);
|
||||
|
||||
struct _MetaWaylandDataSourceClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* send) (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type,
|
||||
gint fd);
|
||||
void (* target) (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type);
|
||||
void (* cancel) (MetaWaylandDataSource *source);
|
||||
|
||||
void (* action) (MetaWaylandDataSource *source,
|
||||
uint32_t action);
|
||||
void (* drop_performed) (MetaWaylandDataSource *source);
|
||||
void (* drag_finished) (MetaWaylandDataSource *source);
|
||||
};
|
||||
|
||||
struct _MetaWaylandDataDevice
|
||||
{
|
||||
uint32_t selection_serial;
|
||||
uint32_t primary_serial;
|
||||
MetaWaylandDataSource *selection_data_source;
|
||||
MetaWaylandDataSource *dnd_data_source;
|
||||
MetaWaylandDataSource *primary_data_source;
|
||||
struct wl_listener selection_data_source_listener;
|
||||
struct wl_list resource_list;
|
||||
struct wl_list primary_resource_list;
|
||||
MetaWaylandDragGrab *current_grab;
|
||||
struct wl_client *focus_client;
|
||||
|
||||
@@ -89,42 +66,7 @@ void meta_wayland_data_device_set_dnd_source (MetaWaylandDataDevice *data_de
|
||||
void meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandDataSource *source,
|
||||
guint32 serial);
|
||||
void meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandDataSource *source,
|
||||
guint32 serial);
|
||||
|
||||
gboolean meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type);
|
||||
|
||||
gboolean meta_wayland_data_source_has_mime_type (const MetaWaylandDataSource *source,
|
||||
const gchar *mime_type);
|
||||
|
||||
struct wl_array *
|
||||
meta_wayland_data_source_get_mime_types (const MetaWaylandDataSource *source);
|
||||
|
||||
gboolean meta_wayland_data_source_has_target (MetaWaylandDataSource *source);
|
||||
|
||||
void meta_wayland_data_source_set_has_target (MetaWaylandDataSource *source,
|
||||
gboolean has_target);
|
||||
|
||||
void meta_wayland_data_source_cancel (MetaWaylandDataSource *source);
|
||||
|
||||
void meta_wayland_data_source_send (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type,
|
||||
gint fd);
|
||||
|
||||
void meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source);
|
||||
|
||||
uint32_t meta_wayland_data_source_get_actions (MetaWaylandDataSource *source);
|
||||
uint32_t meta_wayland_data_source_get_user_action (MetaWaylandDataSource *source);
|
||||
uint32_t meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source);
|
||||
|
||||
void meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
|
||||
uint32_t dnd_actions);
|
||||
void meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
|
||||
uint32_t action);
|
||||
void meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
|
||||
uint32_t action);
|
||||
void meta_wayland_data_device_unset_dnd_selection (MetaWaylandDataDevice *data_device);
|
||||
|
||||
const MetaWaylandDragDestFuncs *
|
||||
meta_wayland_data_device_get_drag_dest_funcs (void);
|
||||
|
138
src/wayland/meta-wayland-data-offer-primary.c
Normal file
138
src/wayland/meta-wayland-data-offer-primary.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright © 2011 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-wayland-data-offer-primary.h"
|
||||
|
||||
#include <gio/gunixoutputstream.h>
|
||||
#include <glib-unix.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "core/display-private.h"
|
||||
#include "gtk-primary-selection-server-protocol.h"
|
||||
#include "wayland/meta-wayland-data-offer.h"
|
||||
|
||||
static void
|
||||
transfer_cb (MetaSelection *selection,
|
||||
GAsyncResult *res,
|
||||
GOutputStream *stream)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!meta_selection_transfer_finish (selection, res, &error))
|
||||
{
|
||||
g_warning ("Could not fetch selection data: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_output_stream_close (stream, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
primary_offer_receive (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
const char *mime_type,
|
||||
int32_t fd)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
GOutputStream *stream;
|
||||
GList *mime_types;
|
||||
gboolean found;
|
||||
|
||||
mime_types = meta_selection_get_mimetypes (meta_display_get_selection (display),
|
||||
META_SELECTION_PRIMARY);
|
||||
found = g_list_find_custom (mime_types, mime_type, (GCompareFunc) g_strcmp0) != NULL;
|
||||
g_list_free_full (mime_types, g_free);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
close (fd);
|
||||
return;
|
||||
}
|
||||
|
||||
stream = g_unix_output_stream_new (fd, TRUE);
|
||||
meta_selection_transfer_async (meta_display_get_selection (display),
|
||||
META_SELECTION_PRIMARY,
|
||||
mime_type,
|
||||
-1,
|
||||
stream,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) transfer_cb,
|
||||
stream);
|
||||
}
|
||||
|
||||
static void
|
||||
primary_offer_destroy (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static const struct gtk_primary_selection_offer_interface primary_offer_interface = {
|
||||
primary_offer_receive,
|
||||
primary_offer_destroy,
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_primary_offer (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
|
||||
|
||||
if (offer->source)
|
||||
{
|
||||
if (offer == meta_wayland_data_source_get_current_offer (offer->source))
|
||||
{
|
||||
meta_wayland_data_source_cancel (offer->source);
|
||||
meta_wayland_data_source_set_current_offer (offer->source, NULL);
|
||||
}
|
||||
|
||||
g_object_remove_weak_pointer (G_OBJECT (offer->source),
|
||||
(gpointer *)&offer->source);
|
||||
offer->source = NULL;
|
||||
}
|
||||
|
||||
meta_display_sync_wayland_input_focus (meta_get_display ());
|
||||
g_slice_free (MetaWaylandDataOffer, offer);
|
||||
}
|
||||
|
||||
MetaWaylandDataOffer *
|
||||
meta_wayland_data_offer_primary_new (struct wl_resource *target)
|
||||
{
|
||||
MetaWaylandDataOffer *offer;
|
||||
|
||||
offer = g_slice_new0 (MetaWaylandDataOffer);
|
||||
offer->selection_type = META_SELECTION_PRIMARY;
|
||||
offer->resource = wl_resource_create (wl_resource_get_client (target),
|
||||
>k_primary_selection_offer_interface,
|
||||
wl_resource_get_version (target), 0);
|
||||
wl_resource_set_implementation (offer->resource,
|
||||
&primary_offer_interface,
|
||||
offer,
|
||||
destroy_primary_offer);
|
||||
return offer;
|
||||
}
|
31
src/wayland/meta-wayland-data-offer-primary.h
Normal file
31
src/wayland/meta-wayland-data-offer-primary.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright © 2011 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_OFFER_PRIMARY_H
|
||||
#define META_WAYLAND_DATA_OFFER_PRIMARY_H
|
||||
|
||||
#include "meta-wayland-data-offer.h"
|
||||
|
||||
MetaWaylandDataOffer * meta_wayland_data_offer_primary_new (struct wl_resource *target);
|
||||
|
||||
#endif /* META_WAYLAND_DATA_OFFER_PRIMARY_H */
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user