Compare commits

...

29 Commits

Author SHA1 Message Date
162d6d45a0 cogl/egl: Use EGL_IMG_context_priority
As long as the context_priority extension is available request a high
priority context, to help the compositor look fluid despite heavy GPU usage
from other applications at a regular priority.

This becomes sort of pointless if/when unredirection applies, should still
help with overview/workspace switch animations, or if the application is
not fullscreen.

Based on a similar patch by Daniel Stone to Weston.
2019-01-21 16:33:44 +01:00
ff507273d2 startup-notification: Silence warning
Warning in question:

../src/core/startup-notification.c:646:16: error: unused variable ‘display’ [-Werror=unused-variable]
2019-01-18 18:18:57 +01:00
f033d0e846 core: Add MetaLaunchContext
This is a GAppLaunchContext subclass meant to replace usage of
GdkAppLaunchContext in gnome-shell.

Launch contexts get created from the MetaStartupNotification as
they are closely related. The messaging underneath depends on
the availability of a X11 display, if there is one we go through
it (and libsn). If there is none, we still create startup sequences
manually for wayland clients.
2019-01-18 17:03:57 +00:00
ca67d52cac x11: Add method to launch applications, using SnLauncher
The method spawns a launch request that will get caught by the
SnMonitor we have in place to handle X11 startup notification
messages.
2019-01-18 17:03:57 +00:00
60d22b7cd0 wayland: Accept NULL primary data source
A NULL argument is expected here in order to unset the selection,
meta_wayland_data_device_set_primary() accepts a NULL source, but
gtk_primary_selection_device.set_selection was not handling a
NULL wl_resource.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/335
2019-01-18 13:52:05 +00:00
e9778eba18 build: Pass --quiet to glib-genmarshal
We don't need to know it read the input file really.
2019-01-17 20:42:10 +00:00
56d260cfb3 screen-cast-monitor-stream-src: Only send cursor bitmap when it changes
To avoid unnecessary pixel copying, only send the cursor bitmap when it
changes. This also allows the receiver to know when the cursor bitmap
actually changed.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
c45d5f53ff cursor-tracker: Emit cursor-changed after renderer was updated
Otherwise the cursor retrieved via meta_cursor_renderer_get_cursor() is
out of date.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
4e402b3972 screen-cast: Add 'cursor-mode' to allow decoupled cursor updates
The 'cursor-mode', which currently is limited to RecordMonitor(), allows
the user to either do screen casts where the cursor is hidden, embedded
in the framebuffer, or sent as PipeWire stream metadata.

The latter allows the user to get cursor updates sent, including the
cursor sprite, without requiring a stage paint each frame. Currently
this is done by using the cursor sprite texture, and either reading
directly from, or drawing to an offscreen framebuffer which is read from
instead, in case the texture is scaled.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
79d99cbe3f cursor-renderer: Add API to allow inhibiting HW cursor
There may be reasons to temporarly inhibit the HW cursor under certain
circumstances. Allow adding such inhibitations by adding API to the
cursor renderer to allow API users to add generic inhibitors with
whatever logic is deemed necessary.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
328eff7352 screen-cast/monitor-stream-src: Copy content before cursor is drawn
To get a consistent behaviour no matter whether HW cursors are in use or
not, make sure to copy the framebuffer content before the stage overlays
(cursor sprite textures) are painted.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
ed5c1f433b backends/stage: Emit signal between painting actors and overlays
Will be used by screen casting for embedding the cursor separately, or
not including at all.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
7ac2083134 backends/stage: Fix minor style issue
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
bd97b11414 renderer: Add API to get view from logical monitor
Will be used to get the view scale for a logical monitor, which is
necessary for passing cursor sprites via PipeWire.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
0da0207eed screen-cast: Add getters to fetch object owners
MetaBackend owns MetaScreenCast which owns MetaScreenCastSession which
owns MetaScreenCastStream. Make it possible to fetch objects in the
oppositev direction too.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
08229a6f5d screen-cast-monitor-stream: Don't pass monitor manager when creating
It can be fetched indirectly from the monitor already.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
50071303af clutter/stage: Add clutter_stage_is_redraw_queued() API
This will be used by the screen casting code to check whether it should
wait for a frame before reading cursor state, or send only the cursor
update, if no redraw is queued.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
2b2d77dc3e cursor-tracker: Add 'cursor-moved' signal
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
2019-01-16 17:09:51 +00:00
a0909c3440 constraints: Fix titlebars going off the bottom
The "current" rect includes the frame, so in order to keep the
titlebar on screen, window movement must be restricted to at
most (height - titlebar_height) past the work area bottom.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/391
2019-01-16 01:19:32 +01:00
22f865122c renderer/native: Prefer hardware rendering for primary GPU
Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.

Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.

The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.

The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet.  Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.

The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.

Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>

https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2019-01-13 10:30:44 +00:00
60ac2838b5 renderer/native: Move primary GPU choosing later
Moves the primary GPU choosing to after all secondary gpu data has been
created.

This makes it possible for a future patch to start looking at secondary
gpu data in choose_primary_gpu () to determine if it is using a hardware
driver or a software renderer.

Co-authored by: Pekka Paalanen <pekka.paalanen@collabora.com>

https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2019-01-13 10:30:44 +00:00
dfde2f59da renderer/native: Secondary gpu data for all
Initialize the secondary GPU data for all GPUs, even the primary one. By
not looking at the primary_gpu_kms member, a future patch is allowed to
postpone choosing the primary GPU.

A future patch will use the secondary GPU data to decide which GPU will
become the primary GPU.

Co-authored by: Pekka Paalanen <pekka.paalanen@collabora.com>

https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2019-01-13 10:30:44 +00:00
3d2ca9a67f renderer/native: Count devices on EGLDevice check
create_renderer_gpu_data_egl_device () relied on the primary GPU being
already chosen for the "EGLDevice currently only works with single GPU
systems" error message. A future patch will choose the primary GPU after
this, not before, so this check needs to be rewritten before the
initialization order is changed.

The new check is implemented exactly as the error message says: there
must be exactly one GPU, otherwise fail.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2019-01-13 10:30:44 +00:00
9182c8b801 backends/native: Move primary_gpu into MetaRendererNative
Make the choosing and identity of the primary GPU an internal detail to
the native renderer. MonitorManagerKms did not need it for anything.

The primary GPU logic remains unchanged.

This allows follow-up patches to change how the renderer chooses the
primary GPU. It will be easier for the renderer to use private
information for choosing.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2019-01-13 10:30:44 +00:00
1def099047 backends/native: Re-order primary GPU choosing logic
This is a step towards moving the primary GPU logic into the native
renderer exclusively. In the future the renderer will have one more
criterion on choosing the primary GPU than MetaMonitorManagerKms should
know about: does a GPU offer hardware rendering.

The choosing of primary GPU is separated from the discovery of GPUs.
When GPUs are discovered and added to the list, the MetaGpuKmsFlag is
now populated correctly and used in choosing.

Choosing the primary GPU is done after all GPUs have been found and is
slightly different from before:

- Skipping devices that do not belong to our seat now works instead of
becoming the primary GPU.

- Fall back to any non-platform, non-boot_vga device if neither kind is
found.

The old preference of platform over boot_vga device is kept.

The hotplug path will continue creating a gpu_kms without flags, because
at that point the primary GPU has already been chosen and the flags are
irrelevant.

Co-authored by: Pekka Paalanen <pekka.paalanen@collabora.com>

https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2019-01-13 10:30:44 +00:00
ddb0ef1e8d backends/native: Add flags to MetaGpuKms
Add a flags field to MetaGpuKms. In following commits, the flags defined
here will be set and used for choosing the primary GPU.

Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>

https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2019-01-13 10:30:44 +00:00
a56a59feee Remove po/ChangeLog
Ain’t nobody need ChangeLogs for a while now.
2019-01-12 14:53:13 +01:00
174df4eaeb Remove po/Makevars
Follow-up to 763ae36cee
2019-01-12 14:51:46 +01:00
e3e933c47a clutter/x11: Implement keycode remap to keysyms on virtual key devices
Keycode lookup can fail for serveral reasons, e.g. if there is no combination of
modifiers and keycodes that can produce the target keysym with the current
keyboard layout.

In case the keycode lookup fails, remap temporarily the keysym to an unused
keycodes.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/109
2019-01-11 17:29:27 +01:00
52 changed files with 1647 additions and 5335 deletions

View File

@ -13,5 +13,8 @@ RUN dnf -y update && dnf -y upgrade && \
# Unpackaged versions
dnf install -y https://copr-be.cloud.fedoraproject.org/results/jadahl/mutter-ci/fedora-29-x86_64/00836095-gsettings-desktop-schemas/gsettings-desktop-schemas-3.30.1-1.20181206git918efdd69be53.fc29.x86_64.rpm https://copr-be.cloud.fedoraproject.org/results/jadahl/mutter-ci/fedora-29-x86_64/00836095-gsettings-desktop-schemas/gsettings-desktop-schemas-devel-3.30.1-1.20181206git918efdd69be53.fc29.x86_64.rpm && \
# Packages not yet in stable
dnf install -y https://kojipkgs.fedoraproject.org//packages/pipewire/0.2.5/1.fc29/x86_64/pipewire-0.2.5-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/pipewire/0.2.5/1.fc29/x86_64/pipewire-devel-0.2.5-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/pipewire/0.2.5/1.fc29/x86_64/pipewire-libs-0.2.5-1.fc29.x86_64.rpm && \
dnf install -y intltool redhat-rpm-config make && \
dnf clean all

View File

