Compare commits
120 Commits
cherry-pic
...
wip/rstrod
Author | SHA1 | Date | |
---|---|---|---|
![]() |
31c3695314 | ||
![]() |
b79e74f13f | ||
![]() |
be0e1a65e5 | ||
![]() |
0dccf69cb3 | ||
![]() |
e4da08218a | ||
![]() |
d720a0a366 | ||
![]() |
b0067b45b9 | ||
![]() |
325d3ebb2a | ||
![]() |
3680d75a76 | ||
![]() |
c697d2a7a9 | ||
![]() |
0a50755fd6 | ||
![]() |
c15c8facfe | ||
![]() |
4c765238ae | ||
![]() |
b4bb859a6a | ||
![]() |
9c9551c1bd | ||
![]() |
333d775aba | ||
![]() |
a280a6dbf3 | ||
![]() |
f3765bf412 | ||
![]() |
a6f95bc8cd | ||
![]() |
064788cbc9 | ||
![]() |
7aed7293e3 | ||
![]() |
e9d41e0898 | ||
![]() |
bac2a0752b | ||
![]() |
5f1325ed0a | ||
![]() |
00a06c5538 | ||
![]() |
2a2697910a | ||
![]() |
e4339aed83 | ||
![]() |
4d5869f6e9 | ||
![]() |
214aced750 | ||
![]() |
4ac2899576 | ||
![]() |
76c34858d1 | ||
![]() |
ea6535c639 | ||
![]() |
18b68e3a84 | ||
![]() |
3bdfbf97b9 | ||
![]() |
a7f2145965 | ||
![]() |
ffa30f50f2 | ||
![]() |
0ec335395d | ||
![]() |
46dccd898e | ||
![]() |
fcd55e6f59 | ||
![]() |
c5f0fc1276 | ||
![]() |
7ca0fee437 | ||
![]() |
1d8384372a | ||
![]() |
851954b7ed | ||
![]() |
fef2ecd1e2 | ||
![]() |
c74dc7ce45 | ||
![]() |
63cee05c65 | ||
![]() |
6628d12f3c | ||
![]() |
3e8364d11d | ||
![]() |
58c2c2c444 | ||
![]() |
1fe3adcd95 | ||
![]() |
a53eb8dcbd | ||
![]() |
06be60bc72 | ||
![]() |
e8a3341700 | ||
![]() |
847d37b4f1 | ||
![]() |
01d147a2d7 | ||
![]() |
e27c63e41b | ||
![]() |
6dc7bacf08 | ||
![]() |
29e7a69729 | ||
![]() |
68337774fc | ||
![]() |
0c9eb18b06 | ||
![]() |
e19a294e44 | ||
![]() |
b0267c1a4e | ||
![]() |
c60c2f997c | ||
![]() |
591e7c5760 | ||
![]() |
acca2962f1 | ||
![]() |
c94ee761af | ||
![]() |
9cde0a78d8 | ||
![]() |
a96f057ff1 | ||
![]() |
d165eb90a1 | ||
![]() |
53a5c6a14a | ||
![]() |
71288b22ba | ||
![]() |
988f6e72fe | ||
![]() |
8eccb68687 | ||
![]() |
b2a035348b | ||
![]() |
d820815472 | ||
![]() |
f459cd37ff | ||
![]() |
0f93452488 | ||
![]() |
f8d99dc004 | ||
![]() |
162ae22349 | ||
![]() |
779ae37332 | ||
![]() |
a7727a59ed | ||
![]() |
5eaa81574a | ||
![]() |
8cae9adbbb | ||
![]() |
b3f236a323 | ||
![]() |
da26d24daf | ||
![]() |
ad2e9282dc | ||
![]() |
b9f5f93956 | ||
![]() |
3712f8c99d | ||
![]() |
3e2294ce44 | ||
![]() |
2d36f92c55 | ||
![]() |
f607df49ec | ||
![]() |
eda1b3ba67 | ||
![]() |
c3590cea72 | ||
![]() |
b2cc2b1064 | ||
![]() |
2fb46fd078 | ||
![]() |
5e56384636 | ||
![]() |
4e57e4c4f8 | ||
![]() |
c8552cf160 | ||
![]() |
988fac3f18 | ||
![]() |
c19274706d | ||
![]() |
a54976da15 | ||
![]() |
71cfb52ece | ||
![]() |
aadf25b1f7 | ||
![]() |
e5be12c644 | ||
![]() |
60b62af343 | ||
![]() |
8a74b269a6 | ||
![]() |
0537907b0c | ||
![]() |
e8a09942e9 | ||
![]() |
63c33c5bb2 | ||
![]() |
5df0172ac0 | ||
![]() |
b65f3c3985 | ||
![]() |
22e507e315 | ||
![]() |
d4c6c73ef5 | ||
![]() |
946acd6034 | ||
![]() |
f28c56ee3e | ||
![]() |
ac1dcec926 | ||
![]() |
dcfaf95ff4 | ||
![]() |
34f5bdeea3 | ||
![]() |
ca71b0eb1a | ||
![]() |
ca4209d88a |
13
NEWS
13
NEWS
@@ -1,3 +1,16 @@
|
||||
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]
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "clutter/clutter-input-method.h"
|
||||
#include "clutter/clutter-input-method-private.h"
|
||||
#include "clutter/clutter-input-focus-private.h"
|
||||
#include "clutter/clutter-device-manager-private.h"
|
||||
|
||||
typedef struct _ClutterInputMethodPrivate ClutterInputMethodPrivate;
|
||||
|
||||
@@ -442,3 +443,46 @@ clutter_input_method_filter_key_event (ClutterInputMethod *im,
|
||||
|
||||
return im_class->filter_key_event (im, (const ClutterEvent *) key);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_input_method_forward_key (ClutterInputMethod *im,
|
||||
uint32_t keyval,
|
||||
uint32_t keycode,
|
||||
uint32_t state,
|
||||
uint64_t time_,
|
||||
gboolean press)
|
||||
{
|
||||
ClutterInputMethodPrivate *priv;
|
||||
ClutterDeviceManager *device_manager;
|
||||
ClutterInputDevice *keyboard;
|
||||
ClutterStage *stage;
|
||||
ClutterEvent *event;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
|
||||
|
||||
priv = clutter_input_method_get_instance_private (im);
|
||||
if (!priv->focus)
|
||||
return;
|
||||
|
||||
device_manager = clutter_device_manager_get_default ();
|
||||
keyboard = clutter_device_manager_get_core_device (device_manager,
|
||||
CLUTTER_KEYBOARD_DEVICE);
|
||||
stage = _clutter_input_device_get_stage (keyboard);
|
||||
if (stage == NULL)
|
||||
return;
|
||||
|
||||
event = clutter_event_new (press ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
|
||||
event->key.time = time_;
|
||||
event->key.flags = CLUTTER_EVENT_FLAG_INPUT_METHOD;
|
||||
event->key.modifier_state = state;
|
||||
event->key.keyval = keyval;
|
||||
event->key.hardware_keycode = keycode;
|
||||
event->key.unicode_value = clutter_keysym_to_unicode (keyval);
|
||||
|
||||
clutter_event_set_device (event, keyboard);
|
||||
clutter_event_set_source_device (event, keyboard);
|
||||
clutter_event_set_stage (event, stage);
|
||||
|
||||
clutter_event_put (event);
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
@@ -85,4 +85,12 @@ void clutter_input_method_notify_key_event (ClutterInputMethod *im,
|
||||
CLUTTER_AVAILABLE_IN_MUTTER
|
||||
void clutter_input_method_request_toggle_input_panel (ClutterInputMethod *im);
|
||||
|
||||
CLUTTER_AVAILABLE_IN_MUTTER
|
||||
void clutter_input_method_forward_key (ClutterInputMethod *im,
|
||||
uint32_t keyval,
|
||||
uint32_t keycode,
|
||||
uint32_t state,
|
||||
uint64_t time_,
|
||||
gboolean press);
|
||||
|
||||
#endif /* __CLUTTER_INPUT_METHOD_H__ */
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
@@ -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,
|
||||
|
@@ -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));
|
||||
|
@@ -267,8 +267,9 @@ is_touch_device (XIAnyClassInfo **classes,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_touchpad_device (ClutterBackendX11 *backend_x11,
|
||||
XIDeviceInfo *info)
|
||||
query_exists_device_property (ClutterBackendX11 *backend_x11,
|
||||
XIDeviceInfo *info,
|
||||
const gchar *property)
|
||||
{
|
||||
gulong nitems, bytes_after;
|
||||
guint32 *data = NULL;
|
||||
@@ -276,7 +277,7 @@ is_touchpad_device (ClutterBackendX11 *backend_x11,
|
||||
Atom type;
|
||||
Atom prop;
|
||||
|
||||
prop = XInternAtom (backend_x11->xdpy, "libinput Tapping Enabled", True);
|
||||
prop = XInternAtom (backend_x11->xdpy, property, True);
|
||||
if (prop == None)
|
||||
return FALSE;
|
||||
|
||||
@@ -297,6 +298,21 @@ is_touchpad_device (ClutterBackendX11 *backend_x11,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_touchpad_device (ClutterBackendX11 *backend_x11,
|
||||
XIDeviceInfo *info)
|
||||
{
|
||||
if (query_exists_device_property (backend_x11, info,
|
||||
"libinput Tapping Enabled"))
|
||||
return TRUE;
|
||||
|
||||
if (query_exists_device_property (backend_x11, info,
|
||||
"Synaptics Off"))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_device_ids (ClutterBackendX11 *backend_x11,
|
||||
XIDeviceInfo *info,
|
||||
@@ -1803,7 +1819,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
|
||||
_clutter_input_device_set_stage (device, NULL);
|
||||
}
|
||||
|
||||
_clutter_input_device_reset_scroll_info (source_device);
|
||||
if (clutter_input_device_get_device_mode (source_device) == CLUTTER_INPUT_MODE_SLAVE)
|
||||
_clutter_input_device_reset_scroll_info (source_device);
|
||||
|
||||
clutter_event_set_device (event, device);
|
||||
clutter_event_set_source_device (event, source_device);
|
||||
|
@@ -38,6 +38,14 @@
|
||||
|
||||
typedef struct _ClutterKeymapX11Class ClutterKeymapX11Class;
|
||||
typedef struct _DirectionCacheEntry DirectionCacheEntry;
|
||||
typedef struct _ClutterKeymapKey ClutterKeymapKey;
|
||||
|
||||
struct _ClutterKeymapKey
|
||||
{
|
||||
guint keycode;
|
||||
guint group;
|
||||
guint level;
|
||||
};
|
||||
|
||||
struct _DirectionCacheEntry
|
||||
{
|
||||
@@ -59,6 +67,7 @@ struct _ClutterKeymapX11
|
||||
|
||||
ClutterModifierType num_lock_mask;
|
||||
ClutterModifierType scroll_lock_mask;
|
||||
ClutterModifierType level3_shift_mask;
|
||||
|
||||
PangoDirection current_direction;
|
||||
|
||||
@@ -69,6 +78,7 @@ struct _ClutterKeymapX11
|
||||
Atom current_group_atom;
|
||||
guint current_cache_serial;
|
||||
DirectionCacheEntry group_direction_cache[4];
|
||||
int current_group;
|
||||
#endif
|
||||
|
||||
guint caps_lock_state : 1;
|
||||
@@ -198,6 +208,9 @@ get_xkb (ClutterKeymapX11 *keymap_x11)
|
||||
if (keymap_x11->scroll_lock_mask == 0)
|
||||
keymap_x11->scroll_lock_mask = XkbKeysymToModifiers (backend_x11->xdpy,
|
||||
XK_Scroll_Lock);
|
||||
if (keymap_x11->level3_shift_mask == 0)
|
||||
keymap_x11->level3_shift_mask = XkbKeysymToModifiers (backend_x11->xdpy,
|
||||
XK_ISO_Level3_Shift);
|
||||
|
||||
return keymap_x11->xkb_desc;
|
||||
}
|
||||
@@ -469,6 +482,7 @@ static void
|
||||
clutter_keymap_x11_init (ClutterKeymapX11 *keymap)
|
||||
{
|
||||
keymap->current_direction = PANGO_DIRECTION_NEUTRAL;
|
||||
keymap->current_group = -1;
|
||||
}
|
||||
|
||||
static ClutterTranslateReturn
|
||||
@@ -498,7 +512,8 @@ clutter_keymap_x11_translate_event (ClutterEventTranslator *translator,
|
||||
{
|
||||
case XkbStateNotify:
|
||||
CLUTTER_NOTE (EVENT, "Updating keyboard state");
|
||||
update_direction (keymap_x11, XkbStateGroup (&xkb_event->state));
|
||||
keymap_x11->current_group = XkbStateGroup (&xkb_event->state);
|
||||
update_direction (keymap_x11, keymap_x11->current_group);
|
||||
update_locked_mods (keymap_x11, xkb_event->state.locked_mods);
|
||||
retval = CLUTTER_TRANSLATE_REMOVE;
|
||||
break;
|
||||
@@ -665,3 +680,164 @@ _clutter_keymap_x11_get_direction (ClutterKeymapX11 *keymap)
|
||||
#endif
|
||||
return PANGO_DIRECTION_NEUTRAL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_keymap_x11_get_entries_for_keyval (ClutterKeymapX11 *keymap_x11,
|
||||
guint keyval,
|
||||
ClutterKeymapKey **keys,
|
||||
gint *n_keys)
|
||||
{
|
||||
#ifdef HAVE_XKB
|
||||
if (CLUTTER_BACKEND_X11 (keymap_x11->backend)->use_xkb)
|
||||
{
|
||||
XkbDescRec *xkb = get_xkb (keymap_x11);
|
||||
GArray *retval;
|
||||
gint keycode;
|
||||
|
||||
keycode = keymap_x11->min_keycode;
|
||||
retval = g_array_new (FALSE, FALSE, sizeof (ClutterKeymapKey));
|
||||
|
||||
while (keycode <= keymap_x11->max_keycode)
|
||||
{
|
||||
gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode);
|
||||
gint group = 0;
|
||||
gint level = 0;
|
||||
gint total_syms = XkbKeyNumSyms (xkb, keycode);
|
||||
gint i = 0;
|
||||
KeySym *entry;
|
||||
|
||||
/* entry is an array with all syms for group 0, all
|
||||
* syms for group 1, etc. and for each group the
|
||||
* shift level syms are in order
|
||||
*/
|
||||
entry = XkbKeySymsPtr (xkb, keycode);
|
||||
|
||||
while (i < total_syms)
|
||||
{
|
||||
g_assert (i == (group * max_shift_levels + level));
|
||||
|
||||
if (entry[i] == keyval)
|
||||
{
|
||||
ClutterKeymapKey key;
|
||||
|
||||
key.keycode = keycode;
|
||||
key.group = group;
|
||||
key.level = level;
|
||||
|
||||
g_array_append_val (retval, key);
|
||||
|
||||
g_assert (XkbKeySymEntry (xkb, keycode, level, group) ==
|
||||
keyval);
|
||||
}
|
||||
|
||||
++level;
|
||||
|
||||
if (level == max_shift_levels)
|
||||
{
|
||||
level = 0;
|
||||
++group;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
++keycode;
|
||||
}
|
||||
|
||||
if (retval->len > 0)
|
||||
{
|
||||
*keys = (ClutterKeymapKey*) retval->data;
|
||||
*n_keys = retval->len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*keys = NULL;
|
||||
*n_keys = 0;
|
||||
}
|
||||
|
||||
g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
|
||||
|
||||
return *n_keys > 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
|
||||
uint32_t level,
|
||||
gboolean enable)
|
||||
{
|
||||
#ifdef HAVE_XKB
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
|
||||
uint32_t modifiers[] = {
|
||||
0,
|
||||
ShiftMask,
|
||||
keymap_x11->level3_shift_mask,
|
||||
keymap_x11->level3_shift_mask | ShiftMask,
|
||||
};
|
||||
uint32_t value = 0;
|
||||
|
||||
if (!backend_x11->use_xkb)
|
||||
return;
|
||||
|
||||
level = CLAMP (level, 0, G_N_ELEMENTS (modifiers) - 1);
|
||||
|
||||
if (enable)
|
||||
value = modifiers[level];
|
||||
else
|
||||
value = 0;
|
||||
|
||||
XkbLatchModifiers (clutter_x11_get_default_display (),
|
||||
XkbUseCoreKbd, modifiers[level],
|
||||
value);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
clutter_keymap_x11_get_current_group (ClutterKeymapX11 *keymap_x11)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
|
||||
XkbStateRec state_rec;
|
||||
|
||||
if (keymap_x11->current_group >= 0)
|
||||
return keymap_x11->current_group;
|
||||
|
||||
XkbGetState (backend_x11->xdpy, XkbUseCoreKbd, &state_rec);
|
||||
return XkbStateGroup (&state_rec);
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_keymap_x11_keycode_for_keyval (ClutterKeymapX11 *keymap_x11,
|
||||
guint keyval,
|
||||
guint *keycode_out,
|
||||
guint *level_out)
|
||||
{
|
||||
ClutterKeymapKey *keys;
|
||||
gint i, n_keys, group;
|
||||
gboolean found = FALSE;
|
||||
|
||||
g_return_val_if_fail (keycode_out != NULL, FALSE);
|
||||
g_return_val_if_fail (level_out != NULL, FALSE);
|
||||
|
||||
group = clutter_keymap_x11_get_current_group (keymap_x11);
|
||||
|
||||
if (!clutter_keymap_x11_get_entries_for_keyval (keymap_x11, keyval, &keys, &n_keys))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < n_keys && !found; i++)
|
||||
{
|
||||
if (keys[i].group == group)
|
||||
{
|
||||
*keycode_out = keys[i].keycode;
|
||||
*level_out = keys[i].level;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (keys);
|
||||
return found;
|
||||
}
|
||||
|
@@ -51,6 +51,14 @@ gboolean _clutter_keymap_x11_get_is_modifier (ClutterKeymapX11 *keymap,
|
||||
|
||||
PangoDirection _clutter_keymap_x11_get_direction (ClutterKeymapX11 *keymap);
|
||||
|
||||
gboolean clutter_keymap_x11_keycode_for_keyval (ClutterKeymapX11 *keymap_x11,
|
||||
guint keyval,
|
||||
guint *keycode_out,
|
||||
guint *level_out);
|
||||
void clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
|
||||
uint32_t level,
|
||||
gboolean enable);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_KEYMAP_X11_H__ */
|
||||
|
@@ -32,6 +32,8 @@
|
||||
|
||||
#include "clutter-virtual-input-device.h"
|
||||
#include "x11/clutter-virtual-input-device-x11.h"
|
||||
#include "x11/clutter-backend-x11.h"
|
||||
#include "x11/clutter-keymap-x11.h"
|
||||
|
||||
struct _ClutterVirtualInputDeviceX11
|
||||
{
|
||||
@@ -135,11 +137,27 @@ clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtu
|
||||
uint32_t keyval,
|
||||
ClutterKeyState key_state)
|
||||
{
|
||||
KeyCode keycode;
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
ClutterKeymapX11 *keymap = backend_x11->keymap;
|
||||
uint32_t keycode, level;
|
||||
|
||||
if (!clutter_keymap_x11_keycode_for_keyval (keymap, keyval, &keycode, &level))
|
||||
{
|
||||
g_warning ("No keycode found for keyval %x in current group", keyval);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode) &&
|
||||
key_state == CLUTTER_KEY_STATE_PRESSED)
|
||||
clutter_keymap_x11_latch_modifiers (keymap, level, TRUE);
|
||||
|
||||
keycode = XKeysymToKeycode (clutter_x11_get_default_display (), keyval);
|
||||
XTestFakeKeyEvent (clutter_x11_get_default_display (),
|
||||
keycode, key_state == CLUTTER_KEY_STATE_PRESSED, 0);
|
||||
(KeyCode) keycode,
|
||||
key_state == CLUTTER_KEY_STATE_PRESSED, 0);
|
||||
|
||||
if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode) &&
|
||||
key_state == CLUTTER_KEY_STATE_RELEASED)
|
||||
clutter_keymap_x11_latch_modifiers (keymap, level, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -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++)
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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;
|
||||
|
||||
/**
|
||||
|
@@ -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 */
|
||||
};
|
||||
|
@@ -502,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);
|
||||
|
||||
@@ -514,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,
|
||||
|
16
configure.ac
16
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], [2])
|
||||
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"])
|
||||
@@ -290,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"
|
||||
|
||||
@@ -549,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}
|
||||
|
@@ -103,7 +103,7 @@
|
||||
</key>
|
||||
|
||||
<key name="experimental-features" type="as">
|
||||
<default>[]</default>
|
||||
<default>['scale-monitor-framebuffer']</default>
|
||||
<summary>Enable experimental features</summary>
|
||||
<description>
|
||||
To enable experimental features, add the feature keyword to the list.
|
||||
@@ -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
|
||||
|
@@ -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,6 +159,8 @@ 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-private.h \
|
||||
@@ -159,6 +169,9 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
||||
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 \
|
||||
@@ -176,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 \
|
||||
@@ -304,6 +319,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
||||
core/stack.h \
|
||||
core/stack-tracker.c \
|
||||
core/stack-tracker.h \
|
||||
core/stereo.c \
|
||||
core/stereo.h \
|
||||
core/util.c \
|
||||
meta/util.h \
|
||||
core/util-private.h \
|
||||
@@ -357,6 +374,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 \
|
||||
@@ -370,6 +391,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 \
|
||||
@@ -431,10 +454,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 \
|
||||
@@ -540,6 +563,7 @@ 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 \
|
||||
@@ -760,3 +784,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 $< $@
|
||||
|
@@ -26,6 +26,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include <clutter/clutter-mutter.h>
|
||||
#include <meta/meta-backend.h>
|
||||
#include <meta/main.h>
|
||||
@@ -35,10 +37,12 @@
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
#include "meta-cursor-tracker-private.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 +62,8 @@ enum
|
||||
KEYMAP_CHANGED,
|
||||
KEYMAP_LAYOUT_GROUP_CHANGED,
|
||||
LAST_DEVICE_CHANGED,
|
||||
|
||||
SUSPENDING,
|
||||
RESUMING,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
@@ -92,6 +97,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;
|
||||
@@ -112,15 +118,21 @@ struct _MetaBackendPrivate
|
||||
MetaDnd *dnd;
|
||||
|
||||
UpClient *up_client;
|
||||
guint sleep_signal_id;
|
||||
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,
|
||||
@@ -139,11 +151,10 @@ 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);
|
||||
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);
|
||||
@@ -418,28 +429,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)
|
||||
{
|
||||
@@ -472,11 +461,12 @@ 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))
|
||||
@@ -563,31 +553,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)
|
||||
@@ -618,20 +602,106 @@ lid_is_closed_changed_cb (UpClient *client,
|
||||
}
|
||||
|
||||
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)
|
||||
inhibit_sleep (MetaBackend *backend)
|
||||
{
|
||||
gboolean suspending;
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
g_autoptr (GVariant) fd_variant = NULL;
|
||||
g_autoptr (GUnixFDList) fd_list = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
int handle, fd;
|
||||
|
||||
g_variant_get (parameters, "(b)", &suspending);
|
||||
if (suspending)
|
||||
if (priv->inhibit_sleep_fd >= 0)
|
||||
{
|
||||
g_warning ("tried to inhibit suspend when already inhibited");
|
||||
|
||||
if (priv->inhibit_sleep_fd == 0)
|
||||
g_warning ("but, really, something went wrong, the fd is 0");
|
||||
return;
|
||||
}
|
||||
|
||||
g_warning ("inhibiting suspend temporarily");
|
||||
|
||||
if (!login1_manager_call_inhibit_sync (priv->logind_proxy,
|
||||
"sleep",
|
||||
"Display Server",
|
||||
"Prepare for suspend",
|
||||
"delay",
|
||||
NULL,
|
||||
&fd_variant,
|
||||
&fd_list,
|
||||
priv->cancellable,
|
||||
&error))
|
||||
{
|
||||
g_warning ("Failed to inhibit sleep: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
handle = g_variant_get_handle (fd_variant);
|
||||
fd = g_unix_fd_list_get (fd_list, handle, &error);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
g_warning ("Failed to fetch sleep inhibitor fd: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->inhibit_sleep_fd = fd;
|
||||
}
|
||||
|
||||
static void
|
||||
uninhibit_sleep (MetaBackend *backend)
|
||||
{
|
||||
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
|
||||
|
||||
if (priv->inhibit_sleep_fd < 0)
|
||||
{
|
||||
g_warning ("tried to uninhibit suspend when not inhibited");
|
||||
return;
|
||||
}
|
||||
else if (priv->inhibit_sleep_fd == 0)
|
||||
g_warning ("uninhibiting suspend but suspend fd is 0!");
|
||||
else
|
||||
g_warning ("uninhibiting suspend");
|
||||
|
||||
close (priv->inhibit_sleep_fd);
|
||||
priv->inhibit_sleep_fd = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_for_sleep_cb (MetaBackend *backend,
|
||||
gboolean suspending)
|
||||
{
|
||||
if (suspending) {
|
||||
g_warning ("preparing to suspend");
|
||||
g_signal_emit (backend, signals[SUSPENDING], 0);
|
||||
g_warning ("suspending");
|
||||
uninhibit_sleep (backend);
|
||||
return;
|
||||
}
|
||||
|
||||
g_warning ("preparing to resume");
|
||||
inhibit_sleep (backend);
|
||||
g_signal_emit (backend, signals[RESUMING], 0);
|
||||
meta_idle_monitor_reset_idletime (meta_idle_monitor_get_core ());
|
||||
g_warning ("resuming");
|
||||
}
|
||||
|
||||
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
|
||||
@@ -639,7 +709,9 @@ 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);
|
||||
@@ -648,17 +720,22 @@ system_bus_gotten_cb (GObject *object,
|
||||
|
||||
priv = meta_backend_get_instance_private (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);
|
||||
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
|
||||
@@ -670,9 +747,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);
|
||||
|
||||
@@ -824,6 +898,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)
|
||||
*/
|
||||
|
@@ -35,6 +35,9 @@
|
||||
|
||||
#include "meta-stage-private.h"
|
||||
|
||||
G_DEFINE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
struct _MetaCursorRendererPrivate
|
||||
{
|
||||
float current_x;
|
||||
@@ -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,7 @@ 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
|
||||
@@ -284,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);
|
||||
@@ -67,19 +67,18 @@ 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 */
|
||||
|
@@ -64,6 +64,13 @@ meta_gpu_has_hotplug_mode_update (MetaGpu *gpu)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_gpu_poll_hardware (MetaGpu *gpu)
|
||||
{
|
||||
if (META_GPU_GET_CLASS (gpu)->poll_hardware)
|
||||
META_GPU_GET_CLASS (gpu)->poll_hardware (gpu);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gpu_read_current (MetaGpu *gpu,
|
||||
GError **error)
|
||||
|
@@ -35,12 +35,14 @@ struct _MetaGpuClass
|
||||
|
||||
gboolean (* read_current) (MetaGpu *gpu,
|
||||
GError **error);
|
||||
void (* poll_hardware) (MetaGpu *gpu);
|
||||
};
|
||||
|
||||
int meta_gpu_get_kms_fd (MetaGpu *gpu);
|
||||
|
||||
const char * meta_gpu_get_kms_file_path (MetaGpu *gpu);
|
||||
|
||||
void meta_gpu_poll_hardware (MetaGpu *gpu);
|
||||
gboolean meta_gpu_read_current (MetaGpu *gpu,
|
||||
GError **error);
|
||||
|
||||
|
@@ -246,7 +246,8 @@ meta_idle_monitor_init (MetaIdleMonitor *monitor)
|
||||
/* 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_CONNECT_SIGNALS |
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
"org.gnome.SessionManager",
|
||||
"/org/gnome/SessionManager",
|
||||
|
@@ -40,6 +40,7 @@ struct _MetaMonitorConfigManager
|
||||
MetaMonitorConfigStore *config_store;
|
||||
|
||||
MetaMonitorsConfig *current_config;
|
||||
MetaMonitorsConfig *initial_config;
|
||||
GQueue config_history;
|
||||
};
|
||||
|
||||
@@ -559,6 +560,91 @@ create_preferred_logical_monitor_config (MetaMonitorManager *monitor_ma
|
||||
return logical_monitor_config;
|
||||
}
|
||||
|
||||
static MetaLogicalMonitorConfig *
|
||||
create_logical_monitor_config_from_output (MetaMonitorManager *monitor_manager,
|
||||
MetaMonitor *monitor,
|
||||
MetaLogicalMonitorConfig *primary_logical_monitor_config,
|
||||
MetaLogicalMonitorLayoutMode layout_mode)
|
||||
{
|
||||
MetaOutput *output;
|
||||
MetaCrtc *crtc;
|
||||
|
||||
output = meta_monitor_get_main_output (monitor);
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
return create_preferred_logical_monitor_config (monitor_manager,
|
||||
monitor,
|
||||
crtc->rect.x,
|
||||
crtc->rect.y,
|
||||
primary_logical_monitor_config,
|
||||
layout_mode);
|
||||
}
|
||||
|
||||
MetaMonitorsConfig *
|
||||
meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager)
|
||||
{
|
||||
MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
|
||||
MetaMonitorsConfig *initial_config;
|
||||
GList *logical_monitor_configs;
|
||||
MetaMonitor *primary_monitor;
|
||||
MetaLogicalMonitorLayoutMode layout_mode;
|
||||
MetaLogicalMonitorConfig *primary_logical_monitor_config;
|
||||
GList *monitors;
|
||||
GList *l;
|
||||
|
||||
if (config_manager->initial_config != NULL)
|
||||
return g_object_ref (config_manager->initial_config);
|
||||
|
||||
if (meta_monitor_config_store_get_config_count (config_manager->config_store) > 0)
|
||||
return NULL;
|
||||
|
||||
primary_monitor = find_primary_monitor (monitor_manager);
|
||||
if (!primary_monitor || !meta_monitor_is_active (primary_monitor))
|
||||
return NULL;
|
||||
|
||||
layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
|
||||
|
||||
primary_logical_monitor_config =
|
||||
create_logical_monitor_config_from_output (monitor_manager,
|
||||
primary_monitor,
|
||||
NULL,
|
||||
layout_mode);
|
||||
|
||||
primary_logical_monitor_config->is_primary = TRUE;
|
||||
logical_monitor_configs = g_list_append (NULL,
|
||||
primary_logical_monitor_config);
|
||||
|
||||
monitors = meta_monitor_manager_get_monitors (monitor_manager);
|
||||
for (l = monitors; l; l = l->next)
|
||||
{
|
||||
MetaMonitor *monitor = l->data;
|
||||
MetaLogicalMonitorConfig *logical_monitor_config;
|
||||
|
||||
if (monitor == primary_monitor)
|
||||
continue;
|
||||
|
||||
if (!meta_monitor_is_active (monitor))
|
||||
continue;
|
||||
|
||||
logical_monitor_config =
|
||||
create_logical_monitor_config_from_output (monitor_manager,
|
||||
monitor,
|
||||
primary_logical_monitor_config,
|
||||
layout_mode);
|
||||
|
||||
logical_monitor_configs = g_list_append (logical_monitor_configs,
|
||||
logical_monitor_config);
|
||||
}
|
||||
|
||||
initial_config = meta_monitors_config_new (monitor_manager,
|
||||
logical_monitor_configs,
|
||||
layout_mode,
|
||||
META_MONITORS_CONFIG_FLAG_NONE);
|
||||
|
||||
config_manager->initial_config = g_object_ref (initial_config);
|
||||
|
||||
return initial_config;
|
||||
}
|
||||
|
||||
MetaMonitorsConfig *
|
||||
meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager)
|
||||
{
|
||||
@@ -1085,6 +1171,7 @@ meta_monitor_config_manager_dispose (GObject *object)
|
||||
META_MONITOR_CONFIG_MANAGER (object);
|
||||
|
||||
g_clear_object (&config_manager->current_config);
|
||||
g_clear_object (&config_manager->initial_config);
|
||||
meta_monitor_config_manager_clear_history (config_manager);
|
||||
|
||||
G_OBJECT_CLASS (meta_monitor_config_manager_parent_class)->dispose (object);
|
||||
|
@@ -87,6 +87,7 @@ gboolean meta_monitor_config_manager_assign (MetaMonitorManager *manager,
|
||||
|
||||
MetaMonitorsConfig * meta_monitor_config_manager_get_stored (MetaMonitorConfigManager *config_manager);
|
||||
|
||||
MetaMonitorsConfig * meta_monitor_config_manager_create_initial (MetaMonitorConfigManager *config_manager);
|
||||
MetaMonitorsConfig * meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_manager);
|
||||
|
||||
MetaMonitorsConfig * meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_manager);
|
||||
|
@@ -496,9 +496,11 @@ should_use_stored_config (MetaMonitorManager *manager)
|
||||
MetaMonitorsConfig *
|
||||
meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
||||
{
|
||||
g_autoptr (MetaMonitorsConfig) initial_config = NULL;
|
||||
MetaMonitorsConfig *config = NULL;
|
||||
GError *error = NULL;
|
||||
gboolean use_stored_config;
|
||||
MetaMonitorsConfigKey *current_state_key;
|
||||
MetaMonitorsConfigMethod method;
|
||||
MetaMonitorsConfigMethod fallback_method =
|
||||
META_MONITORS_CONFIG_METHOD_TEMPORARY;
|
||||
@@ -509,6 +511,18 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
||||
else
|
||||
method = META_MONITORS_CONFIG_METHOD_TEMPORARY;
|
||||
|
||||
initial_config = meta_monitor_config_manager_create_initial (manager->config_manager);
|
||||
|
||||
if (initial_config)
|
||||
{
|
||||
current_state_key = meta_create_monitors_config_key_for_current_state (manager);
|
||||
|
||||
/* don't ever reuse initial configuration, if the monitor topology changed
|
||||
*/
|
||||
if (current_state_key && !meta_monitors_config_key_equal (current_state_key, initial_config->key))
|
||||
g_clear_object (&initial_config);
|
||||
}
|
||||
|
||||
if (use_stored_config)
|
||||
{
|
||||
config = meta_monitor_config_manager_get_stored (manager->config_manager);
|
||||
@@ -576,6 +590,25 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
||||
g_clear_object (&config);
|
||||
}
|
||||
|
||||
config = g_steal_pointer (&initial_config);
|
||||
if (config)
|
||||
{
|
||||
if (!meta_monitor_manager_apply_monitors_config (manager,
|
||||
config,
|
||||
method,
|
||||
&error))
|
||||
{
|
||||
g_clear_object (&config);
|
||||
g_warning ("Failed to use current monitor configuration: %s",
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
config = meta_monitor_config_manager_create_linear (manager->config_manager);
|
||||
if (config)
|
||||
{
|
||||
@@ -585,6 +618,8 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
||||
&error))
|
||||
{
|
||||
g_clear_object (&config);
|
||||
g_warning ("Failed to use linear monitor configuration: %s",
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
@@ -602,6 +637,8 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager)
|
||||
&error))
|
||||
{
|
||||
g_clear_object (&config);
|
||||
g_warning ("Failed to use fallback monitor configuration: %s",
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
|
@@ -203,13 +203,9 @@ meta_monitor_get_main_output (MetaMonitor *monitor)
|
||||
gboolean
|
||||
meta_monitor_is_active (MetaMonitor *monitor)
|
||||
{
|
||||
MetaOutput *output;
|
||||
MetaCrtc *crtc;
|
||||
MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor);
|
||||
|
||||
output = meta_monitor_get_main_output (monitor);
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
|
||||
return crtc && crtc->current_mode;
|
||||
return !!priv->current_mode;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -1411,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)
|
||||
{
|
||||
@@ -1430,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
|
||||
|
@@ -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)
|
||||
@@ -87,7 +102,11 @@ meta_screen_cast_monitor_stream_src_get_specs (MetaScreenCastStreamSrc *src,
|
||||
logical_monitor = meta_monitor_get_logical_monitor (monitor);
|
||||
mode = meta_monitor_get_current_mode (monitor);
|
||||
|
||||
scale = logical_monitor->scale;
|
||||
if (meta_is_stage_views_scaled ())
|
||||
scale = logical_monitor->scale;
|
||||
else
|
||||
scale = 1.0;
|
||||
|
||||
*width = (int) roundf (logical_monitor->rect.width * scale);
|
||||
*height = (int) roundf (logical_monitor->rect.height * scale);
|
||||
*frame_rate = meta_monitor_mode_get_refresh_rate (mode);
|
||||
@@ -102,18 +121,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 +287,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 +334,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 +568,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 +581,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,22 +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);
|
||||
buffer = pw_stream_dequeue_buffer (priv->pipewire_stream);
|
||||
if (!buffer)
|
||||
{
|
||||
g_warning ("Failed to peek at PipeWire buffer");
|
||||
g_warning ("Failed to dequeue at PipeWire buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer->datas[0].type == priv->pipewire_type->data.MemFd)
|
||||
spa_buffer = buffer->buffer;
|
||||
|
||||
if (spa_buffer->datas[0].data)
|
||||
{
|
||||
map = mmap (NULL, buffer->datas[0].maxsize + buffer->datas[0].mapoffset,
|
||||
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",
|
||||
@@ -171,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
|
||||
@@ -266,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 =
|
||||
@@ -276,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)
|
||||
@@ -304,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));
|
||||
}
|
||||
@@ -326,7 +435,6 @@ 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;
|
||||
@@ -345,7 +453,10 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src,
|
||||
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);
|
||||
@@ -358,7 +469,8 @@ 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, "Fru", &max_framerate,
|
||||
PROP_RANGE (&min_framerate,
|
||||
@@ -372,7 +484,8 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src,
|
||||
result = pw_stream_connect (pipewire_stream,
|
||||
PW_DIRECTION_OUTPUT,
|
||||
NULL,
|
||||
PW_STREAM_FLAG_NONE,
|
||||
(PW_STREAM_FLAG_DRIVER |
|
||||
PW_STREAM_FLAG_MAP_BUFFERS),
|
||||
params, G_N_ELEMENTS (params));
|
||||
if (result != 0)
|
||||
{
|
||||
@@ -469,6 +582,7 @@ init_spa_type (MetaSpaType *type,
|
||||
spa_type_media_subtype_map (map, &type->media_subtype);
|
||||
spa_type_format_video_map (map, &type->format_video);
|
||||
spa_type_video_format_map (map, &type->video_format);
|
||||
type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor);
|
||||
}
|
||||
|
||||
static MetaPipeWireSource *
|
||||
|
@@ -24,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,9 +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 << 3),
|
||||
META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS = (1 << 1),
|
||||
} MetaExperimentalFeature;
|
||||
|
||||
#define META_TYPE_SETTINGS (meta_settings_get_type ())
|
||||
|
@@ -263,10 +263,6 @@ 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
|
||||
|
@@ -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
|
||||
|
@@ -60,6 +60,8 @@ struct _MetaBackendNativePrivate
|
||||
{
|
||||
MetaLauncher *launcher;
|
||||
MetaBarrierManagerNative *barrier_manager;
|
||||
|
||||
gboolean is_paused;
|
||||
};
|
||||
typedef struct _MetaBackendNativePrivate MetaBackendNativePrivate;
|
||||
|
||||
@@ -332,6 +334,15 @@ meta_backend_native_post_init (MetaBackend *backend)
|
||||
NULL, NULL);
|
||||
clutter_evdev_set_relative_motion_filter (manager, relative_motion_filter,
|
||||
meta_backend_get_monitor_manager (backend));
|
||||
|
||||
g_signal_connect (G_OBJECT (backend),
|
||||
"suspending",
|
||||
G_CALLBACK (meta_backend_native_pause),
|
||||
NULL);
|
||||
g_signal_connect (G_OBJECT (backend),
|
||||
"resuming",
|
||||
G_CALLBACK (meta_backend_native_resume),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static MetaMonitorManager *
|
||||
@@ -631,11 +642,23 @@ meta_backend_native_pause (MetaBackendNative *native)
|
||||
meta_backend_get_monitor_manager (backend);
|
||||
MetaMonitorManagerKms *monitor_manager_kms =
|
||||
META_MONITOR_MANAGER_KMS (monitor_manager);
|
||||
MetaBackendNativePrivate *priv =
|
||||
meta_backend_native_get_instance_private (native);
|
||||
|
||||
if (priv->is_paused)
|
||||
{
|
||||
g_warning ("tried to pause when already paused\n");
|
||||
return;
|
||||
}
|
||||
|
||||
g_warning ("pausing\n");
|
||||
|
||||
clutter_evdev_release_devices ();
|
||||
clutter_egl_freeze_master_clock ();
|
||||
|
||||
meta_monitor_manager_kms_pause (monitor_manager_kms);
|
||||
|
||||
priv->is_paused = TRUE;
|
||||
}
|
||||
|
||||
void meta_backend_native_resume (MetaBackendNative *native)
|
||||
@@ -645,11 +668,36 @@ 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;
|
||||
MetaBackendNativePrivate *priv =
|
||||
meta_backend_native_get_instance_private (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 (!priv->is_paused)
|
||||
{
|
||||
g_warning ("tried to resume when not paused\n");
|
||||
return;
|
||||
}
|
||||
g_warning ("resuming\n");
|
||||
|
||||
if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_UNSTABLE_TEXTURES))
|
||||
{
|
||||
g_warning ("purging glphy cache\n");
|
||||
clutter_clear_glyph_cache ();
|
||||
g_warning ("refreshing cursor\n");
|
||||
meta_screen_update_cursor (display->screen);
|
||||
g_warning ("redrawing window and background textures\n");
|
||||
g_signal_emit_by_name (display, "gl-video-memory-purged");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("gpu doesn't have unstable textures problem, so we're good there\n");
|
||||
}
|
||||
|
||||
meta_monitor_manager_kms_resume (monitor_manager_kms);
|
||||
|
||||
clutter_evdev_reclaim_devices ();
|
||||
@@ -658,10 +706,8 @@ 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_reset_idletime (idle_monitor);
|
||||
|
||||
priv->is_paused = FALSE;
|
||||
}
|
||||
|
@@ -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;
|
||||
@@ -371,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;
|
||||
@@ -564,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;
|
||||
@@ -609,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);
|
||||
|
||||
@@ -621,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;
|
||||
|
||||
@@ -656,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
|
||||
@@ -706,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)
|
||||
{
|
||||
@@ -738,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;
|
||||
}
|
||||
|
||||
@@ -805,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);
|
||||
@@ -929,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,
|
||||
@@ -982,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,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 =
|
||||
@@ -1033,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);
|
||||
}
|
||||
|
||||
@@ -1112,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,6 +68,8 @@ struct _MetaGpuKms
|
||||
int max_buffer_height;
|
||||
|
||||
gboolean page_flips_not_supported;
|
||||
|
||||
gboolean resources_init_failed_before;
|
||||
};
|
||||
|
||||
G_DEFINE_QUARK (MetaGpuKmsError, meta_gpu_kms_error)
|
||||
@@ -143,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;
|
||||
}
|
||||
@@ -204,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,
|
||||
@@ -234,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,
|
||||
@@ -250,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;
|
||||
}
|
||||
@@ -281,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
|
||||
@@ -706,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
|
||||
@@ -731,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
|
||||
@@ -742,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;
|
||||
@@ -768,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,
|
||||
@@ -801,6 +854,13 @@ meta_gpu_kms_new (MetaMonitorManagerKms *monitor_manager_kms,
|
||||
*/
|
||||
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);
|
||||
@@ -824,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,
|
||||
|
@@ -40,6 +40,8 @@ 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;
|
||||
@@ -59,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);
|
||||
|
||||
@@ -92,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 */
|
||||
|
@@ -280,14 +280,25 @@ sync_active (MetaLauncher *self)
|
||||
gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy));
|
||||
|
||||
if (active == self->session_active)
|
||||
return;
|
||||
{
|
||||
g_warning ("tried to sync activeness when already in sync");
|
||||
return;
|
||||
}
|
||||
|
||||
g_warning ("syncing activeness");
|
||||
self->session_active = active;
|
||||
|
||||
if (active)
|
||||
meta_backend_native_resume (backend_native);
|
||||
{
|
||||
g_warning ("inactive -> active");
|
||||
meta_backend_native_resume (backend_native);
|
||||
}
|
||||
else
|
||||
meta_backend_native_pause (backend_native);
|
||||
{
|
||||
g_warning ("active -> inactive");
|
||||
meta_backend_native_pause (backend_native);
|
||||
}
|
||||
g_warning ("activeness synced");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -296,6 +307,7 @@ on_active_changed (Login1Session *session,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaLauncher *self = user_data;
|
||||
g_warning ("got active changed notification");
|
||||
sync_active (self);
|
||||
}
|
||||
|
||||
|
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
@@ -694,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;
|
||||
}
|
||||
|
||||
|
@@ -96,8 +96,6 @@ typedef struct _MetaRendererNativeGpuData
|
||||
#ifdef HAVE_EGL_DEVICE
|
||||
struct {
|
||||
EGLDeviceEXT device;
|
||||
|
||||
gboolean no_egl_output_drm_flip_event;
|
||||
} egl;
|
||||
#endif
|
||||
|
||||
@@ -993,14 +991,29 @@ meta_renderer_native_choose_egl_config (CoglDisplay *cogl_display,
|
||||
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
MetaEgl *egl = meta_backend_get_egl (backend);
|
||||
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
||||
EGLDisplay egl_display = cogl_renderer_egl->edpy;
|
||||
|
||||
return choose_egl_config_from_gbm_format (egl,
|
||||
egl_display,
|
||||
attributes,
|
||||
GBM_FORMAT_XRGB8888,
|
||||
out_config,
|
||||
error);
|
||||
switch (renderer_gpu_data->mode)
|
||||
{
|
||||
case META_RENDERER_NATIVE_MODE_GBM:
|
||||
return choose_egl_config_from_gbm_format (egl,
|
||||
egl_display,
|
||||
attributes,
|
||||
GBM_FORMAT_XRGB8888,
|
||||
out_config,
|
||||
error);
|
||||
#ifdef HAVE_EGL_DEVICE
|
||||
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
||||
return meta_egl_choose_first_config (egl,
|
||||
egl_display,
|
||||
attributes,
|
||||
out_config,
|
||||
error);
|
||||
#endif
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1271,18 +1284,20 @@ flip_egl_stream (MetaOnscreenNative *onscreen_native,
|
||||
MetaRendererNativeGpuData *renderer_gpu_data;
|
||||
EGLDisplay *egl_display;
|
||||
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
||||
MetaGpuKmsFlipClosureContainer *closure_container;
|
||||
EGLAttrib *acquire_attribs;
|
||||
GError *error = NULL;
|
||||
|
||||
renderer_gpu_data =
|
||||
meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
|
||||
onscreen_native->render_gpu);
|
||||
if (renderer_gpu_data->egl.no_egl_output_drm_flip_event)
|
||||
return FALSE;
|
||||
|
||||
closure_container =
|
||||
meta_gpu_kms_wrap_flip_closure (onscreen_native->render_gpu, flip_closure);
|
||||
|
||||
acquire_attribs = (EGLAttrib[]) {
|
||||
EGL_DRM_FLIP_EVENT_DATA_NV,
|
||||
(EGLAttrib) flip_closure,
|
||||
(EGLAttrib) closure_container,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
@@ -1296,11 +1311,10 @@ flip_egl_stream (MetaOnscreenNative *onscreen_native,
|
||||
if (error->domain != META_EGL_ERROR ||
|
||||
error->code != EGL_RESOURCE_BUSY_EXT)
|
||||
{
|
||||
g_warning ("Failed to flip EGL stream (%s), relying on clock from "
|
||||
"now on", error->message);
|
||||
renderer_gpu_data->egl.no_egl_output_drm_flip_event = TRUE;
|
||||
g_warning ("Failed to flip EGL stream: %s", error->message);
|
||||
}
|
||||
g_error_free (error);
|
||||
meta_gpu_kms_flip_closure_container_free (closure_container);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1607,12 +1621,23 @@ gbm_get_next_fb_id (MetaGpuKms *gpu_kms,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < gbm_bo_get_plane_count (next_bo); i++)
|
||||
if (gbm_bo_get_handle_for_plane (next_bo, 0).s32 == -1)
|
||||
{
|
||||
strides[i] = gbm_bo_get_stride_for_plane (next_bo, i);
|
||||
handles[i] = gbm_bo_get_handle_for_plane (next_bo, i).u32;
|
||||
offsets[i] = gbm_bo_get_offset (next_bo, i);
|
||||
modifiers[i] = gbm_bo_get_modifier (next_bo);
|
||||
/* Failed to fetch handle to plane, falling back to old method */
|
||||
strides[0] = gbm_bo_get_stride (next_bo);
|
||||
handles[0] = gbm_bo_get_handle (next_bo).u32;
|
||||
offsets[0] = 0;
|
||||
modifiers[0] = DRM_FORMAT_MOD_INVALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < gbm_bo_get_plane_count (next_bo); i++)
|
||||
{
|
||||
strides[i] = gbm_bo_get_stride_for_plane (next_bo, i);
|
||||
handles[i] = gbm_bo_get_handle_for_plane (next_bo, i).u32;
|
||||
offsets[i] = gbm_bo_get_offset (next_bo, i);
|
||||
modifiers[i] = gbm_bo_get_modifier (next_bo);
|
||||
}
|
||||
}
|
||||
|
||||
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
@@ -2097,7 +2122,7 @@ meta_renderer_native_create_surface_egl_device (CoglOnscreen *onscreen,
|
||||
EGLOutputLayerEXT output_layer;
|
||||
EGLAttrib output_attribs[3];
|
||||
EGLint stream_attribs[] = {
|
||||
EGL_STREAM_FIFO_LENGTH_KHR, 1,
|
||||
EGL_STREAM_FIFO_LENGTH_KHR, 0,
|
||||
EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
|
||||
EGL_NONE
|
||||
};
|
||||
@@ -2720,9 +2745,14 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
|
||||
MetaMonitor *main_monitor;
|
||||
MetaOutput *main_output;
|
||||
MetaCrtc *crtc;
|
||||
MetaMonitorTransform crtc_transform;
|
||||
|
||||
main_monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
|
||||
main_output = meta_monitor_get_main_output (main_monitor);
|
||||
crtc = meta_output_get_assigned_crtc (main_output);
|
||||
crtc_transform =
|
||||
meta_monitor_logical_to_crtc_transform (main_monitor,
|
||||
logical_monitor->transform);
|
||||
|
||||
/*
|
||||
* Pick any monitor and output and check; all CRTCs of a logical monitor will
|
||||
@@ -2731,10 +2761,64 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
|
||||
|
||||
if (meta_monitor_manager_is_transform_handled (monitor_manager,
|
||||
crtc,
|
||||
crtc->transform))
|
||||
crtc_transform))
|
||||
return META_MONITOR_TRANSFORM_NORMAL;
|
||||
else
|
||||
return crtc->transform;
|
||||
return crtc_transform;
|
||||
}
|
||||
|
||||
static CoglContext *
|
||||
cogl_context_from_renderer_native (MetaRendererNative *renderer_native)
|
||||
{
|
||||
MetaMonitorManager *monitor_manager =
|
||||
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
||||
MetaBackend *backend = meta_monitor_manager_get_backend (monitor_manager);
|
||||
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
||||
|
||||
return clutter_backend_get_cogl_context (clutter_backend);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_force_shadow_fb (MetaRendererNative *renderer_native,
|
||||
MetaGpuKms *primary_gpu)
|
||||
{
|
||||
CoglContext *cogl_context =
|
||||
cogl_context_from_renderer_native (renderer_native);
|
||||
CoglGpuInfo *info = &cogl_context->gpu;
|
||||
int kms_fd;
|
||||
uint64_t prefer_shadow = 0;
|
||||
|
||||
switch (info->architecture)
|
||||
{
|
||||
case COGL_GPU_INFO_ARCHITECTURE_UNKNOWN:
|
||||
case COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE:
|
||||
case COGL_GPU_INFO_ARCHITECTURE_SGX:
|
||||
case COGL_GPU_INFO_ARCHITECTURE_MALI:
|
||||
return FALSE;
|
||||
case COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE:
|
||||
case COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE:
|
||||
case COGL_GPU_INFO_ARCHITECTURE_SWRAST:
|
||||
break;
|
||||
}
|
||||
|
||||
kms_fd = meta_gpu_kms_get_fd (primary_gpu);
|
||||
if (drmGetCap (kms_fd, DRM_CAP_DUMB_PREFER_SHADOW, &prefer_shadow) == 0)
|
||||
{
|
||||
if (prefer_shadow)
|
||||
{
|
||||
static gboolean logged_once = FALSE;
|
||||
|
||||
if (!logged_once)
|
||||
{
|
||||
g_message ("Forcing shadow framebuffer");
|
||||
logged_once = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static MetaRendererView *
|
||||
@@ -2746,10 +2830,8 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
|
||||
renderer_native->monitor_manager_kms;
|
||||
MetaMonitorManager *monitor_manager =
|
||||
META_MONITOR_MANAGER (monitor_manager_kms);
|
||||
MetaBackend *backend = meta_monitor_manager_get_backend (monitor_manager);
|
||||
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
||||
CoglContext *cogl_context =
|
||||
clutter_backend_get_cogl_context (clutter_backend);
|
||||
cogl_context_from_renderer_native (renderer_native);
|
||||
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
|
||||
MetaGpuKms *primary_gpu;
|
||||
CoglDisplayEGL *cogl_display_egl;
|
||||
@@ -2784,7 +2866,8 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
|
||||
if (!onscreen)
|
||||
g_error ("Failed to allocate onscreen framebuffer: %s", error->message);
|
||||
|
||||
if (view_transform != META_MONITOR_TRANSFORM_NORMAL)
|
||||
if (view_transform != META_MONITOR_TRANSFORM_NORMAL ||
|
||||
should_force_shadow_fb (renderer_native, primary_gpu))
|
||||
{
|
||||
offscreen = meta_renderer_native_create_offscreen (renderer_native,
|
||||
cogl_context,
|
||||
@@ -2907,10 +2990,11 @@ meta_renderer_native_set_property (GObject *object,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_secondary_egl_config (MetaEgl *egl,
|
||||
EGLDisplay egl_display,
|
||||
EGLConfig *egl_config,
|
||||
GError **error)
|
||||
create_secondary_egl_config (MetaEgl *egl,
|
||||
MetaRendererNativeMode mode,
|
||||
EGLDisplay egl_display,
|
||||
EGLConfig *egl_config,
|
||||
GError **error)
|
||||
{
|
||||
EGLint attributes[] = {
|
||||
EGL_RED_SIZE, 1,
|
||||
@@ -2923,12 +3007,26 @@ create_secondary_egl_config (MetaEgl *egl,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
return choose_egl_config_from_gbm_format (egl,
|
||||
egl_display,
|
||||
attributes,
|
||||
GBM_FORMAT_XRGB8888,
|
||||
egl_config,
|
||||
error);
|
||||
switch (mode)
|
||||
{
|
||||
case META_RENDERER_NATIVE_MODE_GBM:
|
||||
return choose_egl_config_from_gbm_format (egl,
|
||||
egl_display,
|
||||
attributes,
|
||||
GBM_FORMAT_XRGB8888,
|
||||
egl_config,
|
||||
error);
|
||||
#ifdef HAVE_EGL_DEVICE
|
||||
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
||||
return meta_egl_choose_first_config (egl,
|
||||
egl_display,
|
||||
attributes,
|
||||
egl_config,
|
||||
error);
|
||||
#endif
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static EGLContext
|
||||
@@ -2972,7 +3070,8 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
|
||||
EGLContext egl_context;
|
||||
char **missing_gl_extensions;
|
||||
|
||||
if (!create_secondary_egl_config (egl,egl_display, &egl_config, error))
|
||||
if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display,
|
||||
&egl_config, error))
|
||||
return FALSE;
|
||||
|
||||
egl_context = create_secondary_egl_context (egl, egl_display, egl_config, error);
|
||||
|
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "meta-backend-x11.h"
|
||||
#include "meta-stage-private.h"
|
||||
#include "backends/meta-cursor-sprite-xcursor.h"
|
||||
|
||||
struct _MetaCursorRendererX11Private
|
||||
{
|
||||
@@ -59,13 +60,18 @@ meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer,
|
||||
|
||||
gboolean has_server_cursor = FALSE;
|
||||
|
||||
if (cursor_sprite)
|
||||
if (cursor_sprite && META_IS_CURSOR_SPRITE_XCURSOR (cursor_sprite))
|
||||
{
|
||||
MetaCursor cursor = meta_cursor_sprite_get_meta_cursor (cursor_sprite);
|
||||
MetaCursorSpriteXcursor *sprite_xcursor =
|
||||
META_CURSOR_SPRITE_XCURSOR (cursor_sprite);
|
||||
MetaCursor cursor;
|
||||
|
||||
cursor = meta_cursor_sprite_xcursor_get_cursor (sprite_xcursor);
|
||||
if (cursor != META_CURSOR_NONE)
|
||||
{
|
||||
Cursor xcursor = meta_cursor_create_x_cursor (xdisplay, cursor);
|
||||
Cursor xcursor;
|
||||
|
||||
xcursor = meta_create_x_cursor (xdisplay, cursor);
|
||||
XDefineCursor (xdisplay, xwindow, xcursor);
|
||||
XFlush (xdisplay);
|
||||
XFreeCursor (xdisplay, xcursor);
|
||||
|
@@ -44,6 +44,8 @@ struct _MetaGpuXrandr
|
||||
|
||||
int max_screen_width;
|
||||
int max_screen_height;
|
||||
|
||||
gboolean need_hardware_poll;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaGpuXrandr, meta_gpu_xrandr, META_TYPE_GPU)
|
||||
@@ -81,6 +83,14 @@ get_xmode_name (XRRModeInfo *xmode)
|
||||
return g_strdup_printf ("%dx%d", width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gpu_xrandr_poll_hardware (MetaGpu *gpu)
|
||||
{
|
||||
MetaGpuXrandr *gpu_xrandr = META_GPU_XRANDR (gpu);
|
||||
|
||||
gpu_xrandr->need_hardware_poll = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_gpu_xrandr_read_current (MetaGpu *gpu,
|
||||
GError **error)
|
||||
@@ -148,8 +158,18 @@ meta_gpu_xrandr_read_current (MetaGpu *gpu,
|
||||
monitor_manager->screen_width = WidthOfScreen (screen);
|
||||
monitor_manager->screen_height = HeightOfScreen (screen);
|
||||
|
||||
resources = XRRGetScreenResourcesCurrent (xdisplay,
|
||||
DefaultRootWindow (xdisplay));
|
||||
if (gpu_xrandr->need_hardware_poll)
|
||||
{
|
||||
resources = XRRGetScreenResources (xdisplay,
|
||||
DefaultRootWindow (xdisplay));
|
||||
gpu_xrandr->need_hardware_poll = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
resources = XRRGetScreenResourcesCurrent (xdisplay,
|
||||
DefaultRootWindow (xdisplay));
|
||||
}
|
||||
|
||||
if (!resources)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
@@ -282,6 +302,7 @@ meta_gpu_xrandr_finalize (GObject *object)
|
||||
static void
|
||||
meta_gpu_xrandr_init (MetaGpuXrandr *gpu_xrandr)
|
||||
{
|
||||
gpu_xrandr->need_hardware_poll = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -293,4 +314,5 @@ meta_gpu_xrandr_class_init (MetaGpuXrandrClass *klass)
|
||||
object_class->finalize = meta_gpu_xrandr_finalize;
|
||||
|
||||
gpu_class->read_current = meta_gpu_xrandr_read_current;
|
||||
gpu_class->poll_hardware = meta_gpu_xrandr_poll_hardware;
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "meta-backend-x11.h"
|
||||
#include "meta-input-settings-x11.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/Xatom.h>
|
||||
@@ -34,6 +35,9 @@
|
||||
#ifdef HAVE_LIBGUDEV
|
||||
#include <gudev/gudev.h>
|
||||
#endif
|
||||
#ifdef __linux
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
#include <meta/errors.h>
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
@@ -43,6 +47,8 @@ typedef struct _MetaInputSettingsX11Private
|
||||
#ifdef HAVE_LIBGUDEV
|
||||
GUdevClient *udev_client;
|
||||
#endif
|
||||
gboolean syndaemon_spawned;
|
||||
GPid syndaemon_pid;
|
||||
} MetaInputSettingsX11Private;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettingsX11, meta_input_settings_x11,
|
||||
@@ -159,6 +165,318 @@ change_property (ClutterInputDevice *device,
|
||||
meta_XFree (data_ret);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_device_synaptics (ClutterInputDevice *device)
|
||||
{
|
||||
guchar *has_setting;
|
||||
|
||||
/* We just need looking for a synaptics-specific property */
|
||||
has_setting = get_property (device, "Synaptics Off", XA_INTEGER, 8, 1);
|
||||
if (!has_setting)
|
||||
return FALSE;
|
||||
|
||||
meta_XFree (has_setting);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_device_libinput (ClutterInputDevice *device)
|
||||
{
|
||||
guchar *has_setting;
|
||||
|
||||
/* We just need looking for a synaptics-specific property */
|
||||
has_setting = get_property (device, "libinput Send Events Modes Available", XA_INTEGER, 8, 2);
|
||||
if (!has_setting)
|
||||
return FALSE;
|
||||
|
||||
meta_XFree (has_setting);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
change_x_device_left_handed (ClutterInputDevice *device,
|
||||
gboolean left_handed)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
||||
XDevice *xdevice;
|
||||
guchar *buttons;
|
||||
guint buttons_capacity = 16, n_buttons;
|
||||
|
||||
xdevice = XOpenDevice(xdisplay, clutter_input_device_get_device_id (device));
|
||||
if (!xdevice)
|
||||
return;
|
||||
|
||||
if (display)
|
||||
meta_error_trap_push (display);
|
||||
buttons = g_new (guchar, buttons_capacity);
|
||||
n_buttons = XGetDeviceButtonMapping (xdisplay, xdevice,
|
||||
buttons, buttons_capacity);
|
||||
|
||||
while (n_buttons > buttons_capacity)
|
||||
{
|
||||
buttons_capacity = n_buttons;
|
||||
buttons = (guchar *) g_realloc (buttons,
|
||||
buttons_capacity * sizeof (guchar));
|
||||
|
||||
n_buttons = XGetDeviceButtonMapping (xdisplay, xdevice,
|
||||
buttons, buttons_capacity);
|
||||
}
|
||||
|
||||
buttons[0] = left_handed ? 3 : 1;
|
||||
buttons[2] = left_handed ? 1 : 3;
|
||||
XSetDeviceButtonMapping (xdisplay, xdevice, buttons, n_buttons);
|
||||
g_free (buttons);
|
||||
|
||||
if (display && meta_error_trap_pop_with_return (display))
|
||||
{
|
||||
g_warning ("Could not set left-handed for %s",
|
||||
clutter_input_device_get_device_name (device));
|
||||
}
|
||||
|
||||
XCloseDevice (xdisplay, xdevice);
|
||||
}
|
||||
|
||||
static void
|
||||
change_synaptics_tap_left_handed (ClutterInputDevice *device,
|
||||
gboolean tap_enabled,
|
||||
gboolean left_handed)
|
||||
{
|
||||
guchar *tap_action;
|
||||
|
||||
tap_action = get_property (device, "Synaptics Tap Action",
|
||||
XA_INTEGER, 8, 7);
|
||||
if (!tap_action)
|
||||
return;
|
||||
|
||||
tap_action[4] = tap_enabled ? (left_handed ? 3 : 1) : 0;
|
||||
tap_action[5] = tap_enabled ? (left_handed ? 1 : 3) : 0;
|
||||
tap_action[6] = tap_enabled ? 2 : 0;
|
||||
|
||||
change_property (device, "Synaptics Tap Action",
|
||||
XA_INTEGER, 8, tap_action, 7);
|
||||
meta_XFree (tap_action);
|
||||
|
||||
change_x_device_left_handed (device, left_handed);
|
||||
}
|
||||
|
||||
static void
|
||||
change_x_device_speed (ClutterInputDevice *device,
|
||||
gdouble speed)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
||||
XDevice *xdevice;
|
||||
XPtrFeedbackControl feedback;
|
||||
XFeedbackState *states, *state;
|
||||
int i, num_feedbacks, motion_threshold, numerator, denominator;
|
||||
gfloat motion_acceleration;
|
||||
|
||||
xdevice = XOpenDevice(xdisplay, clutter_input_device_get_device_id (device));
|
||||
if (!xdevice)
|
||||
return;
|
||||
/* Get the list of feedbacks for the device */
|
||||
states = XGetFeedbackControl (xdisplay, xdevice, &num_feedbacks);
|
||||
if (!states)
|
||||
return;
|
||||
|
||||
/* Calculate acceleration and threshold */
|
||||
motion_acceleration = (speed + 1) * 5; /* speed is [-1..1], map to [0..10] */
|
||||
motion_threshold = CLAMP (10 - floor (motion_acceleration), 1, 10);
|
||||
|
||||
if (motion_acceleration >= 1.0)
|
||||
{
|
||||
/* we want to get the acceleration, with a resolution of 0.5
|
||||
*/
|
||||
if ((motion_acceleration - floor (motion_acceleration)) < 0.25)
|
||||
{
|
||||
numerator = floor (motion_acceleration);
|
||||
denominator = 1;
|
||||
}
|
||||
else if ((motion_acceleration - floor (motion_acceleration)) < 0.5)
|
||||
{
|
||||
numerator = ceil (2.0 * motion_acceleration);
|
||||
denominator = 2;
|
||||
}
|
||||
else if ((motion_acceleration - floor (motion_acceleration)) < 0.75)
|
||||
{
|
||||
numerator = floor (2.0 *motion_acceleration);
|
||||
denominator = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
numerator = ceil (motion_acceleration);
|
||||
denominator = 1;
|
||||
}
|
||||
}
|
||||
else if (motion_acceleration < 1.0 && motion_acceleration > 0)
|
||||
{
|
||||
/* This we do to 1/10ths */
|
||||
numerator = floor (motion_acceleration * 10) + 1;
|
||||
denominator= 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
numerator = -1;
|
||||
denominator = -1;
|
||||
}
|
||||
|
||||
if (display)
|
||||
meta_error_trap_push (display);
|
||||
|
||||
state = (XFeedbackState *) states;
|
||||
|
||||
for (i = 0; i < num_feedbacks; i++)
|
||||
{
|
||||
if (state->class == PtrFeedbackClass)
|
||||
{
|
||||
/* And tell the device */
|
||||
feedback.class = PtrFeedbackClass;
|
||||
feedback.length = sizeof (XPtrFeedbackControl);
|
||||
feedback.id = state->id;
|
||||
feedback.threshold = motion_threshold;
|
||||
feedback.accelNum = numerator;
|
||||
feedback.accelDenom = denominator;
|
||||
|
||||
XChangeFeedbackControl (xdisplay, xdevice,
|
||||
DvAccelNum | DvAccelDenom | DvThreshold,
|
||||
(XFeedbackControl *) &feedback);
|
||||
break;
|
||||
}
|
||||
|
||||
state = (XFeedbackState *) ((char *) state + state->length);
|
||||
}
|
||||
|
||||
if (display && meta_error_trap_pop_with_return (display))
|
||||
{
|
||||
g_warning ("Could not set synaptics touchpad acceleration for %s",
|
||||
clutter_input_device_get_device_name (device));
|
||||
}
|
||||
|
||||
XFreeFeedbackList (states);
|
||||
XCloseDevice (xdisplay, xdevice);
|
||||
}
|
||||
|
||||
static void
|
||||
change_x_device_scroll_button (ClutterInputDevice *device,
|
||||
guint button)
|
||||
{
|
||||
guchar value;
|
||||
|
||||
value = button > 0 ? 1 : 0;
|
||||
change_property (device, "Evdev Wheel Emulation",
|
||||
XA_INTEGER, 8, &value, 1);
|
||||
if (button > 0)
|
||||
{
|
||||
value = button;
|
||||
change_property (device, "Evdev Wheel Emulation Button",
|
||||
XA_INTEGER, 8, &value, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that syndaemon dies together with us, to avoid running several of
|
||||
* them */
|
||||
static void
|
||||
setup_syndaemon (gpointer user_data)
|
||||
{
|
||||
#ifdef __linux
|
||||
prctl (PR_SET_PDEATHSIG, SIGHUP);
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
have_program_in_path (const char *name)
|
||||
{
|
||||
gchar *path;
|
||||
gboolean result;
|
||||
|
||||
path = g_find_program_in_path (name);
|
||||
result = (path != NULL);
|
||||
g_free (path);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
syndaemon_died (GPid pid,
|
||||
gint status,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (user_data);
|
||||
MetaInputSettingsX11Private *priv =
|
||||
meta_input_settings_x11_get_instance_private (settings_x11);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_spawn_check_exit_status (status, &error))
|
||||
{
|
||||
if ((WIFSIGNALED (status) && WTERMSIG (status) != SIGHUP) ||
|
||||
error->domain == G_SPAWN_EXIT_ERROR)
|
||||
g_warning ("Syndaemon exited unexpectedly: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_spawn_close_pid (pid);
|
||||
priv->syndaemon_spawned = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_synaptics_disable_w_typing (MetaInputSettings *settings,
|
||||
gboolean state)
|
||||
{
|
||||
MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (settings);
|
||||
MetaInputSettingsX11Private *priv =
|
||||
meta_input_settings_x11_get_instance_private (settings_x11);
|
||||
|
||||
if (state)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GPtrArray *args;
|
||||
|
||||
if (priv->syndaemon_spawned)
|
||||
return;
|
||||
|
||||
if (!have_program_in_path ("syndaemon"))
|
||||
return;
|
||||
|
||||
args = g_ptr_array_new ();
|
||||
|
||||
g_ptr_array_add (args, "syndaemon");
|
||||
g_ptr_array_add (args, "-i");
|
||||
g_ptr_array_add (args, "1.0");
|
||||
g_ptr_array_add (args, "-t");
|
||||
g_ptr_array_add (args, "-K");
|
||||
g_ptr_array_add (args, "-R");
|
||||
g_ptr_array_add (args, NULL);
|
||||
|
||||
/* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid
|
||||
* double-forking, otherwise syndaemon will immediately get
|
||||
* killed again through (PR_SET_PDEATHSIG when the intermediate
|
||||
* process dies */
|
||||
g_spawn_async (g_get_home_dir (), (char **) args->pdata, NULL,
|
||||
G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL,
|
||||
&priv->syndaemon_pid, &error);
|
||||
|
||||
priv->syndaemon_spawned = (error == NULL);
|
||||
g_ptr_array_free (args, TRUE);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Failed to launch syndaemon: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_child_watch_add (priv->syndaemon_pid, syndaemon_died, settings);
|
||||
}
|
||||
}
|
||||
else if (priv->syndaemon_spawned)
|
||||
{
|
||||
kill (priv->syndaemon_pid, SIGHUP);
|
||||
priv->syndaemon_spawned = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_input_settings_x11_set_send_events (MetaInputSettings *settings,
|
||||
ClutterInputDevice *device,
|
||||
@@ -167,6 +485,13 @@ meta_input_settings_x11_set_send_events (MetaInputSettings *settings,
|
||||
guchar values[2] = { 0 }; /* disabled, disabled-on-external-mouse */
|
||||
guchar *available;
|
||||
|
||||
if (is_device_synaptics (device))
|
||||
{
|
||||
values[0] = mode != G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED;
|
||||
change_property (device, "Synaptics Off", XA_INTEGER, 8, &values, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
available = get_property (device, "libinput Send Events Modes Available",
|
||||
XA_INTEGER, 8, 2);
|
||||
if (!available)
|
||||
@@ -219,6 +544,13 @@ meta_input_settings_x11_set_speed (MetaInputSettings *settings,
|
||||
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
||||
gfloat value = speed;
|
||||
|
||||
if (is_device_synaptics (device) ||
|
||||
!is_device_libinput (device))
|
||||
{
|
||||
change_x_device_speed (device, speed);
|
||||
return;
|
||||
}
|
||||
|
||||
change_property (device, "libinput Accel Speed",
|
||||
XInternAtom (xdisplay, "FLOAT", False),
|
||||
32, &value, 1);
|
||||
@@ -245,6 +577,24 @@ meta_input_settings_x11_set_left_handed (MetaInputSettings *settings,
|
||||
else
|
||||
{
|
||||
value = enabled ? 1 : 0;
|
||||
|
||||
if (is_device_synaptics (device))
|
||||
{
|
||||
GSettings *settings;
|
||||
|
||||
settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad");
|
||||
change_synaptics_tap_left_handed (device,
|
||||
g_settings_get_boolean (settings, "tap-to-click"),
|
||||
enabled);
|
||||
g_object_unref (settings);
|
||||
return;
|
||||
}
|
||||
else if (!is_device_libinput (device))
|
||||
{
|
||||
change_x_device_left_handed (device, enabled);
|
||||
return;
|
||||
}
|
||||
|
||||
change_property (device, "libinput Left Handed Enabled",
|
||||
XA_INTEGER, 8, &value, 1);
|
||||
}
|
||||
@@ -257,6 +607,12 @@ meta_input_settings_x11_set_disable_while_typing (MetaInputSettings *settings,
|
||||
{
|
||||
guchar value = (enabled) ? 1 : 0;
|
||||
|
||||
if (is_device_synaptics (device))
|
||||
{
|
||||
set_synaptics_disable_w_typing (settings, enabled);
|
||||
return;
|
||||
}
|
||||
|
||||
change_property (device, "libinput Disable While Typing Enabled",
|
||||
XA_INTEGER, 8, &value, 1);
|
||||
}
|
||||
@@ -268,6 +624,20 @@ meta_input_settings_x11_set_tap_enabled (MetaInputSettings *settings,
|
||||
{
|
||||
guchar value = (enabled) ? 1 : 0;
|
||||
|
||||
if (is_device_synaptics (device))
|
||||
{
|
||||
GDesktopTouchpadHandedness handedness;
|
||||
GSettings *settings;
|
||||
|
||||
settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad");
|
||||
handedness = g_settings_get_enum (settings, "left-handed");
|
||||
g_object_unref (settings);
|
||||
|
||||
change_synaptics_tap_left_handed (device, enabled,
|
||||
handedness == G_DESKTOP_TOUCHPAD_HANDEDNESS_LEFT);
|
||||
return;
|
||||
}
|
||||
|
||||
change_property (device, "libinput Tapping Enabled",
|
||||
XA_INTEGER, 8, &value, 1);
|
||||
}
|
||||
@@ -290,6 +660,27 @@ meta_input_settings_x11_set_invert_scroll (MetaInputSettings *settings,
|
||||
{
|
||||
guchar value = (inverted) ? 1 : 0;
|
||||
|
||||
if (is_device_synaptics (device))
|
||||
{
|
||||
gint32 *scrolling_distance;
|
||||
|
||||
scrolling_distance = get_property (device, "Synaptics Scrolling Distance",
|
||||
XA_INTEGER, 32, 2);
|
||||
if (scrolling_distance)
|
||||
{
|
||||
scrolling_distance[0] = inverted ?
|
||||
-abs (scrolling_distance[0]) : abs (scrolling_distance[0]);
|
||||
scrolling_distance[1] = inverted ?
|
||||
-abs (scrolling_distance[1]) : abs (scrolling_distance[1]);
|
||||
|
||||
change_property (device, "Synaptics Scrolling Distance",
|
||||
XA_INTEGER, 32, scrolling_distance, 2);
|
||||
meta_XFree (scrolling_distance);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
change_property (device, "libinput Natural Scrolling Enabled",
|
||||
XA_INTEGER, 8, &value, 1);
|
||||
}
|
||||
@@ -303,6 +694,22 @@ meta_input_settings_x11_set_edge_scroll (MetaInputSettings *settings,
|
||||
guchar *current = NULL;
|
||||
guchar *available = NULL;
|
||||
|
||||
if (is_device_synaptics (device))
|
||||
{
|
||||
current = get_property (device, "Synaptics Edge Scrolling",
|
||||
XA_INTEGER, 8, 3);
|
||||
if (current)
|
||||
{
|
||||
current[0] = !!edge_scroll_enabled;
|
||||
current[1] = !!edge_scroll_enabled;
|
||||
change_property (device, "Synaptics Edge Scrolling",
|
||||
XA_INTEGER, 8, current, 3);
|
||||
meta_XFree (current);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
available = get_property (device, "libinput Scroll Methods Available",
|
||||
XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
|
||||
if (!available || !available[SCROLL_METHOD_FIELD_EDGE])
|
||||
@@ -332,6 +739,22 @@ meta_input_settings_x11_set_two_finger_scroll (MetaInputSettings *set
|
||||
guchar *current = NULL;
|
||||
guchar *available = NULL;
|
||||
|
||||
if (is_device_synaptics (device))
|
||||
{
|
||||
current = get_property (device, "Synaptics Two-Finger Scrolling",
|
||||
XA_INTEGER, 8, 2);
|
||||
if (current)
|
||||
{
|
||||
current[0] = !!two_finger_scroll_enabled;
|
||||
current[1] = !!two_finger_scroll_enabled;
|
||||
change_property (device, "Synaptics Two-Finger Scrolling",
|
||||
XA_INTEGER, 8, current, 2);
|
||||
meta_XFree (current);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
available = get_property (device, "libinput Scroll Methods Available",
|
||||
XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
|
||||
if (!available || !available[SCROLL_METHOD_FIELD_2FG])
|
||||
@@ -359,6 +782,17 @@ meta_input_settings_x11_has_two_finger_scroll (MetaInputSettings *settings,
|
||||
guchar *available = NULL;
|
||||
gboolean has_two_finger = TRUE;
|
||||
|
||||
if (is_device_synaptics (device))
|
||||
{
|
||||
available = get_property (device, "Synaptics Capabilities",
|
||||
XA_INTEGER, 8, 4);
|
||||
if (!available || !available[3])
|
||||
has_two_finger = FALSE;
|
||||
|
||||
meta_XFree (available);
|
||||
return has_two_finger;
|
||||
}
|
||||
|
||||
available = get_property (device, "libinput Scroll Methods Available",
|
||||
XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
|
||||
if (!available || !available[SCROLL_METHOD_FIELD_2FG])
|
||||
@@ -373,6 +807,12 @@ meta_input_settings_x11_set_scroll_button (MetaInputSettings *settings,
|
||||
ClutterInputDevice *device,
|
||||
guint button)
|
||||
{
|
||||
if (!is_device_libinput (device))
|
||||
{
|
||||
change_x_device_scroll_button (device, button);
|
||||
return;
|
||||
}
|
||||
|
||||
change_property (device, "libinput Button Scrolling Button",
|
||||
XA_INTEGER, 32, &button, 1);
|
||||
}
|
||||
|
@@ -60,6 +60,10 @@ struct _MetaMonitorManagerXrandr
|
||||
Display *xdisplay;
|
||||
int rr_event_base;
|
||||
int rr_error_base;
|
||||
|
||||
guint logind_watch_id;
|
||||
guint logind_signal_sub_id;
|
||||
|
||||
gboolean has_randr15;
|
||||
|
||||
/*
|
||||
@@ -95,6 +99,8 @@ typedef struct _MetaMonitorXrandrData
|
||||
GQuark quark_meta_monitor_xrandr_data;
|
||||
#endif /* HAVE_RANDR15 */
|
||||
|
||||
static void meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr);
|
||||
|
||||
Display *
|
||||
meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr)
|
||||
{
|
||||
@@ -966,6 +972,62 @@ meta_monitor_manager_xrandr_get_default_layout_mode (MetaMonitorManager *manager
|
||||
return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
|
||||
}
|
||||
|
||||
static void
|
||||
logind_signal_handler (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaMonitorManagerXrandr *manager_xrandr = user_data;
|
||||
gboolean suspending;
|
||||
|
||||
if (!g_str_equal (signal_name, "PrepareForSleep"))
|
||||
return;
|
||||
|
||||
g_variant_get (parameters, "(b)", &suspending);
|
||||
if (!suspending)
|
||||
{
|
||||
meta_gpu_poll_hardware (manager_xrandr->gpu);
|
||||
meta_monitor_manager_xrandr_update (manager_xrandr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
logind_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaMonitorManagerXrandr *manager_xrandr = user_data;
|
||||
|
||||
manager_xrandr->logind_signal_sub_id = g_dbus_connection_signal_subscribe (connection,
|
||||
"org.freedesktop.login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"PrepareForSleep",
|
||||
"/org/freedesktop/login1",
|
||||
NULL,
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
logind_signal_handler,
|
||||
manager_xrandr,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
logind_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaMonitorManagerXrandr *manager_xrandr = user_data;
|
||||
|
||||
if (connection && manager_xrandr->logind_signal_sub_id > 0)
|
||||
g_dbus_connection_signal_unsubscribe (connection, manager_xrandr->logind_signal_sub_id);
|
||||
|
||||
manager_xrandr->logind_signal_sub_id = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_xrandr_constructed (GObject *object)
|
||||
{
|
||||
@@ -1024,12 +1086,23 @@ meta_monitor_manager_xrandr_finalize (GObject *object)
|
||||
g_hash_table_destroy (manager_xrandr->tiled_monitor_atoms);
|
||||
g_free (manager_xrandr->supported_scales);
|
||||
|
||||
if (manager_xrandr->logind_watch_id > 0)
|
||||
g_bus_unwatch_name (manager_xrandr->logind_watch_id);
|
||||
manager_xrandr->logind_watch_id = 0;
|
||||
|
||||
G_OBJECT_CLASS (meta_monitor_manager_xrandr_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr)
|
||||
{
|
||||
manager_xrandr->logind_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
|
||||
"org.freedesktop.login1",
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
logind_appeared,
|
||||
logind_vanished,
|
||||
manager_xrandr,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1063,27 +1136,39 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass)
|
||||
g_quark_from_static_string ("-meta-monitor-xrandr-data");
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
XEvent *event)
|
||||
static gboolean
|
||||
is_xvnc (MetaMonitorManager *manager)
|
||||
{
|
||||
MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
|
||||
GList *l;
|
||||
|
||||
for (l = meta_gpu_get_outputs (manager_xrandr->gpu); l; l = l->next)
|
||||
if (g_str_has_prefix (((MetaOutput *)l->data)->name, "VNC-"))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_monitor_manager_xrandr_update (MetaMonitorManagerXrandr *manager_xrandr)
|
||||
{
|
||||
MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_xrandr);
|
||||
MetaGpuXrandr *gpu_xrandr;
|
||||
XRRScreenResources *resources;
|
||||
gboolean is_hotplug;
|
||||
gboolean is_our_configuration;
|
||||
|
||||
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
|
||||
return FALSE;
|
||||
|
||||
XRRUpdateConfiguration (event);
|
||||
unsigned int timestamp;
|
||||
|
||||
meta_monitor_manager_read_current_state (manager);
|
||||
|
||||
gpu_xrandr = META_GPU_XRANDR (manager_xrandr->gpu);
|
||||
resources = meta_gpu_xrandr_get_resources (gpu_xrandr);
|
||||
|
||||
is_hotplug = resources->timestamp < resources->configTimestamp;
|
||||
timestamp = resources->timestamp;
|
||||
if (is_xvnc (manager))
|
||||
timestamp += 100;
|
||||
|
||||
is_hotplug = (timestamp < resources->configTimestamp);
|
||||
is_our_configuration = (resources->timestamp ==
|
||||
manager_xrandr->last_xrandr_set_timestamp);
|
||||
if (is_hotplug)
|
||||
@@ -1108,6 +1193,19 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xra
|
||||
|
||||
meta_monitor_manager_xrandr_rebuild_derived (manager, config);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager_xrandr,
|
||||
XEvent *event)
|
||||
{
|
||||
|
||||
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
|
||||
return FALSE;
|
||||
|
||||
XRRUpdateConfiguration (event);
|
||||
|
||||
meta_monitor_manager_xrandr_update (manager_xrandr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -26,6 +26,8 @@
|
||||
|
||||
#include "backends/x11/nested/meta-cursor-renderer-x11-nested.h"
|
||||
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
|
||||
struct _MetaCursorRendererX11Nested
|
||||
|
@@ -51,10 +51,14 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
|
||||
MetaMonitor *main_monitor;
|
||||
MetaOutput *main_output;
|
||||
MetaCrtc *crtc;
|
||||
MetaMonitorTransform crtc_transform;
|
||||
|
||||
main_monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
|
||||
main_output = meta_monitor_get_main_output (main_monitor);
|
||||
crtc = meta_output_get_assigned_crtc (main_output);
|
||||
crtc_transform =
|
||||
meta_monitor_logical_to_crtc_transform (main_monitor,
|
||||
logical_monitor->transform);
|
||||
/*
|
||||
* Pick any monitor and output and check; all CRTCs of a logical monitor will
|
||||
* always have the same transform assigned to them.
|
||||
@@ -62,10 +66,10 @@ calculate_view_transform (MetaMonitorManager *monitor_manager,
|
||||
|
||||
if (meta_monitor_manager_is_transform_handled (monitor_manager,
|
||||
crtc,
|
||||
crtc->transform))
|
||||
crtc_transform))
|
||||
return META_MONITOR_TRANSFORM_NORMAL;
|
||||
else
|
||||
return crtc->transform;
|
||||
return crtc_transform;
|
||||
}
|
||||
|
||||
static MetaRendererView *
|
||||
|
@@ -143,7 +143,8 @@ meta_actor_is_untransformed (ClutterActor *actor,
|
||||
* transform.
|
||||
*/
|
||||
gboolean
|
||||
meta_actor_painting_untransformed (int paint_width,
|
||||
meta_actor_painting_untransformed (CoglFramebuffer *fb,
|
||||
int paint_width,
|
||||
int paint_height,
|
||||
int *x_origin,
|
||||
int *y_origin)
|
||||
@@ -153,8 +154,8 @@ meta_actor_painting_untransformed (int paint_width,
|
||||
float viewport[4];
|
||||
int i;
|
||||
|
||||
cogl_get_modelview_matrix (&modelview);
|
||||
cogl_get_projection_matrix (&projection);
|
||||
cogl_framebuffer_get_modelview_matrix (fb, &modelview);
|
||||
cogl_framebuffer_get_projection_matrix (fb, &projection);
|
||||
|
||||
cogl_matrix_multiply (&modelview_projection,
|
||||
&projection,
|
||||
@@ -173,7 +174,7 @@ meta_actor_painting_untransformed (int paint_width,
|
||||
vertices[3].y = paint_height;
|
||||
vertices[3].z = 0;
|
||||
|
||||
cogl_get_viewport (viewport);
|
||||
cogl_framebuffer_get_viewport4fv (fb, viewport);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
|
@@ -31,9 +31,10 @@ gboolean meta_actor_is_untransformed (ClutterActor *actor,
|
||||
int *x_origin,
|
||||
int *y_origin);
|
||||
|
||||
gboolean meta_actor_painting_untransformed (int paint_width,
|
||||
int paint_height,
|
||||
int *x_origin,
|
||||
int *y_origin);
|
||||
gboolean meta_actor_painting_untransformed (CoglFramebuffer *fb,
|
||||
int paint_width,
|
||||
int paint_height,
|
||||
int *x_origin,
|
||||
int *y_origin);
|
||||
|
||||
#endif /* __META_CLUTTER_UTILS_H__ */
|
||||
|
@@ -21,6 +21,10 @@ struct _MetaCompositor
|
||||
gint64 server_time_query_time;
|
||||
gint64 server_time_offset;
|
||||
|
||||
int glx_opcode;
|
||||
guint stereo_tree_ext : 1;
|
||||
guint have_stereo_windows : 1;
|
||||
|
||||
guint server_time_is_monotonic_time : 1;
|
||||
guint no_mipmaps : 1;
|
||||
|
||||
@@ -61,6 +65,11 @@ void meta_end_modal_for_plugin (MetaCompositor *compositor,
|
||||
gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
|
||||
gint64 monotonic_time);
|
||||
|
||||
gboolean meta_compositor_window_is_stereo (MetaScreen *screen,
|
||||
Window xwindow);
|
||||
void meta_compositor_select_stereo_notify (MetaScreen *screen,
|
||||
Window xwindow);
|
||||
|
||||
void meta_compositor_flash_window (MetaCompositor *compositor,
|
||||
MetaWindow *window);
|
||||
|
||||
|
@@ -70,6 +70,8 @@
|
||||
#include "meta-window-group-private.h"
|
||||
#include "window-private.h" /* to check window->hidden */
|
||||
#include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */
|
||||
#include "stack-tracker.h"
|
||||
#include "stereo.h"
|
||||
#include "util-private.h"
|
||||
#include "backends/meta-dnd-private.h"
|
||||
#include "frame.h"
|
||||
@@ -487,6 +489,97 @@ redirect_windows (MetaScreen *screen)
|
||||
}
|
||||
}
|
||||
|
||||
#define GLX_STEREO_TREE_EXT 0x20F5
|
||||
#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
|
||||
#define GLX_STEREO_NOTIFY_EXT 0x00000000
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
unsigned long serial;
|
||||
Bool send_event;
|
||||
Display *display;
|
||||
int extension;
|
||||
int evtype;
|
||||
Drawable window;
|
||||
Bool stereo_tree;
|
||||
} StereoNotifyEvent;
|
||||
|
||||
static gboolean
|
||||
screen_has_stereo_tree_ext (MetaScreen *screen)
|
||||
{
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
const char *extensions_string;
|
||||
|
||||
static const char * (*query_extensions_string) (Display *display,
|
||||
int screen);
|
||||
|
||||
if (query_extensions_string == NULL)
|
||||
query_extensions_string =
|
||||
(const char * (*) (Display *, int))
|
||||
cogl_get_proc_address ("glXQueryExtensionsString");
|
||||
|
||||
extensions_string = query_extensions_string (xdisplay,
|
||||
meta_screen_get_screen_number (screen));
|
||||
|
||||
return extensions_string && strstr (extensions_string, "EXT_stereo_tree") != 0;
|
||||
}
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
gboolean
|
||||
meta_compositor_window_is_stereo (MetaScreen *screen,
|
||||
Window xwindow)
|
||||
{
|
||||
MetaCompositor *compositor = get_compositor_for_screen (screen);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
static int (*query_drawable) (Display *dpy,
|
||||
Drawable draw,
|
||||
int attribute,
|
||||
unsigned int *value);
|
||||
|
||||
if (compositor->stereo_tree_ext)
|
||||
{
|
||||
unsigned int stereo_tree = 0;
|
||||
|
||||
if (query_drawable == NULL)
|
||||
query_drawable =
|
||||
(int (*) (Display *, Drawable, int, unsigned int *))
|
||||
cogl_get_proc_address ("glXQueryDrawable");
|
||||
|
||||
query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree);
|
||||
|
||||
return stereo_tree != 0;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_select_stereo_notify (MetaScreen *screen,
|
||||
Window xwindow)
|
||||
{
|
||||
MetaCompositor *compositor = get_compositor_for_screen (screen);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
static void (*select_event) (Display *dpy,
|
||||
Drawable draw,
|
||||
unsigned long event_mask);
|
||||
|
||||
if (compositor->stereo_tree_ext)
|
||||
{
|
||||
if (select_event == NULL)
|
||||
select_event =
|
||||
(void (*) (Display *, Drawable, unsigned long))
|
||||
cogl_get_proc_address ("glXSelectEvent");
|
||||
|
||||
select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_manage (MetaCompositor *compositor)
|
||||
{
|
||||
@@ -495,6 +588,8 @@ meta_compositor_manage (MetaCompositor *compositor)
|
||||
MetaScreen *screen = display->screen;
|
||||
MetaBackend *backend = meta_get_backend ();
|
||||
|
||||
compositor->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
|
||||
|
||||
meta_screen_set_cm_selection (display->screen);
|
||||
|
||||
compositor->stage = meta_backend_get_stage (backend);
|
||||
@@ -759,6 +854,23 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
||||
if (window)
|
||||
process_damage (compositor, (XDamageNotifyEvent *) event, window);
|
||||
}
|
||||
else if (!meta_is_wayland_compositor () &&
|
||||
event->type == GenericEvent &&
|
||||
event->xcookie.extension == compositor->glx_opcode)
|
||||
{
|
||||
if (event->xcookie.evtype == GLX_STEREO_NOTIFY_EXT)
|
||||
{
|
||||
StereoNotifyEvent *stereo_event = (StereoNotifyEvent *)(event->xcookie.data);
|
||||
window = meta_display_lookup_x_window (compositor->display, stereo_event->window);
|
||||
|
||||
if (window != NULL)
|
||||
{
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
meta_window_actor_stereo_notify (window_actor, stereo_event->stereo_tree);
|
||||
meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compositor->have_x11_sync_object)
|
||||
meta_sync_ring_handle_event (event);
|
||||
@@ -969,6 +1081,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
GList *stack)
|
||||
{
|
||||
GList *old_stack;
|
||||
int stereo_window_count = 0;
|
||||
|
||||
/* This is painful because hidden windows that we are in the process
|
||||
* of animating out of existence. They'll be at the bottom of the
|
||||
@@ -1044,6 +1157,8 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
* near the front of the other.)
|
||||
*/
|
||||
compositor->windows = g_list_prepend (compositor->windows, actor);
|
||||
if (meta_window_actor_is_stereo (actor))
|
||||
stereo_window_count++;
|
||||
|
||||
stack = g_list_remove (stack, window);
|
||||
old_stack = g_list_remove (old_stack, actor);
|
||||
@@ -1051,6 +1166,8 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
|
||||
sync_actor_stacking (compositor);
|
||||
|
||||
meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
|
||||
|
||||
if (compositor->top_window_actor)
|
||||
g_signal_handlers_disconnect_by_func (compositor->top_window_actor,
|
||||
on_top_window_actor_destroyed,
|
||||
@@ -1259,6 +1376,17 @@ meta_compositor_new (MetaDisplay *display)
|
||||
meta_post_paint_func,
|
||||
compositor,
|
||||
NULL);
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
int glx_major_opcode, glx_first_event, glx_first_error;
|
||||
|
||||
if (XQueryExtension (xdisplay,
|
||||
"GLX",
|
||||
&glx_major_opcode, &glx_first_event, &glx_first_error))
|
||||
compositor->glx_opcode = glx_major_opcode;
|
||||
}
|
||||
|
||||
return compositor;
|
||||
}
|
||||
|
||||
|
@@ -325,6 +325,7 @@ setup_pipeline (MetaBackgroundActor *self,
|
||||
PipelineFlags pipeline_flags = 0;
|
||||
guint8 opacity;
|
||||
float color_component;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPipelineFilter filter;
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
|
||||
@@ -417,8 +418,12 @@ setup_pipeline (MetaBackgroundActor *self,
|
||||
color_component,
|
||||
opacity / 255.);
|
||||
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
if (!priv->force_bilinear &&
|
||||
meta_actor_painting_untransformed (actor_pixel_rect->width, actor_pixel_rect->height, NULL, NULL))
|
||||
meta_actor_painting_untransformed (fb,
|
||||
actor_pixel_rect->width,
|
||||
actor_pixel_rect->height,
|
||||
NULL, NULL))
|
||||
filter = COGL_PIPELINE_FILTER_NEAREST;
|
||||
else
|
||||
filter = COGL_PIPELINE_FILTER_LINEAR;
|
||||
|
@@ -279,6 +279,34 @@ meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
|
||||
image->in_cache = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_cache_unload_all:
|
||||
* @cache: a #MetaBackgroundImageCache
|
||||
*
|
||||
* Remove all entries from the cache and unloads them; this would be used
|
||||
* if textures in video memory have been invalidated.
|
||||
*/
|
||||
void
|
||||
meta_background_image_cache_unload_all (MetaBackgroundImageCache *cache)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_return_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache));
|
||||
|
||||
g_hash_table_iter_init (&iter, cache->images);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
MetaBackgroundImage *image = value;
|
||||
|
||||
g_clear_pointer (&image->texture, cogl_object_unref);
|
||||
image->in_cache = FALSE;
|
||||
image->loaded = FALSE;
|
||||
}
|
||||
|
||||
g_hash_table_remove_all (cache->images);
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE (MetaBackgroundImage, meta_background_image, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user