Compare commits
29 Commits
3.31.4
...
wip/carlos
Author | SHA1 | Date | |
---|---|---|---|
162d6d45a0 | |||
ff507273d2 | |||
f033d0e846 | |||
ca67d52cac | |||
60d22b7cd0 | |||
e9778eba18 | |||
56d260cfb3 | |||
c45d5f53ff | |||
4e402b3972 | |||
79d99cbe3f | |||
328eff7352 | |||
ed5c1f433b | |||
7ac2083134 | |||
bd97b11414 | |||
0da0207eed | |||
08229a6f5d | |||
50071303af | |||
2b2d77dc3e | |||
a0909c3440 | |||
22f865122c | |||
60ac2838b5 | |||
dfde2f59da | |||
3d2ca9a67f | |||
9182c8b801 | |||
1def099047 | |||
ddb0ef1e8d | |||
a56a59feee | |||
174df4eaeb | |||
e3e933c47a |
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
|
@ -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__ */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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')
|
||||
|
5062
po/ChangeLog
5062
po/ChangeLog
File diff suppressed because it is too large
Load Diff
68
po/Makevars
68
po/Makevars
@ -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
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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 */
|
||||
|
@ -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 *
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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 *
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
258
src/core/meta-launch-context.c
Normal file
258
src/core/meta-launch-context.c
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
35
src/meta/meta-launch-context.h
Normal file
35
src/meta/meta-launch-context.h
Normal 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 */
|
@ -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);
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Reference in New Issue
Block a user