@ -3731,6 +3731,17 @@ clutter_stage_ensure_redraw (ClutterStage *stage)
_clutter_master_clock_start_running (master_clock);
}
/**
* clutter_stage_is_redraw_queued: (skip)
*/
gboolean
clutter_stage_is_redraw_queued (ClutterStage *stage)
{
ClutterStagePrivate *priv = stage->priv;
return priv->redraw_pending;
}
/**
* clutter_stage_queue_redraw:
* @stage: the #ClutterStage

View File

@ -250,6 +250,9 @@ void clutter_stage_ensure_viewport (ClutterStage
CLUTTER_EXPORT
void clutter_stage_ensure_redraw (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_stage_is_redraw_queued (ClutterStage *stage);
#ifdef CLUTTER_ENABLE_EXPERIMENTAL_API
CLUTTER_EXPORT
void clutter_stage_set_sync_delay (ClutterStage *stage,

View File

@ -491,7 +491,7 @@ clutter_marshal = gnome.genmarshal('clutter-marshal',
prefix: '_clutter_marshal',
sources: 'clutter-marshal.list',
valist_marshallers: true,
extra_args: ['--prototypes'],
extra_args: ['--prototypes', '--quiet'],
install_dir: clutter_clutter_includedir,
install_header: true,
)

View File

@ -76,6 +76,9 @@ struct _ClutterKeymapX11
DirectionCacheEntry group_direction_cache[4];
int current_group;
GHashTable *reserved_keycodes;
GQueue *available_keycodes;
guint caps_lock_state : 1;
guint num_lock_state : 1;
guint has_direction : 1;
@ -422,15 +425,97 @@ clutter_keymap_x11_set_property (GObject *gobject,
}
}
static void
clutter_keymap_x11_refresh_reserved_keycodes (ClutterKeymapX11 *keymap_x11)
{
Display *dpy = clutter_x11_get_default_display ();
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, keymap_x11->reserved_keycodes);
while (g_hash_table_iter_next (&iter, &key, &value))
{
guint reserved_keycode = GPOINTER_TO_UINT (key);
guint reserved_keysym = GPOINTER_TO_UINT (value);
guint actual_keysym = XkbKeycodeToKeysym (dpy, reserved_keycode, 0, 0);
/* If an available keycode is no longer mapped to the stored keysym, then
* the keycode should not be considered available anymore and should be
* removed both from the list of available and reserved keycodes.
*/
if (reserved_keysym != actual_keysym)
{
g_hash_table_iter_remove (&iter);
g_queue_remove (keymap_x11->available_keycodes, key);
}
}
}
static gboolean
clutter_keymap_x11_replace_keycode (ClutterKeymapX11 *keymap_x11,
KeyCode keycode,
KeySym keysym)
{
if (CLUTTER_BACKEND_X11 (keymap_x11->backend)->use_xkb)
{
Display *dpy = clutter_x11_get_default_display ();
XkbDescPtr xkb = get_xkb (keymap_x11);
XkbMapChangesRec changes;
XFlush (dpy);
xkb->device_spec = XkbUseCoreKbd;
memset (&changes, 0, sizeof(changes));
if (keysym != NoSymbol)
{
int types[XkbNumKbdGroups] = { XkbOneLevelIndex };
XkbChangeTypesOfKey (xkb, keycode, 1, XkbGroup1Mask, types, &changes);
XkbKeySymEntry (xkb, keycode, 0, 0) = keysym;
}
else
{
/* Reset to NoSymbol */
XkbChangeTypesOfKey (xkb, keycode, 0, XkbGroup1Mask, NULL, &changes);
}
changes.changed = XkbKeySymsMask | XkbKeyTypesMask;
changes.first_key_sym = keycode;
changes.num_key_syms = 1;
changes.first_type = 0;
changes.num_types = xkb->map->num_types;
XkbChangeMap (dpy, xkb, &changes);
XFlush (dpy);
return TRUE;
}
return FALSE;
}
static void
clutter_keymap_x11_finalize (GObject *gobject)
{
ClutterKeymapX11 *keymap;
ClutterEventTranslator *translator;
GHashTableIter iter;
gpointer key, value;
keymap = CLUTTER_KEYMAP_X11 (gobject);
translator = CLUTTER_EVENT_TRANSLATOR (keymap);
clutter_keymap_x11_refresh_reserved_keycodes (keymap);
g_hash_table_iter_init (&iter, keymap->reserved_keycodes);
while (g_hash_table_iter_next (&iter, &key, &value))
{
guint keycode = GPOINTER_TO_UINT (key);
clutter_keymap_x11_replace_keycode (keymap, keycode, NoSymbol);
}
g_hash_table_destroy (keymap->reserved_keycodes);
g_queue_free (keymap->available_keycodes);
_clutter_backend_remove_event_translator (keymap->backend, translator);
if (keymap->xkb_desc != NULL)
@ -462,6 +547,8 @@ clutter_keymap_x11_init (ClutterKeymapX11 *keymap)
{
keymap->current_direction = PANGO_DIRECTION_NEUTRAL;
keymap->current_group = -1;
keymap->reserved_keycodes = g_hash_table_new (NULL, NULL);
keymap->available_keycodes = g_queue_new ();
}
static ClutterTranslateReturn
@ -731,6 +818,72 @@ clutter_keymap_x11_get_entries_for_keyval (ClutterKeymapX11 *keymap_x11,
}
}
static guint
clutter_keymap_x11_get_available_keycode (ClutterKeymapX11 *keymap_x11)
{
if (CLUTTER_BACKEND_X11 (keymap_x11->backend)->use_xkb)
{
clutter_keymap_x11_refresh_reserved_keycodes (keymap_x11);
if (g_hash_table_size (keymap_x11->reserved_keycodes) < 5)
{
Display *dpy = clutter_x11_get_default_display ();
XkbDescPtr xkb = get_xkb (keymap_x11);
guint i;
for (i = xkb->max_key_code; i >= xkb->min_key_code; --i)
{
if (XkbKeycodeToKeysym (dpy, i, 0, 0) == NoSymbol)
return i;
}
}
return GPOINTER_TO_UINT (g_queue_pop_head (keymap_x11->available_keycodes));
}
return 0;
}
gboolean clutter_keymap_x11_reserve_keycode (ClutterKeymapX11 *keymap_x11,
guint keyval,
guint *keycode_out)
{
g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap_x11), FALSE);
g_return_val_if_fail (keyval != 0, FALSE);
g_return_val_if_fail (keycode_out != NULL, FALSE);
*keycode_out = clutter_keymap_x11_get_available_keycode (keymap_x11);
if (*keycode_out == NoSymbol)
{
g_warning ("Cannot reserve a keycode for keyval %d: no available keycode", keyval);
return FALSE;
}
if (!clutter_keymap_x11_replace_keycode (keymap_x11, *keycode_out, keyval))
{
g_warning ("Failed to remap keycode %d to keyval %d", *keycode_out, keyval);
return FALSE;
}
g_hash_table_insert (keymap_x11->reserved_keycodes, GUINT_TO_POINTER (*keycode_out), GUINT_TO_POINTER (keyval));
g_queue_remove (keymap_x11->available_keycodes, GUINT_TO_POINTER (*keycode_out));
return TRUE;
}
void clutter_keymap_x11_release_keycode_if_needed (ClutterKeymapX11 *keymap_x11,
guint keycode)
{
g_return_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap_x11));
if (!g_hash_table_contains (keymap_x11->reserved_keycodes, GUINT_TO_POINTER (keycode)) ||
g_queue_index (keymap_x11->available_keycodes, GUINT_TO_POINTER (keycode)) != -1)
return;
g_queue_push_tail (keymap_x11->available_keycodes, GUINT_TO_POINTER (keycode));
}
void
clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
uint32_t level,

View File

@ -58,7 +58,11 @@ gboolean clutter_keymap_x11_keycode_for_keyval (ClutterKeymapX11 *keymap_x11,
void clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
uint32_t level,
gboolean enable);
gboolean clutter_keymap_x11_reserve_keycode (ClutterKeymapX11 *keymap_x11,
guint keyval,
guint *keycode_out);
void clutter_keymap_x11_release_keycode_if_needed (ClutterKeymapX11 *keymap_x11,
guint keycode);
G_END_DECLS
#endif /* __CLUTTER_KEYMAP_X11_H__ */

View File

@ -141,8 +141,13 @@ clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtu
if (!clutter_keymap_x11_keycode_for_keyval (keymap, keyval, &keycode, &level))
{
g_warning ("No keycode found for keyval %x in current group", keyval);
return;
level = 0;
if (!clutter_keymap_x11_reserve_keycode (keymap, keyval, &keycode))
{
g_warning ("No keycode found for keyval %x in current group", keyval);
return;
}
}
if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode) &&
@ -153,9 +158,13 @@ clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtu
(KeyCode) keycode,
key_state == CLUTTER_KEY_STATE_PRESSED, 0);
if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode) &&
key_state == CLUTTER_KEY_STATE_RELEASED)
clutter_keymap_x11_latch_modifiers (keymap, level, FALSE);
if (key_state == CLUTTER_KEY_STATE_RELEASED)
{
if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode))
clutter_keymap_x11_latch_modifiers (keymap, level, FALSE);
clutter_keymap_x11_release_keycode_if_needed (keymap, keycode);
}
}
static void

View File

@ -147,3 +147,11 @@ COGL_WINSYS_FEATURE_BEGIN (surfaceless_context,
"surfaceless_context\0",
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT)
COGL_WINSYS_FEATURE_END ()
#ifdef EGL_IMG_context_priority
COGL_WINSYS_FEATURE_BEGIN (context_priority,
"IMG\0",
"context_priority\0",
COGL_EGL_WINSYS_FEATURE_CONTEXT_PRIORITY)
COGL_WINSYS_FEATURE_END ()
#endif

View File

@ -105,7 +105,8 @@ typedef enum _CoglEGLWinsysFeature
COGL_EGL_WINSYS_FEATURE_CREATE_CONTEXT =1L<<3,
COGL_EGL_WINSYS_FEATURE_BUFFER_AGE =1L<<4,
COGL_EGL_WINSYS_FEATURE_FENCE_SYNC =1L<<5,
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT =1L<<6
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT =1L<<6,
COGL_EGL_WINSYS_FEATURE_CONTEXT_PRIORITY =1L<<7,
} CoglEGLWinsysFeature;
typedef struct _CoglRendererEGL

View File

@ -345,7 +345,7 @@ try_create_context (CoglDisplay *display,
CoglRendererEGL *egl_renderer = renderer->winsys;
EGLDisplay edpy;
EGLConfig config;
EGLint attribs[9];
EGLint attribs[11];
EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS];
GError *config_error = NULL;
const char *error_message;
@ -394,7 +394,15 @@ try_create_context (CoglDisplay *display,
attribs[5] = EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
attribs[6] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
attribs[7] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
attribs[8] = EGL_NONE;
if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_CONTEXT_PRIORITY)
{
attribs[8] = EGL_CONTEXT_PRIORITY_LEVEL_IMG;
attribs[9] = EGL_CONTEXT_PRIORITY_HIGH_IMG;
attribs[10] = EGL_NONE;
}
else
attribs[8] = EGL_NONE;
}
else if (display->renderer->driver == COGL_DRIVER_GLES2)
{
@ -416,6 +424,17 @@ try_create_context (CoglDisplay *display,
goto fail;
}
if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_CONTEXT_PRIORITY)
{
EGLint value = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
eglQueryContext(egl_renderer->edpy, egl_display->egl_context,
EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value);
if (value != EGL_CONTEXT_PRIORITY_HIGH_IMG)
g_warning ("Failed to obtain high priority context");
}
if (egl_renderer->platform_vtable->context_created &&
!egl_renderer->platform_vtable->context_created (display, error))
return FALSE;

View File

@ -43,7 +43,7 @@ libinput_req = '>= 1.4'
gbm_req = '>= 10.3'
# screen cast version requirements
libpipewire_req = '>= 0.2.2'
libpipewire_req = '>= 0.2.5'
gnome = import('gnome')
pkg = import('pkgconfig')

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +0,0 @@
# Makefile variables for PO directory in any package using GNU gettext.
# Usually the message domain is the same as the package name.
DOMAIN = $(PACKAGE)
# These two variables depend on the location of this directory.
subdir = po
top_builddir = ..
# These options get passed to xgettext.
XGETTEXT_OPTIONS = --from-code=UTF-8 --keyword=_ --keyword=N_ \
--keyword=C_:1c,2 --keyword=NC_:1c,2 \
--keyword=g_dngettext:2,3 --add-comments \
--flag=g_dngettext:2:pass-c-format \
--flag=g_strdup_printf:1:c-format \
--flag=g_string_printf:2:c-format \
--flag=g_string_append_printf:2:c-format \
--flag=g_error_new:3:c-format \
--flag=g_set_error:4:c-format \
--flag=g_markup_printf_escaped:1:c-format \
--flag=g_log:3:c-format \
--flag=g_print:1:c-format \
--flag=g_printerr:1:c-format \
--flag=g_printf:1:c-format \
--flag=g_fprintf:2:c-format \
--flag=g_sprintf:2:c-format \
--flag=g_snprintf:3:c-format
# This is the copyright holder that gets inserted into the header of the
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
# package. (Note that the msgstr strings, extracted from the package's
# sources, belong to the copyright holder of the package.) Translators are
# expected to transfer the copyright for their translations to this person
# or entity, or to disclaim their copyright. The empty string stands for
# the public domain; in this case the translators are expected to disclaim
# their copyright.
COPYRIGHT_HOLDER = Translation copyright holder
# This is the email address or URL to which the translators shall report
# bugs in the untranslated strings:
# - Strings which are not entire sentences, see the maintainer guidelines
# in the GNU gettext documentation, section 'Preparing Strings'.
# - Strings which use unclear terms or require additional context to be
# understood.
# - Strings which make invalid assumptions about notation of date, time or
# money.
# - Pluralisation problems.
# - Incorrect English spelling.
# - Incorrect formatting.
# It can be your email address, or a mailing list address where translators
# can write to without being subscribed, or the URL of a web page through
# which the translators can contact you.
MSGID_BUGS_ADDRESS = https://gitlab.gnome.org/GNOME/mutter/issues
# This is the list of locale categories, beyond LC_MESSAGES, for which the
# message catalogs shall be used. It is usually empty.
EXTRA_LOCALE_CATEGORIES =
# Ignore the timestamp of the .pot file, as git clones do not have
# deterministic timestamps, and .po files are updated by translators
# (only) in GNOME projects.
PO_DEPENDS_ON_POT = no
# This tells whether or not to forcibly update $(DOMAIN).pot and
# regenerate PO files on "make dist". Possible values are "yes" and
# "no". Set this to no if the POT file and PO files are maintained
# externally.
DIST_DEPENDS_ON_UPDATE_PO = no

