Compare commits
147 Commits
citadel
...
wip/textur
Author | SHA1 | Date | |
---|---|---|---|
|
625ea86672 | ||
|
395d463c08 | ||
|
2fc0652886 | ||
|
6ff42c2ab2 | ||
|
f9907d1978 | ||
|
45c5f557bd | ||
|
53d63ea72b | ||
|
f6e8e867b4 | ||
|
a566c6677c | ||
|
cb06e1ef33 | ||
|
a30c8fb83d | ||
|
e3a42dc873 | ||
|
efd7b8987f | ||
|
c96aacabf7 | ||
|
af61b66953 | ||
|
baf11d2471 | ||
|
01c763470e | ||
|
c9065da442 | ||
|
5f8a4f560f | ||
|
47577432e4 | ||
|
4ee9462fcd | ||
|
c275c1de52 | ||
|
a9965bb57a | ||
|
9cc2fa2526 | ||
|
f439b0432d | ||
|
ab39558506 | ||
|
9d72eeeb58 | ||
|
eea0a2b11d | ||
|
bcacaf4562 | ||
|
5ae7a67b36 | ||
|
7d8ff61069 | ||
|
79b3f56bd3 | ||
|
e371bacd7f | ||
|
62fd182272 | ||
|
f48c8c5824 | ||
|
e3d7b3828e | ||
|
6e14403ac8 | ||
|
ec2471a356 | ||
|
30820ab19e | ||
|
58cc091134 | ||
|
0105dca586 | ||
|
17dd4d32da | ||
|
5b95f809ca | ||
|
3934793255 | ||
|
f3655737bc | ||
|
728ed4fe38 | ||
|
bcba6571f0 | ||
|
4525a74e59 | ||
|
0dd58540b2 | ||
|
ac27fca3ef | ||
|
99bbe001f5 | ||
|
30c09c84c4 | ||
|
81c63df853 | ||
|
3104abba57 | ||
|
13eb4f51c7 | ||
|
7969c473ac | ||
|
a83e72d7c1 | ||
|
910c4e9fe7 | ||
|
2fb5b65e94 | ||
|
e00d6c6273 | ||
|
733ab3b2bc | ||
|
a208d7c33e | ||
|
37bbea649b | ||
|
4035955fc0 | ||
|
a8db59908f | ||
|
a477c73a97 | ||
|
ae228c0556 | ||
|
978cb5b21c | ||
|
e792eca2f5 | ||
|
b9614f0797 | ||
|
6d7bbeddd7 | ||
|
68570353fd | ||
|
566cdcc94b | ||
|
37dc2e5b1b | ||
|
66b9150771 | ||
|
34f5bdeea3 | ||
|
ca71b0eb1a | ||
|
ca4209d88a | ||
|
3288edf677 | ||
|
fe1616668e | ||
|
7d01aec48d | ||
|
a41d84db00 | ||
|
e73b321c2e | ||
|
b6dc2052c3 | ||
|
72965aaaf0 | ||
|
2a6782dc10 | ||
|
5142c8c7e7 | ||
|
abc7ad8e9f | ||
|
1a3f9a3323 | ||
|
235c35182b | ||
|
e4661d7870 | ||
|
9d4c7e4e75 | ||
|
47131b1dad | ||
|
51c0130645 | ||
|
2dd9fc17c1 | ||
|
c7a38c3139 | ||
|
7d52be0229 | ||
|
41303bc01b | ||
|
0d188c3898 | ||
|
28eff93143 | ||
|
b380aa72aa | ||
|
920dc9e5a1 | ||
|
32f02010ae | ||
|
889c56c776 | ||
|
67a4cd898e | ||
|
43d6c0ea61 | ||
|
2872bb1f2a | ||
|
1c00cd5ca3 | ||
|
2919a7f25f | ||
|
ca0d56a3a4 | ||
|
a89baa44ab | ||
|
7076a48bcf | ||
|
1b439c42d1 | ||
|
928a40f328 | ||
|
59397266ed | ||
|
d0147591b3 | ||
|
25c7e52ada | ||
|
99d766c044 | ||
|
fcd4c816c4 | ||
|
2a63a47d5a | ||
|
c80e2c9ae5 | ||
|
d3d5eb8e1b | ||
|
4837cec89f | ||
|
32329e6c00 | ||
|
89261be556 | ||
|
e3e76d658b | ||
|
34644b2133 | ||
|
7da4e8cf14 | ||
|
23c3f8bb18 | ||
|
60866e0f85 | ||
|
45c02645f3 | ||
|
e515e37a7e | ||
|
957f4ec69d | ||
|
a98eb107be | ||
|
1851fa2bd0 | ||
|
de7d7bbf3d | ||
|
7ac551cd05 | ||
|
8696a79477 | ||
|
b2f9de98d0 | ||
|
2da2489da5 | ||
|
31779404f0 | ||
|
b096c0ac33 | ||
|
44a7f74dcd | ||
|
3832c6b607 | ||
|
14b7e79d3c | ||
|
e99b0b9368 | ||
|
de294f34bb |
45
NEWS
45
NEWS
@ -1,3 +1,48 @@
|
||||
3.28.3
|
||||
======
|
||||
* Handle touch events on server-side titlebars [Carlos; #770185]
|
||||
* Fix crash with unhandled mouse buttons on titlebars [Olivier; #160]
|
||||
* Fix Korean Hangul support on wayland [Changwoo; #152]
|
||||
* Fix crash when taking up from suspend [Jonas; #786929]
|
||||
* Fix crash with parent-less modal dialogs [Olivier; #174]
|
||||
* Misc. bug fixes [Olivier, Georges; #83, #112, #150, #104,
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Olivier Fourdan, Carlos Garnacho, Georges Basile Stavracas Neto,
|
||||
Changwoo Ryu, Marco Trevisan (Treviño)
|
||||
|
||||
3.28.2
|
||||
======
|
||||
* Take inhibitors into account for monitoring idle [Bastien; #705942]
|
||||
* Fix window animations on wayland [Georges; #780292]
|
||||
* Misc. bug fixes [Mario, Jonas, Olivier, Florian; gnome-shell#157, #130,
|
||||
#21, #124, !96, #138, !102, #781471]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Olivier Fourdan, Carlos Garnacho, Florian Müllner,
|
||||
Georges Basile Stavracas Neto, Bastien Nocera, Mario Sanchez Prada,
|
||||
Ray Strode, Marco Trevisan (Treviño)
|
||||
|
||||
3.28.1
|
||||
======
|
||||
* Fix various input-method regressions [Carlos; #65, #74, #66]
|
||||
* Fix wayland build on FreeBSD [Ting-Wei; #792280, #792717]
|
||||
* Fix swapped colors in screenshots (again) [Carlos; #72]
|
||||
* Allow building with elogind [Rasmus; !46]
|
||||
* Consider display rotation for cursor [Olivier; #85]
|
||||
* Fall back to non-modifier GBM surfaces [Daniel; #84]
|
||||
* Disable KMS modifiers by default [Jonas; #81]
|
||||
* Misc bug fixes [handsome-feng; !45]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Olivier Fourdan, Carlos Garnacho, handsome-feng, Yussuf Khalil,
|
||||
Ting-Wei Lan, Aleksandr Mezin, Alberts Muktupāvels,
|
||||
Georges Basile Stavracas Neto, Benjamin Otte, Daniel Stone, Rasmus Thomsen,
|
||||
Marco Trevisan (Treviño), Daniel van Vugt
|
||||
|
||||
Translators:
|
||||
Emin Tufan Çetin [tr], Dušan Kazik [sk], Matej Urbančič [sl]
|
||||
|
||||
3.28.0
|
||||
======
|
||||
* Fix xdg-foreign regression [Carlos; #63]
|
||||
|
@ -692,7 +692,7 @@ Cally_@LIBMUTTER_API_VERSION@_gir_CFLAGS = $(AM_CPPFLAGS) $(CLUTTER_CFLAGS)
|
||||
Cally_@LIBMUTTER_API_VERSION@_gir_SCANNERFLAGS = \
|
||||
--warn-all \
|
||||
--c-include='cally/cally.h' \
|
||||
--pkg-export=mutter-cally-@LIBMUTTER_API_VERSION@ \
|
||||
--pkg-export=mutter-clutter-@LIBMUTTER_API_VERSION@ \
|
||||
--include-uninstalled=$(top_builddir)/clutter/Clutter-@LIBMUTTER_API_VERSION@.gir
|
||||
|
||||
INTROSPECTION_GIRS += Cally-@LIBMUTTER_API_VERSION@.gir
|
||||
|
@ -1095,7 +1095,7 @@ clutter_event_set_device (ClutterEvent *event,
|
||||
{
|
||||
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
|
||||
|
||||
real_event->device = device;
|
||||
g_set_object (&real_event->device, device);
|
||||
}
|
||||
|
||||
switch (event->type)
|
||||
@ -1364,8 +1364,8 @@ clutter_event_copy (const ClutterEvent *event)
|
||||
{
|
||||
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
|
||||
|
||||
new_real_event->device = real_event->device;
|
||||
new_real_event->source_device = real_event->source_device;
|
||||
g_set_object (&new_real_event->device, real_event->device);
|
||||
g_set_object (&new_real_event->source_device, real_event->source_device);
|
||||
new_real_event->delta_x = real_event->delta_x;
|
||||
new_real_event->delta_y = real_event->delta_y;
|
||||
new_real_event->is_pointer_emulated = real_event->is_pointer_emulated;
|
||||
@ -1435,6 +1435,14 @@ clutter_event_free (ClutterEvent *event)
|
||||
{
|
||||
_clutter_backend_free_event_data (clutter_get_default_backend (), event);
|
||||
|
||||
if (is_event_allocated (event))
|
||||
{
|
||||
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
|
||||
|
||||
g_clear_object (&real_event->device);
|
||||
g_clear_object (&real_event->source_device);
|
||||
}
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
@ -1689,7 +1697,7 @@ clutter_event_set_source_device (ClutterEvent *event,
|
||||
return;
|
||||
|
||||
real_event = (ClutterEventPrivate *) event;
|
||||
real_event->source_device = device;
|
||||
g_set_object (&real_event->source_device, device);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,6 +353,7 @@ clutter_input_method_notify_key_event (ClutterInputMethod *im,
|
||||
copy = clutter_event_copy (event);
|
||||
clutter_event_set_flags (copy, clutter_event_get_flags (event) |
|
||||
CLUTTER_EVENT_FLAG_INPUT_METHOD);
|
||||
clutter_event_set_source_device (copy, clutter_event_get_device (copy));
|
||||
clutter_event_put (copy);
|
||||
clutter_event_free (copy);
|
||||
}
|
||||
|
@ -3722,6 +3722,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_AVAILABLE_IN_ALL
|
||||
void clutter_stage_ensure_redraw (ClutterStage *stage);
|
||||
|
||||
CLUTTER_AVAILABLE_IN_ALL
|
||||
gboolean clutter_stage_is_redraw_queued (ClutterStage *stage);
|
||||
|
||||
#ifdef CLUTTER_ENABLE_EXPERIMENTAL_API
|
||||
CLUTTER_AVAILABLE_IN_1_14
|
||||
void clutter_stage_set_sync_delay (ClutterStage *stage,
|
||||
|
@ -2830,6 +2830,10 @@ clutter_text_key_focus_in (ClutterActor *actor)
|
||||
if (method && priv->editable)
|
||||
{
|
||||
clutter_input_method_focus_in (method, priv->input_focus);
|
||||
clutter_input_focus_set_content_purpose (priv->input_focus,
|
||||
priv->input_purpose);
|
||||
clutter_input_focus_set_content_hints (priv->input_focus,
|
||||
priv->input_hints);
|
||||
update_cursor_location (CLUTTER_TEXT (actor));
|
||||
}
|
||||
|
||||
@ -4511,6 +4515,27 @@ buffer_deleted_text (ClutterTextBuffer *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_text_queue_redraw_or_relayout (ClutterText *self)
|
||||
{
|
||||
ClutterActor *actor = CLUTTER_ACTOR (self);
|
||||
gfloat preferred_width;
|
||||
gfloat preferred_height;
|
||||
|
||||
clutter_text_dirty_cache (self);
|
||||
|
||||
/* we're using our private implementations here to avoid the caching done by ClutterActor */
|
||||
clutter_text_get_preferred_width (actor, -1, NULL, &preferred_width);
|
||||
clutter_text_get_preferred_height (actor, preferred_width, NULL, &preferred_height);
|
||||
|
||||
if (clutter_actor_has_allocation (actor) &&
|
||||
(fabsf (preferred_width - clutter_actor_get_width (actor)) > 0.001 ||
|
||||
fabsf (preferred_height - clutter_actor_get_height (actor)) > 0.001))
|
||||
clutter_actor_queue_relayout (actor);
|
||||
else
|
||||
clutter_text_queue_redraw (actor);
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_notify_text (ClutterTextBuffer *buffer,
|
||||
GParamSpec *spec,
|
||||
@ -4518,9 +4543,7 @@ buffer_notify_text (ClutterTextBuffer *buffer,
|
||||
{
|
||||
g_object_freeze_notify (G_OBJECT (self));
|
||||
|
||||
clutter_text_dirty_cache (self);
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||
clutter_text_queue_redraw_or_relayout (self);
|
||||
|
||||
g_signal_emit (self, text_signals[TEXT_CHANGED], 0);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]);
|
||||
@ -4872,8 +4895,7 @@ clutter_text_set_cursor_visible (ClutterText *self,
|
||||
{
|
||||
priv->cursor_visible = cursor_visible;
|
||||
|
||||
clutter_text_dirty_cache (self);
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||
clutter_text_queue_redraw_or_relayout (self);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_VISIBLE]);
|
||||
}
|
||||
@ -5774,9 +5796,7 @@ clutter_text_set_line_alignment (ClutterText *self,
|
||||
{
|
||||
priv->alignment = alignment;
|
||||
|
||||
clutter_text_dirty_cache (self);
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||
clutter_text_queue_redraw_or_relayout (self);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_ALIGNMENT]);
|
||||
}
|
||||
@ -5831,9 +5851,7 @@ clutter_text_set_use_markup (ClutterText *self,
|
||||
if (setting)
|
||||
clutter_text_set_markup_internal (self, text);
|
||||
|
||||
clutter_text_dirty_cache (self);
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||
clutter_text_queue_redraw_or_relayout (self);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5880,9 +5898,7 @@ clutter_text_set_justify (ClutterText *self,
|
||||
{
|
||||
priv->justify = justify;
|
||||
|
||||
clutter_text_dirty_cache (self);
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||
clutter_text_queue_redraw_or_relayout (self);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_JUSTIFY]);
|
||||
}
|
||||
@ -6449,8 +6465,7 @@ clutter_text_set_preedit_string (ClutterText *self,
|
||||
priv->preedit_set = TRUE;
|
||||
}
|
||||
|
||||
clutter_text_dirty_cache (self);
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||
clutter_text_queue_redraw_or_relayout (self);
|
||||
}
|
||||
|
||||
|
||||
@ -6512,7 +6527,9 @@ clutter_text_set_input_hints (ClutterText *self,
|
||||
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
||||
|
||||
self->priv->input_hints = hints;
|
||||
clutter_input_focus_set_content_hints (self->priv->input_focus, hints);
|
||||
|
||||
if (clutter_input_focus_is_focused (self->priv->input_focus))
|
||||
clutter_input_focus_set_content_hints (self->priv->input_focus, hints);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_INPUT_HINTS]);
|
||||
}
|
||||
|
||||
@ -6531,7 +6548,9 @@ clutter_text_set_input_purpose (ClutterText *self,
|
||||
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
||||
|
||||
self->priv->input_purpose = purpose;
|
||||
clutter_input_focus_set_content_purpose (self->priv->input_focus, purpose);
|
||||
|
||||
if (clutter_input_focus_is_focused (self->priv->input_focus))
|
||||
clutter_input_focus_set_content_purpose (self->priv->input_focus, purpose);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_INPUT_PURPOSE]);
|
||||
}
|
||||
|
||||
|
@ -324,7 +324,6 @@ new_absolute_motion_event (ClutterInputDevice *input_device,
|
||||
_clutter_evdev_event_set_time_usec (event, time_us);
|
||||
event->motion.time = us2ms (time_us);
|
||||
event->motion.stage = stage;
|
||||
event->motion.device = seat->core_pointer;
|
||||
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
|
||||
event->motion.x = x;
|
||||
event->motion.y = y;
|
||||
@ -332,6 +331,7 @@ new_absolute_motion_event (ClutterInputDevice *input_device,
|
||||
&event->motion.x,
|
||||
&event->motion.y);
|
||||
event->motion.axes = axes;
|
||||
clutter_event_set_device (event, seat->core_pointer);
|
||||
clutter_event_set_source_device (event, input_device);
|
||||
|
||||
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
|
||||
@ -519,7 +519,6 @@ notify_proximity (ClutterInputDevice *input_device,
|
||||
|
||||
event->proximity.time = us2ms (time_us);
|
||||
event->proximity.stage = CLUTTER_STAGE (stage);
|
||||
event->proximity.device = seat->core_pointer;
|
||||
clutter_event_set_device_tool (event, device_evdev->last_tool);
|
||||
clutter_event_set_device (event, seat->core_pointer);
|
||||
clutter_event_set_source_device (event, input_device);
|
||||
@ -793,10 +792,12 @@ evdev_add_device (ClutterDeviceManagerEvdev *manager_evdev,
|
||||
if (priv->main_seat->libinput_seat == NULL)
|
||||
seat = priv->main_seat;
|
||||
else
|
||||
seat = clutter_seat_evdev_new (manager_evdev);
|
||||
{
|
||||
seat = clutter_seat_evdev_new (manager_evdev);
|
||||
priv->seats = g_slist_append (priv->seats, seat);
|
||||
}
|
||||
|
||||
clutter_seat_evdev_set_libinput_seat (seat, libinput_seat);
|
||||
priv->seats = g_slist_append (priv->seats, seat);
|
||||
}
|
||||
|
||||
device = _clutter_input_device_evdev_new (manager, seat, libinput_device);
|
||||
@ -919,7 +920,6 @@ clutter_device_manager_evdev_get_device (ClutterDeviceManager *manager,
|
||||
ClutterDeviceManagerEvdev *manager_evdev;
|
||||
ClutterDeviceManagerEvdevPrivate *priv;
|
||||
GSList *l;
|
||||
GSList *device_it;
|
||||
|
||||
manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager);
|
||||
priv = manager_evdev->priv;
|
||||
@ -927,14 +927,10 @@ clutter_device_manager_evdev_get_device (ClutterDeviceManager *manager,
|
||||
for (l = priv->seats; l; l = l->next)
|
||||
{
|
||||
ClutterSeatEvdev *seat = l->data;
|
||||
ClutterInputDevice *device = clutter_seat_evdev_get_device (seat, id);
|
||||
|
||||
for (device_it = seat->devices; device_it; device_it = device_it->next)
|
||||
{
|
||||
ClutterInputDevice *device = device_it->data;
|
||||
|
||||
if (clutter_input_device_get_device_id (device) == id)
|
||||
return device;
|
||||
}
|
||||
if (device)
|
||||
return device;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -1967,6 +1963,7 @@ clutter_device_manager_evdev_constructed (GObject *gobject)
|
||||
xkb_context_unref (ctx);
|
||||
|
||||
priv->main_seat = clutter_seat_evdev_new (manager_evdev);
|
||||
priv->seats = g_slist_append (priv->seats, priv->main_seat);
|
||||
|
||||
dispatch_libinput (manager_evdev);
|
||||
|
||||
|
@ -433,6 +433,8 @@ key_event_is_modifier (ClutterEvent *event)
|
||||
case XKB_KEY_Super_R:
|
||||
case XKB_KEY_Hyper_L:
|
||||
case XKB_KEY_Hyper_R:
|
||||
case XKB_KEY_Caps_Lock:
|
||||
case XKB_KEY_Shift_Lock:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
@ -584,6 +586,12 @@ handle_stickykeys_press (ClutterEvent *event,
|
||||
}
|
||||
|
||||
depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED);
|
||||
/* Ignore the lock modifier mask, that one cannot be sticky, yet the
|
||||
* CAPS_LOCK key itself counts as a modifier as it might be remapped
|
||||
* to some other modifier which can be sticky.
|
||||
*/
|
||||
depressed_mods &= ~CLUTTER_LOCK_MASK;
|
||||
|
||||
new_latched_mask = device->stickykeys_latched_mask;
|
||||
new_locked_mask = device->stickykeys_locked_mask;
|
||||
|
||||
@ -1122,6 +1130,10 @@ clutter_input_device_evdev_process_kbd_a11y_event (ClutterEvent *e
|
||||
{
|
||||
ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device);
|
||||
|
||||
/* Ignore key events injected from IM */
|
||||
if (event->key.flags & CLUTTER_EVENT_FLAG_INPUT_METHOD)
|
||||
goto emit_event;
|
||||
|
||||
if (!device_evdev->a11y_flags & CLUTTER_A11Y_KEYBOARD_ENABLED)
|
||||
goto emit_event;
|
||||
|
||||
|
@ -385,7 +385,6 @@ new_absolute_motion_event (ClutterSeatEvdev *seat,
|
||||
_clutter_evdev_event_set_time_usec (event, time_us);
|
||||
event->motion.time = us2ms (time_us);
|
||||
event->motion.stage = stage;
|
||||
event->motion.device = seat->core_pointer;
|
||||
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
|
||||
event->motion.x = x;
|
||||
event->motion.y = y;
|
||||
@ -631,7 +630,6 @@ notify_scroll (ClutterInputDevice *input_device,
|
||||
_clutter_evdev_event_set_time_usec (event, time_us);
|
||||
event->scroll.time = us2ms (time_us);
|
||||
event->scroll.stage = CLUTTER_STAGE (stage);
|
||||
event->scroll.device = seat->core_pointer;
|
||||
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
|
||||
|
||||
/* libinput pointer axis events are in pointer motion coordinate space.
|
||||
@ -684,7 +682,6 @@ notify_discrete_scroll (ClutterInputDevice *input_device,
|
||||
_clutter_evdev_event_set_time_usec (event, time_us);
|
||||
event->scroll.time = us2ms (time_us);
|
||||
event->scroll.stage = CLUTTER_STAGE (stage);
|
||||
event->scroll.device = seat->core_pointer;
|
||||
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
|
||||
|
||||
event->scroll.direction = direction;
|
||||
@ -813,7 +810,6 @@ clutter_seat_evdev_notify_touch_event (ClutterSeatEvdev *seat,
|
||||
_clutter_evdev_event_set_time_usec (event, time_us);
|
||||
event->touch.time = us2ms (time_us);
|
||||
event->touch.stage = CLUTTER_STAGE (stage);
|
||||
event->touch.device = seat->core_pointer;
|
||||
event->touch.x = x;
|
||||
event->touch.y = y;
|
||||
clutter_input_device_evdev_translate_coordinates (input_device, stage,
|
||||
@ -858,6 +854,24 @@ clutter_seat_evdev_free (ClutterSeatEvdev *seat)
|
||||
g_free (seat);
|
||||
}
|
||||
|
||||
ClutterInputDevice *
|
||||
clutter_seat_evdev_get_device (ClutterSeatEvdev *seat,
|
||||
gint id)
|
||||
{
|
||||
ClutterInputDevice *device;
|
||||
GSList *l;
|
||||
|
||||
for (l = seat->devices; l; l = l->next)
|
||||
{
|
||||
device = l->data;
|
||||
|
||||
if (clutter_input_device_get_device_id (device) == id)
|
||||
return device;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_seat_evdev_set_stage (ClutterSeatEvdev *seat,
|
||||
ClutterStage *stage)
|
||||
|
@ -139,6 +139,9 @@ void clutter_seat_evdev_set_libinput_seat (ClutterSeatEvdev *seat,
|
||||
|
||||
void clutter_seat_evdev_sync_leds (ClutterSeatEvdev *seat);
|
||||
|
||||
ClutterInputDevice * clutter_seat_evdev_get_device (ClutterSeatEvdev *seat,
|
||||
gint id);
|
||||
|
||||
ClutterTouchState * clutter_seat_evdev_acquire_touch_state (ClutterSeatEvdev *seat,
|
||||
int device_slot);
|
||||
|
||||
|
@ -185,6 +185,22 @@ clutter_virtual_input_device_evdev_notify_absolute_motion (ClutterVirtualInputDe
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
translate_to_evdev_button (int button)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRIMARY:
|
||||
return BTN_LEFT;
|
||||
case CLUTTER_BUTTON_SECONDARY:
|
||||
return BTN_RIGHT;
|
||||
case CLUTTER_BUTTON_MIDDLE:
|
||||
return BTN_MIDDLE;
|
||||
default:
|
||||
return button + (BTN_LEFT - 1) - 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_virtual_input_device_evdev_notify_button (ClutterVirtualInputDevice *virtual_device,
|
||||
uint64_t time_us,
|
||||
@ -194,30 +210,33 @@ clutter_virtual_input_device_evdev_notify_button (ClutterVirtualInputDevice *vir
|
||||
ClutterVirtualInputDeviceEvdev *virtual_evdev =
|
||||
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
|
||||
int button_count;
|
||||
int evdev_button;
|
||||
|
||||
if (time_us == CLUTTER_CURRENT_TIME)
|
||||
time_us = g_get_monotonic_time ();
|
||||
|
||||
if (get_button_type (button) != EVDEV_BUTTON_TYPE_BUTTON)
|
||||
evdev_button = translate_to_evdev_button (button);
|
||||
|
||||
if (get_button_type (evdev_button) != EVDEV_BUTTON_TYPE_BUTTON)
|
||||
{
|
||||
g_warning ("Unknown/invalid virtual device button 0x%x pressed",
|
||||
button);
|
||||
evdev_button);
|
||||
return;
|
||||
}
|
||||
|
||||
button_count = update_button_count (virtual_evdev, button, button_state);
|
||||
button_count = update_button_count (virtual_evdev, evdev_button, button_state);
|
||||
if (button_count < 0 || button_count > 1)
|
||||
{
|
||||
g_warning ("Received multiple virtual 0x%x button %s (ignoring)", button,
|
||||
g_warning ("Received multiple virtual 0x%x button %s (ignoring)", evdev_button,
|
||||
button_state == CLUTTER_BUTTON_STATE_PRESSED ? "presses" : "releases");
|
||||
update_button_count (virtual_evdev, button, 1 - button_state);
|
||||
update_button_count (virtual_evdev, evdev_button, 1 - button_state);
|
||||
return;
|
||||
}
|
||||
|
||||
clutter_seat_evdev_notify_button (virtual_evdev->seat,
|
||||
virtual_evdev->device,
|
||||
time_us,
|
||||
button,
|
||||
evdev_button,
|
||||
button_state);
|
||||
}
|
||||
|
||||
|
@ -76,12 +76,12 @@ _clutter_key_event_new_from_evdev (ClutterInputDevice *device,
|
||||
else
|
||||
sym = XKB_KEY_NoSymbol;
|
||||
|
||||
event->key.device = core_device;
|
||||
event->key.stage = stage;
|
||||
event->key.time = _time;
|
||||
_clutter_xkb_translate_state (event, xkb_state, button_state);
|
||||
event->key.hardware_keycode = key;
|
||||
event->key.keyval = sym;
|
||||
clutter_event_set_device (event, core_device);
|
||||
clutter_event_set_source_device (event, device);
|
||||
|
||||
n = xkb_keysym_to_utf8 (sym, buffer, sizeof (buffer));
|
||||
|
@ -92,9 +92,9 @@ static gboolean perf_fake_mouse_cb (gpointer stage)
|
||||
event2->crossing.source = stage;
|
||||
event2->crossing.x = 10;
|
||||
event2->crossing.y = 10;
|
||||
event2->crossing.device = device;
|
||||
event2->crossing.related = NULL;
|
||||
|
||||
clutter_event_set_device (event2, device);
|
||||
clutter_input_device_update_from_event (device, event2, TRUE);
|
||||
|
||||
clutter_event_put (event2);
|
||||
@ -104,7 +104,7 @@ static gboolean perf_fake_mouse_cb (gpointer stage)
|
||||
|
||||
clutter_actor_get_size (stage, &w, &h);
|
||||
event->motion.stage = stage;
|
||||
event->motion.device = device;
|
||||
clutter_event_set_device (event, device);
|
||||
|
||||
/* called about every 60fps, and do 10 picks per stage */
|
||||
for (i = 0; i < 10; i++)
|
||||
|
@ -452,7 +452,7 @@ libmutter_cogl_@LIBMUTTER_API_VERSION@_la_LDFLAGS = \
|
||||
-avoid-version \
|
||||
-export-dynamic \
|
||||
-rpath $(mutterlibdir) \
|
||||
-export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_texture_set_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_|_cogl_winsys_glx_get_vtable|_cogl_winsys_egl_xlib_get_vtable|_cogl_winsys_egl_get_vtable|_cogl_closure_disconnect|_cogl_onscreen_notify_complete|_cogl_onscreen_notify_frame_sync|_cogl_winsys_egl_renderer_connect_common|_cogl_winsys_error_quark|_cogl_set_error|_cogl_poll_renderer_add_fd|_cogl_poll_renderer_add_idle|_cogl_framebuffer_winsys_update_size|_cogl_winsys_egl_make_current|_cogl_pixel_format_get_bytes_per_pixel).*"
|
||||
-export-symbols-regex "^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_texture_set_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_|_cogl_winsys_glx_get_vtable|_cogl_winsys_egl_xlib_get_vtable|_cogl_winsys_egl_get_vtable|_cogl_closure_disconnect|_cogl_onscreen_notify_complete|_cogl_onscreen_notify_frame_sync|_cogl_winsys_egl_renderer_connect_common|_cogl_winsys_error_quark|_cogl_set_error|_cogl_poll_renderer_add_fd|_cogl_poll_renderer_add_idle|_cogl_framebuffer_winsys_update_size|_cogl_winsys_egl_make_current|_cogl_winsys_egl_ensure_current|_cogl_pixel_format_get_bytes_per_pixel).*"
|
||||
|
||||
libmutter_cogl_@LIBMUTTER_API_VERSION@_la_SOURCES = $(cogl_sources_c)
|
||||
nodist_libmutter_cogl_@LIBMUTTER_API_VERSION@_la_SOURCES = $(BUILT_SOURCES)
|
||||
|
@ -1043,5 +1043,6 @@ cogl_atlas_texture_vtable =
|
||||
_cogl_atlas_texture_get_gl_format,
|
||||
_cogl_atlas_texture_get_type,
|
||||
NULL, /* is_foreign */
|
||||
NULL /* set_auto_mipmap */
|
||||
NULL, /* set_auto_mipmap */
|
||||
NULL /* is_get_data_supported */
|
||||
};
|
||||
|
@ -263,6 +263,7 @@ typedef enum _CoglFeatureID
|
||||
COGL_FEATURE_ID_TEXTURE_RG,
|
||||
COGL_FEATURE_ID_BUFFER_AGE,
|
||||
COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL,
|
||||
COGL_FEATURE_ID_UNSTABLE_TEXTURES,
|
||||
|
||||
/*< private >*/
|
||||
_COGL_N_FEATURE_IDS /*< skip >*/
|
||||
|
@ -210,6 +210,9 @@ struct _CoglDriverVtable
|
||||
int rowstride,
|
||||
uint8_t *data);
|
||||
|
||||
CoglBool
|
||||
(* texture_2d_is_get_data_supported) (CoglTexture2D *tex_2d);
|
||||
|
||||
/* Prepares for drawing by flushing the journal, framebuffer state,
|
||||
* pipeline state and attribute state.
|
||||
*/
|
||||
|
@ -109,7 +109,11 @@ _cogl_object_default_unref (void *object)
|
||||
void
|
||||
cogl_object_unref (void *obj)
|
||||
{
|
||||
void (* unref_func) (void *) = ((CoglObject *) obj)->klass->virt_unref;
|
||||
void (* unref_func) (void *);
|
||||
|
||||
_COGL_RETURN_IF_FAIL (obj != NULL);
|
||||
|
||||
unref_func = ((CoglObject *) obj)->klass->virt_unref;
|
||||
unref_func (obj);
|
||||
}
|
||||
|
||||
|
@ -454,6 +454,14 @@ _cogl_sub_texture_get_type (CoglTexture *tex)
|
||||
return _cogl_texture_get_type (sub_tex->full_texture);
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
_cogl_sub_texture_is_get_data_supported (CoglTexture *tex)
|
||||
{
|
||||
CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex);
|
||||
|
||||
return cogl_texture_is_get_data_supported (sub_tex->full_texture);
|
||||
}
|
||||
|
||||
static const CoglTextureVtable
|
||||
cogl_sub_texture_vtable =
|
||||
{
|
||||
@ -476,5 +484,6 @@ cogl_sub_texture_vtable =
|
||||
_cogl_sub_texture_get_gl_format,
|
||||
_cogl_sub_texture_get_type,
|
||||
NULL, /* is_foreign */
|
||||
NULL /* set_auto_mipmap */
|
||||
NULL, /* set_auto_mipmap */
|
||||
_cogl_sub_texture_is_get_data_supported
|
||||
};
|
||||
|
@ -1542,5 +1542,6 @@ cogl_texture_2d_sliced_vtable =
|
||||
_cogl_texture_2d_sliced_get_gl_format,
|
||||
_cogl_texture_2d_sliced_get_type,
|
||||
_cogl_texture_2d_sliced_is_foreign,
|
||||
NULL /* set_auto_mipmap */
|
||||
NULL, /* set_auto_mipmap */
|
||||
NULL /* is_get_data_supported */
|
||||
};
|
||||
|
@ -94,6 +94,15 @@ _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
|
||||
tex_2d->auto_mipmap = value;
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
_cogl_texture_2d_is_get_data_supported (CoglTexture *tex)
|
||||
{
|
||||
CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
|
||||
CoglContext *ctx = tex->context;
|
||||
|
||||
return ctx->driver_vtable->texture_2d_is_get_data_supported (tex_2d);
|
||||
}
|
||||
|
||||
CoglTexture2D *
|
||||
_cogl_texture_2d_create_base (CoglContext *ctx,
|
||||
int width,
|
||||
@ -693,5 +702,6 @@ cogl_texture_2d_vtable =
|
||||
_cogl_texture_2d_get_gl_format,
|
||||
_cogl_texture_2d_get_type,
|
||||
_cogl_texture_2d_is_foreign,
|
||||
_cogl_texture_2d_set_auto_mipmap
|
||||
_cogl_texture_2d_set_auto_mipmap,
|
||||
_cogl_texture_2d_is_get_data_supported
|
||||
};
|
||||
|
@ -755,5 +755,6 @@ cogl_texture_3d_vtable =
|
||||
_cogl_texture_3d_get_gl_format,
|
||||
_cogl_texture_3d_get_type,
|
||||
NULL, /* is_foreign */
|
||||
_cogl_texture_3d_set_auto_mipmap
|
||||
_cogl_texture_3d_set_auto_mipmap,
|
||||
NULL /* is_get_data_supported */
|
||||
};
|
||||
|
@ -149,6 +149,8 @@ struct _CoglTextureVtable
|
||||
/* Only needs to be implemented if is_primitive == TRUE */
|
||||
void (* set_auto_mipmap) (CoglTexture *texture,
|
||||
CoglBool value);
|
||||
|
||||
CoglBool (* is_get_data_supported) (CoglTexture *texture);
|
||||
};
|
||||
|
||||
typedef enum _CoglTextureSoureType {
|
||||
|
@ -773,5 +773,6 @@ cogl_texture_rectangle_vtable =
|
||||
_cogl_texture_rectangle_get_gl_format,
|
||||
_cogl_texture_rectangle_get_type,
|
||||
_cogl_texture_rectangle_is_foreign,
|
||||
_cogl_texture_rectangle_set_auto_mipmap
|
||||
_cogl_texture_rectangle_set_auto_mipmap,
|
||||
NULL /* is_get_data_supported */
|
||||
};
|
||||
|
@ -205,6 +205,15 @@ _cogl_texture_is_foreign (CoglTexture *texture)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CoglBool
|
||||
cogl_texture_is_get_data_supported (CoglTexture *texture)
|
||||
{
|
||||
if (texture->vtable->is_get_data_supported)
|
||||
return texture->vtable->is_get_data_supported (texture);
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cogl_texture_get_width (CoglTexture *texture)
|
||||
{
|
||||
|
@ -511,6 +511,12 @@ CoglBool
|
||||
cogl_texture_allocate (CoglTexture *texture,
|
||||
CoglError **error);
|
||||
|
||||
/**
|
||||
* cogl_texture_is_get_data_supported: (skip)
|
||||
*/
|
||||
CoglBool
|
||||
cogl_texture_is_get_data_supported (CoglTexture *texture);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_TEXTURE_H__ */
|
||||
|
@ -398,6 +398,8 @@ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/
|
||||
* supported with CoglBufferAccess including write support.
|
||||
* @COGL_FEATURE_DEPTH_TEXTURE: Whether #CoglFramebuffer support rendering the
|
||||
* depth buffer to a texture.
|
||||
* @COGL_FEATURE_UNSTABLE_TEXTURES: Whether textures require redrawing on
|
||||
* resume or not.
|
||||
*
|
||||
* Flags for the supported features.
|
||||
*
|
||||
@ -428,7 +430,8 @@ typedef enum
|
||||
COGL_FEATURE_MAP_BUFFER_FOR_READ = (1 << 21),
|
||||
COGL_FEATURE_MAP_BUFFER_FOR_WRITE = (1 << 22),
|
||||
COGL_FEATURE_ONSCREEN_MULTIPLE = (1 << 23),
|
||||
COGL_FEATURE_DEPTH_TEXTURE = (1 << 24)
|
||||
COGL_FEATURE_DEPTH_TEXTURE = (1 << 24),
|
||||
COGL_FEATURE_UNSTABLE_TEXTURES = (1 << 25)
|
||||
} CoglFeatureFlags;
|
||||
|
||||
/**
|
||||
|
@ -1412,22 +1412,12 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
|
||||
if (!cogl_is_offscreen (framebuffer))
|
||||
y = framebuffer_height - y - height;
|
||||
|
||||
required_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
|
||||
format,
|
||||
&gl_intformat,
|
||||
&gl_format,
|
||||
&gl_type);
|
||||
#if HAVE_COGL_GL
|
||||
/* As we are reading pixels, we want to consider the bitmap according to
|
||||
* its real pixel format, not the swizzled channels we pretend face to the
|
||||
* pipeline.
|
||||
*/
|
||||
if ((ctx->driver == COGL_DRIVER_GL || ctx->driver == COGL_DRIVER_GL3) &&
|
||||
(format == COGL_PIXEL_FORMAT_BGRA_8888 ||
|
||||
format == COGL_PIXEL_FORMAT_BGRA_8888_PRE) &&
|
||||
_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE))
|
||||
gl_format = GL_BGRA;
|
||||
#endif
|
||||
required_format = ctx->driver_vtable->pixel_format_to_gl_with_target (ctx,
|
||||
framebuffer->internal_format,
|
||||
format,
|
||||
&gl_intformat,
|
||||
&gl_format,
|
||||
&gl_type);
|
||||
|
||||
/* NB: All offscreen rendering is done upside down so there is no need
|
||||
* to flip in this case... */
|
||||
|
@ -116,4 +116,7 @@ _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d,
|
||||
int rowstride,
|
||||
uint8_t *data);
|
||||
|
||||
CoglBool
|
||||
_cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d);
|
||||
|
||||
#endif /* _COGL_TEXTURE_2D_GL_PRIVATE_H_ */
|
||||
|
@ -470,7 +470,12 @@ allocate_custom_egl_image_external (CoglTexture2D *tex_2d,
|
||||
{
|
||||
CoglTexture *tex = COGL_TEXTURE (tex_2d);
|
||||
CoglContext *ctx = tex->context;
|
||||
CoglPixelFormat internal_format = loader->src.egl_image_external.format;
|
||||
CoglPixelFormat external_format;
|
||||
CoglPixelFormat internal_format;
|
||||
|
||||
external_format = loader->src.egl_image_external.format;
|
||||
internal_format = _cogl_texture_determine_internal_format (tex,
|
||||
external_format);
|
||||
|
||||
_cogl_gl_util_clear_gl_errors (ctx);
|
||||
|
||||
@ -854,13 +859,22 @@ _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d,
|
||||
width,
|
||||
bpp);
|
||||
|
||||
_cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
|
||||
_cogl_bind_gl_texture_transient (tex_2d->gl_target,
|
||||
tex_2d->gl_texture,
|
||||
tex_2d->is_foreign);
|
||||
|
||||
ctx->texture_driver->gl_get_tex_image (ctx,
|
||||
GL_TEXTURE_2D,
|
||||
tex_2d->gl_target,
|
||||
gl_format,
|
||||
gl_type,
|
||||
data);
|
||||
}
|
||||
|
||||
CoglBool
|
||||
_cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d)
|
||||
{
|
||||
if (tex_2d->gl_target == GL_TEXTURE_EXTERNAL_OES)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -714,6 +714,7 @@ _cogl_driver_gl =
|
||||
_cogl_texture_2d_gl_generate_mipmap,
|
||||
_cogl_texture_2d_gl_copy_from_bitmap,
|
||||
_cogl_texture_2d_gl_get_data,
|
||||
_cogl_texture_2d_gl_is_get_data_supported,
|
||||
_cogl_gl_flush_attributes_state,
|
||||
_cogl_clip_stack_gl_flush,
|
||||
_cogl_buffer_gl_create,
|
||||
|
@ -493,6 +493,7 @@ _cogl_driver_gles =
|
||||
_cogl_texture_2d_gl_generate_mipmap,
|
||||
_cogl_texture_2d_gl_copy_from_bitmap,
|
||||
NULL, /* texture_2d_get_data */
|
||||
NULL, /* texture_2d_is_get_data_supported */
|
||||
_cogl_gl_flush_attributes_state,
|
||||
_cogl_clip_stack_gl_flush,
|
||||
_cogl_buffer_gl_create,
|
||||
|
@ -82,6 +82,7 @@ _cogl_driver_nop =
|
||||
_cogl_texture_2d_nop_generate_mipmap,
|
||||
_cogl_texture_2d_nop_copy_from_bitmap,
|
||||
NULL, /* texture_2d_get_data */
|
||||
NULL, /* texture_2d_is_get_data_supported */
|
||||
_cogl_nop_flush_attributes_state,
|
||||
_cogl_clip_stack_nop_flush,
|
||||
};
|
||||
|
@ -1180,5 +1180,6 @@ cogl_texture_pixmap_x11_vtable =
|
||||
_cogl_texture_pixmap_x11_get_gl_format,
|
||||
_cogl_texture_pixmap_x11_get_type,
|
||||
NULL, /* is_foreign */
|
||||
NULL /* set_auto_mipmap */
|
||||
NULL, /* set_auto_mipmap */
|
||||
NULL /* is_get_data_supported */
|
||||
};
|
||||
|
@ -181,6 +181,9 @@ _cogl_winsys_egl_make_current (CoglDisplay *display,
|
||||
EGLSurface read,
|
||||
EGLContext context);
|
||||
|
||||
EGLBoolean
|
||||
_cogl_winsys_egl_ensure_current (CoglDisplay *display);
|
||||
|
||||
#ifdef EGL_KHR_image_base
|
||||
EGLImageKHR
|
||||
_cogl_egl_create_image (CoglContext *ctx,
|
||||
|
@ -309,6 +309,18 @@ _cogl_winsys_egl_make_current (CoglDisplay *display,
|
||||
return ret;
|
||||
}
|
||||
|
||||
EGLBoolean
|
||||
_cogl_winsys_egl_ensure_current (CoglDisplay *display)
|
||||
{
|
||||
CoglDisplayEGL *egl_display = display->winsys;
|
||||
CoglRendererEGL *egl_renderer = display->renderer->winsys;
|
||||
|
||||
return eglMakeCurrent (egl_renderer->edpy,
|
||||
egl_display->current_draw_surface,
|
||||
egl_display->current_read_surface,
|
||||
egl_display->current_context);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_context (CoglDisplay *display)
|
||||
{
|
||||
@ -490,6 +502,7 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error)
|
||||
CoglRenderer *renderer = context->display->renderer;
|
||||
CoglDisplayEGL *egl_display = context->display->winsys;
|
||||
CoglRendererEGL *egl_renderer = renderer->winsys;
|
||||
CoglGpuInfo *info;
|
||||
|
||||
context->winsys = g_new0 (CoglContextEGL, 1);
|
||||
|
||||
@ -502,6 +515,16 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error)
|
||||
if (!_cogl_context_update_features (context, error))
|
||||
return FALSE;
|
||||
|
||||
info = &context->gpu;
|
||||
|
||||
if (info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
|
||||
{
|
||||
context->feature_flags |= COGL_FEATURE_UNSTABLE_TEXTURES;
|
||||
COGL_FLAGS_SET (context->features,
|
||||
COGL_FEATURE_ID_UNSTABLE_TEXTURES,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_SWAP_REGION)
|
||||
{
|
||||
COGL_FLAGS_SET (context->winsys_features,
|
||||
|
@ -832,12 +832,15 @@ update_winsys_features (CoglContext *context, CoglError **error)
|
||||
{
|
||||
CoglGLXDisplay *glx_display = context->display->winsys;
|
||||
CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
|
||||
CoglGpuInfo *info;
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (glx_display->glx_context, FALSE);
|
||||
|
||||
if (!_cogl_context_update_features (context, error))
|
||||
return FALSE;
|
||||
|
||||
info = &context->gpu;
|
||||
|
||||
memcpy (context->winsys_features,
|
||||
glx_renderer->base_winsys_features,
|
||||
sizeof (context->winsys_features));
|
||||
@ -850,7 +853,6 @@ update_winsys_features (CoglContext *context, CoglError **error)
|
||||
|
||||
if (glx_renderer->glXCopySubBuffer || context->glBlitFramebuffer)
|
||||
{
|
||||
CoglGpuInfo *info = &context->gpu;
|
||||
CoglGpuInfoArchitecture arch = info->architecture;
|
||||
|
||||
COGL_FLAGS_SET (context->winsys_features, COGL_WINSYS_FEATURE_SWAP_REGION, TRUE);
|
||||
@ -899,7 +901,6 @@ update_winsys_features (CoglContext *context, CoglError **error)
|
||||
}
|
||||
else
|
||||
{
|
||||
CoglGpuInfo *info = &context->gpu;
|
||||
if (glx_display->have_vblank_counter &&
|
||||
context->display->renderer->xlib_enable_threaded_swap_wait &&
|
||||
info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
|
||||
@ -921,6 +922,14 @@ update_winsys_features (CoglContext *context, CoglError **error)
|
||||
}
|
||||
}
|
||||
|
||||
if (info->vendor == COGL_GPU_INFO_VENDOR_NVIDIA)
|
||||
{
|
||||
context->feature_flags |= COGL_FEATURE_UNSTABLE_TEXTURES;
|
||||
COGL_FLAGS_SET (context->features,
|
||||
COGL_FEATURE_ID_UNSTABLE_TEXTURES,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
/* We'll manually handle queueing dirty events in response to
|
||||
* Expose events from X */
|
||||
COGL_FLAGS_SET (context->private_features,
|
||||
|
30
configure.ac
30
configure.ac
@ -2,7 +2,7 @@ AC_PREREQ(2.62)
|
||||
|
||||
m4_define([mutter_major_version], [3])
|
||||
m4_define([mutter_minor_version], [28])
|
||||
m4_define([mutter_micro_version], [0])
|
||||
m4_define([mutter_micro_version], [3])
|
||||
|
||||
m4_define([mutter_version],
|
||||
[mutter_major_version.mutter_minor_version.mutter_micro_version])
|
||||
@ -245,7 +245,7 @@ AC_ARG_ENABLE(remote-desktop,
|
||||
enable_remote_desktop=no
|
||||
)
|
||||
AS_IF([test "$enable_remote_desktop" = "yes"], [
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES libpipewire-0.1 >= 0.1.8"
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES libpipewire-0.2 >= 0.2.5"
|
||||
AC_DEFINE([HAVE_REMOTE_DESKTOP],[1], [Defined if screen cast and remote desktop support is enabled])
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_REMOTE_DESKTOP],[test "$enable_remote_desktop" = "yes"])
|
||||
@ -262,7 +262,19 @@ AC_SUBST(XWAYLAND_PATH)
|
||||
|
||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
||||
|
||||
MUTTER_NATIVE_BACKEND_MODULES="libdrm >= 2.4.83 libsystemd libinput >= 1.4 gudev-1.0 gbm >= 17.1"
|
||||
PKG_CHECK_MODULES(ELOGIND, [libelogind], [have_elogind=yes], [have_elogind=no])
|
||||
|
||||
if test x$have_elogind = xyes; then
|
||||
logind_provider="libelogind"
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES(SYSTEMD, [libsystemd], [have_systemd=yes], [have_systemd=no])
|
||||
|
||||
if test x$have_systemd = xyes -o -z "$logind_provider"; then
|
||||
logind_provider="libsystemd"
|
||||
fi
|
||||
|
||||
MUTTER_NATIVE_BACKEND_MODULES="libdrm $logind_provider libinput >= 1.4 gudev-1.0 gbm >= 10.3"
|
||||
|
||||
AC_ARG_ENABLE(native-backend,
|
||||
AS_HELP_STRING([--disable-native-backend], [disable mutter native (KMS) backend]),,
|
||||
@ -278,13 +290,24 @@ AS_IF([test "$have_native_backend" = "yes"], [
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_NATIVE_BACKEND],[test "$have_native_backend" = "yes"])
|
||||
|
||||
MUTTER_WAYLAND_EGLSTREAM_MODULES="wayland-eglstream-protocols"
|
||||
|
||||
AC_ARG_ENABLE(egl-device,
|
||||
AS_HELP_STRING([--enable-egl-device], [enable support for EGLDevice on top of KMS]),,
|
||||
enable_egl_device=no
|
||||
have_wayland_eglstream=no
|
||||
)
|
||||
AS_IF([test "$enable_egl_device" = "yes"], [
|
||||
AC_DEFINE([HAVE_EGL_DEVICE],[1], [Defined if EGLDevice support is enabled])
|
||||
PKG_CHECK_EXISTS([$MUTTER_WAYLAND_EGLSTREAM_MODULES], [have_wayland_eglstream=yes], [have_wayland_eglstream=no])
|
||||
])
|
||||
AS_IF([test "$have_wayland_eglstream" = "yes"], [
|
||||
AC_DEFINE([HAVE_WAYLAND_EGLSTREAM],[1],[Defined if Wayland EGLStream protocols are available])
|
||||
PKG_CHECK_MODULES(WAYLAND_EGLSTREAM, [$MUTTER_WAYLAND_EGLSTREAM_MODULES],
|
||||
[ac_wayland_eglstream_pkgdatadir=`$PKG_CONFIG --variable=pkgdatadir $MUTTER_WAYLAND_EGLSTREAM_MODULES`])
|
||||
AC_SUBST(WAYLAND_EGLSTREAM_DATADIR, $ac_wayland_eglstream_pkgdatadir)
|
||||
])
|
||||
AM_CONDITIONAL([HAVE_WAYLAND_EGLSTREAM],[test "$have_wayland_eglstream" = "yes"])
|
||||
|
||||
MUTTER_WAYLAND_MODULES="wayland-server >= 1.13.0"
|
||||
|
||||
@ -537,6 +560,7 @@ mutter-$VERSION
|
||||
Introspection: ${found_introspection}
|
||||
Session management: ${found_sm}
|
||||
Wayland: ${have_wayland}
|
||||
Wayland EGLStream: ${have_wayland_eglstream}
|
||||
Native (KMS) backend: ${have_native_backend}
|
||||
EGLDevice: ${enable_egl_device}
|
||||
Remote desktop: ${enable_remote_desktop}
|
||||
|
@ -120,10 +120,6 @@
|
||||
framebuffers instead of window content,
|
||||
to manage HiDPI monitors. Does not
|
||||
require a restart.
|
||||
• “remote-desktop” — enables remote desktop support. To support
|
||||
remote desktop with screen sharing,
|
||||
“screen-cast” must also be enabled.
|
||||
• “screen-cast” — enables screen cast support.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
|
@ -60,7 +60,7 @@
|
||||
gettext-domain="@GETTEXT_DOMAIN@">
|
||||
|
||||
<key name="xwayland-allow-grabs" type="b">
|
||||
<default>false</default>
|
||||
<default>true</default>
|
||||
<summary>Allow grabs with Xwayland</summary>
|
||||
<description>
|
||||
Allow keyboard grabs issued by X11 applications running in Xwayland
|
||||
@ -73,7 +73,7 @@
|
||||
</key>
|
||||
|
||||
<key name="xwayland-grab-access-rules" type="as">
|
||||
<default>[]</default>
|
||||
<default>['@XWAYLAND_GRAB_DEFAULT_ACCESS_RULES@']</default>
|
||||
<summary>Xwayland applications allowed to issue keyboard grabs</summary>
|
||||
<description>
|
||||
List the resource names or resource class of X11 windows either
|
||||
|
23
po/sl.po
23
po/sl.po
@ -10,8 +10,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: mutter master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
|
||||
"POT-Creation-Date: 2018-03-05 19:32+0000\n"
|
||||
"PO-Revision-Date: 2018-03-06 22:02+0100\n"
|
||||
"POT-Creation-Date: 2018-04-03 20:43+0000\n"
|
||||
"PO-Revision-Date: 2018-04-09 20:28+0200\n"
|
||||
"Last-Translator: Matej Urbančič <mateju@svn.gnome.org>\n"
|
||||
"Language-Team: Slovenian GNOME Translation Team <gnome-si@googlegroups.com>\n"
|
||||
"Language: sl_SI\n"
|
||||
@ -21,7 +21,7 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n"
|
||||
"%100==4 ? 3 : 0);\n"
|
||||
"X-Poedit-SourceCharset: utf-8\n"
|
||||
"X-Generator: Poedit 2.0.4\n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
|
||||
#: data/50-mutter-navigation.xml:6
|
||||
msgid "Navigation"
|
||||
@ -481,7 +481,7 @@ msgstr "Ponovno omogoči tipkovne bližnjice"
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:64
|
||||
msgid "Allow grabs with Xwayland"
|
||||
msgstr ""
|
||||
msgstr "Dovoli zajemanje z XWayland"
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:65
|
||||
msgid ""
|
||||
@ -491,10 +491,14 @@ msgid ""
|
||||
"window or be among the applications white-listed in key “xwayland-grab-"
|
||||
"access-rules”."
|
||||
msgstr ""
|
||||
"Upošteva zajeme s tipkovnico, ki jih sprožijo programi X11, zagnani v okolju "
|
||||
"Xwayland. Če naj se programski zajem upošteva, mora odjemalec ali poslati "
|
||||
"specifično sporočilo X11 na korensko okno ali pa mora biti zaveden na "
|
||||
"seznamu programov v ključu »xwayland-garb-access-rules«."
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:77
|
||||
msgid "Xwayland applications allowed to issue keyboard grabs"
|
||||
msgstr ""
|
||||
msgstr "Program XWayland ima dovoljenje za zajemanje s tipkovnico"
|
||||
|
||||
#: data/org.gnome.mutter.wayland.gschema.xml.in:78
|
||||
msgid ""
|
||||
@ -509,6 +513,15 @@ msgid ""
|
||||
"using the specific keyboard shortcut defined by the keybinding key “restore-"
|
||||
"shortcuts”."
|
||||
msgstr ""
|
||||
"Seznam imen ali razredov virov oken X11, ki lahko sprožijo zajeme v okolju "
|
||||
"Xwayland. Ime oziroma razred vira podanega okna X11 je mogoče pridobiti z "
|
||||
"ukazom »xprop WM_CLASS«. Uporaba pomožnih znakov » * « in » ? « je podprta. "
|
||||
"Vrednosti, ki se začnejo z znakom » ! « so uvrščeni na črni seznam. Ta "
|
||||
"seznam je obravnavan prednostno pred belim seznamom in prekliče zajeme na "
|
||||
"seznamu sistema. Privzeti seznam vključuje ključ: "
|
||||
"»@XWAYLAND_GRAB_DEFAULT_ACCESS_RULES@« Uporabniki lahko prekinejo obstoječi "
|
||||
"zajem z uporabo posebne tipkovne bližnjice, določene s tipkovnim ključem "
|
||||
"»restore-shortcuts«."
|
||||
|
||||
#. TRANSLATORS: This string refers to a button that switches between
|
||||
#. * different modes.
|
||||
|
@ -14,6 +14,7 @@ stackingdir = $(pkgdatadir)/tests/stacking
|
||||
dist_stacking_DATA = \
|
||||
tests/stacking/basic-x11.metatest \
|
||||
tests/stacking/basic-wayland.metatest \
|
||||
tests/stacking/closed-transient.metatest \
|
||||
tests/stacking/minimized.metatest \
|
||||
tests/stacking/mixed-windows.metatest \
|
||||
tests/stacking/set-parent.metatest \
|
||||
|
@ -91,6 +91,12 @@ mutter_built_sources += \
|
||||
gtk-text-input-protocol.c \
|
||||
gtk-text-input-server-protocol.h \
|
||||
$(NULL)
|
||||
|
||||
if HAVE_WAYLAND_EGLSTREAM
|
||||
mutter_built_sources += \
|
||||
wayland-eglstream-controller-server-protocol.h \
|
||||
$(NULL)
|
||||
endif
|
||||
endif
|
||||
|
||||
wayland_protocols = \
|
||||
@ -114,6 +120,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
||||
backends/meta-cursor-tracker-private.h \
|
||||
backends/meta-cursor-renderer.c \
|
||||
backends/meta-cursor-renderer.h \
|
||||
backends/meta-cursor-sprite-xcursor.c \
|
||||
backends/meta-cursor-sprite-xcursor.h \
|
||||
backends/meta-dnd-private.h \
|
||||
backends/meta-egl.c \
|
||||
backends/meta-egl.h \
|
||||
@ -151,16 +159,22 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
||||
backends/meta-output.h \
|
||||
backends/meta-pointer-constraint.c \
|
||||
backends/meta-pointer-constraint.h \
|
||||
backends/meta-screen-cast-window.c \
|
||||
backends/meta-screen-cast-window.h \
|
||||
backends/meta-settings.c \
|
||||
backends/meta-settings-private.h \
|
||||
backends/meta-stage.h \
|
||||
backends/meta-stage-private.h \
|
||||
backends/meta-stage.c \
|
||||
backends/meta-renderer.c \
|
||||
backends/meta-renderer.h \
|
||||
backends/meta-renderer-view.c \
|
||||
backends/meta-renderer-view.h \
|
||||
backends/meta-remote-access-controller.c \
|
||||
backends/meta-remote-access-controller-private.h \
|
||||
meta/meta-remote-access-controller.h \
|
||||
backends/edid-parse.c \
|
||||
backends/edid.h \
|
||||
backends/gsm-inhibitor-flag.h \
|
||||
backends/x11/meta-backend-x11.c \
|
||||
backends/x11/meta-backend-x11.h \
|
||||
backends/x11/meta-barrier-x11.c \
|
||||
@ -175,6 +189,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
||||
backends/x11/meta-gpu-xrandr.h \
|
||||
backends/x11/cm/meta-backend-x11-cm.c \
|
||||
backends/x11/cm/meta-backend-x11-cm.h \
|
||||
backends/x11/cm/meta-cursor-sprite-xfixes.c \
|
||||
backends/x11/cm/meta-cursor-sprite-xfixes.h \
|
||||
backends/x11/cm/meta-renderer-x11-cm.c \
|
||||
backends/x11/cm/meta-renderer-x11-cm.h \
|
||||
backends/x11/nested/meta-backend-x11-nested.c \
|
||||
@ -183,8 +199,6 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
||||
backends/x11/nested/meta-cursor-renderer-x11-nested.h \
|
||||
backends/x11/nested/meta-renderer-x11-nested.c \
|
||||
backends/x11/nested/meta-renderer-x11-nested.h \
|
||||
backends/x11/meta-idle-monitor-xsync.c \
|
||||
backends/x11/meta-idle-monitor-xsync.h \
|
||||
backends/x11/meta-input-settings-x11.c \
|
||||
backends/x11/meta-input-settings-x11.h \
|
||||
backends/x11/meta-monitor-manager-xrandr.c \
|
||||
@ -247,7 +261,7 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
||||
compositor/meta-window-actor.c \
|
||||
compositor/meta-window-actor-private.h \
|
||||
compositor/meta-window-group.c \
|
||||
compositor/meta-window-group.h \
|
||||
compositor/meta-window-group-private.h \
|
||||
compositor/meta-window-shape.c \
|
||||
compositor/region-utils.c \
|
||||
compositor/region-utils.h \
|
||||
@ -358,6 +372,10 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES += \
|
||||
backends/meta-screen-cast-monitor-stream.h \
|
||||
backends/meta-screen-cast-monitor-stream-src.c \
|
||||
backends/meta-screen-cast-monitor-stream-src.h \
|
||||
backends/meta-screen-cast-window-stream-src.c \
|
||||
backends/meta-screen-cast-window-stream-src.h \
|
||||
backends/meta-screen-cast-window-stream.c \
|
||||
backends/meta-screen-cast-window-stream.h \
|
||||
backends/meta-screen-cast-session.c \
|
||||
backends/meta-screen-cast-session.h \
|
||||
backends/meta-screen-cast-stream.c \
|
||||
@ -371,6 +389,8 @@ if HAVE_WAYLAND
|
||||
libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES += \
|
||||
compositor/meta-surface-actor-wayland.c \
|
||||
compositor/meta-surface-actor-wayland.h \
|
||||
wayland/meta-cursor-sprite-wayland.c \
|
||||
wayland/meta-cursor-sprite-wayland.h \
|
||||
wayland/meta-wayland.c \
|
||||
wayland/meta-wayland.h \
|
||||
wayland/meta-wayland-private.h \
|
||||
@ -432,10 +452,10 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES += \
|
||||
wayland/meta-wayland-touch.h \
|
||||
wayland/meta-wayland-surface.c \
|
||||
wayland/meta-wayland-surface.h \
|
||||
wayland/meta-wayland-surface-role-cursor.c \
|
||||
wayland/meta-wayland-surface-role-cursor.h \
|
||||
wayland/meta-wayland-surface-role-tablet-cursor.c \
|
||||
wayland/meta-wayland-surface-role-tablet-cursor.h \
|
||||
wayland/meta-wayland-cursor-surface.c \
|
||||
wayland/meta-wayland-cursor-surface.h \
|
||||
wayland/meta-wayland-tablet-cursor-surface.c \
|
||||
wayland/meta-wayland-tablet-cursor-surface.h \
|
||||
wayland/meta-wayland-actor-surface.c \
|
||||
wayland/meta-wayland-actor-surface.h \
|
||||
wayland/meta-wayland-subsurface.c \
|
||||
@ -487,8 +507,6 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES += \
|
||||
backends/native/meta-default-modes.h \
|
||||
backends/native/meta-gpu-kms.c \
|
||||
backends/native/meta-gpu-kms.h \
|
||||
backends/native/meta-idle-monitor-native.c \
|
||||
backends/native/meta-idle-monitor-native.h \
|
||||
backends/native/meta-input-settings-native.c \
|
||||
backends/native/meta-input-settings-native.h \
|
||||
backends/native/meta-monitor-manager-kms.c \
|
||||
@ -543,10 +561,13 @@ libmutterinclude_headers = \
|
||||
meta/meta-idle-monitor.h \
|
||||
meta/meta-plugin.h \
|
||||
meta/meta-monitor-manager.h \
|
||||
meta/meta-remote-access-controller.h \
|
||||
meta/meta-settings.h \
|
||||
meta/meta-shaped-texture.h \
|
||||
meta/meta-shadow-factory.h \
|
||||
meta/meta-stage.h \
|
||||
meta/meta-window-actor.h \
|
||||
meta/meta-window-group.h \
|
||||
meta/meta-window-shape.h \
|
||||
meta/prefs.h \
|
||||
meta/screen.h \
|
||||
@ -761,3 +782,5 @@ endef
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) code $< $@
|
||||
%-server-protocol.h : $(srcdir)/wayland/protocol/%.xml
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header $< $@
|
||||
%-server-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/%.xml
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) server-header $< $@
|
||||
|
36
src/backends/gsm-inhibitor-flag.h
Normal file
36
src/backends/gsm-inhibitor-flag.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSM_INHIBITOR_FLAG_H__
|
||||
#define __GSM_INHIBITOR_FLAG_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
GSM_INHIBITOR_FLAG_LOGOUT = 1 << 0,
|
||||
GSM_INHIBITOR_FLAG_SWITCH_USER = 1 << 1,
|
||||
GSM_INHIBITOR_FLAG_SUSPEND = 1 << 2,
|
||||
GSM_INHIBITOR_FLAG_IDLE = 1 << 3,
|
||||
GSM_INHIBITOR_FLAG_AUTOMOUNT = 1 << 4
|
||||
} GsmInhibitorFlag;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSM_INHIBITOR_FLAG_H__ */
|
@ -59,8 +59,6 @@ struct _MetaBackendClass
|
||||
|
||||
void (* post_init) (MetaBackend *backend);
|
||||
|
||||
MetaIdleMonitor * (* create_idle_monitor) (MetaBackend *backend,
|
||||
int device_id);
|
||||
MetaMonitorManager * (* create_monitor_manager) (MetaBackend *backend,
|
||||
GError **error);
|
||||
MetaCursorRenderer * (* create_cursor_renderer) (MetaBackend *backend);
|
||||
|
@ -34,11 +34,13 @@
|
||||
#include "meta-input-settings-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
#include "meta-stage.h"
|
||||
#include "meta-stage-private.h"
|
||||
#include "meta-dbus-login1.h"
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
#include "backends/meta-screen-cast.h"
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
#include "backends/meta-remote-desktop.h"
|
||||
#endif
|
||||
|
||||
@ -58,7 +60,8 @@ enum
|
||||
KEYMAP_CHANGED,
|
||||
KEYMAP_LAYOUT_GROUP_CHANGED,
|
||||
LAST_DEVICE_CHANGED,
|
||||
|
||||
SUSPENDING,
|
||||
RESUMING,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
@ -92,6 +95,7 @@ struct _MetaBackendPrivate
|
||||
MetaEgl *egl;
|
||||
MetaSettings *settings;
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
MetaRemoteAccessController *remote_access_controller;
|
||||
MetaDbusSessionWatcher *dbus_session_watcher;
|
||||
MetaScreenCast *screen_cast;
|
||||
MetaRemoteDesktop *remote_desktop;
|
||||
@ -110,12 +114,23 @@ struct _MetaBackendPrivate
|
||||
|
||||
MetaPointerConstraint *client_pointer_constraint;
|
||||
MetaDnd *dnd;
|
||||
|
||||
UpClient *up_client;
|
||||
GCancellable *cancellable;
|
||||
GDBusConnection *system_bus;
|
||||
|
||||
Login1Manager *logind_proxy;
|
||||
int inhibit_sleep_fd;
|
||||
};
|
||||
typedef struct _MetaBackendPrivate MetaBackendPrivate;
|
||||
|
||||
static void
|
||||
initable_iface_init (GInitableIface *initable_iface);
|
||||
|
||||
|
||||
static void prepare_for_sleep_cb (MetaBackend *backend,
|
||||
gboolean suspending);
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaBackend, meta_backend, G_TYPE_OBJECT,
|
||||
G_ADD_PRIVATE (MetaBackend)
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
|
||||
@ -134,8 +149,14 @@ meta_backend_finalize (GObject *object)
|
||||
g_clear_object (&priv->remote_desktop);
|
||||
g_clear_object (&priv->screen_cast);
|
||||
g_clear_object (&priv->dbus_session_watcher);
|
||||
g_clear_object (&priv->remote_access_controller);
|
||||
#endif
|
||||
|
||||
g_object_unref (priv->up_client);
|
||||
g_cancellable_cancel (priv->cancellable);
|
||||
g_clear_object (&priv->cancellable);
|
||||
g_clear_object (&priv->system_bus);
|
||||
|
||||
if (priv->device_update_idle_id)
|
||||
g_source_remove (priv->device_update_idle_id);
|
||||
|
||||
@ -158,7 +179,7 @@ meta_backend_sync_screen_size (MetaBackend *backend)
|
||||
}
|
||||
|
||||
static void
|
||||
center_pointer (MetaBackend *backend)
|
||||
reset_pointer_position (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
MetaMonitorManager *monitor_manager = priv->monitor_manager;
|
||||
@ -167,9 +188,11 @@ center_pointer (MetaBackend *backend)
|
||||
primary =
|
||||
meta_monitor_manager_get_primary_logical_monitor (monitor_manager);
|
||||
|
||||
/* Move the pointer out of the way to avoid hovering over reactive
|
||||
* elements (e.g. users list at login) causing undesired behaviour. */
|
||||
meta_backend_warp_pointer (backend,
|
||||
primary->rect.x + primary->rect.width / 2,
|
||||
primary->rect.y + primary->rect.height / 2);
|
||||
primary->rect.x + primary->rect.width * 0.9,
|
||||
primary->rect.y + primary->rect.height * 0.9);
|
||||
}
|
||||
|
||||
void
|
||||
@ -192,7 +215,7 @@ meta_backend_monitors_changed (MetaBackend *backend)
|
||||
!priv->is_pointer_position_initialized) &&
|
||||
!meta_monitor_manager_is_headless (monitor_manager))
|
||||
{
|
||||
center_pointer (backend);
|
||||
reset_pointer_position (backend);
|
||||
priv->is_pointer_position_initialized = TRUE;
|
||||
}
|
||||
}
|
||||
@ -222,7 +245,9 @@ static MetaIdleMonitor *
|
||||
meta_backend_create_idle_monitor (MetaBackend *backend,
|
||||
int device_id)
|
||||
{
|
||||
return META_BACKEND_GET_CLASS (backend)->create_idle_monitor (backend, device_id);
|
||||
return g_object_new (META_TYPE_IDLE_MONITOR,
|
||||
"device-id", device_id,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -402,28 +427,6 @@ meta_backend_create_input_settings (MetaBackend *backend)
|
||||
return META_BACKEND_GET_CLASS (backend)->create_input_settings (backend);
|
||||
}
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
static gboolean
|
||||
is_screen_cast_enabled (MetaBackend *backend)
|
||||
{
|
||||
MetaSettings *settings = meta_backend_get_settings (backend);
|
||||
|
||||
return meta_settings_is_experimental_feature_enabled (
|
||||
settings,
|
||||
META_EXPERIMENTAL_FEATURE_SCREEN_CAST);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_remote_desktop_enabled (MetaBackend *backend)
|
||||
{
|
||||
MetaSettings *settings = meta_backend_get_settings (backend);
|
||||
|
||||
return meta_settings_is_experimental_feature_enabled (
|
||||
settings,
|
||||
META_EXPERIMENTAL_FEATURE_REMOTE_DESKTOP);
|
||||
}
|
||||
#endif /* HAVE_REMOTE_DESKTOP */
|
||||
|
||||
static void
|
||||
meta_backend_real_post_init (MetaBackend *backend)
|
||||
{
|
||||
@ -456,16 +459,17 @@ meta_backend_real_post_init (MetaBackend *backend)
|
||||
priv->input_settings = meta_backend_create_input_settings (backend);
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
priv->remote_access_controller =
|
||||
g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL);
|
||||
priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL);
|
||||
if (is_screen_cast_enabled (backend))
|
||||
priv->screen_cast = meta_screen_cast_new (priv->dbus_session_watcher);
|
||||
if (is_remote_desktop_enabled (backend))
|
||||
priv->remote_desktop = meta_remote_desktop_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 */
|
||||
|
||||
if (!meta_monitor_manager_is_headless (priv->monitor_manager))
|
||||
{
|
||||
center_pointer (backend);
|
||||
reset_pointer_position (backend);
|
||||
priv->is_pointer_position_initialized = TRUE;
|
||||
}
|
||||
}
|
||||
@ -547,31 +551,25 @@ meta_backend_class_init (MetaBackendClass *klass)
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_INT);
|
||||
signals[SUSPENDING] =
|
||||
g_signal_new ("suspending",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
signals[RESUMING] =
|
||||
g_signal_new ("resuming",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
mutter_stage_views = g_getenv ("MUTTER_STAGE_VIEWS");
|
||||
stage_views_disabled = g_strcmp0 (mutter_stage_views, "0") == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
experimental_features_changed (MetaSettings *settings,
|
||||
MetaExperimentalFeature old_experimental_features,
|
||||
MetaBackend *backend)
|
||||
{
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
|
||||
if (is_screen_cast_enabled (backend) && !priv->screen_cast)
|
||||
priv->screen_cast = meta_screen_cast_new (priv->dbus_session_watcher);
|
||||
else if (!is_screen_cast_enabled (backend))
|
||||
g_clear_object (&priv->screen_cast);
|
||||
|
||||
if (is_remote_desktop_enabled (backend) && !priv->remote_desktop)
|
||||
priv->remote_desktop = meta_remote_desktop_new (priv->dbus_session_watcher);
|
||||
else if (!is_remote_desktop_enabled (backend))
|
||||
g_clear_object (&priv->remote_desktop);
|
||||
#endif /* HAVE_REMOTE_DESKTOP */
|
||||
}
|
||||
|
||||
static MetaMonitorManager *
|
||||
meta_backend_create_monitor_manager (MetaBackend *backend,
|
||||
GError **error)
|
||||
@ -590,6 +588,119 @@ meta_backend_create_renderer (MetaBackend *backend,
|
||||
return META_BACKEND_GET_CLASS (backend)->create_renderer (backend, error);
|
||||
}
|
||||
|
||||
static void
|
||||
lid_is_closed_changed_cb (UpClient *client,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (up_client_get_lid_is_closed (client))
|
||||
return;
|
||||
|
||||
meta_idle_monitor_reset_idletime (meta_idle_monitor_get_core ());
|
||||
}
|
||||
|
||||
static void
|
||||
inhibit_sleep (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
g_autoptr (GVariant) fd_variant = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (priv->inhibit_sleep_fd >= 0)
|
||||
return;
|
||||
|
||||
if (!login1_manager_call_inhibit_sync (priv->logind_proxy,
|
||||
"sleep",
|
||||
"Display Server",
|
||||
"Prepare for suspend",
|
||||
"delay",
|
||||
&fd_variant,
|
||||
priv->cancellable,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Failed to inhibit sleep: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->inhibit_sleep_fd = g_variant_get_handle (fd_variant);
|
||||
}
|
||||
|
||||
static void
|
||||
uninhibit_sleep (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
|
||||
close (priv->inhibit_sleep_fd);
|
||||
priv->inhibit_sleep_fd = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_for_sleep_cb (MetaBackend *backend,
|
||||
gboolean suspending)
|
||||
{
|
||||
if (suspending) {
|
||||
g_signal_emit (backend, signals[SUSPENDING], 0);
|
||||
uninhibit_sleep (backend);
|
||||
return;
|
||||
}
|
||||
|
||||
inhibit_sleep (backend);
|
||||
g_signal_emit (backend, signals[RESUMING], 0);
|
||||
meta_idle_monitor_reset_idletime (meta_idle_monitor_get_core ());
|
||||
}
|
||||
|
||||
static Login1Manager *
|
||||
get_logind_proxy (GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
Login1Manager *proxy;
|
||||
|
||||
proxy =
|
||||
login1_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
cancellable, error);
|
||||
if (!proxy)
|
||||
g_prefix_error (error, "Could not get logind proxy: ");
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
static void
|
||||
system_bus_gotten_cb (GObject *object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaBackend *backend = META_BACKEND (user_data);
|
||||
MetaBackendPrivate *priv;
|
||||
g_autoptr (GError) error = NULL;
|
||||
GDBusConnection *bus;
|
||||
|
||||
bus = g_bus_get_finish (res, NULL);
|
||||
if (!bus)
|
||||
return;
|
||||
|
||||
priv = meta_backend_get_instance_private (user_data);
|
||||
priv->system_bus = bus;
|
||||
priv->logind_proxy = get_logind_proxy (priv->cancellable, &error);
|
||||
priv->inhibit_sleep_fd = -1;
|
||||
|
||||
if (!priv->logind_proxy)
|
||||
{
|
||||
g_warning ("Failed to get logind proxy: %s", error->message);
|
||||
}
|
||||
else
|
||||
{
|
||||
inhibit_sleep (backend);
|
||||
g_signal_connect_object (priv->logind_proxy,
|
||||
"prepare-for-sleep",
|
||||
G_CALLBACK (prepare_for_sleep_cb),
|
||||
user_data,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_backend_initable_init (GInitable *initable,
|
||||
GCancellable *cancellable,
|
||||
@ -599,9 +710,6 @@ meta_backend_initable_init (GInitable *initable,
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
|
||||
priv->settings = meta_settings_new (backend);
|
||||
g_signal_connect (priv->settings, "experimental-features-changed",
|
||||
G_CALLBACK (experimental_features_changed),
|
||||
backend);
|
||||
|
||||
priv->egl = g_object_new (META_TYPE_EGL, NULL);
|
||||
|
||||
@ -619,6 +727,16 @@ meta_backend_initable_init (GInitable *initable,
|
||||
|
||||
priv->dnd = g_object_new (META_TYPE_DND, NULL);
|
||||
|
||||
priv->up_client = up_client_new ();
|
||||
g_signal_connect (priv->up_client, "notify::lid-is-closed",
|
||||
G_CALLBACK (lid_is_closed_changed_cb), NULL);
|
||||
|
||||
priv->cancellable = g_cancellable_new ();
|
||||
g_bus_get (G_BUS_TYPE_SYSTEM,
|
||||
priv->cancellable,
|
||||
system_bus_gotten_cb,
|
||||
backend);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -743,6 +861,24 @@ meta_backend_get_remote_desktop (MetaBackend *backend)
|
||||
}
|
||||
#endif /* HAVE_REMOTE_DESKTOP */
|
||||
|
||||
/**
|
||||
* meta_backend_get_remote_access_controller:
|
||||
* @backend: A #MetaBackend
|
||||
*
|
||||
* Return Value: (transfer none): The #MetaRemoteAccessController
|
||||
*/
|
||||
MetaRemoteAccessController *
|
||||
meta_backend_get_remote_access_controller (MetaBackend *backend)
|
||||
{
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
|
||||
return priv->remote_access_controller;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_backend_grab_device: (skip)
|
||||
*/
|
||||
|
@ -33,7 +33,10 @@
|
||||
#include <cogl/cogl.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "meta-stage.h"
|
||||
#include "meta-stage-private.h"
|
||||
|
||||
G_DEFINE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
struct _MetaCursorRendererPrivate
|
||||
{
|
||||
@ -44,6 +47,8 @@ struct _MetaCursorRendererPrivate
|
||||
MetaOverlay *stage_overlay;
|
||||
gboolean handled_by_backend;
|
||||
guint post_paint_func_id;
|
||||
|
||||
GList *hw_cursor_inhibitors;
|
||||
};
|
||||
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
|
||||
|
||||
@ -55,6 +60,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)
|
||||
@ -193,8 +213,8 @@ meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
|
||||
}
|
||||
|
||||
static void
|
||||
update_cursor (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
|
||||
gboolean handled_by_backend;
|
||||
@ -237,7 +257,7 @@ meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
|
||||
return;
|
||||
priv->displayed_cursor = cursor_sprite;
|
||||
|
||||
update_cursor (renderer, cursor_sprite);
|
||||
meta_cursor_renderer_update_cursor (renderer, cursor_sprite);
|
||||
}
|
||||
|
||||
void
|
||||
@ -246,7 +266,7 @@ meta_cursor_renderer_force_update (MetaCursorRenderer *renderer)
|
||||
MetaCursorRendererPrivate *priv =
|
||||
meta_cursor_renderer_get_instance_private (renderer);
|
||||
|
||||
update_cursor (renderer, priv->displayed_cursor);
|
||||
meta_cursor_renderer_update_cursor (renderer, priv->displayed_cursor);
|
||||
}
|
||||
|
||||
void
|
||||
@ -261,7 +281,19 @@ meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
|
||||
priv->current_x = x;
|
||||
priv->current_y = y;
|
||||
|
||||
update_cursor (renderer, priv->displayed_cursor);
|
||||
meta_cursor_renderer_update_cursor (renderer, priv->displayed_cursor);
|
||||
}
|
||||
|
||||
ClutterPoint
|
||||
meta_cursor_renderer_get_position (MetaCursorRenderer *renderer)
|
||||
{
|
||||
MetaCursorRendererPrivate *priv =
|
||||
meta_cursor_renderer_get_instance_private (renderer);
|
||||
|
||||
return (ClutterPoint) {
|
||||
.x = priv->current_x,
|
||||
.y = priv->current_y
|
||||
};
|
||||
}
|
||||
|
||||
MetaCursorSprite *
|
||||
@ -272,27 +304,44 @@ meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
|
||||
return priv->displayed_cursor;
|
||||
}
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
void
|
||||
meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
struct wl_resource *buffer)
|
||||
meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
|
||||
MetaHwCursorInhibitor *inhibitor)
|
||||
{
|
||||
MetaCursorRendererPrivate *priv =
|
||||
meta_cursor_renderer_get_instance_private (renderer);
|
||||
|
||||
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_GET_CLASS (renderer);
|
||||
|
||||
if (renderer_class->realize_cursor_from_wl_buffer)
|
||||
renderer_class->realize_cursor_from_wl_buffer (renderer, cursor_sprite, buffer);
|
||||
priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors,
|
||||
inhibitor);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
meta_cursor_renderer_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
XcursorImage *xc_image)
|
||||
meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
|
||||
MetaHwCursorInhibitor *inhibitor)
|
||||
{
|
||||
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_GET_CLASS (renderer);
|
||||
MetaCursorRendererPrivate *priv =
|
||||
meta_cursor_renderer_get_instance_private (renderer);
|
||||
|
||||
if (renderer_class->realize_cursor_from_xcursor)
|
||||
renderer_class->realize_cursor_from_xcursor (renderer, cursor_sprite, xc_image);
|
||||
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;
|
||||
}
|
||||
|
@ -26,14 +26,22 @@
|
||||
#define META_CURSOR_RENDERER_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include <wayland-server.h>
|
||||
#endif
|
||||
|
||||
#include <meta/screen.h>
|
||||
#include "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);
|
||||
@ -44,14 +52,6 @@ struct _MetaCursorRendererClass
|
||||
|
||||
gboolean (* update_cursor) (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite);
|
||||
#ifdef HAVE_WAYLAND
|
||||
void (* realize_cursor_from_wl_buffer) (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
struct wl_resource *buffer);
|
||||
#endif
|
||||
void (* realize_cursor_from_xcursor) (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
XcursorImage *xc_image);
|
||||
};
|
||||
|
||||
MetaCursorRenderer * meta_cursor_renderer_new (void);
|
||||
@ -62,23 +62,23 @@ void meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
|
||||
void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
|
||||
float x,
|
||||
float y);
|
||||
ClutterPoint meta_cursor_renderer_get_position (MetaCursorRenderer *renderer);
|
||||
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);
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
void meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
struct wl_resource *buffer);
|
||||
#endif
|
||||
|
||||
void meta_cursor_renderer_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
XcursorImage *xc_image);
|
||||
|
||||
void meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite);
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "meta-cursor.h"
|
||||
#include "meta-cursor-renderer.h"
|
||||
#include "backends/x11/cm/meta-cursor-sprite-xfixes.h"
|
||||
|
||||
struct _MetaCursorTracker {
|
||||
GObject parent_instance;
|
||||
@ -46,7 +47,7 @@ struct _MetaCursorTracker {
|
||||
MetaCursorSprite *root_cursor;
|
||||
|
||||
/* The cursor from the X11 server. */
|
||||
MetaCursorSprite *xfixes_cursor;
|
||||
MetaCursorSpriteXfixes *xfixes_cursor;
|
||||
};
|
||||
|
||||
struct _MetaCursorTrackerClass {
|
||||
|
@ -40,14 +40,15 @@
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
|
||||
#include "meta-backend-private.h"
|
||||
#include "backends/x11/cm/meta-cursor-sprite-xfixes.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -218,75 +232,14 @@ static void
|
||||
ensure_xfixes_cursor (MetaCursorTracker *tracker)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
XFixesCursorImage *cursor_image;
|
||||
CoglTexture2D *sprite;
|
||||
guint8 *cursor_data;
|
||||
gboolean free_cursor_data;
|
||||
CoglContext *ctx;
|
||||
CoglError *error = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (tracker->xfixes_cursor)
|
||||
return;
|
||||
|
||||
cursor_image = XFixesGetCursorImage (display->xdisplay);
|
||||
if (!cursor_image)
|
||||
return;
|
||||
|
||||
/* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
|
||||
* quantities as arrays of long; we need to convert on 64 bit */
|
||||
if (sizeof(long) == 4)
|
||||
{
|
||||
cursor_data = (guint8 *)cursor_image->pixels;
|
||||
free_cursor_data = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, j;
|
||||
guint32 *cursor_words;
|
||||
gulong *p;
|
||||
guint32 *q;
|
||||
|
||||
cursor_words = g_new (guint32, cursor_image->width * cursor_image->height);
|
||||
cursor_data = (guint8 *)cursor_words;
|
||||
|
||||
p = cursor_image->pixels;
|
||||
q = cursor_words;
|
||||
for (j = 0; j < cursor_image->height; j++)
|
||||
for (i = 0; i < cursor_image->width; i++)
|
||||
*(q++) = *(p++);
|
||||
|
||||
free_cursor_data = TRUE;
|
||||
}
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
sprite = cogl_texture_2d_new_from_data (ctx,
|
||||
cursor_image->width,
|
||||
cursor_image->height,
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
cursor_image->width * 4, /* stride */
|
||||
cursor_data,
|
||||
&error);
|
||||
|
||||
if (free_cursor_data)
|
||||
g_free (cursor_data);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
meta_warning ("Failed to allocate cursor sprite texture: %s\n", error->message);
|
||||
cogl_error_free (error);
|
||||
}
|
||||
|
||||
if (sprite != NULL)
|
||||
{
|
||||
MetaCursorSprite *cursor_sprite = meta_cursor_sprite_new ();
|
||||
meta_cursor_sprite_set_texture (cursor_sprite,
|
||||
COGL_TEXTURE (sprite),
|
||||
cursor_image->xhot,
|
||||
cursor_image->yhot);
|
||||
cogl_object_unref (sprite);
|
||||
tracker->xfixes_cursor = cursor_sprite;
|
||||
}
|
||||
XFree (cursor_image);
|
||||
tracker->xfixes_cursor = meta_cursor_sprite_xfixes_new (display, &error);
|
||||
if (!tracker->xfixes_cursor)
|
||||
g_warning ("Failed to create XFIXES cursor: %s", error->message);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -308,7 +261,7 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
|
||||
else
|
||||
{
|
||||
ensure_xfixes_cursor (tracker);
|
||||
cursor_sprite = tracker->xfixes_cursor;
|
||||
cursor_sprite = META_CURSOR_SPRITE (tracker->xfixes_cursor);
|
||||
}
|
||||
|
||||
if (cursor_sprite)
|
||||
@ -345,7 +298,7 @@ meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
|
||||
else
|
||||
{
|
||||
ensure_xfixes_cursor (tracker);
|
||||
cursor_sprite = tracker->xfixes_cursor;
|
||||
cursor_sprite = META_CURSOR_SPRITE (tracker->xfixes_cursor);
|
||||
}
|
||||
|
||||
if (cursor_sprite)
|
||||
@ -395,6 +348,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
|
||||
|
@ -23,19 +23,12 @@
|
||||
|
||||
#include "meta-cursor.h"
|
||||
|
||||
#include <meta/errors.h>
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "cogl/cogl.h"
|
||||
#include "meta/common.h"
|
||||
|
||||
#include "display-private.h"
|
||||
#include "screen-private.h"
|
||||
#include "meta-backend-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
PREPARE_AT,
|
||||
TEXTURE_CHANGED,
|
||||
|
||||
@ -44,316 +37,148 @@ enum {
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
struct _MetaCursorSprite
|
||||
typedef struct _MetaCursorSpritePrivate
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
MetaCursor cursor;
|
||||
|
||||
CoglTexture2D *texture;
|
||||
float texture_scale;
|
||||
int hot_x, hot_y;
|
||||
} MetaCursorSpritePrivate;
|
||||
|
||||
int current_frame;
|
||||
XcursorImages *xcursor_images;
|
||||
|
||||
int theme_scale;
|
||||
gboolean theme_dirty;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaCursorSprite, meta_cursor_sprite, G_TYPE_OBJECT)
|
||||
|
||||
static const char *
|
||||
translate_meta_cursor (MetaCursor cursor)
|
||||
{
|
||||
switch (cursor)
|
||||
{
|
||||
case META_CURSOR_DEFAULT:
|
||||
return "left_ptr";
|
||||
case META_CURSOR_NORTH_RESIZE:
|
||||
return "top_side";
|
||||
case META_CURSOR_SOUTH_RESIZE:
|
||||
return "bottom_side";
|
||||
case META_CURSOR_WEST_RESIZE:
|
||||
return "left_side";
|
||||
case META_CURSOR_EAST_RESIZE:
|
||||
return "right_side";
|
||||
case META_CURSOR_SE_RESIZE:
|
||||
return "bottom_right_corner";
|
||||
case META_CURSOR_SW_RESIZE:
|
||||
return "bottom_left_corner";
|
||||
case META_CURSOR_NE_RESIZE:
|
||||
return "top_right_corner";
|
||||
case META_CURSOR_NW_RESIZE:
|
||||
return "top_left_corner";
|
||||
case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
|
||||
return "fleur";
|
||||
case META_CURSOR_BUSY:
|
||||
return "watch";
|
||||
case META_CURSOR_DND_IN_DRAG:
|
||||
return "dnd-none";
|
||||
case META_CURSOR_DND_MOVE:
|
||||
return "dnd-move";
|
||||
case META_CURSOR_DND_COPY:
|
||||
return "dnd-copy";
|
||||
case META_CURSOR_DND_UNSUPPORTED_TARGET:
|
||||
return "dnd-none";
|
||||
case META_CURSOR_POINTING_HAND:
|
||||
return "hand2";
|
||||
case META_CURSOR_CROSSHAIR:
|
||||
return "crosshair";
|
||||
case META_CURSOR_IBEAM:
|
||||
return "xterm";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
Cursor
|
||||
meta_cursor_create_x_cursor (Display *xdisplay,
|
||||
MetaCursor cursor)
|
||||
{
|
||||
return XcursorLibraryLoadCursor (xdisplay, translate_meta_cursor (cursor));
|
||||
}
|
||||
|
||||
static XcursorImages *
|
||||
load_cursor_on_client (MetaCursor cursor, int scale)
|
||||
{
|
||||
return XcursorLibraryLoadImages (translate_meta_cursor (cursor),
|
||||
meta_prefs_get_cursor_theme (),
|
||||
meta_prefs_get_cursor_size () * scale);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_sprite_load_from_xcursor_image (MetaCursorSprite *self,
|
||||
XcursorImage *xc_image)
|
||||
{
|
||||
MetaBackend *meta_backend = meta_get_backend ();
|
||||
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
|
||||
uint width, height, rowstride;
|
||||
CoglPixelFormat cogl_format;
|
||||
ClutterBackend *clutter_backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglTexture2D *texture;
|
||||
CoglError *error = NULL;
|
||||
|
||||
g_assert (self->texture == NULL);
|
||||
|
||||
width = xc_image->width;
|
||||
height = xc_image->height;
|
||||
rowstride = width * 4;
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
|
||||
#else
|
||||
cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
|
||||
#endif
|
||||
|
||||
clutter_backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (clutter_backend);
|
||||
texture = cogl_texture_2d_new_from_data (cogl_context,
|
||||
width, height,
|
||||
cogl_format,
|
||||
rowstride,
|
||||
(uint8_t *) xc_image->pixels,
|
||||
&error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
meta_warning ("Failed to allocate cursor texture: %s\n", error->message);
|
||||
cogl_error_free (error);
|
||||
}
|
||||
|
||||
meta_cursor_sprite_set_texture (self, COGL_TEXTURE (texture),
|
||||
xc_image->xhot, xc_image->yhot);
|
||||
|
||||
if (texture)
|
||||
cogl_object_unref (texture);
|
||||
|
||||
meta_cursor_renderer_realize_cursor_from_xcursor (renderer, self, xc_image);
|
||||
}
|
||||
|
||||
static XcursorImage *
|
||||
meta_cursor_sprite_get_current_frame_image (MetaCursorSprite *self)
|
||||
{
|
||||
return self->xcursor_images->images[self->current_frame];
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_sprite_tick_frame (MetaCursorSprite *self)
|
||||
{
|
||||
XcursorImage *image;
|
||||
|
||||
if (!meta_cursor_sprite_is_animated (self))
|
||||
return;
|
||||
|
||||
self->current_frame++;
|
||||
|
||||
if (self->current_frame >= self->xcursor_images->nimage)
|
||||
self->current_frame = 0;
|
||||
|
||||
image = meta_cursor_sprite_get_current_frame_image (self);
|
||||
|
||||
g_clear_pointer (&self->texture, cogl_object_unref);
|
||||
meta_cursor_sprite_load_from_xcursor_image (self, image);
|
||||
}
|
||||
|
||||
guint
|
||||
meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *self)
|
||||
{
|
||||
if (!meta_cursor_sprite_is_animated (self))
|
||||
return 0;
|
||||
|
||||
return self->xcursor_images->images[self->current_frame]->delay;
|
||||
}
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaCursorSprite,
|
||||
meta_cursor_sprite,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
gboolean
|
||||
meta_cursor_sprite_is_animated (MetaCursorSprite *self)
|
||||
meta_cursor_sprite_is_animated (MetaCursorSprite *sprite)
|
||||
{
|
||||
return (self->xcursor_images &&
|
||||
self->xcursor_images->nimage > 1);
|
||||
}
|
||||
MetaCursorSpriteClass *klass = META_CURSOR_SPRITE_GET_CLASS (sprite);
|
||||
|
||||
MetaCursorSprite *
|
||||
meta_cursor_sprite_new (void)
|
||||
{
|
||||
return g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_sprite_load_from_theme (MetaCursorSprite *self)
|
||||
{
|
||||
XcursorImage *image;
|
||||
|
||||
g_assert (self->cursor != META_CURSOR_NONE);
|
||||
|
||||
self->theme_dirty = FALSE;
|
||||
|
||||
/* We might be reloading with a different scale. If so clear the old data. */
|
||||
if (self->xcursor_images)
|
||||
{
|
||||
g_clear_pointer (&self->texture, cogl_object_unref);
|
||||
XcursorImagesDestroy (self->xcursor_images);
|
||||
}
|
||||
|
||||
self->current_frame = 0;
|
||||
self->xcursor_images = load_cursor_on_client (self->cursor,
|
||||
self->theme_scale);
|
||||
if (!self->xcursor_images)
|
||||
meta_fatal ("Could not find cursor. Perhaps set XCURSOR_PATH?");
|
||||
|
||||
image = meta_cursor_sprite_get_current_frame_image (self);
|
||||
meta_cursor_sprite_load_from_xcursor_image (self, image);
|
||||
}
|
||||
|
||||
MetaCursorSprite *
|
||||
meta_cursor_sprite_from_theme (MetaCursor cursor)
|
||||
{
|
||||
MetaCursorSprite *self;
|
||||
|
||||
self = meta_cursor_sprite_new ();
|
||||
|
||||
self->cursor = cursor;
|
||||
self->theme_dirty = TRUE;
|
||||
|
||||
return self;
|
||||
if (klass->is_animated)
|
||||
return klass->is_animated (sprite);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_sprite_set_texture (MetaCursorSprite *self,
|
||||
meta_cursor_sprite_tick_frame (MetaCursorSprite *sprite)
|
||||
{
|
||||
return META_CURSOR_SPRITE_GET_CLASS (sprite)->tick_frame (sprite);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *sprite)
|
||||
{
|
||||
return META_CURSOR_SPRITE_GET_CLASS (sprite)->get_current_frame_time (sprite);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_sprite_clear_texture (MetaCursorSprite *sprite)
|
||||
{
|
||||
MetaCursorSpritePrivate *priv =
|
||||
meta_cursor_sprite_get_instance_private (sprite);
|
||||
|
||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_sprite_set_texture (MetaCursorSprite *sprite,
|
||||
CoglTexture *texture,
|
||||
int hot_x,
|
||||
int hot_y)
|
||||
{
|
||||
if (self->texture == COGL_TEXTURE_2D (texture) &&
|
||||
self->hot_x == hot_x &&
|
||||
self->hot_y == hot_y)
|
||||
MetaCursorSpritePrivate *priv =
|
||||
meta_cursor_sprite_get_instance_private (sprite);
|
||||
|
||||
if (priv->texture == COGL_TEXTURE_2D (texture) &&
|
||||
priv->hot_x == hot_x &&
|
||||
priv->hot_y == hot_y)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->texture, cogl_object_unref);
|
||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
||||
if (texture)
|
||||
self->texture = cogl_object_ref (texture);
|
||||
self->hot_x = hot_x;
|
||||
self->hot_y = hot_y;
|
||||
priv->texture = cogl_object_ref (texture);
|
||||
priv->hot_x = hot_x;
|
||||
priv->hot_y = hot_y;
|
||||
|
||||
g_signal_emit (self, signals[TEXTURE_CHANGED], 0);
|
||||
g_signal_emit (sprite, signals[TEXTURE_CHANGED], 0);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_sprite_set_texture_scale (MetaCursorSprite *self,
|
||||
meta_cursor_sprite_set_texture_scale (MetaCursorSprite *sprite,
|
||||
float scale)
|
||||
{
|
||||
self->texture_scale = scale;
|
||||
}
|
||||
MetaCursorSpritePrivate *priv =
|
||||
meta_cursor_sprite_get_instance_private (sprite);
|
||||
|
||||
void
|
||||
meta_cursor_sprite_set_theme_scale (MetaCursorSprite *self,
|
||||
int theme_scale)
|
||||
{
|
||||
if (self->theme_scale != theme_scale)
|
||||
self->theme_dirty = TRUE;
|
||||
self->theme_scale = theme_scale;
|
||||
priv->texture_scale = scale;
|
||||
}
|
||||
|
||||
CoglTexture *
|
||||
meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self)
|
||||
meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *sprite)
|
||||
{
|
||||
return COGL_TEXTURE (self->texture);
|
||||
}
|
||||
MetaCursorSpritePrivate *priv =
|
||||
meta_cursor_sprite_get_instance_private (sprite);
|
||||
|
||||
MetaCursor
|
||||
meta_cursor_sprite_get_meta_cursor (MetaCursorSprite *self)
|
||||
{
|
||||
return self->cursor;
|
||||
return COGL_TEXTURE (priv->texture);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
|
||||
meta_cursor_sprite_get_hotspot (MetaCursorSprite *sprite,
|
||||
int *hot_x,
|
||||
int *hot_y)
|
||||
{
|
||||
*hot_x = self->hot_x;
|
||||
*hot_y = self->hot_y;
|
||||
MetaCursorSpritePrivate *priv =
|
||||
meta_cursor_sprite_get_instance_private (sprite);
|
||||
|
||||
*hot_x = priv->hot_x;
|
||||
*hot_y = priv->hot_y;
|
||||
}
|
||||
|
||||
float
|
||||
meta_cursor_sprite_get_texture_scale (MetaCursorSprite *self)
|
||||
meta_cursor_sprite_get_texture_scale (MetaCursorSprite *sprite)
|
||||
{
|
||||
return self->texture_scale;
|
||||
MetaCursorSpritePrivate *priv =
|
||||
meta_cursor_sprite_get_instance_private (sprite);
|
||||
|
||||
return priv->texture_scale;
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_sprite_prepare_at (MetaCursorSprite *self,
|
||||
meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
g_signal_emit (self, signals[PREPARE_AT], 0, x, y);
|
||||
g_signal_emit (sprite, signals[PREPARE_AT], 0, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_sprite_realize_texture (MetaCursorSprite *self)
|
||||
meta_cursor_sprite_realize_texture (MetaCursorSprite *sprite)
|
||||
{
|
||||
if (self->theme_dirty)
|
||||
meta_cursor_sprite_load_from_theme (self);
|
||||
MetaCursorSpriteClass *klass = META_CURSOR_SPRITE_GET_CLASS (sprite);
|
||||
|
||||
if (klass->realize_texture)
|
||||
klass->realize_texture (sprite);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_sprite_init (MetaCursorSprite *self)
|
||||
meta_cursor_sprite_init (MetaCursorSprite *sprite)
|
||||
{
|
||||
self->texture_scale = 1.0f;
|
||||
MetaCursorSpritePrivate *priv =
|
||||
meta_cursor_sprite_get_instance_private (sprite);
|
||||
|
||||
priv->texture_scale = 1.0f;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_sprite_finalize (GObject *object)
|
||||
{
|
||||
MetaCursorSprite *self = META_CURSOR_SPRITE (object);
|
||||
MetaCursorSprite *sprite = META_CURSOR_SPRITE (object);
|
||||
MetaCursorSpritePrivate *priv =
|
||||
meta_cursor_sprite_get_instance_private (sprite);
|
||||
|
||||
if (self->xcursor_images)
|
||||
XcursorImagesDestroy (self->xcursor_images);
|
||||
|
||||
g_clear_pointer (&self->texture, cogl_object_unref);
|
||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
||||
|
||||
G_OBJECT_CLASS (meta_cursor_sprite_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -25,51 +25,50 @@
|
||||
#include <meta/common.h>
|
||||
#include <meta/boxes.h>
|
||||
|
||||
typedef struct _MetaCursorSprite MetaCursorSprite;
|
||||
|
||||
#define META_TYPE_CURSOR_SPRITE (meta_cursor_sprite_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaCursorSprite,
|
||||
meta_cursor_sprite,
|
||||
META, CURSOR_SPRITE,
|
||||
GObject);
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaCursorSprite,
|
||||
meta_cursor_sprite,
|
||||
META, CURSOR_SPRITE,
|
||||
GObject)
|
||||
|
||||
MetaCursorSprite * meta_cursor_sprite_new (void);
|
||||
struct _MetaCursorSpriteClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
MetaCursorSprite * meta_cursor_sprite_from_theme (MetaCursor cursor);
|
||||
void (* realize_texture) (MetaCursorSprite *sprite);
|
||||
gboolean (* is_animated) (MetaCursorSprite *sprite);
|
||||
void (* tick_frame) (MetaCursorSprite *sprite);
|
||||
unsigned int (* get_current_frame_time) (MetaCursorSprite *sprite);
|
||||
};
|
||||
|
||||
|
||||
void meta_cursor_sprite_set_theme_scale (MetaCursorSprite *self,
|
||||
int scale);
|
||||
|
||||
MetaCursor meta_cursor_sprite_get_meta_cursor (MetaCursorSprite *self);
|
||||
|
||||
Cursor meta_cursor_create_x_cursor (Display *xdisplay,
|
||||
MetaCursor cursor);
|
||||
|
||||
void meta_cursor_sprite_prepare_at (MetaCursorSprite *self,
|
||||
void meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
void meta_cursor_sprite_realize_texture (MetaCursorSprite *self);
|
||||
void meta_cursor_sprite_realize_texture (MetaCursorSprite *sprite);
|
||||
|
||||
void meta_cursor_sprite_set_texture (MetaCursorSprite *self,
|
||||
void meta_cursor_sprite_clear_texture (MetaCursorSprite *sprite);
|
||||
|
||||
void meta_cursor_sprite_set_texture (MetaCursorSprite *sprite,
|
||||
CoglTexture *texture,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
|
||||
void meta_cursor_sprite_set_texture_scale (MetaCursorSprite *self,
|
||||
void meta_cursor_sprite_set_texture_scale (MetaCursorSprite *sprite,
|
||||
float scale);
|
||||
|
||||
CoglTexture *meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self);
|
||||
CoglTexture *meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *sprite);
|
||||
|
||||
void meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
|
||||
void meta_cursor_sprite_get_hotspot (MetaCursorSprite *sprite,
|
||||
int *hot_x,
|
||||
int *hot_y);
|
||||
|
||||
float meta_cursor_sprite_get_texture_scale (MetaCursorSprite *self);
|
||||
float meta_cursor_sprite_get_texture_scale (MetaCursorSprite *sprite);
|
||||
|
||||
gboolean meta_cursor_sprite_is_animated (MetaCursorSprite *self);
|
||||
void meta_cursor_sprite_tick_frame (MetaCursorSprite *self);
|
||||
guint meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *self);
|
||||
gboolean meta_cursor_sprite_is_animated (MetaCursorSprite *sprite);
|
||||
|
||||
void meta_cursor_sprite_tick_frame (MetaCursorSprite *sprite);
|
||||
|
||||
unsigned int meta_cursor_sprite_get_current_frame_time (MetaCursorSprite *sprite);
|
||||
|
||||
#endif /* META_CURSOR_H */
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "meta-idle-monitor-dbus.h"
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include <backends/meta-idle-monitor-private.h>
|
||||
#include "meta-dbus-idle-monitor.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
@ -43,6 +44,26 @@ handle_get_idletime (MetaDBusIdleMonitor *skeleton,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_reset_idletime (MetaDBusIdleMonitor *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaIdleMonitor *monitor)
|
||||
{
|
||||
if (!g_getenv ("MUTTER_DEBUG_RESET_IDLETIME"))
|
||||
{
|
||||
g_dbus_method_invocation_return_error_literal (invocation,
|
||||
G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_UNKNOWN_METHOD,
|
||||
"No such method");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
meta_idle_monitor_reset_idletime (meta_idle_monitor_get_core ());
|
||||
meta_dbus_idle_monitor_complete_reset_idletime (skeleton, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MetaDBusIdleMonitor *dbus_monitor;
|
||||
MetaIdleMonitor *monitor;
|
||||
@ -173,6 +194,8 @@ create_monitor_skeleton (GDBusObjectManagerServer *manager,
|
||||
G_CALLBACK (handle_add_user_active_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-remove-watch",
|
||||
G_CALLBACK (handle_remove_watch), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-reset-idletime",
|
||||
G_CALLBACK (handle_reset_idletime), monitor, 0);
|
||||
g_signal_connect_object (skeleton, "handle-get-idletime",
|
||||
G_CALLBACK (handle_get_idletime), monitor, 0);
|
||||
|
||||
|
@ -26,9 +26,6 @@
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "display-private.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaIdleMonitor *monitor;
|
||||
@ -38,28 +35,26 @@ typedef struct
|
||||
GDestroyNotify notify;
|
||||
guint64 timeout_msec;
|
||||
int idle_source_id;
|
||||
GSource *timeout_source;
|
||||
} MetaIdleMonitorWatch;
|
||||
|
||||
struct _MetaIdleMonitor
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GDBusProxy *session_proxy;
|
||||
gboolean inhibited;
|
||||
GHashTable *watches;
|
||||
int device_id;
|
||||
guint64 last_event_time;
|
||||
};
|
||||
|
||||
struct _MetaIdleMonitorClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
gint64 (*get_idletime) (MetaIdleMonitor *monitor);
|
||||
MetaIdleMonitorWatch * (*make_watch) (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
};
|
||||
|
||||
void _meta_idle_monitor_watch_fire (MetaIdleMonitorWatch *watch);
|
||||
void meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor);
|
||||
|
||||
#endif /* META_IDLE_MONITOR_PRIVATE_H */
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <meta/util.h>
|
||||
#include <meta/main.h>
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
#include "gsm-inhibitor-flag.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
#include "meta-idle-monitor-dbus.h"
|
||||
#include "meta-backend-private.h"
|
||||
@ -87,6 +88,7 @@ meta_idle_monitor_dispose (GObject *object)
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (object);
|
||||
|
||||
g_clear_pointer (&monitor->watches, g_hash_table_destroy);
|
||||
g_clear_object (&monitor->session_proxy);
|
||||
|
||||
G_OBJECT_CLASS (meta_idle_monitor_parent_class)->dispose (object);
|
||||
}
|
||||
@ -151,9 +153,118 @@ meta_idle_monitor_class_init (MetaIdleMonitorClass *klass)
|
||||
g_object_class_install_property (object_class, PROP_DEVICE_ID, obj_props[PROP_DEVICE_ID]);
|
||||
}
|
||||
|
||||
static void
|
||||
free_watch (gpointer data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) data;
|
||||
MetaIdleMonitor *monitor = watch->monitor;
|
||||
|
||||
g_object_ref (monitor);
|
||||
|
||||
if (watch->idle_source_id)
|
||||
{
|
||||
g_source_remove (watch->idle_source_id);
|
||||
watch->idle_source_id = 0;
|
||||
}
|
||||
|
||||
if (watch->notify != NULL)
|
||||
watch->notify (watch->user_data);
|
||||
|
||||
if (watch->timeout_source != NULL)
|
||||
g_source_destroy (watch->timeout_source);
|
||||
|
||||
g_object_unref (monitor);
|
||||
g_slice_free (MetaIdleMonitorWatch, watch);
|
||||
}
|
||||
|
||||
static void
|
||||
update_inhibited_watch (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitor *monitor = user_data;
|
||||
MetaIdleMonitorWatch *watch = value;
|
||||
|
||||
if (!watch->timeout_source)
|
||||
return;
|
||||
|
||||
if (monitor->inhibited)
|
||||
{
|
||||
g_source_set_ready_time (watch->timeout_source, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_source_set_ready_time (watch->timeout_source,
|
||||
monitor->last_event_time +
|
||||
watch->timeout_msec * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_inhibited (MetaIdleMonitor *monitor,
|
||||
gboolean inhibited)
|
||||
{
|
||||
if (inhibited == monitor->inhibited)
|
||||
return;
|
||||
|
||||
g_hash_table_foreach (monitor->watches,
|
||||
update_inhibited_watch,
|
||||
monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_inhibited_actions_changed (GDBusProxy *session,
|
||||
GVariant *changed,
|
||||
char **invalidated,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitor *monitor = user_data;
|
||||
GVariant *v;
|
||||
|
||||
v = g_variant_lookup_value (changed, "InhibitedActions", G_VARIANT_TYPE_UINT32);
|
||||
if (v)
|
||||
{
|
||||
gboolean inhibited;
|
||||
|
||||
inhibited = g_variant_get_uint32 (v) & GSM_INHIBITOR_FLAG_IDLE;
|
||||
g_variant_unref (v);
|
||||
|
||||
if (!inhibited)
|
||||
monitor->last_event_time = g_get_monotonic_time ();
|
||||
update_inhibited (monitor, inhibited);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_init (MetaIdleMonitor *monitor)
|
||||
{
|
||||
GVariant *v;
|
||||
|
||||
monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch);
|
||||
monitor->last_event_time = g_get_monotonic_time ();
|
||||
|
||||
/* Monitor inhibitors */
|
||||
monitor->session_proxy =
|
||||
g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
"org.gnome.SessionManager",
|
||||
"/org/gnome/SessionManager",
|
||||
"org.gnome.SessionManager",
|
||||
NULL,
|
||||
NULL);
|
||||
if (!monitor->session_proxy)
|
||||
return;
|
||||
|
||||
g_signal_connect (monitor->session_proxy, "g-properties-changed",
|
||||
G_CALLBACK (meta_idle_monitor_inhibited_actions_changed),
|
||||
monitor);
|
||||
|
||||
v = g_dbus_proxy_get_cached_property (monitor->session_proxy,
|
||||
"InhibitedActions");
|
||||
monitor->inhibited = g_variant_get_uint32 (v) & GSM_INHIBITOR_FLAG_IDLE;
|
||||
g_variant_unref (v);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,6 +296,36 @@ meta_idle_monitor_get_for_device (int device_id)
|
||||
return meta_backend_get_idle_monitor (backend, device_id);
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_next_watch_serial (void)
|
||||
{
|
||||
static guint32 serial = 0;
|
||||
|
||||
g_atomic_int_inc (&serial);
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
idle_monitor_dispatch_timeout (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) user_data;
|
||||
|
||||
_meta_idle_monitor_watch_fire (watch);
|
||||
g_source_set_ready_time (watch->timeout_source, -1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs idle_monitor_source_funcs = {
|
||||
.prepare = NULL,
|
||||
.check = NULL,
|
||||
.dispatch = idle_monitor_dispatch_timeout,
|
||||
.finalize = NULL,
|
||||
};
|
||||
|
||||
static MetaIdleMonitorWatch *
|
||||
make_watch (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
@ -194,11 +335,32 @@ make_watch (MetaIdleMonitor *monitor,
|
||||
{
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
watch = META_IDLE_MONITOR_GET_CLASS (monitor)->make_watch (monitor,
|
||||
timeout_msec,
|
||||
callback,
|
||||
user_data,
|
||||
notify);
|
||||
watch = g_slice_new0 (MetaIdleMonitorWatch);
|
||||
|
||||
watch->monitor = monitor;
|
||||
watch->id = get_next_watch_serial ();
|
||||
watch->callback = callback;
|
||||
watch->user_data = user_data;
|
||||
watch->notify = notify;
|
||||
watch->timeout_msec = timeout_msec;
|
||||
|
||||
if (timeout_msec != 0)
|
||||
{
|
||||
GSource *source = g_source_new (&idle_monitor_source_funcs,
|
||||
sizeof (GSource));
|
||||
|
||||
g_source_set_callback (source, NULL, watch, NULL);
|
||||
if (!monitor->inhibited)
|
||||
{
|
||||
g_source_set_ready_time (source,
|
||||
monitor->last_event_time +
|
||||
timeout_msec * 1000);
|
||||
}
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
|
||||
watch->timeout_source = source;
|
||||
}
|
||||
|
||||
g_hash_table_insert (monitor->watches,
|
||||
GUINT_TO_POINTER (watch->id),
|
||||
@ -314,5 +476,39 @@ meta_idle_monitor_remove_watch (MetaIdleMonitor *monitor,
|
||||
gint64
|
||||
meta_idle_monitor_get_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
return META_IDLE_MONITOR_GET_CLASS (monitor)->get_idletime (monitor);
|
||||
return (g_get_monotonic_time () - monitor->last_event_time) / 1000;
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_reset_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
GList *node, *watch_ids;
|
||||
|
||||
monitor->last_event_time = g_get_monotonic_time ();
|
||||
|
||||
watch_ids = g_hash_table_get_keys (monitor->watches);
|
||||
|
||||
for (node = watch_ids; node != NULL; node = node->next)
|
||||
{
|
||||
guint watch_id = GPOINTER_TO_UINT (node->data);
|
||||
MetaIdleMonitorWatch *watch;
|
||||
|
||||
watch = g_hash_table_lookup (monitor->watches,
|
||||
GUINT_TO_POINTER (watch_id));
|
||||
if (!watch)
|
||||
continue;
|
||||
|
||||
if (watch->timeout_msec == 0)
|
||||
{
|
||||
_meta_idle_monitor_watch_fire ((MetaIdleMonitorWatch *) watch);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_source_set_ready_time (watch->timeout_source,
|
||||
monitor->last_event_time +
|
||||
watch->timeout_msec * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (watch_ids);
|
||||
}
|
||||
|
@ -1088,7 +1088,7 @@ meta_input_settings_changed_cb (GSettings *settings,
|
||||
update_device_natural_scroll (input_settings, NULL);
|
||||
else if (strcmp (key, "tap-to-click") == 0)
|
||||
update_touchpad_tap_enabled (input_settings, NULL);
|
||||
else if (strcmp (key, "tap-and_drag") == 0)
|
||||
else if (strcmp (key, "tap-and-drag") == 0)
|
||||
update_touchpad_tap_and_drag_enabled (input_settings, NULL);
|
||||
else if (strcmp(key, "disable-while-typing") == 0)
|
||||
update_touchpad_disable_while_typing (input_settings, NULL);
|
||||
|
@ -100,11 +100,12 @@ static MetaMonitorTransform
|
||||
derive_monitor_transform (MetaMonitor *monitor)
|
||||
{
|
||||
MetaOutput *main_output;
|
||||
MetaMonitorTransform transform;
|
||||
|
||||
main_output = meta_monitor_get_main_output (monitor);
|
||||
transform = meta_output_get_assigned_crtc (main_output)->transform;
|
||||
|
||||
return meta_monitor_crtc_to_logical_transform (monitor,
|
||||
main_output->crtc->transform);
|
||||
return meta_monitor_crtc_to_logical_transform (monitor, transform);
|
||||
}
|
||||
|
||||
MetaLogicalMonitor *
|
||||
@ -145,7 +146,7 @@ meta_logical_monitor_add_monitor (MetaLogicalMonitor *logical_monitor,
|
||||
|
||||
is_presentation = logical_monitor->is_presentation;
|
||||
logical_monitor->monitors = g_list_append (logical_monitor->monitors,
|
||||
monitor);
|
||||
g_object_ref (monitor));
|
||||
|
||||
for (l = logical_monitor->monitors; l; l = l->next)
|
||||
{
|
||||
@ -157,10 +158,12 @@ meta_logical_monitor_add_monitor (MetaLogicalMonitor *logical_monitor,
|
||||
for (l_output = outputs; l_output; l_output = l_output->next)
|
||||
{
|
||||
MetaOutput *output = l_output->data;
|
||||
MetaCrtc *crtc;
|
||||
|
||||
is_presentation = is_presentation && output->is_presentation;
|
||||
if (output->crtc)
|
||||
output->crtc->logical_monitor = logical_monitor;
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
if (crtc)
|
||||
crtc->logical_monitor = logical_monitor;
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,7 +223,7 @@ foreach_crtc (MetaMonitor *monitor,
|
||||
ForeachCrtcData *data = user_data;
|
||||
|
||||
data->func (data->logical_monitor,
|
||||
monitor_crtc_mode->output->crtc,
|
||||
meta_output_get_assigned_crtc (monitor_crtc_mode->output),
|
||||
data->user_data);
|
||||
|
||||
return TRUE;
|
||||
@ -254,13 +257,17 @@ meta_logical_monitor_init (MetaLogicalMonitor *logical_monitor)
|
||||
}
|
||||
|
||||
static void
|
||||
meta_logical_monitor_finalize (GObject *object)
|
||||
meta_logical_monitor_dispose (GObject *object)
|
||||
{
|
||||
MetaLogicalMonitor *logical_monitor = META_LOGICAL_MONITOR (object);
|
||||
|
||||
g_list_free (logical_monitor->monitors);
|
||||
if (logical_monitor->monitors)
|
||||
{
|
||||
g_list_free_full (logical_monitor->monitors, g_object_unref);
|
||||
logical_monitor->monitors = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (meta_logical_monitor_parent_class)->finalize (object);
|
||||
G_OBJECT_CLASS (meta_logical_monitor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -268,7 +275,7 @@ meta_logical_monitor_class_init (MetaLogicalMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_logical_monitor_finalize;
|
||||
object_class->dispose = meta_logical_monitor_dispose;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -486,7 +486,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
|
||||
output = ((MetaOutput**)crtc_info->outputs->pdata)[j];
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
meta_output_assign_crtc (output, crtc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -531,7 +531,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
|
||||
continue;
|
||||
}
|
||||
|
||||
output->crtc = NULL;
|
||||
meta_output_unassign_crtc (output);
|
||||
output->is_primary = FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,9 @@ static gboolean
|
||||
meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
|
||||
MetaMonitorsConfig *config);
|
||||
|
||||
static MetaMonitor *
|
||||
meta_monitor_manager_get_active_monitor (MetaMonitorManager *manager);
|
||||
|
||||
MetaBackend *
|
||||
meta_monitor_manager_get_backend (MetaMonitorManager *manager)
|
||||
{
|
||||
@ -198,13 +201,17 @@ calculate_monitor_scale (MetaMonitorManager *manager,
|
||||
static float
|
||||
derive_calculated_global_scale (MetaMonitorManager *manager)
|
||||
{
|
||||
MetaMonitor *primary_monitor;
|
||||
MetaMonitor *monitor = NULL;
|
||||
|
||||
primary_monitor = meta_monitor_manager_get_primary_monitor (manager);
|
||||
if (!primary_monitor)
|
||||
monitor = meta_monitor_manager_get_primary_monitor (manager);
|
||||
|
||||
if (!monitor || !meta_monitor_is_active (monitor))
|
||||
monitor = meta_monitor_manager_get_active_monitor (manager);
|
||||
|
||||
if (!monitor)
|
||||
return 1.0;
|
||||
|
||||
return calculate_monitor_scale (manager, primary_monitor);
|
||||
return calculate_monitor_scale (manager, monitor);
|
||||
}
|
||||
|
||||
static float
|
||||
@ -598,7 +605,7 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
||||
{
|
||||
g_clear_object (&config);
|
||||
g_warning ("Failed to use fallback monitor configuration: %s",
|
||||
error->message);
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
@ -1032,12 +1039,13 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
||||
NULL /* properties */);
|
||||
}
|
||||
|
||||
for (l = combined_outputs; l; l = l->next)
|
||||
for (l = combined_outputs, i = 0; l; l = l->next, i++)
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
GVariantBuilder crtcs, modes, clones, properties;
|
||||
GBytes *edid;
|
||||
char *edid_file;
|
||||
MetaCrtc *crtc;
|
||||
int crtc_index;
|
||||
|
||||
g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au"));
|
||||
@ -1131,8 +1139,8 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
|
||||
output->tile_info.tile_h));
|
||||
}
|
||||
|
||||
crtc_index = output->crtc ? g_list_index (combined_crtcs, output->crtc)
|
||||
: -1;
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
crtc_index = crtc ? g_list_index (combined_crtcs, crtc) : -1;
|
||||
g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
|
||||
i, /* ID */
|
||||
(gint64)output->winsys_id,
|
||||
@ -2382,6 +2390,12 @@ meta_monitor_manager_get_laptop_panel (MetaMonitorManager *manager)
|
||||
return find_monitor (manager, meta_monitor_is_laptop_panel);
|
||||
}
|
||||
|
||||
static MetaMonitor *
|
||||
meta_monitor_manager_get_active_monitor (MetaMonitorManager *manager)
|
||||
{
|
||||
return find_monitor (manager, meta_monitor_is_active);
|
||||
}
|
||||
|
||||
MetaMonitor *
|
||||
meta_monitor_manager_get_monitor_from_connector (MetaMonitorManager *manager,
|
||||
const char *connector)
|
||||
@ -2894,11 +2908,7 @@ meta_monitor_manager_get_monitor_for_connector (MetaMonitorManager *manager,
|
||||
|
||||
if (meta_monitor_is_active (monitor) &&
|
||||
g_str_equal (connector, meta_monitor_get_connector (monitor)))
|
||||
{
|
||||
MetaOutput *main_output = meta_monitor_get_main_output (monitor);
|
||||
|
||||
return main_output->crtc->logical_monitor->number;
|
||||
}
|
||||
return meta_monitor_get_logical_monitor (monitor)->number;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -203,11 +203,9 @@ meta_monitor_get_main_output (MetaMonitor *monitor)
|
||||
gboolean
|
||||
meta_monitor_is_active (MetaMonitor *monitor)
|
||||
{
|
||||
MetaOutput *output;
|
||||
MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
|
||||
|
||||
output = meta_monitor_get_main_output (monitor);
|
||||
|
||||
return output->crtc && output->crtc->current_mode;
|
||||
return !!priv->current_mode;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -385,6 +383,21 @@ meta_monitor_crtc_to_logical_transform (MetaMonitor *monitor,
|
||||
return new_transform;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_dispose (GObject *object)
|
||||
{
|
||||
MetaMonitor *monitor = META_MONITOR (object);
|
||||
MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
|
||||
|
||||
if (priv->outputs)
|
||||
{
|
||||
g_list_free_full (priv->outputs, g_object_unref);
|
||||
priv->outputs = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (meta_monitor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_finalize (GObject *object)
|
||||
{
|
||||
@ -393,7 +406,6 @@ meta_monitor_finalize (GObject *object)
|
||||
|
||||
g_hash_table_destroy (priv->mode_ids);
|
||||
g_list_free_full (priv->modes, (GDestroyNotify) meta_monitor_mode_free);
|
||||
g_clear_pointer (&priv->outputs, g_list_free);
|
||||
meta_monitor_spec_free (priv->spec);
|
||||
|
||||
G_OBJECT_CLASS (meta_monitor_parent_class)->finalize (object);
|
||||
@ -412,6 +424,7 @@ meta_monitor_class_init (MetaMonitorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = meta_monitor_dispose;
|
||||
object_class->finalize = meta_monitor_finalize;
|
||||
}
|
||||
|
||||
@ -493,6 +506,7 @@ meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal)
|
||||
for (i = 0; i < output->n_modes; i++)
|
||||
{
|
||||
MetaCrtcMode *crtc_mode = output->modes[i];
|
||||
MetaCrtc *crtc;
|
||||
MetaMonitorMode *mode;
|
||||
gboolean replace;
|
||||
|
||||
@ -526,7 +540,9 @@ meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal)
|
||||
|
||||
if (crtc_mode == output->preferred_mode)
|
||||
monitor_priv->preferred_mode = mode;
|
||||
if (output->crtc && crtc_mode == output->crtc->current_mode)
|
||||
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
if (crtc && crtc_mode == crtc->current_mode)
|
||||
monitor_priv->current_mode = mode;
|
||||
}
|
||||
}
|
||||
@ -545,7 +561,7 @@ meta_monitor_normal_new (MetaGpu *gpu,
|
||||
|
||||
monitor_priv->gpu = gpu;
|
||||
|
||||
monitor_priv->outputs = g_list_append (NULL, output);
|
||||
monitor_priv->outputs = g_list_append (NULL, g_object_ref (output));
|
||||
monitor_priv->winsys_id = output->winsys_id;
|
||||
meta_monitor_generate_spec (monitor);
|
||||
|
||||
@ -568,13 +584,15 @@ meta_monitor_normal_derive_layout (MetaMonitor *monitor,
|
||||
MetaRectangle *layout)
|
||||
{
|
||||
MetaOutput *output;
|
||||
MetaCrtc *crtc;
|
||||
|
||||
output = meta_monitor_get_main_output (monitor);
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
*layout = (MetaRectangle) {
|
||||
.x = output->crtc->rect.x,
|
||||
.y = output->crtc->rect.y,
|
||||
.width = output->crtc->rect.width,
|
||||
.height = output->crtc->rect.height
|
||||
.x = crtc->rect.x,
|
||||
.y = crtc->rect.y,
|
||||
.width = crtc->rect.width,
|
||||
.height = crtc->rect.height
|
||||
};
|
||||
}
|
||||
|
||||
@ -658,7 +676,8 @@ add_tiled_monitor_outputs (MetaGpu *gpu,
|
||||
g_warn_if_fail (output->subpixel_order ==
|
||||
monitor_tiled->origin_output->subpixel_order);
|
||||
|
||||
monitor_priv->outputs = g_list_append (monitor_priv->outputs, output);
|
||||
monitor_priv->outputs = g_list_append (monitor_priv->outputs,
|
||||
g_object_ref (output));
|
||||
}
|
||||
}
|
||||
|
||||
@ -764,12 +783,13 @@ is_monitor_mode_assigned (MetaMonitor *monitor,
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
MetaMonitorCrtcMode *monitor_crtc_mode = &mode->crtc_modes[i];
|
||||
MetaCrtc *crtc;
|
||||
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
if (monitor_crtc_mode->crtc_mode &&
|
||||
(!output->crtc ||
|
||||
output->crtc->current_mode != monitor_crtc_mode->crtc_mode))
|
||||
(!crtc || crtc->current_mode != monitor_crtc_mode->crtc_mode))
|
||||
return FALSE;
|
||||
else if (!monitor_crtc_mode->crtc_mode && output->crtc)
|
||||
else if (!monitor_crtc_mode->crtc_mode && crtc)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1217,14 +1237,16 @@ meta_monitor_tiled_derive_layout (MetaMonitor *monitor,
|
||||
for (l = monitor_priv->outputs; l; l = l->next)
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
MetaCrtc *crtc;
|
||||
|
||||
if (!output->crtc)
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
if (!crtc)
|
||||
continue;
|
||||
|
||||
min_x = MIN (output->crtc->rect.x, min_x);
|
||||
min_y = MIN (output->crtc->rect.y, min_y);
|
||||
max_x = MAX (output->crtc->rect.x + output->crtc->rect.width, max_x);
|
||||
max_y = MAX (output->crtc->rect.y + output->crtc->rect.height, max_y);
|
||||
min_x = MIN (crtc->rect.x, min_x);
|
||||
min_y = MIN (crtc->rect.y, min_y);
|
||||
max_x = MAX (crtc->rect.x + crtc->rect.width, max_x);
|
||||
max_y = MAX (crtc->rect.y + crtc->rect.height, max_y);
|
||||
}
|
||||
|
||||
*layout = (MetaRectangle) {
|
||||
@ -1318,10 +1340,14 @@ meta_monitor_get_spec (MetaMonitor *monitor)
|
||||
MetaLogicalMonitor *
|
||||
meta_monitor_get_logical_monitor (MetaMonitor *monitor)
|
||||
{
|
||||
MetaOutput *output = meta_monitor_get_main_output (monitor);
|
||||
MetaOutput *output;
|
||||
MetaCrtc *crtc;
|
||||
|
||||
if (output->crtc)
|
||||
return output->crtc->logical_monitor;
|
||||
output = meta_monitor_get_main_output (monitor);
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
|
||||
if (crtc)
|
||||
return crtc->logical_monitor;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@ -1381,6 +1407,18 @@ meta_monitor_get_current_mode (MetaMonitor *monitor)
|
||||
return priv->current_mode;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_current_mode_known (MetaMonitor *monitor)
|
||||
{
|
||||
MetaOutput *output;
|
||||
MetaCrtc *crtc;
|
||||
|
||||
output = meta_monitor_get_main_output (monitor);
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
|
||||
return meta_monitor_is_active (monitor) == (crtc && crtc->current_mode);
|
||||
}
|
||||
|
||||
void
|
||||
meta_monitor_derive_current_mode (MetaMonitor *monitor)
|
||||
{
|
||||
@ -1400,6 +1438,8 @@ meta_monitor_derive_current_mode (MetaMonitor *monitor)
|
||||
}
|
||||
|
||||
priv->current_mode = current_mode;
|
||||
|
||||
g_warn_if_fail (is_current_mode_known (monitor));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -21,7 +21,13 @@
|
||||
|
||||
#include "backends/meta-output.h"
|
||||
|
||||
G_DEFINE_TYPE (MetaOutput, meta_output, G_TYPE_OBJECT)
|
||||
typedef struct _MetaOutputPrivate
|
||||
{
|
||||
/* The CRTC driving this output, NULL if the output is not enabled */
|
||||
MetaCrtc *crtc;
|
||||
} MetaOutputPrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaOutput, meta_output, G_TYPE_OBJECT)
|
||||
|
||||
MetaGpu *
|
||||
meta_output_get_gpu (MetaOutput *output)
|
||||
@ -29,6 +35,44 @@ meta_output_get_gpu (MetaOutput *output)
|
||||
return output->gpu;
|
||||
}
|
||||
|
||||
void
|
||||
meta_output_assign_crtc (MetaOutput *output,
|
||||
MetaCrtc *crtc)
|
||||
{
|
||||
MetaOutputPrivate *priv = meta_output_get_instance_private (output);
|
||||
|
||||
g_assert (crtc);
|
||||
|
||||
g_set_object (&priv->crtc, crtc);
|
||||
}
|
||||
|
||||
void
|
||||
meta_output_unassign_crtc (MetaOutput *output)
|
||||
{
|
||||
MetaOutputPrivate *priv = meta_output_get_instance_private (output);
|
||||
|
||||
g_clear_object (&priv->crtc);
|
||||
}
|
||||
|
||||
MetaCrtc *
|
||||
meta_output_get_assigned_crtc (MetaOutput *output)
|
||||
{
|
||||
MetaOutputPrivate *priv = meta_output_get_instance_private (output);
|
||||
|
||||
return priv->crtc;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_output_dispose (GObject *object)
|
||||
{
|
||||
MetaOutput *output = META_OUTPUT (object);
|
||||
MetaOutputPrivate *priv = meta_output_get_instance_private (output);
|
||||
|
||||
g_clear_object (&priv->crtc);
|
||||
|
||||
G_OBJECT_CLASS (meta_output_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_output_finalize (GObject *object)
|
||||
{
|
||||
@ -58,5 +102,6 @@ meta_output_class_init (MetaOutputClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = meta_output_dispose;
|
||||
object_class->finalize = meta_output_finalize;
|
||||
}
|
||||
|
@ -64,9 +64,6 @@ struct _MetaOutput
|
||||
|
||||
MetaGpu *gpu;
|
||||
|
||||
/* The CRTC driving this output, NULL if the output is not enabled */
|
||||
MetaCrtc *crtc;
|
||||
|
||||
/* The low-level ID of this output, used to apply back configuration */
|
||||
glong winsys_id;
|
||||
char *name;
|
||||
@ -122,4 +119,11 @@ G_DECLARE_FINAL_TYPE (MetaOutput, meta_output, META, OUTPUT, GObject)
|
||||
|
||||
MetaGpu * meta_output_get_gpu (MetaOutput *output);
|
||||
|
||||
void meta_output_assign_crtc (MetaOutput *output,
|
||||
MetaCrtc *crtc);
|
||||
|
||||
void meta_output_unassign_crtc (MetaOutput *output);
|
||||
|
||||
MetaCrtc * meta_output_get_assigned_crtc (MetaOutput *output);
|
||||
|
||||
#endif /* META_OUTPUT_H */
|
||||
|
@ -1,7 +1,5 @@
|
||||
/*
|
||||
* Wayland Support
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
* Copyright (C) 2018 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@ -17,26 +15,17 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "meta-wayland-surface-role-tablet-cursor.h"
|
||||
#ifndef META_REMOTE_ACCESS_CONTROLLER_PRIVATE_H
|
||||
#define META_REMOTE_ACCESS_CONTROLLER_PRIVATE_H
|
||||
|
||||
struct _MetaWaylandSurfaceRoleTabletCursor
|
||||
{
|
||||
MetaWaylandSurfaceRoleCursor parent;
|
||||
};
|
||||
#include "meta/meta-remote-access-controller.h"
|
||||
|
||||
G_DEFINE_TYPE (MetaWaylandSurfaceRoleTabletCursor,
|
||||
meta_wayland_surface_role_tablet_cursor,
|
||||
META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR)
|
||||
void meta_remote_access_controller_notify_new_handle (MetaRemoteAccessController *controller,
|
||||
MetaRemoteAccessHandle *handle);
|
||||
|
||||
static void
|
||||
meta_wayland_surface_role_tablet_cursor_init (MetaWaylandSurfaceRoleTabletCursor *role)
|
||||
{
|
||||
}
|
||||
void meta_remote_access_handle_notify_stopped (MetaRemoteAccessHandle *handle);
|
||||
|
||||
static void
|
||||
meta_wayland_surface_role_tablet_cursor_class_init (MetaWaylandSurfaceRoleTabletCursorClass *klass)
|
||||
{
|
||||
}
|
||||
#endif /* META_REMOTE_ACCESS_CONTROLLER_PRIVATE_H */
|
130
src/backends/meta-remote-access-controller.c
Normal file
130
src/backends/meta-remote-access-controller.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
|
||||
enum
|
||||
{
|
||||
HANDLE_STOPPED,
|
||||
|
||||
N_HANDLE_SIGNALS
|
||||
};
|
||||
|
||||
static int handle_signals[N_HANDLE_SIGNALS];
|
||||
|
||||
enum
|
||||
{
|
||||
CONTROLLER_NEW_HANDLE,
|
||||
|
||||
N_CONTROLLER_SIGNALS
|
||||
};
|
||||
|
||||
static int controller_signals[N_CONTROLLER_SIGNALS];
|
||||
|
||||
typedef struct _MetaRemoteAccessHandlePrivate
|
||||
{
|
||||
gboolean has_stopped;
|
||||
} MetaRemoteAccessHandlePrivate;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaRemoteAccessHandle,
|
||||
meta_remote_access_handle,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
struct _MetaRemoteAccessController
|
||||
{
|
||||
GObject parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaRemoteAccessController,
|
||||
meta_remote_access_controller,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
/**
|
||||
* meta_remote_access_handle_stop:
|
||||
* @handle: A #MetaRemoteAccessHandle
|
||||
*
|
||||
* Stop the associated remote access session.
|
||||
*/
|
||||
void
|
||||
meta_remote_access_handle_stop (MetaRemoteAccessHandle *handle)
|
||||
{
|
||||
MetaRemoteAccessHandlePrivate *priv =
|
||||
meta_remote_access_handle_get_instance_private (handle);
|
||||
|
||||
if (priv->has_stopped)
|
||||
return;
|
||||
|
||||
META_REMOTE_ACCESS_HANDLE_GET_CLASS (handle)->stop (handle);
|
||||
}
|
||||
|
||||
void
|
||||
meta_remote_access_handle_notify_stopped (MetaRemoteAccessHandle *handle)
|
||||
{
|
||||
MetaRemoteAccessHandlePrivate *priv =
|
||||
meta_remote_access_handle_get_instance_private (handle);
|
||||
|
||||
priv->has_stopped = TRUE;
|
||||
g_signal_emit (handle, handle_signals[HANDLE_STOPPED], 0);
|
||||
}
|
||||
|
||||
void
|
||||
meta_remote_access_controller_notify_new_handle (MetaRemoteAccessController *controller,
|
||||
MetaRemoteAccessHandle *handle)
|
||||
{
|
||||
g_signal_emit (controller, controller_signals[CONTROLLER_NEW_HANDLE], 0,
|
||||
handle);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_access_handle_init (MetaRemoteAccessHandle *handle)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_access_handle_class_init (MetaRemoteAccessHandleClass *klass)
|
||||
{
|
||||
handle_signals[HANDLE_STOPPED] =
|
||||
g_signal_new ("stopped",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_access_controller_init (MetaRemoteAccessController *controller)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_access_controller_class_init (MetaRemoteAccessControllerClass *klass)
|
||||
{
|
||||
controller_signals[CONTROLLER_NEW_HANDLE] =
|
||||
g_signal_new ("new-handle",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
META_TYPE_REMOTE_ACCESS_HANDLE);
|
||||
}
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
#include "backends/meta-screen-cast-session.h"
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
#include "backends/native/meta-backend-native.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "cogl/cogl.h"
|
||||
@ -59,6 +60,8 @@ struct _MetaRemoteDesktopSession
|
||||
ClutterVirtualInputDevice *virtual_pointer;
|
||||
ClutterVirtualInputDevice *virtual_keyboard;
|
||||
ClutterVirtualInputDevice *virtual_touchscreen;
|
||||
|
||||
MetaRemoteDesktopSessionHandle *handle;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -75,12 +78,41 @@ G_DEFINE_TYPE_WITH_CODE (MetaRemoteDesktopSession,
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_DBUS_SESSION,
|
||||
meta_dbus_session_init_iface))
|
||||
|
||||
struct _MetaRemoteDesktopSessionHandle
|
||||
{
|
||||
MetaRemoteAccessHandle parent;
|
||||
|
||||
MetaRemoteDesktopSession *session;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaRemoteDesktopSessionHandle,
|
||||
meta_remote_desktop_session_handle,
|
||||
META_TYPE_REMOTE_ACCESS_HANDLE)
|
||||
|
||||
static MetaRemoteDesktopSessionHandle *
|
||||
meta_remote_desktop_session_handle_new (MetaRemoteDesktopSession *session);
|
||||
|
||||
static gboolean
|
||||
meta_remote_desktop_session_is_running (MetaRemoteDesktopSession *session)
|
||||
{
|
||||
return !!session->virtual_pointer;
|
||||
}
|
||||
|
||||
static void
|
||||
init_remote_access_handle (MetaRemoteDesktopSession *session)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaRemoteAccessController *remote_access_controller;
|
||||
MetaRemoteAccessHandle *remote_access_handle;
|
||||
|
||||
session->handle = meta_remote_desktop_session_handle_new (session);
|
||||
|
||||
remote_access_controller = meta_backend_get_remote_access_controller (backend);
|
||||
remote_access_handle = META_REMOTE_ACCESS_HANDLE (session->handle);
|
||||
meta_remote_access_controller_notify_new_handle (remote_access_controller,
|
||||
remote_access_handle);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_remote_desktop_session_start (MetaRemoteDesktopSession *session,
|
||||
GError **error)
|
||||
@ -107,6 +139,8 @@ meta_remote_desktop_session_start (MetaRemoteDesktopSession *session,
|
||||
clutter_device_manager_create_virtual_device (device_manager,
|
||||
CLUTTER_TOUCHSCREEN_DEVICE);
|
||||
|
||||
init_remote_access_handle (session);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -126,11 +160,20 @@ meta_remote_desktop_session_close (MetaRemoteDesktopSession *session)
|
||||
|
||||
g_clear_object (&session->virtual_pointer);
|
||||
g_clear_object (&session->virtual_keyboard);
|
||||
g_clear_object (&session->virtual_touchscreen);
|
||||
|
||||
meta_dbus_session_notify_closed (META_DBUS_SESSION (session));
|
||||
meta_dbus_remote_desktop_session_emit_closed (skeleton);
|
||||
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (session));
|
||||
|
||||
if (session->handle)
|
||||
{
|
||||
MetaRemoteAccessHandle *remote_access_handle =
|
||||
META_REMOTE_ACCESS_HANDLE (session->handle);
|
||||
|
||||
meta_remote_access_handle_notify_stopped (remote_access_handle);
|
||||
}
|
||||
|
||||
g_object_unref (session);
|
||||
}
|
||||
|
||||
@ -729,6 +772,7 @@ meta_remote_desktop_session_finalize (GObject *object)
|
||||
|
||||
g_assert (!meta_remote_desktop_session_is_running (session));
|
||||
|
||||
g_clear_object (&session->handle);
|
||||
g_free (session->peer_name);
|
||||
g_free (session->session_id);
|
||||
g_free (session->object_path);
|
||||
@ -763,3 +807,40 @@ meta_remote_desktop_session_class_init (MetaRemoteDesktopSessionClass *klass)
|
||||
|
||||
object_class->finalize = meta_remote_desktop_session_finalize;
|
||||
}
|
||||
|
||||
static MetaRemoteDesktopSessionHandle *
|
||||
meta_remote_desktop_session_handle_new (MetaRemoteDesktopSession *session)
|
||||
{
|
||||
MetaRemoteDesktopSessionHandle *handle;
|
||||
|
||||
handle = g_object_new (META_TYPE_REMOTE_DESKTOP_SESSION_HANDLE, NULL);
|
||||
handle->session = session;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_session_handle_stop (MetaRemoteAccessHandle *handle)
|
||||
{
|
||||
MetaRemoteDesktopSession *session;
|
||||
|
||||
session = META_REMOTE_DESKTOP_SESSION_HANDLE (handle)->session;
|
||||
if (!session)
|
||||
return;
|
||||
|
||||
meta_remote_desktop_session_close (session);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_session_handle_init (MetaRemoteDesktopSessionHandle *handle)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_session_handle_class_init (MetaRemoteDesktopSessionHandleClass *klass)
|
||||
{
|
||||
MetaRemoteAccessHandleClass *remote_access_handle_class =
|
||||
META_REMOTE_ACCESS_HANDLE_CLASS (klass);
|
||||
|
||||
remote_access_handle_class->stop = meta_remote_desktop_session_handle_stop;
|
||||
}
|
||||
|
@ -33,6 +33,12 @@ G_DECLARE_FINAL_TYPE (MetaRemoteDesktopSession, meta_remote_desktop_session,
|
||||
META, REMOTE_DESKTOP_SESSION,
|
||||
MetaDBusRemoteDesktopSessionSkeleton)
|
||||
|
||||
#define META_TYPE_REMOTE_DESKTOP_SESSION_HANDLE (meta_remote_desktop_session_handle_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaRemoteDesktopSessionHandle,
|
||||
meta_remote_desktop_session_handle,
|
||||
META, REMOTE_DESKTOP_SESSION_HANDLE,
|
||||
MetaRemoteAccessHandle)
|
||||
|
||||
char * meta_remote_desktop_session_get_object_path (MetaRemoteDesktopSession *session);
|
||||
|
||||
char * meta_remote_desktop_session_get_session_id (MetaRemoteDesktopSession *session);
|
||||
|
@ -94,6 +94,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-screen-cast-monitor-stream.h"
|
||||
#include "backends/meta-screen-cast-session.h"
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-monitor.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);
|
||||
|
||||
|
@ -26,8 +26,11 @@
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
#include "backends/meta-screen-cast-monitor-stream.h"
|
||||
#include "backends/meta-screen-cast-stream.h"
|
||||
#include "backends/meta-screen-cast-window-stream.h"
|
||||
#include "core/display-private.h"
|
||||
|
||||
#define META_SCREEN_CAST_SESSION_DBUS_PATH "/org/gnome/Mutter/ScreenCast/Session"
|
||||
|
||||
@ -35,12 +38,16 @@ struct _MetaScreenCastSession
|
||||
{
|
||||
MetaDBusScreenCastSessionSkeleton parent;
|
||||
|
||||
MetaScreenCast *screen_cast;
|
||||
|
||||
char *peer_name;
|
||||
|
||||
MetaScreenCastSessionType session_type;
|
||||
char *object_path;
|
||||
|
||||
GList *streams;
|
||||
|
||||
MetaScreenCastSessionHandle *handle;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -57,6 +64,35 @@ G_DEFINE_TYPE_WITH_CODE (MetaScreenCastSession,
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_DBUS_SESSION,
|
||||
meta_dbus_session_init_iface))
|
||||
|
||||
struct _MetaScreenCastSessionHandle
|
||||
{
|
||||
MetaRemoteAccessHandle parent;
|
||||
|
||||
MetaScreenCastSession *session;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaScreenCastSessionHandle,
|
||||
meta_screen_cast_session_handle,
|
||||
META_TYPE_REMOTE_ACCESS_HANDLE)
|
||||
|
||||
static MetaScreenCastSessionHandle *
|
||||
meta_screen_cast_session_handle_new (MetaScreenCastSession *session);
|
||||
|
||||
static void
|
||||
init_remote_access_handle (MetaScreenCastSession *session)
|
||||
{
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaRemoteAccessController *remote_access_controller;
|
||||
MetaRemoteAccessHandle *remote_access_handle;
|
||||
|
||||
session->handle = meta_screen_cast_session_handle_new (session);
|
||||
|
||||
remote_access_controller = meta_backend_get_remote_access_controller (backend);
|
||||
remote_access_handle = META_REMOTE_ACCESS_HANDLE (session->handle);
|
||||
meta_remote_access_controller_notify_new_handle (remote_access_controller,
|
||||
remote_access_handle);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_screen_cast_session_start (MetaScreenCastSession *session,
|
||||
GError **error)
|
||||
@ -71,6 +107,8 @@ meta_screen_cast_session_start (MetaScreenCastSession *session,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
init_remote_access_handle (session);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -94,6 +132,14 @@ meta_screen_cast_session_close (MetaScreenCastSession *session)
|
||||
|
||||
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (session));
|
||||
|
||||
if (session->handle)
|
||||
{
|
||||
MetaRemoteAccessHandle *remote_access_handle =
|
||||
META_REMOTE_ACCESS_HANDLE (session->handle);
|
||||
|
||||
meta_remote_access_handle_notify_stopped (remote_access_handle);
|
||||
}
|
||||
|
||||
g_object_unref (session);
|
||||
}
|
||||
|
||||
@ -115,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)
|
||||
{
|
||||
@ -210,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,
|
||||
@ -223,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;
|
||||
@ -254,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)
|
||||
{
|
||||
@ -291,6 +374,15 @@ handle_record_window (MetaDBusScreenCastSession *skeleton,
|
||||
GVariant *properties_variant)
|
||||
{
|
||||
MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (skeleton);
|
||||
GDBusInterfaceSkeleton *interface_skeleton;
|
||||
GDBusConnection *connection;
|
||||
MetaWindow *window;
|
||||
GError *error = NULL;
|
||||
MetaDisplay *display;
|
||||
GVariant *window_id_variant = NULL;
|
||||
MetaScreenCastWindowStream *window_stream;
|
||||
MetaScreenCastStream *stream;
|
||||
char *stream_path;
|
||||
|
||||
if (!check_permission (session, invocation))
|
||||
{
|
||||
@ -300,9 +392,60 @@ handle_record_window (MetaDBusScreenCastSession *skeleton,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Recording a window not yet supported");
|
||||
if (properties_variant)
|
||||
window_id_variant = g_variant_lookup_value (properties_variant,
|
||||
"window-id",
|
||||
G_VARIANT_TYPE ("t"));
|
||||
|
||||
display = meta_get_display ();
|
||||
if (window_id_variant)
|
||||
{
|
||||
uint64_t window_id;
|
||||
|
||||
g_variant_get (window_id_variant, "t", &window_id);
|
||||
window = meta_display_get_window_from_id (display, window_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
window = meta_display_get_focus_window (display);
|
||||
}
|
||||
|
||||
if (!window)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Window not found");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton);
|
||||
connection = g_dbus_interface_skeleton_get_connection (interface_skeleton);
|
||||
|
||||
window_stream = meta_screen_cast_window_stream_new (session,
|
||||
connection,
|
||||
window,
|
||||
&error);
|
||||
if (!window_stream)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Failed to record window: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
stream = META_SCREEN_CAST_STREAM (window_stream);
|
||||
stream_path = meta_screen_cast_stream_get_object_path (stream);
|
||||
|
||||
session->streams = g_list_append (session->streams, stream);
|
||||
|
||||
g_signal_connect (stream, "closed", G_CALLBACK (on_stream_closed), session);
|
||||
|
||||
meta_dbus_screen_cast_session_complete_record_window (skeleton,
|
||||
invocation,
|
||||
stream_path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -339,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 =
|
||||
@ -361,6 +505,7 @@ meta_screen_cast_session_finalize (GObject *object)
|
||||
{
|
||||
MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (object);
|
||||
|
||||
g_clear_object (&session->handle);
|
||||
g_free (session->peer_name);
|
||||
g_free (session->object_path);
|
||||
|
||||
@ -379,3 +524,40 @@ meta_screen_cast_session_class_init (MetaScreenCastSessionClass *klass)
|
||||
|
||||
object_class->finalize = meta_screen_cast_session_finalize;
|
||||
}
|
||||
|
||||
static MetaScreenCastSessionHandle *
|
||||
meta_screen_cast_session_handle_new (MetaScreenCastSession *session)
|
||||
{
|
||||
MetaScreenCastSessionHandle *handle;
|
||||
|
||||
handle = g_object_new (META_TYPE_SCREEN_CAST_SESSION_HANDLE, NULL);
|
||||
handle->session = session;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_session_handle_stop (MetaRemoteAccessHandle *handle)
|
||||
{
|
||||
MetaScreenCastSession *session;
|
||||
|
||||
session = META_SCREEN_CAST_SESSION_HANDLE (handle)->session;
|
||||
if (!session)
|
||||
return;
|
||||
|
||||
meta_screen_cast_session_close (session);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_session_handle_init (MetaScreenCastSessionHandle *handle)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_session_handle_class_init (MetaScreenCastSessionHandleClass *klass)
|
||||
{
|
||||
MetaRemoteAccessHandleClass *remote_access_handle_class =
|
||||
META_REMOTE_ACCESS_HANDLE_CLASS (klass);
|
||||
|
||||
remote_access_handle_class->stop = meta_screen_cast_session_handle_stop;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "backends/meta-screen-cast.h"
|
||||
|
||||
#include "backends/meta-screen-cast-stream.h"
|
||||
#include "meta/meta-remote-access-controller.h"
|
||||
|
||||
typedef enum _MetaScreenCastSessionType
|
||||
{
|
||||
@ -38,6 +39,12 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastSession, meta_screen_cast_session,
|
||||
META, SCREEN_CAST_SESSION,
|
||||
MetaDBusScreenCastSessionSkeleton)
|
||||
|
||||
#define META_TYPE_SCREEN_CAST_SESSION_HANDLE (meta_screen_cast_session_handle_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaScreenCastSessionHandle,
|
||||
meta_screen_cast_session_handle,
|
||||
META, SCREEN_CAST_SESSION_HANDLE,
|
||||
MetaRemoteAccessHandle)
|
||||
|
||||
char * meta_screen_cast_session_get_object_path (MetaScreenCastSession *session);
|
||||
|
||||
MetaScreenCastSession * meta_screen_cast_session_new (MetaScreenCast *screen_cast,
|
||||
@ -53,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;
|
||||
@ -91,6 +87,9 @@ typedef struct _MetaScreenCastStreamSrcPrivate
|
||||
struct spa_video_info_raw video_format;
|
||||
|
||||
uint64_t last_frame_timestamp_us;
|
||||
|
||||
int stream_width;
|
||||
int stream_height;
|
||||
} MetaScreenCastStreamSrcPrivate;
|
||||
|
||||
static void
|
||||
@ -117,14 +116,81 @@ meta_screen_cast_stream_src_get_specs (MetaScreenCastStreamSrc *src,
|
||||
klass->get_specs (src, width, height, frame_rate);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
meta_screen_cast_stream_src_get_videocrop (MetaScreenCastStreamSrc *src,
|
||||
MetaRectangle *crop_rect)
|
||||
{
|
||||
MetaScreenCastStreamSrcClass *klass =
|
||||
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
|
||||
|
||||
if (klass->get_videocrop)
|
||||
return klass->get_videocrop (src, crop_rect);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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
|
||||
@ -132,8 +198,9 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
|
||||
{
|
||||
MetaScreenCastStreamSrcPrivate *priv =
|
||||
meta_screen_cast_stream_src_get_instance_private (src);
|
||||
uint32_t buffer_id;
|
||||
struct spa_buffer *buffer;
|
||||
MetaRectangle crop_rect;
|
||||
struct pw_buffer *buffer;
|
||||
struct spa_buffer *spa_buffer;
|
||||
uint8_t *map = NULL;
|
||||
uint8_t *data;
|
||||
uint64_t now_us;
|
||||
@ -148,17 +215,24 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
|
||||
if (!priv->pipewire_stream)
|
||||
return;
|
||||
|
||||
buffer_id = pw_stream_get_empty_buffer (priv->pipewire_stream);
|
||||
if (buffer_id == SPA_ID_INVALID)
|
||||
return;
|
||||
|
||||
buffer = pw_stream_peek_buffer (priv->pipewire_stream, buffer_id);
|
||||
|
||||
if (buffer->datas[0].type == priv->pipewire_type->data.MemFd)
|
||||
buffer = pw_stream_dequeue_buffer (priv->pipewire_stream);
|
||||
if (!buffer)
|
||||
{
|
||||
map = mmap (NULL, buffer->datas[0].maxsize + buffer->datas[0].mapoffset,
|
||||
g_warning ("Failed to dequeue at PipeWire buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
spa_buffer = buffer->buffer;
|
||||
|
||||
if (spa_buffer->datas[0].data)
|
||||
{
|
||||
data = spa_buffer->datas[0].data;
|
||||
}
|
||||
else if (spa_buffer->datas[0].type == priv->pipewire_type->data.MemFd)
|
||||
{
|
||||
map = mmap (NULL, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
buffer->datas[0].fd, 0);
|
||||
spa_buffer->datas[0].fd, 0);
|
||||
if (map == MAP_FAILED)
|
||||
{
|
||||
g_warning ("Failed to mmap pipewire stream buffer: %s\n",
|
||||
@ -166,26 +240,54 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
|
||||
return;
|
||||
}
|
||||
|
||||
data = SPA_MEMBER (map, buffer->datas[0].mapoffset, uint8_t);
|
||||
}
|
||||
else if (buffer->datas[0].type == priv->pipewire_type->data.MemPtr)
|
||||
{
|
||||
data = buffer->datas[0].data;
|
||||
data = SPA_MEMBER (map, spa_buffer->datas[0].mapoffset, uint8_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Unhandled spa buffer type: %d", spa_buffer->datas[0].type);
|
||||
return;
|
||||
}
|
||||
|
||||
meta_screen_cast_stream_src_record_frame (src, data);
|
||||
if (meta_screen_cast_stream_src_record_frame (src, data))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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, buffer->datas[0].maxsize + buffer->datas[0].mapoffset);
|
||||
munmap (map, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset);
|
||||
|
||||
buffer->datas[0].chunk->size = buffer->datas[0].maxsize;
|
||||
|
||||
pw_stream_send_buffer (priv->pipewire_stream, buffer_id);
|
||||
pw_stream_queue_buffer (priv->pipewire_stream, buffer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -261,8 +363,8 @@ on_stream_state_changed (void *data,
|
||||
}
|
||||
|
||||
static void
|
||||
on_stream_format_changed (void *data,
|
||||
struct spa_pod *format)
|
||||
on_stream_format_changed (void *data,
|
||||
const struct spa_pod *format)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src = data;
|
||||
MetaScreenCastStreamSrcPrivate *priv =
|
||||
@ -271,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;
|
||||
struct spa_pod *params[1];
|
||||
const struct spa_pod *params[3];
|
||||
const int bpp = 4;
|
||||
|
||||
if (!format)
|
||||
@ -299,6 +401,18 @@ on_stream_format_changed (void *data,
|
||||
":", pipewire_type->param_buffers.buffers, "iru", 16, PROP_RANGE (2, 16),
|
||||
":", pipewire_type->param_buffers.align, "i", 16);
|
||||
|
||||
params[1] = spa_pod_builder_object (
|
||||
&pod_builder,
|
||||
pipewire_type->param.idMeta, pipewire_type->param_meta.Meta,
|
||||
":", 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));
|
||||
}
|
||||
@ -321,18 +435,28 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src,
|
||||
SPA_POD_BUILDER_INIT (buffer, sizeof (buffer));
|
||||
MetaSpaType *spa_type = &priv->spa_type;
|
||||
struct pw_type *pipewire_type = priv->pipewire_type;
|
||||
int width, height;
|
||||
float frame_rate;
|
||||
MetaFraction frame_rate_fraction;
|
||||
struct spa_fraction max_framerate;
|
||||
struct spa_fraction min_framerate;
|
||||
const struct spa_pod *params[1];
|
||||
int result;
|
||||
|
||||
pipewire_stream = pw_stream_new (priv->pipewire_remote,
|
||||
"meta-screen-cast-src",
|
||||
NULL);
|
||||
if (!pipewire_stream)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Failed to create PipeWire stream: %s",
|
||||
strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
meta_screen_cast_stream_src_get_specs (src, &width, &height, &frame_rate);
|
||||
meta_screen_cast_stream_src_get_specs (src,
|
||||
&priv->stream_width,
|
||||
&priv->stream_height,
|
||||
&frame_rate);
|
||||
frame_rate_fraction = meta_fraction_from_double (frame_rate);
|
||||
|
||||
min_framerate = SPA_FRACTION (1, 1);
|
||||
@ -345,25 +469,28 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src,
|
||||
"I", spa_type->media_type.video,
|
||||
"I", spa_type->media_subtype.raw,
|
||||
":", spa_type->format_video.format, "I", spa_type->video_format.BGRx,
|
||||
":", spa_type->format_video.size, "R", &SPA_RECTANGLE (width, height),
|
||||
":", spa_type->format_video.size, "R", &SPA_RECTANGLE (priv->stream_width,
|
||||
priv->stream_height),
|
||||
":", spa_type->format_video.framerate, "F", &SPA_FRACTION (0, 1),
|
||||
":", spa_type->format_video.max_framerate, "Fr", &max_framerate,
|
||||
PROP_RANGE (&min_framerate,
|
||||
&max_framerate));
|
||||
":", spa_type->format_video.max_framerate, "Fru", &max_framerate,
|
||||
PROP_RANGE (&min_framerate,
|
||||
&max_framerate));
|
||||
|
||||
pw_stream_add_listener (pipewire_stream,
|
||||
&priv->pipewire_stream_listener,
|
||||
&stream_events,
|
||||
src);
|
||||
|
||||
if (pw_stream_connect (pipewire_stream,
|
||||
PW_DIRECTION_OUTPUT,
|
||||
NULL,
|
||||
PW_STREAM_FLAG_NONE,
|
||||
params, G_N_ELEMENTS (¶ms)) != 0)
|
||||
result = pw_stream_connect (pipewire_stream,
|
||||
PW_DIRECTION_OUTPUT,
|
||||
NULL,
|
||||
(PW_STREAM_FLAG_DRIVER |
|
||||
PW_STREAM_FLAG_MAP_BUFFERS),
|
||||
params, G_N_ELEMENTS (params));
|
||||
if (result != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Could not connect");
|
||||
"Could not connect: %s", spa_strerror (result));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -455,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 *
|
||||
@ -466,6 +594,12 @@ create_pipewire_source (void)
|
||||
(MetaPipeWireSource *) g_source_new (&pipewire_source_funcs,
|
||||
sizeof (MetaPipeWireSource));
|
||||
pipewire_source->pipewire_loop = pw_loop_new (NULL);
|
||||
if (!pipewire_source->pipewire_loop)
|
||||
{
|
||||
g_source_destroy ((GSource *) pipewire_source);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_source_add_unix_fd (&pipewire_source->base,
|
||||
pw_loop_get_fd (pipewire_source->pipewire_loop),
|
||||
G_IO_IN | G_IO_ERR);
|
||||
@ -491,6 +625,13 @@ meta_screen_cast_stream_src_initable_init (GInitable *initable,
|
||||
meta_screen_cast_stream_src_get_instance_private (src);
|
||||
|
||||
priv->pipewire_source = create_pipewire_source ();
|
||||
if (!priv->pipewire_source)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Failed to create PipeWire source");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
priv->pipewire_core = pw_core_new (priv->pipewire_source->pipewire_loop,
|
||||
NULL);
|
||||
if (!priv->pipewire_core)
|
||||
|
@ -24,8 +24,25 @@
|
||||
#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;
|
||||
|
||||
@ -45,12 +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,8 +26,12 @@
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "backends/meta-screen-cast-stream-src.h"
|
||||
#include "backends/meta-screen-cast.h"
|
||||
|
||||
#include "meta-dbus-screen-cast.h"
|
||||
|
||||
typedef struct _MetaScreenCastSession MetaScreenCastSession;
|
||||
|
||||
#define META_TYPE_SCREEN_CAST_STREAM (meta_screen_cast_stream_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (MetaScreenCastStream, meta_screen_cast_stream,
|
||||
META, SCREEN_CAST_STREAM,
|
||||
@ -48,6 +52,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 +67,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 */
|
||||
|
247
src/backends/meta-screen-cast-window-stream-src.c
Normal file
247
src/backends/meta-screen-cast-window-stream-src.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/meta-screen-cast-window-stream-src.h"
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-screen-cast-window.h"
|
||||
#include "backends/meta-screen-cast-window-stream.h"
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
|
||||
struct _MetaScreenCastWindowStreamSrc
|
||||
{
|
||||
MetaScreenCastStreamSrc parent;
|
||||
|
||||
MetaWindowActor *window_actor;
|
||||
|
||||
unsigned long actor_painted_handler_id;
|
||||
unsigned long actor_destroyed_handler_id;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaScreenCastWindowStreamSrc,
|
||||
meta_screen_cast_window_stream_src,
|
||||
META_TYPE_SCREEN_CAST_STREAM_SRC)
|
||||
|
||||
static MetaScreenCastWindowStream *
|
||||
get_window_stream (MetaScreenCastWindowStreamSrc *window_src)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src;
|
||||
MetaScreenCastStream *stream;
|
||||
|
||||
src = META_SCREEN_CAST_STREAM_SRC (window_src);
|
||||
stream = meta_screen_cast_stream_src_get_stream (src);
|
||||
|
||||
return META_SCREEN_CAST_WINDOW_STREAM (stream);
|
||||
}
|
||||
|
||||
static MetaWindow *
|
||||
get_window (MetaScreenCastWindowStreamSrc *window_src)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream;
|
||||
|
||||
window_stream = get_window_stream (window_src);
|
||||
|
||||
return meta_screen_cast_window_stream_get_window (window_stream);
|
||||
}
|
||||
|
||||
static int
|
||||
get_stream_width (MetaScreenCastWindowStreamSrc *window_src)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream;
|
||||
|
||||
window_stream = get_window_stream (window_src);
|
||||
|
||||
return meta_screen_cast_window_stream_get_width (window_stream);
|
||||
}
|
||||
|
||||
static int
|
||||
get_stream_height (MetaScreenCastWindowStreamSrc *window_src)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream;
|
||||
|
||||
window_stream = get_window_stream (window_src);
|
||||
|
||||
return meta_screen_cast_window_stream_get_height (window_stream);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
capture_into (MetaScreenCastWindowStreamSrc *window_src,
|
||||
uint8_t *data)
|
||||
{
|
||||
MetaRectangle stream_rect;
|
||||
MetaScreenCastWindow *screen_cast_window;
|
||||
|
||||
stream_rect.x = 0;
|
||||
stream_rect.y = 0;
|
||||
stream_rect.width = get_stream_width (window_src);
|
||||
stream_rect.height = get_stream_height (window_src);
|
||||
|
||||
screen_cast_window = META_SCREEN_CAST_WINDOW (window_src->window_actor);
|
||||
meta_screen_cast_window_capture_into (screen_cast_window, &stream_rect, data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_src_get_specs (MetaScreenCastStreamSrc *src,
|
||||
int *width,
|
||||
int *height,
|
||||
float *frame_rate)
|
||||
{
|
||||
MetaScreenCastWindowStreamSrc *window_src =
|
||||
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
|
||||
|
||||
*width = get_stream_width (window_src);
|
||||
*height = get_stream_height (window_src);
|
||||
*frame_rate = 60.0f;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_screen_cast_window_stream_src_get_videocrop (MetaScreenCastStreamSrc *src,
|
||||
MetaRectangle *crop_rect)
|
||||
{
|
||||
MetaScreenCastWindowStreamSrc *window_src =
|
||||
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
|
||||
MetaScreenCastWindow *screen_cast_window;
|
||||
MetaRectangle stream_rect;
|
||||
|
||||
screen_cast_window = META_SCREEN_CAST_WINDOW (window_src->window_actor);
|
||||
meta_screen_cast_window_get_frame_bounds (screen_cast_window, crop_rect);
|
||||
|
||||
stream_rect.x = 0;
|
||||
stream_rect.y = 0;
|
||||
stream_rect.width = get_stream_width (window_src);
|
||||
stream_rect.height = get_stream_height (window_src);
|
||||
|
||||
meta_rectangle_intersect (crop_rect, &stream_rect, crop_rect);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_src_stop (MetaScreenCastWindowStreamSrc *window_src)
|
||||
|
||||
{
|
||||
if (!window_src->window_actor)
|
||||
return;
|
||||
|
||||
if (window_src->actor_painted_handler_id)
|
||||
g_signal_handler_disconnect (window_src->window_actor,
|
||||
window_src->actor_painted_handler_id);
|
||||
window_src->actor_painted_handler_id = 0;
|
||||
|
||||
if (window_src->actor_destroyed_handler_id)
|
||||
g_signal_handler_disconnect (window_src->window_actor,
|
||||
window_src->actor_destroyed_handler_id);
|
||||
window_src->actor_destroyed_handler_id = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
window_actor_painted (MetaWindowActor *actor,
|
||||
MetaScreenCastWindowStreamSrc *window_src)
|
||||
{
|
||||
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src);
|
||||
|
||||
meta_screen_cast_stream_src_maybe_record_frame (src);
|
||||
}
|
||||
|
||||
static void
|
||||
window_actor_destroyed (MetaWindowActor *actor,
|
||||
MetaScreenCastWindowStreamSrc *window_src)
|
||||
{
|
||||
meta_screen_cast_window_stream_src_stop (window_src);
|
||||
window_src->window_actor = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src)
|
||||
{
|
||||
MetaScreenCastWindowStreamSrc *window_src =
|
||||
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
|
||||
MetaWindowActor *window_actor;
|
||||
|
||||
window_actor = meta_window_actor_from_window (get_window (window_src));
|
||||
if (!window_actor)
|
||||
return;
|
||||
|
||||
window_src->window_actor = window_actor;
|
||||
|
||||
window_src->actor_painted_handler_id =
|
||||
g_signal_connect_after (window_src->window_actor,
|
||||
"paint",
|
||||
G_CALLBACK (window_actor_painted),
|
||||
window_src);
|
||||
|
||||
window_src->actor_destroyed_handler_id =
|
||||
g_signal_connect (window_src->window_actor,
|
||||
"destroy",
|
||||
G_CALLBACK (window_actor_destroyed),
|
||||
window_src);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_src_disable (MetaScreenCastStreamSrc *src)
|
||||
{
|
||||
MetaScreenCastWindowStreamSrc *window_src =
|
||||
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
|
||||
|
||||
meta_screen_cast_window_stream_src_stop (window_src);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
|
||||
uint8_t *data)
|
||||
{
|
||||
MetaScreenCastWindowStreamSrc *window_src =
|
||||
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
|
||||
|
||||
capture_into (window_src, data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaScreenCastWindowStreamSrc *
|
||||
meta_screen_cast_window_stream_src_new (MetaScreenCastWindowStream *window_stream,
|
||||
GError **error)
|
||||
{
|
||||
return g_initable_new (META_TYPE_SCREEN_CAST_WINDOW_STREAM_SRC, NULL, error,
|
||||
"stream", window_stream,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_src_init (MetaScreenCastWindowStreamSrc *window_src)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_src_class_init (MetaScreenCastWindowStreamSrcClass *klass)
|
||||
{
|
||||
MetaScreenCastStreamSrcClass *src_class =
|
||||
META_SCREEN_CAST_STREAM_SRC_CLASS (klass);
|
||||
|
||||
src_class->get_specs = meta_screen_cast_window_stream_src_get_specs;
|
||||
src_class->enable = meta_screen_cast_window_stream_src_enable;
|
||||
src_class->disable = meta_screen_cast_window_stream_src_disable;
|
||||
src_class->record_frame = meta_screen_cast_window_stream_src_record_frame;
|
||||
src_class->get_videocrop = meta_screen_cast_window_stream_src_get_videocrop;
|
||||
}
|
37
src/backends/meta-screen-cast-window-stream-src.h
Normal file
37
src/backends/meta-screen-cast-window-stream-src.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef META_SCREEN_CAST_WINDOW_STREAM_SRC_H
|
||||
#define META_SCREEN_CAST_WINDOW_STREAM_SRC_H
|
||||
|
||||
#include "backends/meta-screen-cast-stream-src.h"
|
||||
|
||||
typedef struct _MetaScreenCastWindowStream MetaScreenCastWindowStream;
|
||||
|
||||
#define META_TYPE_SCREEN_CAST_WINDOW_STREAM_SRC (meta_screen_cast_window_stream_src_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaScreenCastWindowStreamSrc,
|
||||
meta_screen_cast_window_stream_src,
|
||||
META, SCREEN_CAST_WINDOW_STREAM_SRC,
|
||||
MetaScreenCastStreamSrc)
|
||||
|
||||
MetaScreenCastWindowStreamSrc * meta_screen_cast_window_stream_src_new (MetaScreenCastWindowStream *window_stream,
|
||||
GError **error);
|
||||
|
||||
#endif /* META_SCREEN_CAST_WINDOW_STREAM_SRC_H */
|
272
src/backends/meta-screen-cast-window-stream.c
Normal file
272
src/backends/meta-screen-cast-window-stream.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/meta-screen-cast-window-stream.h"
|
||||
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-monitor-manager-private.h"
|
||||
#include "backends/meta-screen-cast-window.h"
|
||||
#include "backends/meta-screen-cast-window-stream-src.h"
|
||||
#include "compositor/meta-window-actor-private.h"
|
||||
#include "core/window-private.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_WINDOW,
|
||||
};
|
||||
|
||||
struct _MetaScreenCastWindowStream
|
||||
{
|
||||
MetaScreenCastStream parent;
|
||||
|
||||
MetaWindow *window;
|
||||
|
||||
int stream_width;
|
||||
int stream_height;
|
||||
|
||||
unsigned long window_unmanaged_handler_id;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaScreenCastWindowStream,
|
||||
meta_screen_cast_window_stream,
|
||||
META_TYPE_SCREEN_CAST_STREAM)
|
||||
|
||||
MetaWindow *
|
||||
meta_screen_cast_window_stream_get_window (MetaScreenCastWindowStream *window_stream)
|
||||
{
|
||||
return window_stream->window;
|
||||
}
|
||||
|
||||
int
|
||||
meta_screen_cast_window_stream_get_width (MetaScreenCastWindowStream *window_stream)
|
||||
{
|
||||
return window_stream->stream_width;
|
||||
}
|
||||
|
||||
int
|
||||
meta_screen_cast_window_stream_get_height (MetaScreenCastWindowStream *window_stream)
|
||||
{
|
||||
return window_stream->stream_height;
|
||||
}
|
||||
|
||||
MetaScreenCastWindowStream *
|
||||
meta_screen_cast_window_stream_new (MetaScreenCastSession *session,
|
||||
GDBusConnection *connection,
|
||||
MetaWindow *window,
|
||||
GError **error)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream;
|
||||
MetaLogicalMonitor *logical_monitor;
|
||||
int scale;
|
||||
|
||||
logical_monitor = meta_window_get_main_logical_monitor (window);
|
||||
if (!logical_monitor)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Main logical monitor not found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
window_stream = g_initable_new (META_TYPE_SCREEN_CAST_WINDOW_STREAM,
|
||||
NULL,
|
||||
error,
|
||||
"session", session,
|
||||
"connection", connection,
|
||||
"window", window,
|
||||
NULL);
|
||||
if (!window_stream)
|
||||
return NULL;
|
||||
|
||||
window_stream->window = window;
|
||||
/* We cannot set the stream size to the exact size of the window, because
|
||||
* windows can be resized, whereas streams cannot.
|
||||
* So we set a size equals to the size of the logical monitor for the window.
|
||||
*/
|
||||
scale = (int) ceil (meta_logical_monitor_get_scale (logical_monitor));
|
||||
window_stream->stream_width = logical_monitor->rect.width * scale;
|
||||
window_stream->stream_height = logical_monitor->rect.height * scale;
|
||||
|
||||
return window_stream;
|
||||
}
|
||||
|
||||
static MetaScreenCastStreamSrc *
|
||||
meta_screen_cast_window_stream_create_src (MetaScreenCastStream *stream,
|
||||
GError **error)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream =
|
||||
META_SCREEN_CAST_WINDOW_STREAM (stream);
|
||||
MetaScreenCastWindowStreamSrc *window_stream_src;
|
||||
|
||||
window_stream_src = meta_screen_cast_window_stream_src_new (window_stream,
|
||||
error);
|
||||
if (!window_stream_src)
|
||||
return NULL;
|
||||
|
||||
return META_SCREEN_CAST_STREAM_SRC (window_stream_src);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_set_parameters (MetaScreenCastStream *stream,
|
||||
GVariantBuilder *parameters_builder)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream =
|
||||
META_SCREEN_CAST_WINDOW_STREAM (stream);
|
||||
MetaScreenCastWindow *screen_cast_window =
|
||||
META_SCREEN_CAST_WINDOW (meta_window_actor_from_window (window_stream->window));
|
||||
MetaRectangle bounds;
|
||||
|
||||
meta_screen_cast_window_get_buffer_bounds (screen_cast_window, &bounds);
|
||||
|
||||
g_variant_builder_add (parameters_builder, "{sv}",
|
||||
"position",
|
||||
g_variant_new ("(ii)",
|
||||
bounds.x, bounds.y));
|
||||
|
||||
g_variant_builder_add (parameters_builder, "{sv}",
|
||||
"size",
|
||||
g_variant_new ("(ii)",
|
||||
bounds.width,
|
||||
bounds.height));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_transform_position (MetaScreenCastStream *stream,
|
||||
double stream_x,
|
||||
double stream_y,
|
||||
double *x,
|
||||
double *y)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream =
|
||||
META_SCREEN_CAST_WINDOW_STREAM (stream);
|
||||
MetaScreenCastWindow *screen_cast_window =
|
||||
META_SCREEN_CAST_WINDOW (meta_window_actor_from_window (window_stream->window));
|
||||
|
||||
meta_screen_cast_window_transform_relative_position (screen_cast_window,
|
||||
stream_x,
|
||||
stream_y,
|
||||
x,
|
||||
y);
|
||||
}
|
||||
|
||||
static void
|
||||
on_window_unmanaged (MetaScreenCastWindowStream *window_stream)
|
||||
{
|
||||
meta_screen_cast_stream_close (META_SCREEN_CAST_STREAM (window_stream));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_constructed (GObject *object)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream =
|
||||
META_SCREEN_CAST_WINDOW_STREAM (object);
|
||||
|
||||
window_stream->window_unmanaged_handler_id =
|
||||
g_signal_connect_swapped (window_stream->window, "unmanaged",
|
||||
G_CALLBACK (on_window_unmanaged),
|
||||
window_stream);
|
||||
|
||||
G_OBJECT_CLASS (meta_screen_cast_window_stream_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream =
|
||||
META_SCREEN_CAST_WINDOW_STREAM (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_WINDOW:
|
||||
window_stream->window = g_value_get_object (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream =
|
||||
META_SCREEN_CAST_WINDOW_STREAM (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_WINDOW:
|
||||
g_value_set_object (value, window_stream->window);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_finalize (GObject *object)
|
||||
{
|
||||
MetaScreenCastWindowStream *window_stream =
|
||||
META_SCREEN_CAST_WINDOW_STREAM (object);
|
||||
|
||||
g_signal_handler_disconnect (window_stream->window,
|
||||
window_stream->window_unmanaged_handler_id);
|
||||
|
||||
G_OBJECT_CLASS (meta_screen_cast_window_stream_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_init (MetaScreenCastWindowStream *window_stream)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_stream_class_init (MetaScreenCastWindowStreamClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MetaScreenCastStreamClass *stream_class =
|
||||
META_SCREEN_CAST_STREAM_CLASS (klass);
|
||||
|
||||
object_class->constructed = meta_screen_cast_window_stream_constructed;
|
||||
object_class->set_property = meta_screen_cast_window_stream_set_property;
|
||||
object_class->get_property = meta_screen_cast_window_stream_get_property;
|
||||
object_class->finalize = meta_screen_cast_window_stream_finalize;
|
||||
|
||||
stream_class->create_src = meta_screen_cast_window_stream_create_src;
|
||||
stream_class->set_parameters = meta_screen_cast_window_stream_set_parameters;
|
||||
stream_class->transform_position = meta_screen_cast_window_stream_transform_position;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_WINDOW,
|
||||
g_param_spec_object ("window",
|
||||
"window",
|
||||
"MetaWindow",
|
||||
META_TYPE_WINDOW,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
44
src/backends/meta-screen-cast-window-stream.h
Normal file
44
src/backends/meta-screen-cast-window-stream.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef META_SCREEN_CAST_WINDOW_STREAM_H
|
||||
#define META_SCREEN_CAST_WINDOW_STREAM_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "backends/meta-screen-cast-stream.h"
|
||||
#include "meta/window.h"
|
||||
|
||||
#define META_TYPE_SCREEN_CAST_WINDOW_STREAM (meta_screen_cast_window_stream_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaScreenCastWindowStream,
|
||||
meta_screen_cast_window_stream,
|
||||
META, SCREEN_CAST_WINDOW_STREAM,
|
||||
MetaScreenCastStream)
|
||||
|
||||
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);
|
||||
int meta_screen_cast_window_stream_get_height (MetaScreenCastWindowStream *window_stream);
|
||||
|
||||
#endif /* META_SCREEN_CAST_WINDOW_STREAM_H */
|
71
src/backends/meta-screen-cast-window.c
Normal file
71
src/backends/meta-screen-cast-window.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/meta-screen-cast-window.h"
|
||||
|
||||
G_DEFINE_INTERFACE (MetaScreenCastWindow, meta_screen_cast_window, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
meta_screen_cast_window_default_init (MetaScreenCastWindowInterface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_cast_window_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds)
|
||||
{
|
||||
META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window)->get_buffer_bounds (screen_cast_window,
|
||||
bounds);
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_cast_window_get_frame_bounds (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds)
|
||||
{
|
||||
META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window)->get_frame_bounds (screen_cast_window,
|
||||
bounds);
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_cast_window_transform_relative_position (MetaScreenCastWindow *screen_cast_window,
|
||||
double x,
|
||||
double y,
|
||||
double *x_out,
|
||||
double *y_out)
|
||||
{
|
||||
META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window)->transform_relative_position (screen_cast_window,
|
||||
x,
|
||||
y,
|
||||
x_out,
|
||||
y_out);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
meta_screen_cast_window_capture_into (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds,
|
||||
uint8_t *data)
|
||||
{
|
||||
META_SCREEN_CAST_WINDOW_GET_IFACE (screen_cast_window)->capture_into (screen_cast_window,
|
||||
bounds,
|
||||
data);
|
||||
}
|
74
src/backends/meta-screen-cast-window.h
Normal file
74
src/backends/meta-screen-cast-window.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef META_SCREEN_CAST_WINDOW_H
|
||||
#define META_SCREEN_CAST_WINDOW_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "meta/boxes.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_SCREEN_CAST_WINDOW (meta_screen_cast_window_get_type ())
|
||||
G_DECLARE_INTERFACE (MetaScreenCastWindow, meta_screen_cast_window,
|
||||
META, SCREEN_CAST_WINDOW, GObject)
|
||||
|
||||
struct _MetaScreenCastWindowInterface
|
||||
{
|
||||
GTypeInterface parent_iface;
|
||||
|
||||
void (*get_buffer_bounds) (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds);
|
||||
|
||||
void (*get_frame_bounds) (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds);
|
||||
|
||||
void (*transform_relative_position) (MetaScreenCastWindow *screen_cast_window,
|
||||
double x,
|
||||
double y,
|
||||
double *x_out,
|
||||
double *y_out);
|
||||
|
||||
void (*capture_into) (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds,
|
||||
uint8_t *data);
|
||||
};
|
||||
|
||||
void meta_screen_cast_window_get_buffer_bounds (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds);
|
||||
|
||||
void meta_screen_cast_window_get_frame_bounds (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds);
|
||||
|
||||
void meta_screen_cast_window_transform_relative_position (MetaScreenCastWindow *screen_cast_window,
|
||||
double x,
|
||||
double y,
|
||||
double *x_out,
|
||||
double *y_out);
|
||||
|
||||
void meta_screen_cast_window_capture_into (MetaScreenCastWindow *screen_cast_window,
|
||||
MetaRectangle *bounds,
|
||||
uint8_t *data);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_SCREEN_CAST_WINDOW_H */
|
@ -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,9 +25,17 @@
|
||||
|
||||
#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,
|
||||
@ -35,6 +43,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 */
|
||||
|
@ -31,8 +31,7 @@ typedef enum _MetaExperimentalFeature
|
||||
{
|
||||
META_EXPERIMENTAL_FEATURE_NONE = 0,
|
||||
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER = (1 << 0),
|
||||
META_EXPERIMENTAL_FEATURE_SCREEN_CAST = (1 << 1),
|
||||
META_EXPERIMENTAL_FEATURE_REMOTE_DESKTOP = (1 << 2),
|
||||
META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS = (1 << 1),
|
||||
} MetaExperimentalFeature;
|
||||
|
||||
#define META_TYPE_SETTINGS (meta_settings_get_type ())
|
||||
|
@ -263,10 +263,8 @@ experimental_features_handler (GVariant *features_variant,
|
||||
/* So far no experimental features defined. */
|
||||
if (g_str_equal (feature, "scale-monitor-framebuffer"))
|
||||
features |= META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER;
|
||||
else if (g_str_equal (feature, "screen-cast"))
|
||||
features |= META_EXPERIMENTAL_FEATURE_SCREEN_CAST;
|
||||
else if (g_str_equal (feature, "remote-desktop"))
|
||||
features |= META_EXPERIMENTAL_FEATURE_REMOTE_DESKTOP;
|
||||
else if (g_str_equal (feature, "kms-modifiers"))
|
||||
features |= META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS;
|
||||
else
|
||||
g_info ("Unknown experimental feature '%s'\n", feature);
|
||||
}
|
||||
|
@ -17,39 +17,23 @@
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_STAGE_H
|
||||
#define META_STAGE_H
|
||||
#ifndef META_STAGE_PRIVATE_H
|
||||
#define META_STAGE_PRIVATE_H
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <meta/meta-stage.h>
|
||||
|
||||
#include "meta-cursor.h"
|
||||
#include <meta/boxes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define META_TYPE_STAGE (meta_stage_get_type ())
|
||||
#define META_STAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_STAGE, MetaStage))
|
||||
#define META_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_STAGE, MetaStageClass))
|
||||
#define META_IS_STAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_STAGE))
|
||||
#define META_IS_STAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_STAGE))
|
||||
#define META_STAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_STAGE, MetaStageClass))
|
||||
|
||||
typedef struct _MetaStage MetaStage;
|
||||
typedef struct _MetaStageClass MetaStageClass;
|
||||
typedef struct _MetaOverlay MetaOverlay;
|
||||
|
||||
struct _MetaStageClass
|
||||
{
|
||||
ClutterStageClass parent_class;
|
||||
};
|
||||
|
||||
struct _MetaStage
|
||||
{
|
||||
ClutterStage parent;
|
||||
};
|
||||
|
||||
GType meta_stage_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor *meta_stage_new (void);
|
||||
|
||||
MetaOverlay *meta_stage_create_cursor_overlay (MetaStage *stage);
|
||||
@ -68,4 +52,4 @@ void meta_stage_update_view_layout (MetaStage *stage);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* META_STAGE_H */
|
||||
#endif /* META_STAGE_PRIVATE_H */
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "meta-stage.h"
|
||||
#include "meta-stage-private.h"
|
||||
|
||||
#include <meta/meta-backend.h>
|
||||
#include <meta/meta-monitor-manager.h>
|
||||
@ -30,7 +30,17 @@
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "clutter/clutter-mutter.h"
|
||||
|
||||
struct _MetaOverlay {
|
||||
enum
|
||||
{
|
||||
ACTORS_PAINTED,
|
||||
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS];
|
||||
|
||||
struct _MetaOverlay
|
||||
{
|
||||
gboolean enabled;
|
||||
|
||||
CoglPipeline *pipeline;
|
||||
@ -140,6 +150,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 = priv->overlays; l; l = l->next)
|
||||
meta_overlay_paint (l->data);
|
||||
}
|
||||
@ -179,6 +191,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
|
||||
|
@ -35,15 +35,15 @@
|
||||
#include "clutter/evdev/clutter-evdev.h"
|
||||
#include "meta-barrier-native.h"
|
||||
#include "meta-border.h"
|
||||
#include "meta-idle-monitor-native.h"
|
||||
#include "meta-monitor-manager-kms.h"
|
||||
#include "meta-cursor-renderer-native.h"
|
||||
#include "meta-launcher.h"
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "backends/meta-idle-monitor-private.h"
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-monitor-manager-private.h"
|
||||
#include "backends/meta-pointer-constraint.h"
|
||||
#include "backends/meta-stage.h"
|
||||
#include "backends/meta-stage-private.h"
|
||||
#include "backends/native/meta-clutter-backend-native.h"
|
||||
#include "backends/native/meta-input-settings-native.h"
|
||||
#include "backends/native/meta-renderer-native.h"
|
||||
@ -60,10 +60,6 @@ struct _MetaBackendNativePrivate
|
||||
{
|
||||
MetaLauncher *launcher;
|
||||
MetaBarrierManagerNative *barrier_manager;
|
||||
UpClient *up_client;
|
||||
guint sleep_signal_id;
|
||||
GCancellable *cancellable;
|
||||
GDBusConnection *system_bus;
|
||||
};
|
||||
typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate;
|
||||
|
||||
@ -85,69 +81,9 @@ meta_backend_native_finalize (GObject *object)
|
||||
|
||||
meta_launcher_free (priv->launcher);
|
||||
|
||||
g_object_unref (priv->up_client);
|
||||
if (priv->sleep_signal_id)
|
||||
g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->sleep_signal_id);
|
||||
g_cancellable_cancel (priv->cancellable);
|
||||
g_clear_object (&priv->cancellable);
|
||||
g_clear_object (&priv->system_bus);
|
||||
|
||||
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_for_sleep_cb (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
gboolean suspending;
|
||||
g_variant_get (parameters, "(b)", &suspending);
|
||||
if (suspending)
|
||||
return;
|
||||
meta_idle_monitor_native_reset_idletime (meta_idle_monitor_get_core ());
|
||||
}
|
||||
|
||||
static void
|
||||
system_bus_gotten_cb (GObject *object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaBackendNativePrivate *priv;
|
||||
GDBusConnection *bus;
|
||||
|
||||
bus = g_bus_get_finish (res, NULL);
|
||||
if (!bus)
|
||||
return;
|
||||
|
||||
priv = meta_backend_native_get_instance_private (META_BACKEND_NATIVE (user_data));
|
||||
priv->system_bus = bus;
|
||||
priv->sleep_signal_id = g_dbus_connection_signal_subscribe (priv->system_bus,
|
||||
"org.freedesktop.login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"PrepareForSleep",
|
||||
"/org/freedesktop/login1",
|
||||
NULL,
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
prepare_for_sleep_cb,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
lid_is_closed_changed_cb (UpClient *client,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (up_client_get_lid_is_closed (client))
|
||||
return;
|
||||
|
||||
meta_idle_monitor_native_reset_idletime (meta_idle_monitor_get_core ());
|
||||
}
|
||||
|
||||
static void
|
||||
constrain_to_barriers (ClutterInputDevice *device,
|
||||
guint32 time,
|
||||
@ -398,15 +334,6 @@ meta_backend_native_post_init (MetaBackend *backend)
|
||||
meta_backend_get_monitor_manager (backend));
|
||||
}
|
||||
|
||||
static MetaIdleMonitor *
|
||||
meta_backend_native_create_idle_monitor (MetaBackend *backend,
|
||||
int device_id)
|
||||
{
|
||||
return g_object_new (META_TYPE_IDLE_MONITOR_NATIVE,
|
||||
"device-id", device_id,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static MetaMonitorManager *
|
||||
meta_backend_native_create_monitor_manager (MetaBackend *backend,
|
||||
GError **error)
|
||||
@ -604,7 +531,6 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
|
||||
|
||||
backend_class->post_init = meta_backend_native_post_init;
|
||||
|
||||
backend_class->create_idle_monitor = meta_backend_native_create_idle_monitor;
|
||||
backend_class->create_monitor_manager = meta_backend_native_create_monitor_manager;
|
||||
backend_class->create_cursor_renderer = meta_backend_native_create_cursor_renderer;
|
||||
backend_class->create_renderer = meta_backend_native_create_renderer;
|
||||
@ -637,16 +563,6 @@ meta_backend_native_init (MetaBackendNative *native)
|
||||
}
|
||||
|
||||
priv->barrier_manager = meta_barrier_manager_native_new ();
|
||||
|
||||
priv->up_client = up_client_new ();
|
||||
g_signal_connect (priv->up_client, "notify::lid-is-closed",
|
||||
G_CALLBACK (lid_is_closed_changed_cb), NULL);
|
||||
|
||||
priv->cancellable = g_cancellable_new ();
|
||||
g_bus_get (G_BUS_TYPE_SYSTEM,
|
||||
priv->cancellable,
|
||||
system_bus_gotten_cb,
|
||||
native);
|
||||
}
|
||||
|
||||
MetaLauncher *
|
||||
@ -729,11 +645,20 @@ void meta_backend_native_resume (MetaBackendNative *native)
|
||||
meta_backend_get_monitor_manager (backend);
|
||||
MetaMonitorManagerKms *monitor_manager_kms =
|
||||
META_MONITOR_MANAGER_KMS (monitor_manager);
|
||||
MetaCursorRenderer *cursor_renderer;
|
||||
MetaCursorRendererNative *cursor_renderer_native;
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
||||
CoglContext *cogl_context =
|
||||
clutter_backend_get_cogl_context (clutter_backend);
|
||||
ClutterActor *stage;
|
||||
MetaIdleMonitor *idle_monitor;
|
||||
|
||||
if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES))
|
||||
{
|
||||
clutter_clear_glyph_cache ();
|
||||
meta_screen_update_cursor (display->screen);
|
||||
g_signal_emit_by_name (display, "gl-video-memory-purged");
|
||||
}
|
||||
|
||||
meta_monitor_manager_kms_resume (monitor_manager_kms);
|
||||
|
||||
clutter_evdev_reclaim_devices ();
|
||||
@ -742,10 +667,6 @@ void meta_backend_native_resume (MetaBackendNative *native)
|
||||
stage = meta_backend_get_stage (backend);
|
||||
clutter_actor_queue_redraw (stage);
|
||||
|
||||
cursor_renderer = meta_backend_get_cursor_renderer (backend);
|
||||
cursor_renderer_native = META_CURSOR_RENDERER_NATIVE (cursor_renderer);
|
||||
meta_cursor_renderer_native_force_update (cursor_renderer_native);
|
||||
|
||||
idle_monitor = meta_backend_get_idle_monitor (backend, 0);
|
||||
meta_idle_monitor_native_reset_idletime (idle_monitor);
|
||||
meta_idle_monitor_reset_idletime (idle_monitor);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <meta/meta-backend.h>
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-cursor-sprite-xcursor.h"
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/meta-monitor.h"
|
||||
#include "backends/meta-monitor-manager-private.h"
|
||||
@ -43,6 +44,11 @@
|
||||
#include "core/boxes-private.h"
|
||||
#include "meta/boxes.h"
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
#include "wayland/meta-cursor-sprite-wayland.h"
|
||||
#include "wayland/meta-wayland-buffer.h"
|
||||
#endif
|
||||
|
||||
#ifndef DRM_CAP_CURSOR_WIDTH
|
||||
#define DRM_CAP_CURSOR_WIDTH 0x8
|
||||
#endif
|
||||
@ -113,6 +119,11 @@ static GQuark quark_cursor_renderer_native_gpu_data = 0;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRendererNative, meta_cursor_renderer_native, META_TYPE_CURSOR_RENDERER);
|
||||
|
||||
static void
|
||||
realize_cursor_sprite (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
GList *gpus);
|
||||
|
||||
static MetaCursorNativeGpuState *
|
||||
get_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
|
||||
MetaGpuKms *gpu_kms);
|
||||
@ -152,7 +163,8 @@ static void
|
||||
meta_cursor_renderer_native_finalize (GObject *object)
|
||||
{
|
||||
MetaCursorRendererNative *renderer = META_CURSOR_RENDERER_NATIVE (object);
|
||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (renderer);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (renderer);
|
||||
|
||||
if (priv->animation_timeout_id)
|
||||
g_source_remove (priv->animation_timeout_id);
|
||||
@ -203,7 +215,8 @@ set_crtc_cursor (MetaCursorRendererNative *native,
|
||||
MetaCrtc *crtc,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
|
||||
MetaGpuKms *gpu_kms;
|
||||
int kms_fd;
|
||||
@ -291,9 +304,12 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
|
||||
data->in_cursor_renderer_native;
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);
|
||||
MetaCrtc *crtc;
|
||||
MetaMonitorTransform transform;
|
||||
ClutterRect scaled_crtc_rect;
|
||||
float scale;
|
||||
int crtc_x, crtc_y;
|
||||
int crtc_width, crtc_height;
|
||||
|
||||
if (meta_is_stage_views_scaled ())
|
||||
scale = meta_logical_monitor_get_scale (data->in_logical_monitor);
|
||||
@ -305,17 +321,31 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
|
||||
META_MONITOR_TRANSFORM_NORMAL,
|
||||
&crtc_x, &crtc_y);
|
||||
|
||||
transform = meta_logical_monitor_get_transform (data->in_logical_monitor);
|
||||
if (meta_monitor_transform_is_rotated (transform))
|
||||
{
|
||||
crtc_width = monitor_crtc_mode->crtc_mode->height;
|
||||
crtc_height = monitor_crtc_mode->crtc_mode->width;
|
||||
}
|
||||
else
|
||||
{
|
||||
crtc_width = monitor_crtc_mode->crtc_mode->width;
|
||||
crtc_height = monitor_crtc_mode->crtc_mode->height;
|
||||
}
|
||||
|
||||
scaled_crtc_rect = (ClutterRect) {
|
||||
.origin = {
|
||||
.x = crtc_x / scale,
|
||||
.y = crtc_y / scale
|
||||
},
|
||||
.size = {
|
||||
.width = monitor_crtc_mode->crtc_mode->width / scale,
|
||||
.height = monitor_crtc_mode->crtc_mode->height / scale
|
||||
.width = crtc_width / scale,
|
||||
.height = crtc_height / scale
|
||||
},
|
||||
};
|
||||
|
||||
crtc = meta_output_get_assigned_crtc (monitor_crtc_mode->output);
|
||||
|
||||
if (priv->has_hw_cursor &&
|
||||
clutter_rect_intersection (&scaled_crtc_rect,
|
||||
&data->in_local_cursor_rect,
|
||||
@ -326,7 +356,7 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
|
||||
float crtc_cursor_x, crtc_cursor_y;
|
||||
|
||||
set_crtc_cursor (data->in_cursor_renderer_native,
|
||||
monitor_crtc_mode->output->crtc,
|
||||
crtc,
|
||||
data->in_cursor_sprite);
|
||||
|
||||
gpu_kms = META_GPU_KMS (meta_monitor_get_gpu (monitor));
|
||||
@ -336,7 +366,7 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
|
||||
crtc_cursor_y = (data->in_local_cursor_rect.origin.y -
|
||||
scaled_crtc_rect.origin.y) * scale;
|
||||
drmModeMoveCursor (kms_fd,
|
||||
monitor_crtc_mode->output->crtc->crtc_id,
|
||||
crtc->crtc_id,
|
||||
roundf (crtc_cursor_x),
|
||||
roundf (crtc_cursor_y));
|
||||
|
||||
@ -344,8 +374,7 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
|
||||
}
|
||||
else
|
||||
{
|
||||
set_crtc_cursor (data->in_cursor_renderer_native,
|
||||
monitor_crtc_mode->output->crtc, NULL);
|
||||
set_crtc_cursor (data->in_cursor_renderer_native, crtc, NULL);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -355,7 +384,8 @@ static void
|
||||
update_hw_cursor (MetaCursorRendererNative *native,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
|
||||
MetaMonitorManager *monitor_manager = priv->monitor_manager;
|
||||
GList *logical_monitors;
|
||||
@ -548,18 +578,19 @@ can_draw_cursor_unscaled (MetaCursorRenderer *renderer,
|
||||
|
||||
static gboolean
|
||||
should_have_hw_cursor (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
GList *gpus)
|
||||
{
|
||||
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||
GList *gpus;
|
||||
GList *l;
|
||||
CoglTexture *texture;
|
||||
|
||||
if (!cursor_sprite)
|
||||
return FALSE;
|
||||
|
||||
gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
|
||||
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;
|
||||
@ -593,7 +624,8 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
|
||||
static gboolean
|
||||
meta_cursor_renderer_native_update_animation (MetaCursorRendererNative *native)
|
||||
{
|
||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native);
|
||||
MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
|
||||
|
||||
@ -605,10 +637,11 @@ meta_cursor_renderer_native_update_animation (MetaCursorRendererNative *native)
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
maybe_schedule_cursor_sprite_animation_frame (MetaCursorRendererNative *native,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
gboolean cursor_change;
|
||||
guint delay;
|
||||
|
||||
@ -640,21 +673,78 @@ meta_cursor_renderer_native_trigger_frame (MetaCursorRendererNative *native,
|
||||
}
|
||||
}
|
||||
|
||||
static GList *
|
||||
calculate_cursor_sprite_gpus (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaMonitorManager *monitor_manager = priv->monitor_manager;
|
||||
GList *gpus = NULL;
|
||||
GList *logical_monitors;
|
||||
GList *l;
|
||||
ClutterRect cursor_rect;
|
||||
|
||||
cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
|
||||
|
||||
logical_monitors =
|
||||
meta_monitor_manager_get_logical_monitors (monitor_manager);
|
||||
for (l = logical_monitors; l; l = l->next)
|
||||
{
|
||||
MetaLogicalMonitor *logical_monitor = l->data;
|
||||
MetaRectangle logical_monitor_layout;
|
||||
ClutterRect logical_monitor_rect;
|
||||
GList *monitors, *l_mon;
|
||||
|
||||
logical_monitor_layout =
|
||||
meta_logical_monitor_get_layout (logical_monitor);
|
||||
logical_monitor_rect =
|
||||
meta_rectangle_to_clutter_rect (&logical_monitor_layout);
|
||||
|
||||
if (!clutter_rect_intersection (&cursor_rect, &logical_monitor_rect,
|
||||
NULL))
|
||||
continue;
|
||||
|
||||
monitors = meta_logical_monitor_get_monitors (logical_monitor);
|
||||
for (l_mon = monitors; l_mon; l_mon = l_mon->next)
|
||||
{
|
||||
MetaMonitor *monitor = l_mon->data;
|
||||
MetaGpu *gpu;
|
||||
|
||||
gpu = meta_monitor_get_gpu (monitor);
|
||||
if (!g_list_find (gpus, gpu))
|
||||
gpus = g_list_prepend (gpus, gpu);
|
||||
}
|
||||
}
|
||||
|
||||
return gpus;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
g_autoptr (GList) gpus = NULL;
|
||||
|
||||
if (cursor_sprite)
|
||||
meta_cursor_sprite_realize_texture (cursor_sprite);
|
||||
{
|
||||
meta_cursor_sprite_realize_texture (cursor_sprite);
|
||||
gpus = calculate_cursor_sprite_gpus (renderer, cursor_sprite);
|
||||
realize_cursor_sprite (renderer, cursor_sprite, gpus);
|
||||
}
|
||||
|
||||
meta_cursor_renderer_native_trigger_frame (native, cursor_sprite);
|
||||
maybe_schedule_cursor_sprite_animation_frame (native, cursor_sprite);
|
||||
|
||||
priv->has_hw_cursor = should_have_hw_cursor (renderer, cursor_sprite);
|
||||
priv->has_hw_cursor = should_have_hw_cursor (renderer, cursor_sprite, gpus);
|
||||
update_hw_cursor (native, cursor_sprite);
|
||||
return priv->has_hw_cursor;
|
||||
|
||||
return (priv->has_hw_cursor ||
|
||||
!cursor_sprite ||
|
||||
!meta_cursor_sprite_get_cogl_texture (cursor_sprite));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -690,6 +780,24 @@ ensure_cursor_gpu_state (MetaCursorNativePrivate *cursor_priv,
|
||||
return cursor_gpu_state;
|
||||
}
|
||||
|
||||
static void
|
||||
on_cursor_sprite_texture_changed (MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
MetaCursorNativePrivate *cursor_priv = get_cursor_priv (cursor_sprite);
|
||||
GHashTableIter iter;
|
||||
MetaCursorNativeGpuState *cursor_gpu_state;
|
||||
|
||||
g_hash_table_iter_init (&iter, cursor_priv->gpu_states);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cursor_gpu_state))
|
||||
{
|
||||
guint pending_bo;
|
||||
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
|
||||
g_clear_pointer (&cursor_gpu_state->bos[pending_bo],
|
||||
(GDestroyNotify) gbm_bo_destroy);
|
||||
cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_priv_free (MetaCursorNativePrivate *cursor_priv)
|
||||
{
|
||||
@ -722,6 +830,9 @@ ensure_cursor_priv (MetaCursorSprite *cursor_sprite)
|
||||
cursor_priv,
|
||||
(GDestroyNotify) cursor_priv_free);
|
||||
|
||||
g_signal_connect (cursor_sprite, "texture-changed",
|
||||
G_CALLBACK (on_cursor_sprite_texture_changed), NULL);
|
||||
|
||||
return cursor_priv;
|
||||
}
|
||||
|
||||
@ -789,57 +900,71 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
invalidate_pending_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite,
|
||||
MetaGpuKms *gpu_kms)
|
||||
static gboolean
|
||||
is_cursor_hw_state_valid (MetaCursorSprite *cursor_sprite,
|
||||
MetaGpuKms *gpu_kms)
|
||||
{
|
||||
MetaCursorNativePrivate *cursor_priv;
|
||||
MetaCursorNativeGpuState *cursor_gpu_state;
|
||||
guint pending_bo;
|
||||
|
||||
cursor_priv = get_cursor_priv (cursor_sprite);
|
||||
if (!cursor_priv)
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms);
|
||||
if (!cursor_gpu_state)
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
pending_bo = get_pending_cursor_sprite_gbm_bo_index (cursor_gpu_state);
|
||||
g_clear_pointer (&cursor_gpu_state->bos[pending_bo],
|
||||
(GDestroyNotify) gbm_bo_destroy);
|
||||
cursor_gpu_state->pending_bo_state = META_CURSOR_GBM_BO_STATE_INVALIDATED;
|
||||
switch (cursor_gpu_state->pending_bo_state)
|
||||
{
|
||||
case META_CURSOR_GBM_BO_STATE_SET:
|
||||
case META_CURSOR_GBM_BO_STATE_NONE:
|
||||
return TRUE;
|
||||
case META_CURSOR_GBM_BO_STATE_INVALIDATED:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
static void
|
||||
meta_cursor_renderer_native_realize_cursor_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
|
||||
MetaGpuKms *gpu_kms,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
struct wl_resource *buffer)
|
||||
realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer,
|
||||
MetaGpuKms *gpu_kms,
|
||||
MetaCursorSpriteWayland *sprite_wayland)
|
||||
{
|
||||
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_wayland);
|
||||
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
|
||||
uint32_t gbm_format;
|
||||
uint64_t cursor_width, cursor_height;
|
||||
CoglTexture *texture;
|
||||
uint width, height;
|
||||
MetaWaylandBuffer *buffer;
|
||||
struct wl_resource *buffer_resource;
|
||||
struct wl_shm_buffer *shm_buffer;
|
||||
|
||||
cursor_renderer_gpu_data =
|
||||
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
|
||||
if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
|
||||
return;
|
||||
|
||||
/* Destroy any previous pending cursor buffer; we'll always either fail (which
|
||||
* should unset, or succeed, which will set new buffer.
|
||||
*/
|
||||
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms);
|
||||
if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms))
|
||||
return;
|
||||
|
||||
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
|
||||
width = cogl_texture_get_width (texture);
|
||||
height = cogl_texture_get_height (texture);
|
||||
|
||||
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
|
||||
buffer = meta_cursor_sprite_wayland_get_buffer (sprite_wayland);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
buffer_resource = meta_wayland_buffer_get_resource (buffer);
|
||||
if (!buffer_resource)
|
||||
return;
|
||||
|
||||
shm_buffer = wl_shm_buffer_get (buffer_resource);
|
||||
if (shm_buffer)
|
||||
{
|
||||
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
|
||||
@ -913,47 +1038,27 @@ meta_cursor_renderer_native_realize_cursor_from_wl_buffer_for_gpu (MetaCursorRen
|
||||
set_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms, bo);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
struct wl_resource *buffer)
|
||||
{
|
||||
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
GList *gpus;
|
||||
GList *l;
|
||||
|
||||
gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
|
||||
for (l = gpus; l; l = l->next)
|
||||
{
|
||||
MetaGpuKms *gpu_kms = l->data;
|
||||
|
||||
meta_cursor_renderer_native_realize_cursor_from_wl_buffer_for_gpu (
|
||||
renderer,
|
||||
gpu_kms,
|
||||
cursor_sprite,
|
||||
buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
meta_cursor_renderer_native_realize_cursor_from_xcursor_for_gpu (MetaCursorRenderer *renderer,
|
||||
MetaGpuKms *gpu_kms,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
XcursorImage *xc_image)
|
||||
realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer *renderer,
|
||||
MetaGpuKms *gpu_kms,
|
||||
MetaCursorSpriteXcursor *sprite_xcursor)
|
||||
{
|
||||
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
|
||||
MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
|
||||
XcursorImage *xc_image;
|
||||
|
||||
cursor_renderer_gpu_data =
|
||||
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
|
||||
if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken)
|
||||
return;
|
||||
|
||||
invalidate_pending_cursor_sprite_gbm_bo (cursor_sprite, gpu_kms);
|
||||
if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms))
|
||||
return;
|
||||
|
||||
xc_image = meta_cursor_sprite_xcursor_get_current_image (sprite_xcursor);
|
||||
|
||||
load_cursor_sprite_gbm_buffer_for_gpu (native,
|
||||
gpu_kms,
|
||||
@ -966,26 +1071,45 @@ meta_cursor_renderer_native_realize_cursor_from_xcursor_for_gpu (MetaCursorRende
|
||||
}
|
||||
|
||||
static void
|
||||
meta_cursor_renderer_native_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
XcursorImage *xc_image)
|
||||
realize_cursor_sprite_for_gpu (MetaCursorRenderer *renderer,
|
||||
MetaGpuKms *gpu_kms,
|
||||
MetaCursorSprite *cursor_sprite)
|
||||
{
|
||||
#ifdef HAVE_WAYLAND
|
||||
if (META_IS_CURSOR_SPRITE_WAYLAND (cursor_sprite))
|
||||
{
|
||||
MetaCursorSpriteWayland *sprite_wayland =
|
||||
META_CURSOR_SPRITE_WAYLAND (cursor_sprite);
|
||||
|
||||
realize_cursor_sprite_from_wl_buffer_for_gpu (renderer,
|
||||
gpu_kms,
|
||||
sprite_wayland);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (META_IS_CURSOR_SPRITE_XCURSOR (cursor_sprite))
|
||||
{
|
||||
MetaCursorSpriteXcursor *sprite_xcursor =
|
||||
META_CURSOR_SPRITE_XCURSOR (cursor_sprite);
|
||||
|
||||
realize_cursor_sprite_from_xcursor_for_gpu (renderer,
|
||||
gpu_kms,
|
||||
sprite_xcursor);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
realize_cursor_sprite (MetaCursorRenderer *renderer,
|
||||
MetaCursorSprite *cursor_sprite,
|
||||
GList *gpus)
|
||||
{
|
||||
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
|
||||
MetaCursorRendererNativePrivate *priv =
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
GList *gpus;
|
||||
GList *l;
|
||||
|
||||
gpus = meta_monitor_manager_get_gpus (priv->monitor_manager);
|
||||
for (l = gpus; l; l = l->next)
|
||||
{
|
||||
MetaGpuKms *gpu_kms = l->data;
|
||||
|
||||
meta_cursor_renderer_native_realize_cursor_from_xcursor_for_gpu (
|
||||
renderer,
|
||||
gpu_kms,
|
||||
cursor_sprite,
|
||||
xc_image);
|
||||
realize_cursor_sprite_for_gpu (renderer, gpu_kms, cursor_sprite);
|
||||
}
|
||||
}
|
||||
|
||||
@ -997,12 +1121,6 @@ meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
|
||||
|
||||
object_class->finalize = meta_cursor_renderer_native_finalize;
|
||||
renderer_class->update_cursor = meta_cursor_renderer_native_update_cursor;
|
||||
#ifdef HAVE_WAYLAND
|
||||
renderer_class->realize_cursor_from_wl_buffer =
|
||||
meta_cursor_renderer_native_realize_cursor_from_wl_buffer;
|
||||
#endif
|
||||
renderer_class->realize_cursor_from_xcursor =
|
||||
meta_cursor_renderer_native_realize_cursor_from_xcursor;
|
||||
|
||||
quark_cursor_sprite = g_quark_from_static_string ("-meta-cursor-native");
|
||||
quark_cursor_renderer_native_gpu_data =
|
||||
@ -1017,14 +1135,13 @@ force_update_hw_cursor (MetaCursorRendererNative *native)
|
||||
meta_cursor_renderer_native_get_instance_private (native);
|
||||
|
||||
priv->hw_state_invalidated = TRUE;
|
||||
update_hw_cursor (native, meta_cursor_renderer_get_cursor (renderer));
|
||||
meta_cursor_renderer_force_update (renderer);
|
||||
}
|
||||
|
||||
static void
|
||||
on_monitors_changed (MetaMonitorManager *monitors,
|
||||
MetaCursorRendererNative *native)
|
||||
{
|
||||
/* Our tracking is all messed up, so force an update. */
|
||||
force_update_hw_cursor (native);
|
||||
}
|
||||
|
||||
@ -1096,9 +1213,3 @@ static void
|
||||
meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
|
||||
{
|
||||
force_update_hw_cursor (native);
|
||||
}
|
||||
|
@ -32,8 +32,6 @@ G_DECLARE_FINAL_TYPE (MetaCursorRendererNative, meta_cursor_renderer_native,
|
||||
META, CURSOR_RENDERER_NATIVE,
|
||||
MetaCursorRenderer)
|
||||
|
||||
void meta_cursor_renderer_native_force_update (MetaCursorRendererNative *renderer);
|
||||
|
||||
MetaCursorRendererNative * meta_cursor_renderer_native_new (MetaBackend *backend);
|
||||
|
||||
#endif /* META_CURSOR_RENDERER_NATIVE_H */
|
||||
|
@ -47,6 +47,12 @@ typedef struct _MetaKmsSource
|
||||
MetaGpuKms *gpu_kms;
|
||||
} MetaKmsSource;
|
||||
|
||||
typedef struct _MetaGpuKmsFlipClosureContainer
|
||||
{
|
||||
GClosure *flip_closure;
|
||||
MetaGpuKms *gpu_kms;
|
||||
} MetaGpuKmsFlipClosureContainer;
|
||||
|
||||
struct _MetaGpuKms
|
||||
{
|
||||
MetaGpu parent;
|
||||
@ -62,8 +68,11 @@ struct _MetaGpuKms
|
||||
int max_buffer_height;
|
||||
|
||||
gboolean page_flips_not_supported;
|
||||
|
||||
gboolean resources_init_failed_before;
|
||||
};
|
||||
|
||||
G_DEFINE_QUARK (MetaGpuKmsError, meta_gpu_kms_error)
|
||||
G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU)
|
||||
|
||||
static gboolean
|
||||
@ -104,8 +113,10 @@ get_crtc_drm_connectors (MetaGpu *gpu,
|
||||
for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
MetaCrtc *assigned_crtc;
|
||||
|
||||
if (output->crtc == crtc)
|
||||
assigned_crtc = meta_output_get_assigned_crtc (output);
|
||||
if (assigned_crtc == crtc)
|
||||
g_array_append_val (connectors_array, output->winsys_id);
|
||||
}
|
||||
|
||||
@ -140,7 +151,10 @@ meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
|
||||
connectors, n_connectors,
|
||||
mode) != 0)
|
||||
{
|
||||
g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name);
|
||||
if (mode)
|
||||
g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name);
|
||||
else
|
||||
g_warning ("Failed to disable CRTC");
|
||||
g_free (connectors);
|
||||
return FALSE;
|
||||
}
|
||||
@ -185,8 +199,10 @@ meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
|
||||
for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
MetaCrtc *assigned_crtc;
|
||||
|
||||
if (output->crtc == crtc)
|
||||
assigned_crtc = meta_output_get_assigned_crtc (output);
|
||||
if (assigned_crtc == crtc)
|
||||
{
|
||||
connected_crtc_found = TRUE;
|
||||
break;
|
||||
@ -199,11 +215,26 @@ meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct _GpuClosureContainer
|
||||
MetaGpuKmsFlipClosureContainer *
|
||||
meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
|
||||
GClosure *flip_closure)
|
||||
{
|
||||
GClosure *flip_closure;
|
||||
MetaGpuKms *gpu_kms;
|
||||
} GpuClosureContainer;
|
||||
MetaGpuKmsFlipClosureContainer *closure_container;
|
||||
|
||||
closure_container = g_new0 (MetaGpuKmsFlipClosureContainer, 1);
|
||||
*closure_container = (MetaGpuKmsFlipClosureContainer) {
|
||||
.flip_closure = flip_closure,
|
||||
.gpu_kms = gpu_kms
|
||||
};
|
||||
|
||||
return closure_container;
|
||||
}
|
||||
|
||||
void
|
||||
meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container)
|
||||
{
|
||||
g_free (closure_container);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
|
||||
@ -229,14 +260,11 @@ meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
|
||||
|
||||
if (!gpu_kms->page_flips_not_supported)
|
||||
{
|
||||
GpuClosureContainer *closure_container;
|
||||
MetaGpuKmsFlipClosureContainer *closure_container;
|
||||
int kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
|
||||
closure_container = g_new0 (GpuClosureContainer, 1);
|
||||
*closure_container = (GpuClosureContainer) {
|
||||
.flip_closure = flip_closure,
|
||||
.gpu_kms = gpu_kms
|
||||
};
|
||||
closure_container = meta_gpu_kms_wrap_flip_closure (gpu_kms,
|
||||
flip_closure);
|
||||
|
||||
ret = drmModePageFlip (kms_fd,
|
||||
crtc->crtc_id,
|
||||
@ -245,7 +273,7 @@ meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
|
||||
closure_container);
|
||||
if (ret != 0 && ret != -EACCES)
|
||||
{
|
||||
g_free (closure_container);
|
||||
meta_gpu_kms_flip_closure_container_free (closure_container);
|
||||
g_warning ("Failed to flip: %s", strerror (-ret));
|
||||
gpu_kms->page_flips_not_supported = TRUE;
|
||||
}
|
||||
@ -276,12 +304,12 @@ page_flip_handler (int fd,
|
||||
unsigned int usec,
|
||||
void *user_data)
|
||||
{
|
||||
GpuClosureContainer *closure_container = user_data;
|
||||
MetaGpuKmsFlipClosureContainer *closure_container = user_data;
|
||||
GClosure *flip_closure = closure_container->flip_closure;
|
||||
MetaGpuKms *gpu_kms = closure_container->gpu_kms;
|
||||
|
||||
invoke_flip_closure (flip_closure, gpu_kms);
|
||||
g_free (closure_container);
|
||||
meta_gpu_kms_flip_closure_container_free (closure_container);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -701,20 +729,34 @@ init_outputs (MetaGpuKms *gpu_kms,
|
||||
setup_output_clones (gpu);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_resources_init (MetaKmsResources *resources,
|
||||
int fd)
|
||||
static gboolean
|
||||
meta_kms_resources_init (MetaKmsResources *resources,
|
||||
int fd,
|
||||
GError **error)
|
||||
|
||||
{
|
||||
drmModeRes *drm_resources;
|
||||
unsigned int i;
|
||||
|
||||
drm_resources = drmModeGetResources (fd);
|
||||
|
||||
if (!drm_resources)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"Calling drmModeGetResources() failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
resources->resources = drm_resources;
|
||||
|
||||
resources->n_encoders = (unsigned int) drm_resources->count_encoders;
|
||||
resources->encoders = g_new (drmModeEncoder *, resources->n_encoders);
|
||||
for (i = 0; i < resources->n_encoders; i++)
|
||||
resources->encoders[i] = drmModeGetEncoder (fd, drm_resources->encoders[i]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -726,7 +768,7 @@ meta_kms_resources_release (MetaKmsResources *resources)
|
||||
drmModeFreeEncoder (resources->encoders[i]);
|
||||
g_free (resources->encoders);
|
||||
|
||||
drmModeFreeResources (resources->resources);
|
||||
g_clear_pointer (&resources->resources, drmModeFreeResources);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -737,8 +779,18 @@ meta_gpu_kms_read_current (MetaGpu *gpu,
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_gpu_get_monitor_manager (gpu);
|
||||
MetaKmsResources resources;
|
||||
g_autoptr (GError) local_error = NULL;
|
||||
|
||||
meta_kms_resources_init (&resources, gpu_kms->fd);
|
||||
if (!meta_kms_resources_init (&resources, gpu_kms->fd, &local_error))
|
||||
{
|
||||
if (!gpu_kms->resources_init_failed_before)
|
||||
{
|
||||
g_warning ("meta_kms_resources_init failed: %s, assuming we have no outputs",
|
||||
local_error->message);
|
||||
gpu_kms->resources_init_failed_before = TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gpu_kms->max_buffer_width = resources.resources->max_width;
|
||||
gpu_kms->max_buffer_height = resources.resources->max_height;
|
||||
@ -751,6 +803,8 @@ meta_gpu_kms_read_current (MetaGpu *gpu,
|
||||
are freed by the platform-independent layer. */
|
||||
free_resources (gpu_kms);
|
||||
|
||||
g_assert (resources.resources->count_connectors > 0);
|
||||
|
||||
init_connectors (gpu_kms, resources.resources);
|
||||
init_modes (gpu_kms, resources.resources);
|
||||
init_crtcs (gpu_kms, &resources);
|
||||
@ -761,6 +815,12 @@ meta_gpu_kms_read_current (MetaGpu *gpu,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms)
|
||||
{
|
||||
return gpu_kms->n_connectors > 0;
|
||||
}
|
||||
|
||||
MetaGpuKms *
|
||||
meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
|
||||
const char *kms_file_path,
|
||||
@ -774,11 +834,46 @@ meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
|
||||
GSource *source;
|
||||
MetaKmsSource *kms_source;
|
||||
MetaGpuKms *gpu_kms;
|
||||
drmModeRes *drm_resources;
|
||||
guint n_connectors;
|
||||
int kms_fd;
|
||||
|
||||
kms_fd = meta_launcher_open_restricted (launcher, kms_file_path, error);
|
||||
if (kms_fd == -1)
|
||||
return FALSE;
|
||||
return NULL;
|
||||
|
||||
/* Some GPUs might have no connectors, for example dedicated GPUs on PRIME (hybrid) laptops.
|
||||
* These GPUs cannot render anything on separate screens, and they are aggressively switched
|
||||
* off by the kernel.
|
||||
*
|
||||
* If we add these PRIME GPUs to the GPU list anyway, Mutter keeps awakening the secondary GPU,
|
||||
* and doing this causes a considerable stuttering. These GPUs are usually put to sleep again
|
||||
* after ~2s without a workload.
|
||||
*
|
||||
* For now, to avoid this situation, only create the MetaGpuKms when the GPU has any connectors.
|
||||
*/
|
||||
drm_resources = drmModeGetResources (kms_fd);
|
||||
|
||||
if (!drm_resources)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No resources");
|
||||
meta_launcher_close_restricted (launcher, kms_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n_connectors = drm_resources->count_connectors;
|
||||
|
||||
drmModeFreeResources (drm_resources);
|
||||
|
||||
if (n_connectors == 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
META_GPU_KMS_ERROR,
|
||||
META_GPU_KMS_ERROR_NO_CONNECTORS,
|
||||
"No connectors available in this GPU. This is probably a dedicated GPU in a hybrid setup.");
|
||||
meta_launcher_close_restricted (launcher, kms_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gpu_kms = g_object_new (META_TYPE_GPU_KMS,
|
||||
"monitor-manager", monitor_manager_kms,
|
||||
@ -789,6 +884,8 @@ meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
|
||||
|
||||
drmSetClientCap (gpu_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
|
||||
|
||||
meta_gpu_kms_read_current (META_GPU (gpu_kms), NULL);
|
||||
|
||||
source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource));
|
||||
kms_source = (MetaKmsSource *) source;
|
||||
kms_source->fd_tag = g_source_add_unix_fd (source,
|
||||
|
@ -29,9 +29,19 @@
|
||||
#include "backends/meta-gpu.h"
|
||||
#include "backends/native/meta-monitor-manager-kms.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_GPU_KMS_ERROR_NO_CONNECTORS,
|
||||
} MetaGpuKmsError;
|
||||
|
||||
#define META_GPU_KMS_ERROR (meta_gpu_kms_error_quark ())
|
||||
GQuark meta_gpu_kms_error_quark (void);
|
||||
|
||||
#define META_TYPE_GPU_KMS (meta_gpu_kms_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaGpuKms, meta_gpu_kms, META, GPU_KMS, MetaGpu)
|
||||
|
||||
typedef struct _MetaGpuKmsFlipClosureContainer MetaGpuKmsFlipClosureContainer;
|
||||
|
||||
typedef struct _MetaKmsResources
|
||||
{
|
||||
drmModeRes *resources;
|
||||
@ -51,6 +61,8 @@ gboolean meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
|
||||
int y,
|
||||
uint32_t fb_id);
|
||||
|
||||
gboolean meta_gpu_kms_can_have_outputs (MetaGpuKms *gpu_kms);
|
||||
|
||||
gboolean meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
|
||||
MetaCrtc *crtc);
|
||||
|
||||
@ -84,4 +96,9 @@ gboolean meta_drm_mode_equal (const drmModeModeInfo *one,
|
||||
|
||||
float meta_calculate_drm_mode_refresh_rate (const drmModeModeInfo *mode);
|
||||
|
||||
MetaGpuKmsFlipClosureContainer * meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
|
||||
GClosure *flip_closure);
|
||||
|
||||
void meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container);
|
||||
|
||||
#endif /* META_GPU_KMS_H */
|
||||
|
@ -1,200 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "meta-idle-monitor-native.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
|
||||
#include <meta/util.h>
|
||||
#include "display-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct _MetaIdleMonitorNative
|
||||
{
|
||||
MetaIdleMonitor parent;
|
||||
|
||||
guint64 last_event_time;
|
||||
};
|
||||
|
||||
struct _MetaIdleMonitorNativeClass
|
||||
{
|
||||
MetaIdleMonitorClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
MetaIdleMonitorWatch base;
|
||||
|
||||
GSource *timeout_source;
|
||||
} MetaIdleMonitorWatchNative;
|
||||
|
||||
G_DEFINE_TYPE (MetaIdleMonitorNative, meta_idle_monitor_native, META_TYPE_IDLE_MONITOR)
|
||||
|
||||
static gint64
|
||||
meta_idle_monitor_native_get_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor);
|
||||
|
||||
return (g_get_monotonic_time () - monitor_native->last_event_time) / 1000;
|
||||
}
|
||||
|
||||
static guint32
|
||||
get_next_watch_serial (void)
|
||||
{
|
||||
static guint32 serial = 0;
|
||||
g_atomic_int_inc (&serial);
|
||||
return serial;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
native_dispatch_timeout (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaIdleMonitorWatchNative *watch_native = user_data;
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native;
|
||||
|
||||
_meta_idle_monitor_watch_fire (watch);
|
||||
g_source_set_ready_time (watch_native->timeout_source, -1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs native_source_funcs = {
|
||||
NULL, /* prepare */
|
||||
NULL, /* check */
|
||||
native_dispatch_timeout,
|
||||
NULL, /* finalize */
|
||||
};
|
||||
|
||||
static void
|
||||
free_watch (gpointer data)
|
||||
{
|
||||
MetaIdleMonitorWatchNative *watch_native = data;
|
||||
MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native;
|
||||
MetaIdleMonitor *monitor = watch->monitor;
|
||||
|
||||
g_object_ref (monitor);
|
||||
|
||||
if (watch->idle_source_id)
|
||||
{
|
||||
g_source_remove (watch->idle_source_id);
|
||||
watch->idle_source_id = 0;
|
||||
}
|
||||
|
||||
if (watch->notify != NULL)
|
||||
watch->notify (watch->user_data);
|
||||
|
||||
if (watch_native->timeout_source != NULL)
|
||||
g_source_destroy (watch_native->timeout_source);
|
||||
|
||||
g_object_unref (monitor);
|
||||
g_slice_free (MetaIdleMonitorWatchNative, watch_native);
|
||||
}
|
||||
|
||||
static MetaIdleMonitorWatch *
|
||||
meta_idle_monitor_native_make_watch (MetaIdleMonitor *monitor,
|
||||
guint64 timeout_msec,
|
||||
MetaIdleMonitorWatchFunc callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
MetaIdleMonitorWatchNative *watch_native;
|
||||
MetaIdleMonitorWatch *watch;
|
||||
MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor);
|
||||
|
||||
watch_native = g_slice_new0 (MetaIdleMonitorWatchNative);
|
||||
watch = (MetaIdleMonitorWatch *) watch_native;
|
||||
|
||||
watch->monitor = monitor;
|
||||
watch->id = get_next_watch_serial ();
|
||||
watch->callback = callback;
|
||||
watch->user_data = user_data;
|
||||
watch->notify = notify;
|
||||
watch->timeout_msec = timeout_msec;
|
||||
|
||||
if (timeout_msec != 0)
|
||||
{
|
||||
GSource *source = g_source_new (&native_source_funcs, sizeof (GSource));
|
||||
|
||||
g_source_set_callback (source, NULL, watch, NULL);
|
||||
g_source_set_ready_time (source, monitor_native->last_event_time + timeout_msec * 1000);
|
||||
g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
|
||||
watch_native->timeout_source = source;
|
||||
}
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_native_class_init (MetaIdleMonitorNativeClass *klass)
|
||||
{
|
||||
MetaIdleMonitorClass *idle_monitor_class = META_IDLE_MONITOR_CLASS (klass);
|
||||
|
||||
idle_monitor_class->get_idletime = meta_idle_monitor_native_get_idletime;
|
||||
idle_monitor_class->make_watch = meta_idle_monitor_native_make_watch;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_idle_monitor_native_init (MetaIdleMonitorNative *monitor_native)
|
||||
{
|
||||
MetaIdleMonitor *monitor = META_IDLE_MONITOR (monitor_native);
|
||||
|
||||
monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch);
|
||||
monitor_native->last_event_time = g_get_monotonic_time ();
|
||||
}
|
||||
|
||||
void
|
||||
meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor)
|
||||
{
|
||||
MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor);
|
||||
GList *node, *watch_ids;
|
||||
|
||||
monitor_native->last_event_time = g_get_monotonic_time ();
|
||||
|
||||
watch_ids = g_hash_table_get_keys (monitor->watches);
|
||||
|
||||
for (node = watch_ids; node != NULL; node = node->next)
|
||||
{
|
||||
guint watch_id = GPOINTER_TO_UINT (node->data);
|
||||
MetaIdleMonitorWatchNative *watch;
|
||||
|
||||
watch = g_hash_table_lookup (monitor->watches, GUINT_TO_POINTER (watch_id));
|
||||
if (!watch)
|
||||
continue;
|
||||
|
||||
if (watch->base.timeout_msec == 0)
|
||||
{
|
||||
_meta_idle_monitor_watch_fire ((MetaIdleMonitorWatch *) watch);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_source_set_ready_time (watch->timeout_source,
|
||||
monitor_native->last_event_time +
|
||||
watch->base.timeout_msec * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (watch_ids);
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adapted from gnome-session/gnome-session/gs-idle-monitor.c and
|
||||
* from gnome-desktop/libgnome-desktop/gnome-idle-monitor.c
|
||||
*/
|
||||
|
||||
#ifndef META_IDLE_MONITOR_NATIVE_H
|
||||
#define META_IDLE_MONITOR_NATIVE_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <meta/meta-idle-monitor.h>
|
||||
|
||||
#define META_TYPE_IDLE_MONITOR_NATIVE (meta_idle_monitor_native_get_type ())
|
||||
#define META_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNative))
|
||||
#define META_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass))
|
||||
#define META_IS_IDLE_MONITOR_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_IDLE_MONITOR_NATIVE))
|
||||
#define META_IS_IDLE_MONITOR_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_IDLE_MONITOR_NATIVE))
|
||||
#define META_IDLE_MONITOR_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_IDLE_MONITOR_NATIVE, MetaIdleMonitorNativeClass))
|
||||
|
||||
typedef struct _MetaIdleMonitorNative MetaIdleMonitorNative;
|
||||
typedef struct _MetaIdleMonitorNativeClass MetaIdleMonitorNativeClass;
|
||||
|
||||
GType meta_idle_monitor_native_get_type (void);
|
||||
|
||||
void meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor);
|
||||
|
||||
#endif /* META_IDLE_MONITOR_NATIVE_H */
|
@ -44,7 +44,6 @@
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/native/meta-backend-native.h"
|
||||
#include "meta-cursor-renderer-native.h"
|
||||
#include "meta-idle-monitor-native.h"
|
||||
#include "meta-renderer-native.h"
|
||||
|
||||
struct _MetaLauncher
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "meta-crtc-kms.h"
|
||||
#include "meta-gpu-kms.h"
|
||||
#include "meta-output-kms.h"
|
||||
#include "wayland/meta-wayland-outputs.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -188,7 +189,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
|
||||
MetaOutput *output = g_ptr_array_index (crtc_info->outputs, j);
|
||||
|
||||
output->is_dirty = TRUE;
|
||||
output->crtc = crtc;
|
||||
meta_output_assign_crtc (output, crtc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,7 +250,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
|
||||
continue;
|
||||
}
|
||||
|
||||
output->crtc = NULL;
|
||||
meta_output_unassign_crtc (output);
|
||||
output->is_primary = FALSE;
|
||||
}
|
||||
}
|
||||
@ -415,9 +416,15 @@ void
|
||||
meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms)
|
||||
{
|
||||
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
|
||||
ClutterBackend *clutter_backend = clutter_get_default_backend ();
|
||||
CoglContext *cogl_context =
|
||||
clutter_backend_get_cogl_context (clutter_backend);
|
||||
|
||||
meta_monitor_manager_kms_connect_uevent_handler (manager_kms);
|
||||
handle_hotplug_event (manager);
|
||||
|
||||
if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES))
|
||||
meta_wayland_outputs_redraw (meta_wayland_compositor_get_default ());
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -642,10 +649,12 @@ meta_monitor_manager_kms_initable_init (GInitable *initable,
|
||||
GError **error)
|
||||
{
|
||||
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);
|
||||
|
||||
@ -674,16 +683,19 @@ meta_monitor_manager_kms_initable_init (GInitable *initable,
|
||||
gpu_paths = get_gpu_paths (manager_kms, GPU_TYPE_SECONDARY, primary_gpu_path);
|
||||
for (l = gpu_paths; l; l = l->next)
|
||||
{
|
||||
GError *secondary_error = NULL;
|
||||
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);
|
||||
g_error_free (secondary_error);
|
||||
if (g_error_matches (secondary_error, META_GPU_KMS_ERROR, META_GPU_KMS_ERROR_NO_CONNECTORS))
|
||||
g_message ("Ignoring GPU %s due to the lack of connectors", gpu_path);
|
||||
else
|
||||
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),
|
||||
@ -691,6 +703,24 @@ meta_monitor_manager_kms_initable_init (GInitable *initable,
|
||||
}
|
||||
g_list_free_full (gpu_paths, g_free);
|
||||
|
||||
can_have_outputs = FALSE;
|
||||
for (l = meta_monitor_manager_get_gpus (manager); l; l = l->next)
|
||||
{
|
||||
MetaGpuKms *gpu_kms = l->data;
|
||||
|
||||
if (meta_gpu_kms_can_have_outputs (gpu_kms))
|
||||
{
|
||||
can_have_outputs = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!can_have_outputs)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"No GPUs with outputs found");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -64,11 +64,13 @@ typedef struct _MetaOutputKms
|
||||
void
|
||||
meta_output_kms_set_underscan (MetaOutput *output)
|
||||
{
|
||||
if (!output->crtc)
|
||||
MetaCrtc *crtc;
|
||||
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
meta_crtc_kms_set_underscan (output->crtc,
|
||||
output->is_underscanning);
|
||||
meta_crtc_kms_set_underscan (crtc, output->is_underscanning);
|
||||
}
|
||||
|
||||
void
|
||||
@ -600,14 +602,14 @@ meta_create_kms_output (MetaGpuKms *gpu_kms,
|
||||
|
||||
if (crtc->crtc_id == output_kms->current_encoder->crtc_id)
|
||||
{
|
||||
output->crtc = crtc;
|
||||
meta_output_assign_crtc (output, crtc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output->crtc = NULL;
|
||||
meta_output_unassign_crtc (output);
|
||||
}
|
||||
|
||||
if (old_output)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user