View File

@ -49,4 +49,8 @@ typedef struct _MetaTileInfo MetaTileInfo;
typedef struct _MetaRenderer MetaRenderer;
typedef struct _MetaRendererView MetaRendererView;
typedef struct _MetaScreenCast MetaScreenCast;
typedef struct _MetaScreenCastSession MetaScreenCastSession;
typedef struct _MetaScreenCastStream MetaScreenCastStream;
#endif /* META_BACKEND_TYPE_H */

View File

@ -504,7 +504,8 @@ meta_backend_real_post_init (MetaBackend *backend)
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 (priv->dbus_session_watcher);
priv->screen_cast = meta_screen_cast_new (backend,
priv->dbus_session_watcher);
priv->remote_desktop = meta_remote_desktop_new (priv->dbus_session_watcher);
#endif /* HAVE_REMOTE_DESKTOP */

View File

@ -34,6 +34,9 @@
#include "meta/meta-backend.h"
#include "meta/util.h"
G_DEFINE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor,
G_TYPE_OBJECT)
struct _MetaCursorRendererPrivate
{
float current_x;
@ -43,6 +46,8 @@ struct _MetaCursorRendererPrivate
MetaOverlay *stage_overlay;
gboolean handled_by_backend;
guint post_paint_func_id;
GList *hw_cursor_inhibitors;
};
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
@ -54,6 +59,21 @@ static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT);
static gboolean
meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor,
MetaCursorSprite *cursor_sprite)
{
MetaHwCursorInhibitorInterface *iface =
META_HW_CURSOR_INHIBITOR_GET_IFACE (inhibitor);
return iface->is_cursor_sprite_inhibited (inhibitor, cursor_sprite);
}
static void
meta_hw_cursor_inhibitor_default_init (MetaHwCursorInhibitorInterface *iface)
{
}
void
meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
@ -282,3 +302,45 @@ meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
return priv->displayed_cursor;
}
void
meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
MetaHwCursorInhibitor *inhibitor)
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors,
inhibitor);
}
void
meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
MetaHwCursorInhibitor *inhibitor)
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
priv->hw_cursor_inhibitors = g_list_remove (priv->hw_cursor_inhibitors,
inhibitor);
}
gboolean
meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
GList *l;
for (l = priv->hw_cursor_inhibitors; l; l = l->next)
{
MetaHwCursorInhibitor *inhibitor = l->data;
if (meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (inhibitor,
cursor_sprite))
return TRUE;
}
return FALSE;
}

View File

@ -27,8 +27,21 @@
#include <glib-object.h>
#include "backends/meta-backend-types.h"
#include "backends/meta-cursor.h"
#define META_TYPE_HW_CURSOR_INHIBITOR (meta_hw_cursor_inhibitor_get_type ())
G_DECLARE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor,
META, HW_CURSOR_INHIBITOR, GObject)
struct _MetaHwCursorInhibitorInterface
{
GTypeInterface parent_iface;
gboolean (* is_cursor_sprite_inhibited) (MetaHwCursorInhibitor *inhibitor,
MetaCursorSprite *cursor_sprite);
};
#define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaCursorRenderer, meta_cursor_renderer,
META, CURSOR_RENDERER, GObject);
@ -54,6 +67,15 @@ void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
void meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
MetaHwCursorInhibitor *inhibitor);
void meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
MetaHwCursorInhibitor *inhibitor);
gboolean meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);
ClutterRect meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);

View File

@ -48,6 +48,7 @@ G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
enum {
CURSOR_CHANGED,
CURSOR_MOVED,
LAST_SIGNAL
};
@ -117,11 +118,15 @@ change_cursor_renderer (MetaCursorTracker *tracker)
static void
sync_cursor (MetaCursorTracker *tracker)
{
if (update_displayed_cursor (tracker))
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
gboolean cursor_changed = FALSE;
cursor_changed = update_displayed_cursor (tracker);
if (update_effective_cursor (tracker))
change_cursor_renderer (tracker);
if (cursor_changed)
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
}
static void
@ -158,6 +163,15 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[CURSOR_MOVED] = g_signal_new ("cursor-moved",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 2,
G_TYPE_FLOAT,
G_TYPE_FLOAT);
}
/**
@ -342,6 +356,8 @@ meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_set_position (cursor_renderer, new_x, new_y);
g_signal_emit (tracker, signals[CURSOR_MOVED], 0, new_x, new_y);
}
static void

View File

@ -142,6 +142,24 @@ meta_renderer_get_views (MetaRenderer *renderer)
return priv->views;
}
MetaRendererView *
meta_renderer_get_view_from_logical_monitor (MetaRenderer *renderer,
MetaLogicalMonitor *logical_monitor)
{
GList *l;
for (l = meta_renderer_get_views (renderer); l; l = l->next)
{
MetaRendererView *view = l->data;
if (meta_renderer_view_get_logical_monitor (view) ==
logical_monitor)
return view;
}
return NULL;
}
static void
meta_renderer_finalize (GObject *object)
{

View File

@ -53,4 +53,7 @@ void meta_renderer_set_legacy_view (MetaRenderer *renderer,
GList * meta_renderer_get_views (MetaRenderer *renderer);
MetaRendererView * meta_renderer_get_view_from_logical_monitor (MetaRenderer *renderer,
MetaLogicalMonitor *logical_monitor);
#endif /* META_RENDERER_H */

View File

@ -24,23 +24,38 @@
#include "backends/meta-screen-cast-monitor-stream-src.h"
#include <spa/buffer/meta.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor.h"
#include "backends/meta-screen-cast-monitor-stream.h"
#include "backends/meta-screen-cast-session.h"
#include "clutter/clutter.h"
#include "clutter/clutter-mutter.h"
#include "core/boxes-private.h"
struct _MetaScreenCastMonitorStreamSrc
{
MetaScreenCastStreamSrc parent;
gulong stage_painted_handler_id;
gboolean cursor_bitmap_invalid;
gulong actors_painted_handler_id;
gulong paint_handler_id;
gulong cursor_moved_handler_id;
gulong cursor_changed_handler_id;
};
G_DEFINE_TYPE (MetaScreenCastMonitorStreamSrc,
meta_screen_cast_monitor_stream_src,
META_TYPE_SCREEN_CAST_STREAM_SRC)
static void
hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface);
G_DEFINE_TYPE_WITH_CODE (MetaScreenCastMonitorStreamSrc,
meta_screen_cast_monitor_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 (MetaScreenCastMonitorStreamSrc *monitor_src)
@ -102,18 +117,164 @@ stage_painted (ClutterActor *actor,
meta_screen_cast_stream_src_maybe_record_frame (src);
}
static MetaBackend *
get_backend (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_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 gboolean
is_cursor_in_stream (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaBackend *backend = get_backend (monitor_src);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaMonitor *monitor;
MetaLogicalMonitor *logical_monitor;
MetaRectangle logical_monitor_layout;
ClutterRect logical_monitor_rect;
MetaCursorSprite *cursor_sprite;
monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor);
logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor);
logical_monitor_rect =
meta_rectangle_to_clutter_rect (&logical_monitor_layout);
cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
if (cursor_sprite)
{
ClutterRect cursor_rect;
cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
cursor_sprite);
return clutter_rect_intersection (&cursor_rect,
&logical_monitor_rect,
NULL);
}
else
{
ClutterPoint cursor_position;
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
return clutter_rect_contains_point (&logical_monitor_rect,
&cursor_position);
}
}
static void
sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src);
ClutterStage *stage = get_stage (monitor_src);
if (!is_cursor_in_stream (monitor_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,
MetaScreenCastMonitorStreamSrc *monitor_src)
{
sync_cursor_state (monitor_src);
}
static void
cursor_changed (MetaCursorTracker *cursor_tracker,
MetaScreenCastMonitorStreamSrc *monitor_src)
{
monitor_src->cursor_bitmap_invalid = TRUE;
sync_cursor_state (monitor_src);
}
static MetaCursorRenderer *
get_cursor_renderer (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_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
inhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaCursorRenderer *cursor_renderer;
MetaHwCursorInhibitor *inhibitor;
cursor_renderer = get_cursor_renderer (monitor_src);
inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src);
meta_cursor_renderer_add_hw_cursor_inhibitor (cursor_renderer, inhibitor);
}
static void
uninhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaCursorRenderer *cursor_renderer;
MetaHwCursorInhibitor *inhibitor;
cursor_renderer = get_cursor_renderer (monitor_src);
inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src);
meta_cursor_renderer_remove_hw_cursor_inhibitor (cursor_renderer, inhibitor);
}
static void
meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
MetaBackend *backend = get_backend (monitor_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 (monitor_src);
monitor_src->stage_painted_handler_id =
g_signal_connect_after (stage, "paint",
G_CALLBACK (stage_painted),
monitor_src);
switch (meta_screen_cast_stream_get_cursor_mode (stream))
{
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
monitor_src->cursor_moved_handler_id =
g_signal_connect_after (cursor_tracker, "cursor-moved",
G_CALLBACK (cursor_moved),
monitor_src);
monitor_src->cursor_changed_handler_id =
g_signal_connect_after (cursor_tracker, "cursor-changed",
G_CALLBACK (cursor_changed),
monitor_src);
/* Intentional fall-through */
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
monitor_src->actors_painted_handler_id =
g_signal_connect (stage, "actors-painted",
G_CALLBACK (stage_painted),
monitor_src);
break;
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
inhibit_hw_cursor (monitor_src);
monitor_src->paint_handler_id =
g_signal_connect_after (stage, "paint",
G_CALLBACK (stage_painted),
monitor_src);
break;
}
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
}
@ -122,14 +283,43 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
MetaBackend *backend = get_backend (monitor_src);
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
ClutterStage *stage;
stage = get_stage (monitor_src);
g_signal_handler_disconnect (stage, monitor_src->stage_painted_handler_id);
monitor_src->stage_painted_handler_id = 0;
if (monitor_src->actors_painted_handler_id)
{
g_signal_handler_disconnect (stage,
monitor_src->actors_painted_handler_id);
monitor_src->actors_painted_handler_id = 0;
}
if (monitor_src->paint_handler_id)
{
g_signal_handler_disconnect (stage,
monitor_src->paint_handler_id);
monitor_src->paint_handler_id = 0;
uninhibit_hw_cursor (monitor_src);
}
if (monitor_src->cursor_moved_handler_id)
{
g_signal_handler_disconnect (cursor_tracker,
monitor_src->cursor_moved_handler_id);
monitor_src->cursor_moved_handler_id = 0;
}
if (monitor_src->cursor_changed_handler_id)
{
g_signal_handler_disconnect (cursor_tracker,
monitor_src->cursor_changed_handler_id);
monitor_src->cursor_changed_handler_id = 0;
}
}
static void
static gboolean
meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
{
@ -140,9 +330,226 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
MetaLogicalMonitor *logical_monitor;
stage = get_stage (monitor_src);
if (!clutter_stage_is_redraw_queued (stage))
return FALSE;
monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor);
clutter_stage_capture_into (stage, FALSE, &logical_monitor->rect, data);
return TRUE;
}
static gboolean
draw_cursor_sprite_via_offscreen (MetaScreenCastMonitorStreamSrc *monitor_src,
CoglTexture *cursor_texture,
int bitmap_width,
int bitmap_height,
uint32_t *bitmap_data,
GError **error)
{
MetaBackend *backend = get_backend (monitor_src);
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
CoglContext *cogl_context =
clutter_backend_get_cogl_context (clutter_backend);
CoglTexture2D *bitmap_texture;
CoglOffscreen *offscreen;
CoglFramebuffer *fb;
CoglPipeline *pipeline;
CoglColor clear_color;
bitmap_texture = cogl_texture_2d_new_with_size (cogl_context,
bitmap_width, bitmap_height);
cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (bitmap_texture),
FALSE);
if (!cogl_texture_allocate (COGL_TEXTURE (bitmap_texture), error))
{
cogl_object_unref (bitmap_texture);
return FALSE;
}
offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (bitmap_texture));
fb = COGL_FRAMEBUFFER (offscreen);
cogl_object_unref (bitmap_texture);
if (!cogl_framebuffer_allocate (fb, error))
{
cogl_object_unref (fb);
return FALSE;
}
pipeline = cogl_pipeline_new (cogl_context);
cogl_pipeline_set_layer_texture (pipeline, 0, cursor_texture);
cogl_pipeline_set_layer_filters (pipeline, 0,
COGL_PIPELINE_FILTER_LINEAR,
COGL_PIPELINE_FILTER_LINEAR);
cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);
cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color);
cogl_framebuffer_draw_rectangle (fb, pipeline,
-1, 1, 1, -1);
cogl_object_unref (pipeline);
cogl_framebuffer_read_pixels (fb,
0, 0,
bitmap_width, bitmap_height,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
(uint8_t *) bitmap_data);
cogl_object_unref (fb);
return TRUE;
}
static void
meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
MetaBackend *backend = get_backend (monitor_src);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaSpaType *spa_type = meta_screen_cast_stream_src_get_spa_type (src);
GError *error = NULL;
MetaCursorSprite *cursor_sprite;
CoglTexture *cursor_texture;
MetaMonitor *monitor;
MetaLogicalMonitor *logical_monitor;
MetaRectangle logical_monitor_layout;
ClutterRect logical_monitor_rect;
MetaRendererView *view;
float view_scale;
ClutterPoint cursor_position;
struct spa_meta_bitmap *spa_meta_bitmap;
cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
if (cursor_sprite)
cursor_texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
else
cursor_texture = NULL;
if (!is_cursor_in_stream (monitor_src))
{
spa_meta_cursor->id = 0;
return;
}
monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor);
logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor);
logical_monitor_rect =
meta_rectangle_to_clutter_rect (&logical_monitor_layout);
view = meta_renderer_get_view_from_logical_monitor (renderer,
logical_monitor);
if (view)
view_scale = clutter_stage_view_get_scale (CLUTTER_STAGE_VIEW (view));
else
view_scale = 1.0;
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
cursor_position.x -= logical_monitor_rect.origin.x;
cursor_position.y -= logical_monitor_rect.origin.y;
cursor_position.x *= view_scale;
cursor_position.y *= view_scale;
spa_meta_cursor->id = 1;
spa_meta_cursor->position.x = (int32_t) roundf (cursor_position.x);
spa_meta_cursor->position.y = (int32_t) roundf (cursor_position.y);
if (!monitor_src->cursor_bitmap_invalid)
{
spa_meta_cursor->hotspot.x = 0;
spa_meta_cursor->hotspot.y = 0;
spa_meta_cursor->bitmap_offset = 0;
return;
}
monitor_src->cursor_bitmap_invalid = FALSE;
spa_meta_cursor->bitmap_offset = sizeof (struct spa_meta_cursor);
spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor,
spa_meta_cursor->bitmap_offset,
struct spa_meta_bitmap);
spa_meta_bitmap->format = spa_type->video_format.RGBA;
spa_meta_bitmap->offset = sizeof (struct spa_meta_bitmap);
if (cursor_texture)
{
float cursor_scale;
float bitmap_scale;
int hotspot_x, hotspot_y;
int texture_width, texture_height;
int bitmap_width, bitmap_height;
uint32_t *bitmap_data;
cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite);
bitmap_scale = view_scale * cursor_scale;
meta_cursor_sprite_get_hotspot (cursor_sprite, &hotspot_x, &hotspot_y);
spa_meta_cursor->hotspot.x = (int32_t) roundf (hotspot_x * bitmap_scale);
spa_meta_cursor->hotspot.y = (int32_t) roundf (hotspot_y * bitmap_scale);
texture_width = cogl_texture_get_width (cursor_texture);
texture_height = cogl_texture_get_height (cursor_texture);
bitmap_width = texture_width * bitmap_scale;
bitmap_height = texture_height * bitmap_scale;
spa_meta_bitmap->size.width = bitmap_width;
spa_meta_bitmap->size.height = bitmap_height;
spa_meta_bitmap->stride = bitmap_width * 4;
bitmap_data = SPA_MEMBER (spa_meta_bitmap,
spa_meta_bitmap->offset,
uint32_t);
if (texture_width == bitmap_width &&
texture_height == bitmap_height)
{
cogl_texture_get_data (cursor_texture,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
texture_width * 4,
(uint8_t *) bitmap_data);
}
else
{
if (!draw_cursor_sprite_via_offscreen (monitor_src,
cursor_texture,
bitmap_width,
bitmap_height,
bitmap_data,
&error))
{
g_warning ("Failed to draw cursor via offscreen: %s",
error->message);
g_error_free (error);
spa_meta_cursor->id = 0;
}
}
}
else
{
spa_meta_cursor->hotspot.x = 0;
spa_meta_cursor->hotspot.y = 0;
*spa_meta_bitmap = (struct spa_meta_bitmap) { 0 };
}
}
static gboolean
meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor,
MetaCursorSprite *cursor_sprite)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (inhibitor);
return is_cursor_in_stream (monitor_src);
}
static void
hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface)
{
iface->is_cursor_sprite_inhibited =
meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited;
}
MetaScreenCastMonitorStreamSrc *
@ -157,6 +564,7 @@ meta_screen_cast_monitor_stream_src_new (MetaScreenCastMonitorStream *monitor_s
static void
meta_screen_cast_monitor_stream_src_init (MetaScreenCastMonitorStreamSrc *monitor_src)
{
monitor_src->cursor_bitmap_invalid = TRUE;
}
static void
@ -169,4 +577,6 @@ meta_screen_cast_monitor_stream_src_class_init (MetaScreenCastMonitorStreamSrcCl
src_class->enable = meta_screen_cast_monitor_stream_src_enable;
src_class->disable = meta_screen_cast_monitor_stream_src_disable;
src_class->record_frame = meta_screen_cast_monitor_stream_src_record_frame;
src_class->set_cursor_metadata =
meta_screen_cast_monitor_stream_src_set_cursor_metadata;
}

View File

@ -105,12 +105,15 @@ meta_screen_cast_monitor_stream_get_monitor (MetaScreenCastMonitorStream *monito
}
MetaScreenCastMonitorStream *
meta_screen_cast_monitor_stream_new (GDBusConnection *connection,
MetaMonitorManager *monitor_manager,
MetaMonitor *monitor,
ClutterStage *stage,
GError **error)
meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session,
GDBusConnection *connection,
MetaMonitor *monitor,
ClutterStage *stage,
MetaScreenCastCursorMode cursor_mode,
GError **error)
{
MetaGpu *gpu = meta_monitor_get_gpu (monitor);
MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
MetaScreenCastMonitorStream *monitor_stream;
if (!meta_monitor_is_active (monitor))
@ -122,7 +125,9 @@ meta_screen_cast_monitor_stream_new (GDBusConnection *connection,
monitor_stream = g_initable_new (META_TYPE_SCREEN_CAST_MONITOR_STREAM,
NULL,
error,
"session", session,
"connection", connection,
"cursor-mode", cursor_mode,
"monitor", monitor,
NULL);
if (!monitor_stream)

View File

@ -27,6 +27,7 @@
#include "backends/meta-monitor-manager-private.h"
#include "backends/meta-screen-cast-stream.h"
#include "backends/meta-screen-cast.h"
#define META_TYPE_SCREEN_CAST_MONITOR_STREAM (meta_screen_cast_monitor_stream_get_type ())
G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream,
@ -34,11 +35,12 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream,
META, SCREEN_CAST_MONITOR_STREAM,
MetaScreenCastStream)
MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (GDBusConnection *connection,
MetaMonitorManager *monitor_manager,
MetaMonitor *monitor,
ClutterStage *stage,
GError **error);
MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session,
GDBusConnection *connection,
MetaMonitor *monitor,
ClutterStage *stage,
MetaScreenCastCursorMode cursor_mode,
GError **error);
ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream);

View File

@ -38,6 +38,8 @@ struct _MetaScreenCastSession
{
MetaDBusScreenCastSessionSkeleton parent;
MetaScreenCast *screen_cast;
char *peer_name;
MetaScreenCastSessionType session_type;
@ -159,6 +161,12 @@ meta_screen_cast_session_get_stream (MetaScreenCastSession *session,
return NULL;
}
MetaScreenCast *
meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session)
{
return session->screen_cast;
}
char *
meta_screen_cast_session_get_object_path (MetaScreenCastSession *session)
{
@ -254,6 +262,20 @@ on_stream_closed (MetaScreenCastStream *stream,
meta_screen_cast_session_close (session);
}
static gboolean
is_valid_cursor_mode (MetaScreenCastCursorMode cursor_mode)
{
switch (cursor_mode)
{
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
return TRUE;
}
return FALSE;
}
static gboolean
handle_record_monitor (MetaDBusScreenCastSession *skeleton,
GDBusMethodInvocation *invocation,
@ -267,6 +289,7 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitor *monitor;
MetaScreenCastCursorMode cursor_mode;
ClutterStage *stage;
GError *error = NULL;
MetaScreenCastMonitorStream *monitor_stream;
@ -298,12 +321,28 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
return TRUE;
}
if (!g_variant_lookup (properties_variant, "cursor-mode", "u", &cursor_mode))
{
cursor_mode = META_SCREEN_CAST_CURSOR_MODE_HIDDEN;
}
else
{
if (!is_valid_cursor_mode (cursor_mode))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Unknown cursor mode");
return TRUE;
}
}
stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
monitor_stream = meta_screen_cast_monitor_stream_new (connection,
monitor_manager,
monitor_stream = meta_screen_cast_monitor_stream_new (session,
connection,
monitor,
stage,
cursor_mode,
&error);
if (!monitor_stream)
{
@ -382,7 +421,8 @@ handle_record_window (MetaDBusScreenCastSession *skeleton,
interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton);
connection = g_dbus_interface_skeleton_get_connection (interface_skeleton);
window_stream = meta_screen_cast_window_stream_new (connection,
window_stream = meta_screen_cast_window_stream_new (session,
connection,
window,
&error);
if (!window_stream)
@ -442,6 +482,7 @@ meta_screen_cast_session_new (MetaScreenCast *screen_cast,
static unsigned int global_session_number = 0;
session = g_object_new (META_TYPE_SCREEN_CAST_SESSION, NULL);
session->screen_cast = screen_cast;
session->session_type = session_type;
session->peer_name = g_strdup (peer_name);
session->object_path =

View File

@ -60,4 +60,6 @@ void meta_screen_cast_session_close (MetaScreenCastSession *session);
MetaScreenCastStream * meta_screen_cast_session_get_stream (MetaScreenCastSession *session,
const char *path);
MetaScreenCast * meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session);
#endif /* META_SCREEN_CAST_SESSION_H */

View File

@ -40,6 +40,10 @@
#define PRIVATE_OWNER_FROM_FIELD(TypeName, field_ptr, field_name) \
(TypeName *)((guint8 *)(field_ptr) - G_PRIVATE_OFFSET (TypeName, field_name))
#define CURSOR_META_SIZE(width, height) \
(sizeof (struct spa_meta_cursor) + \
sizeof (struct spa_meta_bitmap) + width * height * 4)
enum
{
PROP_0,
@ -57,14 +61,6 @@ enum
static guint signals[N_SIGNALS];
typedef struct _MetaSpaType
{
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_video format_video;
struct spa_type_video_format video_format;
} MetaSpaType;
typedef struct _MetaPipeWireSource
{
GSource base;
@ -133,14 +129,68 @@ meta_screen_cast_stream_src_get_videocrop (MetaScreenCastStreamSrc *src,
return FALSE;
}
static void
static gboolean
meta_screen_cast_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
{
MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
klass->record_frame (src, data);
return klass->record_frame (src, data);
}
static void
meta_screen_cast_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor)
{
MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
if (klass->set_cursor_metadata)
klass->set_cursor_metadata (src, spa_meta_cursor);
}
MetaSpaType *
meta_screen_cast_stream_src_get_spa_type (MetaScreenCastStreamSrc *src)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
return &priv->spa_type;
}
static void
add_cursor_metadata (MetaScreenCastStreamSrc *src,
struct spa_buffer *spa_buffer)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
MetaSpaType *spa_type = &priv->spa_type;
struct spa_meta_cursor *spa_meta_cursor;
spa_meta_cursor = spa_buffer_find_meta (spa_buffer, spa_type->meta_cursor);
if (spa_meta_cursor)
meta_screen_cast_stream_src_set_cursor_metadata (src, spa_meta_cursor);
}
static void
maybe_record_cursor (MetaScreenCastStreamSrc *src,
struct spa_buffer *spa_buffer,
uint8_t *data)
{
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
switch (meta_screen_cast_stream_get_cursor_mode (stream))
{
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
return;
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
add_cursor_metadata (src, spa_buffer);
return;
}
g_assert_not_reached ();
}
void
@ -151,7 +201,6 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
MetaRectangle crop_rect;
struct pw_buffer *buffer;
struct spa_buffer *spa_buffer;
struct spa_meta_video_crop *spa_meta_video_crop;
uint8_t *map = NULL;
uint8_t *data;
uint64_t now_us;
@ -199,35 +248,45 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
return;
}
meta_screen_cast_stream_src_record_frame (src, data);
/* Update VideoCrop if needed */
spa_meta_video_crop = spa_buffer_find_meta (spa_buffer, priv->pipewire_type->meta.VideoCrop);
if (spa_meta_video_crop)
if (meta_screen_cast_stream_src_record_frame (src, data))
{
if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
struct spa_meta_video_crop *spa_meta_video_crop;
spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
/* Update VideoCrop if needed */
spa_meta_video_crop =
spa_buffer_find_meta (spa_buffer, priv->pipewire_type->meta.VideoCrop);
if (spa_meta_video_crop)
{
spa_meta_video_crop->x = crop_rect.x;
spa_meta_video_crop->y = crop_rect.y;
spa_meta_video_crop->width = crop_rect.width;
spa_meta_video_crop->height = crop_rect.height;
}
else
{
spa_meta_video_crop->x = 0;
spa_meta_video_crop->y = 0;
spa_meta_video_crop->width = priv->stream_width;
spa_meta_video_crop->height = priv->stream_height;
if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
{
spa_meta_video_crop->x = crop_rect.x;
spa_meta_video_crop->y = crop_rect.y;
spa_meta_video_crop->width = crop_rect.width;
spa_meta_video_crop->height = crop_rect.height;
}
else
{
spa_meta_video_crop->x = 0;
spa_meta_video_crop->y = 0;
spa_meta_video_crop->width = priv->stream_width;
spa_meta_video_crop->height = priv->stream_height;
}
}
}
else
{
spa_buffer->datas[0].chunk->size = 0;
}
maybe_record_cursor (src, spa_buffer, data);
priv->last_frame_timestamp_us = now_us;
if (map)
munmap (map, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset);
spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
pw_stream_queue_buffer (priv->pipewire_stream, buffer);
}
@ -314,7 +373,7 @@ on_stream_format_changed (void *data,
uint8_t params_buffer[1024];
int32_t width, height, stride, size;
struct spa_pod_builder pod_builder;
const struct spa_pod *params[2];
const struct spa_pod *params[3];
const int bpp = 4;
if (!format)
@ -348,6 +407,12 @@ on_stream_format_changed (void *data,
":", pipewire_type->param_meta.type, "I", pipewire_type->meta.VideoCrop,
":", pipewire_type->param_meta.size, "i", sizeof (struct spa_meta_video_crop));
params[2] = spa_pod_builder_object (
&pod_builder,
pipewire_type->param.idMeta, pipewire_type->param_meta.Meta,
":", pipewire_type->param_meta.type, "I", priv->spa_type.meta_cursor,
":", pipewire_type->param_meta.size, "i", CURSOR_META_SIZE (64, 64));
pw_stream_finish_format (priv->pipewire_stream, 0,
params, G_N_ELEMENTS (params));
}
@ -517,6 +582,7 @@ init_spa_type (MetaSpaType *type,
spa_type_media_subtype_map (map, &type->media_subtype);
spa_type_format_video_map (map, &type->format_video);
spa_type_video_format_map (map, &type->video_format);
type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor);
}
static MetaPipeWireSource *

View File

@ -24,10 +24,26 @@
#define META_SCREEN_CAST_STREAM_SRC_H
#include <glib-object.h>
#include <spa/param/video/format-utils.h>
#include <spa/buffer/meta.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-cursor-renderer.h"
#include "backends/meta-cursor.h"
#include "backends/meta-renderer.h"
#include "clutter/clutter.h"
#include "cogl/cogl.h"
#include "meta/boxes.h"
typedef struct _MetaSpaType
{
struct spa_type_media_type media_type;
struct spa_type_media_subtype media_subtype;
struct spa_type_format_video format_video;
struct spa_type_video_format video_format;
uint32_t meta_cursor;
} MetaSpaType;
typedef struct _MetaScreenCastStream MetaScreenCastStream;
#define META_TYPE_SCREEN_CAST_STREAM_SRC (meta_screen_cast_stream_src_get_type ())
@ -46,14 +62,18 @@ struct _MetaScreenCastStreamSrcClass
float *frame_rate);
void (* enable) (MetaScreenCastStreamSrc *src);
void (* disable) (MetaScreenCastStreamSrc *src);
void (* record_frame) (MetaScreenCastStreamSrc *src,
uint8_t *data);
gboolean (* record_frame) (MetaScreenCastStreamSrc *src,
uint8_t *data);
gboolean (* get_videocrop) (MetaScreenCastStreamSrc *src,
MetaRectangle *crop_rect);
void (* set_cursor_metadata) (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor);
};
void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src);
MetaScreenCastStream * meta_screen_cast_stream_src_get_stream (MetaScreenCastStreamSrc *src);
MetaSpaType * meta_screen_cast_stream_src_get_spa_type (MetaScreenCastStreamSrc *src);
#endif /* META_SCREEN_CAST_STREAM_SRC_H */

View File

@ -24,13 +24,17 @@
#include "backends/meta-screen-cast-stream.h"
#include "backends/meta-screen-cast-session.h"
#define META_SCREEN_CAST_STREAM_DBUS_PATH "/org/gnome/Mutter/ScreenCast/Stream"
enum
{
PROP_0,
PROP_SESSION,
PROP_CONNECTION,
PROP_CURSOR_MODE,
};
enum
@ -44,9 +48,13 @@ static guint signals[N_SIGNALS];
typedef struct _MetaScreenCastStreamPrivate
{
MetaScreenCastSession *session;
GDBusConnection *connection;
char *object_path;
MetaScreenCastCursorMode cursor_mode;
MetaScreenCastStreamSrc *src;
} MetaScreenCastStreamPrivate;
@ -97,6 +105,15 @@ on_stream_src_ready (MetaScreenCastStreamSrc *src,
meta_dbus_screen_cast_stream_emit_pipewire_stream_added (skeleton, node_id);
}
MetaScreenCastSession *
meta_screen_cast_stream_get_session (MetaScreenCastStream *stream)
{
MetaScreenCastStreamPrivate *priv =
meta_screen_cast_stream_get_instance_private (stream);
return priv->session;
}
gboolean
meta_screen_cast_stream_start (MetaScreenCastStream *stream,
GError **error)
@ -150,6 +167,15 @@ meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream,
y);
}
MetaScreenCastCursorMode
meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream)
{
MetaScreenCastStreamPrivate *priv =
meta_screen_cast_stream_get_instance_private (stream);
return priv->cursor_mode;
}
static void
meta_screen_cast_stream_set_property (GObject *object,
guint prop_id,
@ -162,9 +188,15 @@ meta_screen_cast_stream_set_property (GObject *object,
switch (prop_id)
{
case PROP_SESSION:
priv->session = g_value_get_object (value);
break;
case PROP_CONNECTION:
priv->connection = g_value_get_object (value);
break;
case PROP_CURSOR_MODE:
priv->cursor_mode = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -182,9 +214,15 @@ meta_screen_cast_stream_get_property (GObject *object,
switch (prop_id)
{
case PROP_SESSION:
g_value_set_object (value, priv->session);
break;
case PROP_CONNECTION:
g_value_set_object (value, priv->connection);
break;
case PROP_CURSOR_MODE:
g_value_set_uint (value, priv->cursor_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -256,6 +294,16 @@ meta_screen_cast_stream_class_init (MetaScreenCastStreamClass *klass)
object_class->set_property = meta_screen_cast_stream_set_property;
object_class->get_property = meta_screen_cast_stream_get_property;
g_object_class_install_property (object_class,
PROP_SESSION,
g_param_spec_object ("session",
"session",
"MetaScreenSession",
META_TYPE_SCREEN_CAST_SESSION,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_CONNECTION,
g_param_spec_object ("connection",
@ -266,6 +314,18 @@ meta_screen_cast_stream_class_init (MetaScreenCastStreamClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class,
PROP_CURSOR_MODE,
g_param_spec_uint ("cursor-mode",
"cursor-mode",
"Cursor mode",
META_SCREEN_CAST_CURSOR_MODE_HIDDEN,
META_SCREEN_CAST_CURSOR_MODE_METADATA,
META_SCREEN_CAST_CURSOR_MODE_HIDDEN,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
signals[CLOSED] = g_signal_new ("closed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,

View File

@ -26,6 +26,8 @@
#include <glib-object.h>
#include "backends/meta-screen-cast-stream-src.h"
#include "backends/meta-screen-cast.h"
#include "meta-dbus-screen-cast.h"
#define META_TYPE_SCREEN_CAST_STREAM (meta_screen_cast_stream_get_type ())
@ -48,6 +50,8 @@ struct _MetaScreenCastStreamClass
double *y);
};
MetaScreenCastSession * meta_screen_cast_stream_get_session (MetaScreenCastStream *stream);
gboolean meta_screen_cast_stream_start (MetaScreenCastStream *stream,
GError **error);
@ -61,4 +65,6 @@ void meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream,
double *x,
double *y);
MetaScreenCastCursorMode meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream);
#endif /* META_SCREEN_CAST_STREAM_H */

View File

@ -207,7 +207,7 @@ meta_screen_cast_window_stream_src_disable (MetaScreenCastStreamSrc *src)
meta_screen_cast_window_stream_src_stop (window_src);
}
static void
static gboolean
meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
{
@ -215,6 +215,8 @@ meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
capture_into (window_src, data);
return TRUE;
}
MetaScreenCastWindowStreamSrc *

View File

@ -71,9 +71,10 @@ meta_screen_cast_window_stream_get_height (MetaScreenCastWindowStream *window_st
}
MetaScreenCastWindowStream *
meta_screen_cast_window_stream_new (GDBusConnection *connection,
MetaWindow *window,
GError **error)
meta_screen_cast_window_stream_new (MetaScreenCastSession *session,
GDBusConnection *connection,
MetaWindow *window,
GError **error)
{
MetaScreenCastWindowStream *window_stream;
MetaLogicalMonitor *logical_monitor;
@ -90,6 +91,7 @@ meta_screen_cast_window_stream_new (GDBusConnection *connection,
window_stream = g_initable_new (META_TYPE_SCREEN_CAST_WINDOW_STREAM,
NULL,
error,
"session", session,
"connection", connection,
"window", window,
NULL);

View File

@ -32,9 +32,10 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastWindowStream,
META, SCREEN_CAST_WINDOW_STREAM,
MetaScreenCastStream)
MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (GDBusConnection *connection,
MetaWindow *window,
GError **error);
MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (MetaScreenCastSession *session,
GDBusConnection *connection,
MetaWindow *window,
GError **error);
MetaWindow * meta_screen_cast_window_stream_get_window (MetaScreenCastWindowStream *window_stream);
int meta_screen_cast_window_stream_get_width (MetaScreenCastWindowStream *window_stream);

View File

@ -43,6 +43,7 @@ struct _MetaScreenCast
GList *sessions;
MetaDbusSessionWatcher *session_watcher;
MetaBackend *backend;
};
static void
@ -62,12 +63,20 @@ meta_screen_cast_get_connection (MetaScreenCast *screen_cast)
return g_dbus_interface_skeleton_get_connection (interface_skeleton);
}
MetaBackend *
meta_screen_cast_get_backend (MetaScreenCast *screen_cast)
{
return screen_cast->backend;
}
static gboolean
register_remote_desktop_screen_cast_session (MetaScreenCastSession *session,
const char *remote_desktop_session_id,
GError **error)
{
MetaBackend *backend = meta_get_backend ();
MetaScreenCast *screen_cast =
meta_screen_cast_session_get_screen_cast (session);
MetaBackend *backend = meta_screen_cast_get_backend (screen_cast);
MetaRemoteDesktop *remote_desktop = meta_backend_get_remote_desktop (backend);
MetaRemoteDesktopSession *remote_desktop_session;
@ -244,11 +253,13 @@ meta_screen_cast_finalize (GObject *object)
}
MetaScreenCast *
meta_screen_cast_new (MetaDbusSessionWatcher *session_watcher)
meta_screen_cast_new (MetaBackend *backend,
MetaDbusSessionWatcher *session_watcher)
{
MetaScreenCast *screen_cast;
screen_cast = g_object_new (META_TYPE_SCREEN_CAST, NULL);
screen_cast->backend = backend;
screen_cast->session_watcher = session_watcher;
return screen_cast;

View File

@ -25,10 +25,18 @@
#include <glib-object.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-dbus-session-watcher.h"
#include "meta-dbus-screen-cast.h"
typedef enum _MetaScreenCastCursorMode
{
META_SCREEN_CAST_CURSOR_MODE_HIDDEN = 0,
META_SCREEN_CAST_CURSOR_MODE_EMBEDDED = 1,
META_SCREEN_CAST_CURSOR_MODE_METADATA = 2,
} MetaScreenCastCursorMode;
#define META_TYPE_SCREEN_CAST (meta_screen_cast_get_type ())
G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast,
META, SCREEN_CAST,
@ -36,6 +44,9 @@ G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast,
GDBusConnection * meta_screen_cast_get_connection (MetaScreenCast *screen_cast);
MetaScreenCast * meta_screen_cast_new (MetaDbusSessionWatcher *session_watcher);
MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast);
MetaScreenCast * meta_screen_cast_new (MetaBackend *backend,
MetaDbusSessionWatcher *session_watcher);
#endif /* META_SCREEN_CAST_H */

View File

@ -30,7 +30,17 @@
#include "meta/meta-monitor-manager.h"
#include "meta/util.h"
struct _MetaOverlay {
enum
{
ACTORS_PAINTED,
N_SIGNALS
};
static guint signals[N_SIGNALS];
struct _MetaOverlay
{
gboolean enabled;
CoglPipeline *pipeline;
@ -141,6 +151,8 @@ meta_stage_paint (ClutterActor *actor)
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
g_signal_emit (stage, signals[ACTORS_PAINTED], 0);
for (l = stage->overlays; l; l = l->next)
meta_overlay_paint (l->data);
}
@ -178,6 +190,13 @@ meta_stage_class_init (MetaStageClass *klass)
stage_class->activate = meta_stage_activate;
stage_class->deactivate = meta_stage_deactivate;
signals[ACTORS_PAINTED] = g_signal_new ("actors-painted",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void

View File

@ -586,6 +586,10 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
if (!cursor_sprite)
return FALSE;
if (meta_cursor_renderer_is_hw_cursors_inhibited (renderer,
cursor_sprite))
return FALSE;
for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = l->data;

View File

@ -77,6 +77,8 @@ struct _MetaGpuKms
gboolean page_flips_not_supported;
gboolean resources_init_failed_before;
MetaGpuKmsFlag flags;
};
G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU)
@ -457,6 +459,18 @@ meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
}
}
gboolean
meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms)
{
return !!(gpu_kms->flags & META_GPU_KMS_FLAG_BOOT_VGA);
}
gboolean
meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms)
{
return !!(gpu_kms->flags & META_GPU_KMS_FLAG_PLATFORM_DEVICE);
}
static void
free_resources (MetaGpuKms *gpu_kms)
{
@ -897,6 +911,7 @@ meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms)
MetaGpuKms *
meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
const char *kms_file_path,
MetaGpuKmsFlag flags,
GError **error)
{
MetaMonitorManager *monitor_manager =
@ -917,6 +932,7 @@ meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
"monitor-manager", monitor_manager_kms,
NULL);
gpu_kms->flags = flags;
gpu_kms->fd = kms_fd;
gpu_kms->file_path = g_strdup (kms_file_path);

View File

@ -44,8 +44,16 @@ typedef struct _MetaKmsResources
typedef void (*MetaKmsFlipCallback) (void *user_data);
typedef enum _MetaGpuKmsFlag
{
META_GPU_KMS_FLAG_NONE = 0,
META_GPU_KMS_FLAG_BOOT_VGA = (1 << 0),
META_GPU_KMS_FLAG_PLATFORM_DEVICE = (1 << 1),
} MetaGpuKmsFlag;
MetaGpuKms * meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
const char *kms_file_path,
MetaGpuKmsFlag flags,
GError **error);
gboolean meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
@ -59,6 +67,9 @@ gboolean meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms);
gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
MetaCrtc *crtc);
gboolean meta_gpu_kms_is_boot_vga (MetaGpuKms *gpu_kms);
gboolean meta_gpu_kms_is_platform_device (MetaGpuKms *gpu_kms);
gboolean meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
MetaCrtc *crtc,
int x,

View File

@ -84,8 +84,6 @@ struct _MetaMonitorManagerKms
{
MetaMonitorManager parent_instance;
MetaGpuKms *primary_gpu;
GUdevClient *udev;
guint uevent_handler_id;
};
@ -418,7 +416,8 @@ handle_gpu_hotplug (MetaMonitorManagerKms *manager_kms,
}
}
gpu_kms = meta_gpu_kms_new (manager_kms, gpu_path, &error);
gpu_kms = meta_gpu_kms_new (manager_kms, gpu_path,
META_GPU_KMS_FLAG_NONE, &error);
if (!gpu_kms)
{
g_warning ("Failed to hotplug secondary gpu '%s': %s",
@ -579,22 +578,9 @@ meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager)
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
}
MetaGpuKms *
meta_monitor_manager_kms_get_primary_gpu (MetaMonitorManagerKms *manager_kms)
{
return manager_kms->primary_gpu;
}
typedef enum
{
GPU_TYPE_PRIMARY,
GPU_TYPE_SECONDARY
} GpuType;
static GList *
get_gpu_paths (MetaMonitorManagerKms *manager_kms,
GpuType gpu_type,
const char *filtered_gpu_path)
static gboolean
init_gpus (MetaMonitorManagerKms *manager_kms,
GError **error)
{
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
MetaBackend *backend = meta_monitor_manager_get_backend (manager);
@ -604,7 +590,7 @@ get_gpu_paths (MetaMonitorManagerKms *manager_kms,
const char *seat_id;
GList *devices;
GList *l;
GList *gpu_paths = NULL;
MetaGpuKmsFlag flags = META_GPU_KMS_FLAG_NONE;
enumerator = g_udev_enumerator_new (manager_kms->udev);
@ -619,18 +605,24 @@ get_gpu_paths (MetaMonitorManagerKms *manager_kms,
devices = g_udev_enumerator_execute (enumerator);
if (!devices)
return NULL;
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"No GPUs found with udev");
return FALSE;
}
seat_id = meta_launcher_get_seat_id (launcher);
for (l = devices; l; l = l->next)
{
GUdevDevice *dev = l->data;
MetaGpuKms *gpu_kms;
g_autoptr (GUdevDevice) platform_device = NULL;
g_autoptr (GUdevDevice) pci_device = NULL;
const char *device_path;
const char *device_type;
const char *device_seat;
GError *local_error = NULL;
/* Filter out devices that are not character device, like card0-VGA-1. */
if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR)
@ -641,8 +633,6 @@ get_gpu_paths (MetaMonitorManagerKms *manager_kms,
continue;
device_path = g_udev_device_get_device_file (dev);
if (g_strcmp0 (device_path, filtered_gpu_path) == 0)
continue;
device_seat = g_udev_device_get_property (dev, "ID_SEAT");
if (!device_seat)
@ -650,16 +640,6 @@ get_gpu_paths (MetaMonitorManagerKms *manager_kms,
/* When ID_SEAT is not set, it means seat0. */
device_seat = "seat0";
}
else if (g_strcmp0 (device_seat, "seat0") != 0 &&
gpu_type == GPU_TYPE_PRIMARY)
{
/*
* If the device has been explicitly assigned other seat
* than seat0, it is probably the right device to use.
*/
gpu_paths = g_list_append (gpu_paths, g_strdup (device_path));
break;
}
/* Skip devices that do not belong to our seat. */
if (g_strcmp0 (seat_id, device_seat))
@ -668,38 +648,40 @@ get_gpu_paths (MetaMonitorManagerKms *manager_kms,
platform_device = g_udev_device_get_parent_with_subsystem (dev,
"platform",
NULL);
if (platform_device != NULL && gpu_type == GPU_TYPE_PRIMARY)
{
gpu_paths = g_list_append (gpu_paths, g_strdup (device_path));
break;
}
if (platform_device != NULL)
flags |= META_GPU_KMS_FLAG_PLATFORM_DEVICE;
pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL);
if (pci_device != NULL)
{
if (gpu_type == GPU_TYPE_PRIMARY)
{
int boot_vga;
boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device,
"boot_vga");
if (boot_vga == 1)
{
gpu_paths = g_list_append (gpu_paths, g_strdup (device_path));
break;
}
}
if (g_udev_device_get_sysfs_attr_as_int (pci_device,
"boot_vga") == 1)
flags |= META_GPU_KMS_FLAG_BOOT_VGA;
}
if (gpu_type == GPU_TYPE_SECONDARY)
gpu_kms = meta_gpu_kms_new (manager_kms, device_path, flags,
&local_error);
if (!gpu_kms)
{
gpu_paths = g_list_append (gpu_paths, g_strdup (device_path));
g_warning ("Failed to open gpu '%s': %s",
device_path, local_error->message);
g_clear_error (&local_error);
continue;
}
meta_monitor_manager_add_gpu (manager, META_GPU (gpu_kms));
}
g_list_free_full (devices, g_object_unref);
return gpu_paths;
if (!meta_monitor_manager_get_gpus (manager))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"No GPUs found");
return FALSE;
}
return TRUE;
}
static gboolean
@ -710,54 +692,17 @@ meta_monitor_manager_kms_initable_init (GInitable *initable,
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (initable);
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
const char *subsystems[2] = { "drm", NULL };
GList *gpu_paths;
g_autofree char *primary_gpu_path = NULL;
GList *l;
gboolean can_have_outputs;
manager_kms->udev = g_udev_client_new (subsystems);
gpu_paths = get_gpu_paths (manager_kms, GPU_TYPE_PRIMARY, NULL);
if (g_list_length (gpu_paths) != 1)
{
g_list_free_full (gpu_paths, g_free);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Could not find a primary drm kms device");
return FALSE;
}
primary_gpu_path = g_strdup (gpu_paths->data);
manager_kms->primary_gpu = meta_gpu_kms_new (manager_kms,
primary_gpu_path,
error);
g_list_free_full (gpu_paths, g_free);
if (!manager_kms->primary_gpu)
return FALSE;
meta_monitor_manager_kms_connect_uevent_handler (manager_kms);
meta_monitor_manager_add_gpu (META_MONITOR_MANAGER (manager_kms),
META_GPU (manager_kms->primary_gpu));
gpu_paths = get_gpu_paths (manager_kms, GPU_TYPE_SECONDARY, primary_gpu_path);
for (l = gpu_paths; l; l = l->next)
if (!init_gpus (manager_kms, error))
{
g_autoptr (GError) secondary_error = NULL;
char *gpu_path = l->data;
MetaGpuKms *gpu_kms;
gpu_kms = meta_gpu_kms_new (manager_kms, gpu_path, &secondary_error);
if (!gpu_kms)
{
g_warning ("Failed to open secondary gpu '%s': %s",
gpu_path, secondary_error->message);
continue;
}
meta_monitor_manager_add_gpu (META_MONITOR_MANAGER (manager_kms),
META_GPU (gpu_kms));
return FALSE;
}
g_list_free_full (gpu_paths, g_free);
can_have_outputs = FALSE;
for (l = meta_monitor_manager_get_gpus (manager); l; l = l->next)

View File

@ -35,8 +35,6 @@ G_DECLARE_FINAL_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms,
META, MONITOR_MANAGER_KMS,
MetaMonitorManager)
MetaGpuKms * meta_monitor_manager_kms_get_primary_gpu (MetaMonitorManagerKms *manager_kms);
void meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms);
void meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms);

View File

@ -112,6 +112,7 @@ typedef struct _MetaRendererNativeGpuData
*/
struct {
MetaSharedFramebufferCopyMode copy_mode;
gboolean is_hardware_rendering;
/* For GPU blit mode */
EGLContext egl_context;
@ -195,6 +196,7 @@ struct _MetaRendererNative
MetaRenderer parent;
MetaMonitorManagerKms *monitor_manager_kms;
MetaGpuKms *primary_gpu_kms;
MetaGles3 *gles3;
gboolean use_modifiers;
@ -2857,12 +2859,8 @@ static CoglRenderer *
meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer)
{
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaMonitorManagerKms *monitor_manager_kms =
renderer_native->monitor_manager_kms;
MetaGpuKms *primary_gpu =
meta_monitor_manager_kms_get_primary_gpu (monitor_manager_kms);
return create_cogl_renderer_for_gpu (primary_gpu);
return create_cogl_renderer_for_gpu (renderer_native->primary_gpu_kms);
}
static void
@ -2965,14 +2963,11 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
MetaLogicalMonitor *logical_monitor)
{
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaMonitorManagerKms *monitor_manager_kms =
renderer_native->monitor_manager_kms;
MetaMonitorManager *monitor_manager =
META_MONITOR_MANAGER (monitor_manager_kms);
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
CoglContext *cogl_context =
cogl_context_from_renderer_native (renderer_native);
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
MetaGpuKms *primary_gpu;
CoglDisplayEGL *cogl_display_egl;
CoglOnscreenEGL *onscreen_egl;
MetaMonitorTransform view_transform;
@ -2993,9 +2988,8 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
width = roundf (logical_monitor->rect.width * scale);
height = roundf (logical_monitor->rect.height * scale);
primary_gpu = meta_monitor_manager_kms_get_primary_gpu (monitor_manager_kms);
onscreen = meta_renderer_native_create_onscreen (renderer_native,
primary_gpu,
renderer_native->primary_gpu_kms,
logical_monitor,
cogl_context,
view_transform,
@ -3006,7 +3000,8 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
g_error ("Failed to allocate onscreen framebuffer: %s", error->message);
if (view_transform != META_MONITOR_TRANSFORM_NORMAL ||
should_force_shadow_fb (renderer_native, primary_gpu))
should_force_shadow_fb (renderer_native,
renderer_native->primary_gpu_kms))
{
offscreen = meta_renderer_native_create_offscreen (renderer_native,
cogl_context,
@ -3213,6 +3208,8 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
EGLConfig egl_config;
EGLContext egl_context;
char **missing_gl_extensions;
const char *renderer_str;
gboolean is_hardware;
if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display,
&egl_config, error))
@ -3235,6 +3232,14 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
return FALSE;
}
renderer_str = (const char *) glGetString (GL_RENDERER);
if (g_str_has_prefix (renderer_str, "llvmpipe") ||
g_str_has_prefix (renderer_str, "softpipe") ||
g_str_has_prefix (renderer_str, "swrast"))
is_hardware = FALSE;
else
is_hardware = TRUE;
if (!meta_gles3_has_extensions (renderer_native->gles3,
&missing_gl_extensions,
"GL_OES_EGL_image_external",
@ -3250,6 +3255,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
g_free (missing_gl_extensions);
}
renderer_gpu_data->secondary.is_hardware_rendering = is_hardware;
renderer_gpu_data->secondary.egl_context = egl_context;
renderer_gpu_data->secondary.egl_config = egl_config;
renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_GPU;
@ -3260,6 +3266,7 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
static void
init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data)
{
renderer_gpu_data->secondary.is_hardware_rendering = FALSE;
renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_CPU;
}
@ -3278,18 +3285,26 @@ init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data)
init_secondary_gpu_data_cpu (renderer_gpu_data);
}
static gboolean
gpu_kms_is_hardware_rendering (MetaRendererNative *renderer_native,
MetaGpuKms *gpu_kms)
{
MetaRendererNativeGpuData *data;
data = meta_renderer_native_get_gpu_data (renderer_native, gpu_kms);
return data->secondary.is_hardware_rendering;
}
static MetaRendererNativeGpuData *
create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native,
MetaGpuKms *gpu_kms,
GError **error)
{
MetaMonitorManagerKms *monitor_manager_kms;
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
struct gbm_device *gbm_device;
EGLDisplay egl_display;
int kms_fd;
MetaRendererNativeGpuData *renderer_gpu_data;
MetaGpuKms *primary_gpu;
if (!meta_egl_has_extensions (egl, EGL_NO_DISPLAY, NULL,
"EGL_MESA_platform_gbm",
@ -3333,10 +3348,7 @@ create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native,
renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_GBM;
renderer_gpu_data->egl_display = egl_display;
monitor_manager_kms = renderer_native->monitor_manager_kms;
primary_gpu = meta_monitor_manager_kms_get_primary_gpu (monitor_manager_kms);
if (gpu_kms != primary_gpu)
init_secondary_gpu_data (renderer_gpu_data);
init_secondary_gpu_data (renderer_gpu_data);
return renderer_gpu_data;
}
@ -3457,22 +3469,27 @@ get_egl_device_display (MetaRendererNative *renderer_native,
error);
}
static int
count_drm_devices (MetaRendererNative *renderer_native)
{
MetaMonitorManager *monitor_manager =
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
return g_list_length (meta_monitor_manager_get_gpus (monitor_manager));
}
static MetaRendererNativeGpuData *
create_renderer_gpu_data_egl_device (MetaRendererNative *renderer_native,
MetaGpuKms *gpu_kms,
GError **error)
{
MetaMonitorManagerKms *monitor_manager_kms =
renderer_native->monitor_manager_kms;
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
MetaGpuKms *primary_gpu;
char **missing_extensions;
EGLDeviceEXT egl_device;
EGLDisplay egl_display;
MetaRendererNativeGpuData *renderer_gpu_data;
primary_gpu = meta_monitor_manager_kms_get_primary_gpu (monitor_manager_kms);
if (gpu_kms != primary_gpu)
if (count_drm_devices (renderer_native) != 1)
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
@ -3624,6 +3641,57 @@ on_gpu_added (MetaMonitorManager *monitor_manager,
_cogl_winsys_egl_ensure_current (cogl_display);
}
static MetaGpuKms *
choose_primary_gpu (MetaMonitorManager *manager,
MetaRendererNative *renderer_native)
{
GList *gpus = meta_monitor_manager_get_gpus (manager);
GList *l;
int allow_sw;
/*
* Check first hardware rendering devices, and if none found,
* then software rendering devices.
*/
for (allow_sw = 0; allow_sw < 2; allow_sw++)
{
/* Prefer a platform device */
for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
if (meta_gpu_kms_is_platform_device (gpu_kms) &&
(allow_sw == 1 ||
gpu_kms_is_hardware_rendering (renderer_native, gpu_kms)))
return gpu_kms;
}
/* Otherwise a device we booted with */
for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
if (meta_gpu_kms_is_boot_vga (gpu_kms) &&
(allow_sw == 1 ||
gpu_kms_is_hardware_rendering (renderer_native, gpu_kms)))
return gpu_kms;
}
/* Fall back to any device */
for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
if (allow_sw == 1 ||
gpu_kms_is_hardware_rendering (renderer_native, gpu_kms))
return gpu_kms;
}
}
g_assert_not_reached ();
return NULL;
}
static gboolean
meta_renderer_native_initable_init (GInitable *initable,
GCancellable *cancellable,
@ -3646,6 +3714,9 @@ meta_renderer_native_initable_init (GInitable *initable,
return FALSE;
}
renderer_native->primary_gpu_kms = choose_primary_gpu (monitor_manager,
renderer_native);
return TRUE;
}

View File

@ -1594,7 +1594,7 @@ constrain_titlebar_visible (MetaWindow *window,
MetaFrameBorders borders;
meta_frame_calc_borders (window->frame, &borders);
bottom_amount = info->current.height + borders.visible.bottom;
bottom_amount = info->current.height - borders.visible.top;
vert_amount_onscreen = borders.visible.top;
}
else
@ -1673,7 +1673,7 @@ constrain_partially_onscreen (MetaWindow *window,
MetaFrameBorders borders;
meta_frame_calc_borders (window->frame, &borders);
bottom_amount = info->current.height + borders.visible.bottom;
bottom_amount = info->current.height - borders.visible.top;
vert_amount_onscreen = borders.visible.top;
}
else

View File

@ -0,0 +1,258 @@
/*
* Copyright (C) 2018 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#include "config.h"
#include <gio/gdesktopappinfo.h>
#include "core/display-private.h"
#include "meta/meta-launch-context.h"
#include "x11/meta-startup-notification-x11.h"
typedef struct _MetaLaunchContext MetaLaunchContext;
struct _MetaLaunchContext
{
GAppLaunchContext parent_instance;
MetaDisplay *display;
MetaWorkspace *workspace;
uint32_t timestamp;
};
G_DEFINE_TYPE (MetaLaunchContext, meta_launch_context,
G_TYPE_APP_LAUNCH_CONTEXT)
enum
{
PROP_DISPLAY = 1,
PROP_WORKSPACE,
PROP_TIMESTAMP,
N_PROPS
};
static GParamSpec *props[N_PROPS] = { 0, };
static void
meta_launch_context_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaLaunchContext *context = META_LAUNCH_CONTEXT (object);
switch (prop_id)
{
case PROP_DISPLAY:
context->display = g_value_get_object (value);
break;
case PROP_WORKSPACE:
meta_launch_context_set_workspace (context,
g_value_get_object (value));
break;
case PROP_TIMESTAMP:
meta_launch_context_set_timestamp (context,
g_value_get_uint (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
meta_launch_context_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaLaunchContext *context = META_LAUNCH_CONTEXT (object);
switch (prop_id)
{
case PROP_DISPLAY:
g_value_set_object (value, context->display);
break;
case PROP_WORKSPACE:
g_value_set_object (value, context->workspace);
break;
case PROP_TIMESTAMP:
g_value_set_uint (value, context->timestamp);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
meta_launch_context_finalize (GObject *object)
{
G_OBJECT_CLASS (meta_launch_context_parent_class)->finalize (object);
}
static void
meta_launch_context_constructed (GObject *object)
{
MetaLaunchContext *context = META_LAUNCH_CONTEXT (object);
G_OBJECT_CLASS (meta_launch_context_parent_class)->constructed (object);
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
"DISPLAY", getenv ("DISPLAY"));
g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (context),
"WAYLAND_DISPLAY", getenv ("WAYLAND_DISPLAY"));
}
static gchar *
meta_launch_context_get_startup_notify_id (GAppLaunchContext *launch_context,
GAppInfo *info,
GList *files)
{
MetaLaunchContext *context = META_LAUNCH_CONTEXT (launch_context);
MetaDisplay *display = context->display;
int workspace_idx = -1;
gchar *startup_id;
if (context->workspace)
workspace_idx = meta_workspace_index (context->workspace);
if (display->x11_display)
{
/* If there is a X11 display, we prefer going entirely through
* libsn, as SnMonitor expects to keep a view of the full lifetime
* of the startup sequence. We can't avoid it when launching and
* expect that a "remove" message from a X11 client will be handled.
*/
startup_id =
meta_x11_startup_notification_launch (display->x11_display,
info,
workspace_idx,
context->timestamp);
}
if (!startup_id)
{
const gchar *application_id = NULL;
MetaStartupNotification *sn;
MetaStartupSequence *seq;
startup_id = g_uuid_string_random ();
/* Fallback through inserting our own startup sequence, this
* will be enough for wayland clients.
*/
if (G_IS_DESKTOP_APP_INFO (info))
{
application_id =
g_desktop_app_info_get_filename (G_DESKTOP_APP_INFO (info));
}
sn = meta_display_get_startup_notification (context->display);
seq = g_object_new (META_TYPE_STARTUP_SEQUENCE,
"id", startup_id,
"application-id", application_id,
"name", g_app_info_get_name (info),
"workspace", workspace_idx,
"timestamp", context->timestamp,
NULL);
meta_startup_notification_add_sequence (sn, seq);
g_object_unref (seq);
}
return startup_id;
}
static void
meta_launch_context_launch_failed (GAppLaunchContext *launch_context,
const gchar *startup_notify_id)
{
MetaLaunchContext *context = META_LAUNCH_CONTEXT (launch_context);
MetaStartupNotification *sn;
MetaStartupSequence *seq;
sn = meta_display_get_startup_notification (context->display);
seq = meta_startup_notification_lookup_sequence (sn, startup_notify_id);
if (seq)
{
meta_startup_sequence_complete (seq);
meta_startup_notification_remove_sequence (sn, seq);
}
}
static void
meta_launch_context_class_init (MetaLaunchContextClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GAppLaunchContextClass *ctx_class = G_APP_LAUNCH_CONTEXT_CLASS (klass);
object_class->finalize = meta_launch_context_finalize;
object_class->constructed = meta_launch_context_constructed;
object_class->set_property = meta_launch_context_set_property;
object_class->get_property = meta_launch_context_get_property;
ctx_class->get_startup_notify_id = meta_launch_context_get_startup_notify_id;
ctx_class->launch_failed = meta_launch_context_launch_failed;
props[PROP_DISPLAY] =
g_param_spec_object ("display",
"display",
"Display",
META_TYPE_DISPLAY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
props[PROP_WORKSPACE] =
g_param_spec_object ("workspace",
"workspace",
"Workspace",
META_TYPE_WORKSPACE,
G_PARAM_READWRITE);
props[PROP_TIMESTAMP] =
g_param_spec_uint ("timestamp",
"timestamp",
"Timestamp",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, N_PROPS, props);
}
static void
meta_launch_context_init (MetaLaunchContext *context)
{
}
void
meta_launch_context_set_workspace (MetaLaunchContext *context,
MetaWorkspace *workspace)
{
g_return_if_fail (META_IS_LAUNCH_CONTEXT (context));
g_return_if_fail (META_IS_WORKSPACE (workspace));
g_set_object (&context->workspace, workspace);
}
void
meta_launch_context_set_timestamp (MetaLaunchContext *context,
uint32_t timestamp)
{
g_return_if_fail (META_IS_LAUNCH_CONTEXT (context));
context->timestamp = timestamp;
}

View File

@ -631,3 +631,19 @@ meta_startup_notification_get_sequences (MetaStartupNotification *sn)
{
return sn->startup_sequences;
}
/**
* meta_startup_notification_create_launcher:
* @sn: a #MetaStartupNotification
*
* Creates an app launch context.
*
* Returns: (transfer full): a launch context.
**/
MetaLaunchContext *
meta_startup_notification_create_launcher (MetaStartupNotification *sn)
{
return g_object_new (META_TYPE_LAUNCH_CONTEXT,
"display", sn->display,
NULL);
}

View File

@ -334,6 +334,7 @@ mutter_sources = [
'core/meta-inhibit-shortcuts-dialog.c',
'core/meta-inhibit-shortcuts-dialog-default.c',
'core/meta-inhibit-shortcuts-dialog-default-private.h',
'core/meta-launch-context.c',
'core/meta-sound-player.c',
'core/meta-workspace-manager.c',
'core/meta-workspace-manager-private.h',
@ -726,6 +727,7 @@ subdir('meta')
mutter_marshal = gnome.genmarshal('meta-marshal',
sources: ['meta-marshal.list'],
prefix: 'meta_marshal',
extra_args: ['--quiet'],
internal: true,
)
mutter_built_sources += mutter_marshal

View File

@ -18,6 +18,7 @@ mutter_public_headers = [
'meta-dnd.h',
'meta-idle-monitor.h',
'meta-inhibit-shortcuts-dialog.h',
'meta-launch-context.h',
'meta-monitor-manager.h',
'meta-plugin.h',
'meta-remote-access-controller.h',

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2018 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_LAUNCH_CONTEXT_H
#define META_LAUNCH_CONTEXT_H
#include <meta/workspace.h>
G_DECLARE_FINAL_TYPE (MetaLaunchContext, meta_launch_context, META, LAUNCH_CONTEXT, GAppLaunchContext)
#define META_TYPE_LAUNCH_CONTEXT (meta_launch_context_get_type ())
void meta_launch_context_set_timestamp (MetaLaunchContext *context,
uint32_t timestamp);
void meta_launch_context_set_workspace (MetaLaunchContext *context,
MetaWorkspace *workspace);
#endif /* META_LAUNCH_CONTEXT_H */

View File

@ -19,6 +19,8 @@
#ifndef META_STARTUP_NOTIFICATION_H
#define META_STARTUP_NOTIFICATION_H
#include <meta/meta-launch-context.h>
#define META_TYPE_STARTUP_SEQUENCE (meta_startup_sequence_get_type ())
#define META_TYPE_STARTUP_NOTIFICATION (meta_startup_notification_get_type ())
@ -32,6 +34,9 @@ GType meta_startup_notification_get_type (void);
*/
GSList * meta_startup_notification_get_sequences (MetaStartupNotification *sn);
MetaLaunchContext *
meta_startup_notification_create_launcher (MetaStartupNotification *sn);
GType meta_startup_sequence_get_type (void);
const char * meta_startup_sequence_get_id (MetaStartupSequence *sequence);

View File

@ -71,7 +71,15 @@
Record a single monitor.
Available @properties include: (none)
Available @properties include:
* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below)
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="RecordMonitor">
<arg name="connector" type="s" direction="in" />
@ -84,7 +92,7 @@
@properties: Properties used determining what window to select
@stream_path: Path to the new stream object
Record a single window.
Record a single window. The cursor will not be included.
Available @properties include:

View File

@ -1734,9 +1734,10 @@ primary_device_set_selection (struct wl_client *client,
uint32_t serial)
{
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandDataSource *source;
MetaWaylandDataSource *source = NULL;
source = wl_resource_get_user_data (source_resource);
if (source_resource)
source = wl_resource_get_user_data (source_resource);
meta_wayland_data_device_set_primary (data_device, source, serial);
}

View File

@ -19,6 +19,8 @@
#include "config.h"
#include "meta-startup-notification-x11.h"
#include <gio/gdesktopappinfo.h>
#include "core/display-private.h"
#include "core/startup-notification-private.h"
#include "meta/meta-x11-errors.h"
@ -296,3 +298,72 @@ meta_x11_startup_notification_handle_xevent (MetaX11Display *x11_display,
return sn_display_process_event (x11_sn->sn_display, xevent);
}
typedef void (* SetAppIdFunc) (SnLauncherContext *context,
const char *app_id);
gchar *
meta_x11_startup_notification_launch (MetaX11Display *x11_display,
GAppInfo *app_info,
uint32_t timestamp,
int workspace)
{
gchar *startup_id = NULL;
#ifdef HAVE_STARTUP_NOTIFICATION
MetaX11StartupNotification *x11_sn = x11_display->startup_notification;
SnLauncherContext *sn_launcher;
int screen;
screen = meta_x11_display_get_screen_number (x11_display);
sn_launcher = sn_launcher_context_new (x11_sn->sn_display, screen);
sn_launcher_context_set_name (sn_launcher, g_app_info_get_name (app_info));
sn_launcher_context_set_workspace (sn_launcher, workspace);
sn_launcher_context_set_binary_name (sn_launcher,
g_app_info_get_executable (app_info));
if (G_IS_DESKTOP_APP_INFO (app_info))
{
const char *application_id;
SetAppIdFunc func = NULL;
GModule *self;
application_id =
g_desktop_app_info_get_filename (G_DESKTOP_APP_INFO (app_info));
self = g_module_open (NULL, G_MODULE_BIND_MASK);
/* This here is a terrible workaround to bypass a libsn bug that is not
* likely to get fixed at this point.
* sn_launcher_context_set_application_id is correctly defined in the
* sn-launcher.h file, but it's mistakenly called
* sn_launcher_set_application_id in the C file.
*
* We look up the symbol instead, but still prefer the correctly named
* function, if one were ever to be added.
*/
if (!g_module_symbol (self, "sn_launcher_context_set_application_id",
(gpointer *) &func))
{
g_module_symbol (self, "sn_launcher_set_application_id",
(gpointer *) &func);
}
if (func)
func (sn_launcher, application_id);
g_module_close (self);
}
sn_launcher_context_initiate (sn_launcher,
g_get_prgname (),
g_app_info_get_name (app_info),
timestamp);
startup_id = g_strdup (sn_launcher_context_get_startup_id (sn_launcher));
/* Fire and forget, we have a SnMonitor in addition */
sn_launcher_context_unref (sn_launcher);
#endif /* HAVE_STARTUP_NOTIFICATION */
return startup_id;
}

View File

@ -36,4 +36,9 @@ void meta_x11_startup_notification_release (MetaX11Display *x11_display);
gboolean meta_x11_startup_notification_handle_xevent (MetaX11Display *x11_display,
XEvent *xevent);
gchar * meta_x11_startup_notification_launch (MetaX11Display *x11_display,
GAppInfo *app_info,
uint32_t timestamp,
int workspace);
#endif /* META_X11_STARTUP_NOTIFICATION_H */