backends/kms: Implement privacy screen handling and setting

Privacy screen events on connector are handled as notification events
that won't cause any monitors reconfiguration but will emit monitors
changed on DBus, so that the new value can be fetched.

We monitor the hardware state so that we can also handle the case of
devices with hw-switchers only.

In case a software state is available it means we can also support
changing the state, and if so expose the state as unlocked.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1952>
This commit is contained in:
Marco Trevisan (Treviño) 2021-03-22 01:27:39 +01:00 committed by Marge Bot
parent 4b0a10c562
commit 47d7bc7a13
12 changed files with 302 additions and 3 deletions

View File

@ -29,6 +29,8 @@ typedef enum _MetaKmsConnectorProp
META_KMS_CONNECTOR_PROP_UNDERSCAN, META_KMS_CONNECTOR_PROP_UNDERSCAN,
META_KMS_CONNECTOR_PROP_UNDERSCAN_HBORDER, META_KMS_CONNECTOR_PROP_UNDERSCAN_HBORDER,
META_KMS_CONNECTOR_PROP_UNDERSCAN_VBORDER, META_KMS_CONNECTOR_PROP_UNDERSCAN_VBORDER,
META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE,
META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE,
META_KMS_CONNECTOR_N_PROPS META_KMS_CONNECTOR_N_PROPS
} MetaKmsConnectorProp; } MetaKmsConnectorProp;

View File

@ -19,6 +19,7 @@
#include "config.h" #include "config.h"
#include "backends/meta-output.h"
#include "backends/native/meta-kms-connector.h" #include "backends/native/meta-kms-connector.h"
#include "backends/native/meta-kms-connector-private.h" #include "backends/native/meta-kms-connector-private.h"
@ -59,6 +60,14 @@ struct _MetaKmsConnector
G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT) G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT)
typedef enum _MetaKmsPrivacyScreenHwState
{
META_KMS_PRIVACY_SCREEN_HW_STATE_DISABLED,
META_KMS_PRIVACY_SCREEN_HW_STATE_ENABLED,
META_KMS_PRIVACY_SCREEN_HW_STATE_DISABLED_LOCKED,
META_KMS_PRIVACY_SCREEN_HW_STATE_ENABLED_LOCKED,
} MetaKmsPrivacyScreenHwState;
MetaKmsDevice * MetaKmsDevice *
meta_kms_connector_get_device (MetaKmsConnector *connector) meta_kms_connector_get_device (MetaKmsConnector *connector)
{ {
@ -132,6 +141,20 @@ meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector)
return underscan_prop_id != 0; return underscan_prop_id != 0;
} }
gboolean
meta_kms_connector_is_privacy_screen_supported (MetaKmsConnector *connector)
{
return meta_kms_connector_get_prop_id (connector,
META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE) != 0;
}
static gboolean
has_privacy_screen_software_toggle (MetaKmsConnector *connector)
{
return meta_kms_connector_get_prop_id (connector,
META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE) != 0;
}
static void static void
sync_fd_held (MetaKmsConnector *connector, sync_fd_held (MetaKmsConnector *connector,
MetaKmsImplDevice *impl_device) MetaKmsImplDevice *impl_device)
@ -181,9 +204,44 @@ set_panel_orientation (MetaKmsConnectorState *state,
} }
} }
static void
set_privacy_screen (MetaKmsConnectorState *state,
MetaKmsConnector *connector,
drmModePropertyPtr prop,
uint64_t value)
{
if (!meta_kms_connector_is_privacy_screen_supported (connector))
return;
switch (value)
{
case META_KMS_PRIVACY_SCREEN_HW_STATE_DISABLED:
state->privacy_screen_state = META_PRIVACY_SCREEN_DISABLED;
break;
case META_KMS_PRIVACY_SCREEN_HW_STATE_DISABLED_LOCKED:
state->privacy_screen_state = META_PRIVACY_SCREEN_DISABLED;
state->privacy_screen_state |= META_PRIVACY_SCREEN_LOCKED;
break;
case META_KMS_PRIVACY_SCREEN_HW_STATE_ENABLED:
state->privacy_screen_state = META_PRIVACY_SCREEN_ENABLED;
break;
case META_KMS_PRIVACY_SCREEN_HW_STATE_ENABLED_LOCKED:
state->privacy_screen_state = META_PRIVACY_SCREEN_ENABLED;
state->privacy_screen_state |= META_PRIVACY_SCREEN_LOCKED;
break;
default:
state->privacy_screen_state = META_PRIVACY_SCREEN_DISABLED;
g_warning ("Unknown privacy screen state: %" G_GUINT64_FORMAT, value);
}
if (!has_privacy_screen_software_toggle (connector))
state->privacy_screen_state |= META_PRIVACY_SCREEN_LOCKED;
}
static void static void
state_set_properties (MetaKmsConnectorState *state, state_set_properties (MetaKmsConnectorState *state,
MetaKmsImplDevice *impl_device, MetaKmsImplDevice *impl_device,
MetaKmsConnector *connector,
drmModeConnector *drm_connector) drmModeConnector *drm_connector)
{ {
int fd; int fd;
@ -216,6 +274,10 @@ state_set_properties (MetaKmsConnectorState *state,
else if ((prop->flags & DRM_MODE_PROP_RANGE) && else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
strcmp (prop->name, "non-desktop") == 0) strcmp (prop->name, "non-desktop") == 0)
state->non_desktop = drm_connector->prop_values[i]; state->non_desktop = drm_connector->prop_values[i];
else if (prop->prop_id == meta_kms_connector_get_prop_id (connector,
META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE))
set_privacy_screen (state, connector, prop,
drm_connector->prop_values[i]);
drmModeFreeProperty (prop); drmModeFreeProperty (prop);
} }
@ -554,9 +616,25 @@ meta_kms_connector_state_changes (MetaKmsConnectorState *state,
if (!kms_modes_equal (state->modes, new_state->modes)) if (!kms_modes_equal (state->modes, new_state->modes))
return META_KMS_UPDATE_CHANGE_FULL; return META_KMS_UPDATE_CHANGE_FULL;
if (state->privacy_screen_state != new_state->privacy_screen_state)
return META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN;
return META_KMS_UPDATE_CHANGE_NONE; return META_KMS_UPDATE_CHANGE_NONE;
} }
static void
meta_kms_connector_update_state_changes (MetaKmsConnector *connector,
MetaKmsUpdateChanges changes,
MetaKmsConnectorState *new_state)
{
MetaKmsConnectorState *current_state = connector->current_state;
g_return_if_fail (changes != META_KMS_UPDATE_CHANGE_FULL);
if (changes & META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN)
current_state->privacy_screen_state = new_state->privacy_screen_state;
}
static MetaKmsUpdateChanges static MetaKmsUpdateChanges
meta_kms_connector_read_state (MetaKmsConnector *connector, meta_kms_connector_read_state (MetaKmsConnector *connector,
MetaKmsImplDevice *impl_device, MetaKmsImplDevice *impl_device,
@ -593,7 +671,7 @@ meta_kms_connector_read_state (MetaKmsConnector *connector,
state_set_blobs (state, connector, impl_device, drm_connector); state_set_blobs (state, connector, impl_device, drm_connector);
state_set_properties (state, impl_device, drm_connector); state_set_properties (state, impl_device, connector, drm_connector);
state->subpixel_order = state->subpixel_order =
drm_subpixel_order_to_cogl_subpixel_order (drm_connector->subpixel); drm_subpixel_order_to_cogl_subpixel_order (drm_connector->subpixel);
@ -615,14 +693,18 @@ meta_kms_connector_read_state (MetaKmsConnector *connector,
else else
connector_changes = meta_kms_connector_state_changes (current_state, state); connector_changes = meta_kms_connector_state_changes (current_state, state);
if (connector_changes == META_KMS_UPDATE_CHANGE_NONE) changes |= connector_changes;
if (!(changes & META_KMS_UPDATE_CHANGE_FULL))
{ {
meta_kms_connector_update_state_changes (connector,
connector_changes,
state);
connector->current_state = g_steal_pointer (&current_state); connector->current_state = g_steal_pointer (&current_state);
} }
else else
{ {
connector->current_state = g_steal_pointer (&state); connector->current_state = g_steal_pointer (&state);
changes |= connector_changes;
} }
out: out:
@ -686,6 +768,36 @@ meta_kms_connector_predict_state (MetaKmsConnector *connector,
} }
} }
if (has_privacy_screen_software_toggle (connector))
{
GList *connector_updates;
connector_updates = meta_kms_update_get_connector_updates (update);
for (l = connector_updates; l; l = l->next)
{
MetaKmsConnectorUpdate *connector_update = l->data;
if (connector_update->connector != connector)
continue;
if (connector_update->privacy_screen.has_update &&
!(current_state->privacy_screen_state &
META_PRIVACY_SCREEN_LOCKED))
{
if (connector_update->privacy_screen.is_enabled)
{
current_state->privacy_screen_state =
META_PRIVACY_SCREEN_ENABLED;
}
else
{
current_state->privacy_screen_state =
META_PRIVACY_SCREEN_DISABLED;
}
}
}
}
impl_device = meta_kms_device_get_impl_device (connector->device); impl_device = meta_kms_device_get_impl_device (connector->device);
sync_fd_held (connector, impl_device); sync_fd_held (connector, impl_device);
} }
@ -724,6 +836,16 @@ init_properties (MetaKmsConnector *connector,
.name = "underscan vborder", .name = "underscan vborder",
.type = DRM_MODE_PROP_RANGE, .type = DRM_MODE_PROP_RANGE,
}, },
[META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE] =
{
.name = "privacy-screen sw-state",
.type = DRM_MODE_PROP_ENUM,
},
[META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_HW_STATE] =
{
.name = "privacy-screen hw-state",
.type = DRM_MODE_PROP_ENUM,
},
} }
}; };

View File

@ -49,6 +49,7 @@ typedef struct _MetaKmsConnectorState
gboolean has_scaling; gboolean has_scaling;
gboolean non_desktop; gboolean non_desktop;
MetaPrivacyScreenState privacy_screen_state;
CoglSubpixelOrder subpixel_order; CoglSubpixelOrder subpixel_order;
@ -74,4 +75,6 @@ const MetaKmsConnectorState * meta_kms_connector_get_current_state (MetaKmsConne
gboolean meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector); gboolean meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector);
gboolean meta_kms_connector_is_privacy_screen_supported (MetaKmsConnector *connector);
#endif /* META_KMS_CONNECTOR_H */ #endif /* META_KMS_CONNECTOR_H */

View File

@ -196,6 +196,22 @@ process_connector_update (MetaKmsImplDevice *impl_device,
return FALSE; return FALSE;
} }
if (connector_update->privacy_screen.has_update)
{
meta_topic (META_DEBUG_KMS,
"[atomic] Toggling privacy screen to %d on connector %u (%s)",
connector_update->privacy_screen.is_enabled,
meta_kms_connector_get_id (connector),
meta_kms_impl_device_get_path (impl_device));
if (!add_connector_property (impl_device,
connector, req,
META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE,
connector_update->privacy_screen.is_enabled,
error))
return FALSE;
}
return TRUE; return TRUE;
} }

View File

@ -260,6 +260,22 @@ process_connector_update (MetaKmsImplDevice *impl_device,
return FALSE; return FALSE;
} }
if (connector_update->privacy_screen.has_update)
{
meta_topic (META_DEBUG_KMS,
"[simple] Toggling privacy screen to %d on connector %u (%s)",
connector_update->privacy_screen.is_enabled,
meta_kms_connector_get_id (connector),
meta_kms_impl_device_get_path (impl_device));
if (!set_connector_property (impl_device,
connector,
META_KMS_CONNECTOR_PROP_PRIVACY_SCREEN_SW_STATE,
connector_update->privacy_screen.is_enabled,
error))
return FALSE;
}
return TRUE; return TRUE;
} }

View File

@ -69,6 +69,7 @@ typedef enum _MetaKmsUpdateChanges
META_KMS_UPDATE_CHANGE_NONE = 0, META_KMS_UPDATE_CHANGE_NONE = 0,
META_KMS_UPDATE_CHANGE_GAMMA = 1 << 0, META_KMS_UPDATE_CHANGE_GAMMA = 1 << 0,
META_KMS_UPDATE_CHANGE_NO_DEVICES = 1 << 1, META_KMS_UPDATE_CHANGE_NO_DEVICES = 1 << 1,
META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN = 1 << 2,
META_KMS_UPDATE_CHANGE_FULL = -1, META_KMS_UPDATE_CHANGE_FULL = -1,
} MetaKmsUpdateChanges; } MetaKmsUpdateChanges;

View File

@ -77,6 +77,11 @@ typedef struct _MetaKmsConnectorUpdate
uint64_t hborder; uint64_t hborder;
uint64_t vborder; uint64_t vborder;
} underscanning; } underscanning;
struct {
gboolean has_update;
gboolean is_enabled;
} privacy_screen;
} MetaKmsConnectorUpdate; } MetaKmsConnectorUpdate;
typedef struct _MetaKmsPageFlipListener typedef struct _MetaKmsPageFlipListener

View File

@ -349,6 +349,21 @@ meta_kms_update_unset_underscanning (MetaKmsUpdate *update,
connector_update->underscanning.is_active = FALSE; connector_update->underscanning.is_active = FALSE;
} }
void
meta_kms_update_set_privacy_screen (MetaKmsUpdate *update,
MetaKmsConnector *connector,
gboolean enabled)
{
MetaKmsConnectorUpdate *connector_update;
g_assert (meta_kms_connector_get_device (connector) == update->device);
g_assert (!update->power_save);
connector_update = ensure_connector_update (update, connector);
connector_update->privacy_screen.has_update = TRUE;
connector_update->privacy_screen.is_enabled = enabled;
}
void void
meta_kms_update_set_power_save (MetaKmsUpdate *update) meta_kms_update_set_power_save (MetaKmsUpdate *update)
{ {

View File

@ -101,6 +101,10 @@ void meta_kms_update_set_underscanning (MetaKmsUpdate *update,
void meta_kms_update_unset_underscanning (MetaKmsUpdate *update, void meta_kms_update_unset_underscanning (MetaKmsUpdate *update,
MetaKmsConnector *connector); MetaKmsConnector *connector);
void meta_kms_update_set_privacy_screen (MetaKmsUpdate *update,
MetaKmsConnector *connector,
gboolean enabled);
void meta_kms_update_set_power_save (MetaKmsUpdate *update); void meta_kms_update_set_power_save (MetaKmsUpdate *update);
void meta_kms_update_mode_set (MetaKmsUpdate *update, void meta_kms_update_mode_set (MetaKmsUpdate *update,

View File

@ -37,6 +37,8 @@
#include "backends/meta-monitor.h" #include "backends/meta-monitor.h"
#include "config.h" #include "config.h"
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms-types.h"
#include "backends/native/meta-monitor-manager-native.h" #include "backends/native/meta-monitor-manager-native.h"
#include <drm.h> #include <drm.h>
@ -518,6 +520,9 @@ on_kms_resources_changed (MetaKms *kms,
return; return;
} }
if (changes == META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN)
return;
handle_hotplug_event (manager); handle_hotplug_event (manager);
} }
@ -696,6 +701,65 @@ allocate_virtual_monitor_id (MetaMonitorManagerNative *manager_native)
} }
} }
static void
on_kms_privacy_screen_update_result (const MetaKmsFeedback *kms_feedback,
gpointer user_data)
{
MetaMonitorManager *manager = user_data;
MetaBackend *backend = meta_monitor_manager_get_backend (manager);
MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend));
if (meta_kms_feedback_get_result (kms_feedback) == META_KMS_FEEDBACK_FAILED)
return;
on_kms_resources_changed (kms,
META_KMS_UPDATE_CHANGE_PRIVACY_SCREEN,
manager);
}
static gboolean
meta_monitor_manager_native_set_privacy_screen_enabled (MetaMonitorManager *manager,
gboolean enabled)
{
MetaMonitorManagerClass *manager_class;
MetaBackend *backend = meta_monitor_manager_get_backend (manager);
MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend));
gboolean any_update = FALSE;
GList *l;
manager_class =
META_MONITOR_MANAGER_CLASS (meta_monitor_manager_native_parent_class);
if (!manager_class->set_privacy_screen_enabled (manager, enabled))
return FALSE;
for (l = meta_kms_get_devices (kms); l; l = l->next)
{
MetaKmsDevice *kms_device = l->data;
MetaKmsUpdate *kms_update;
kms_update = meta_kms_get_pending_update (kms, kms_device);
if (kms_update)
{
meta_kms_update_remove_result_listeners (
kms_update, on_kms_privacy_screen_update_result, manager);
meta_kms_update_add_result_listener (
kms_update, on_kms_privacy_screen_update_result, manager);
any_update = TRUE;
}
}
if (any_update)
{
ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
clutter_stage_schedule_update (stage);
}
return TRUE;
}
static MetaVirtualMonitor * static MetaVirtualMonitor *
meta_monitor_manager_native_create_virtual_monitor (MetaMonitorManager *manager, meta_monitor_manager_native_create_virtual_monitor (MetaMonitorManager *manager,
const MetaVirtualMonitorInfo *info, const MetaVirtualMonitorInfo *info,
@ -819,6 +883,8 @@ meta_monitor_manager_native_class_init (MetaMonitorManagerNativeClass *klass)
meta_monitor_manager_native_get_crtc_gamma; meta_monitor_manager_native_get_crtc_gamma;
manager_class->set_crtc_gamma = manager_class->set_crtc_gamma =
meta_monitor_manager_native_set_crtc_gamma; meta_monitor_manager_native_set_crtc_gamma;
manager_class->set_privacy_screen_enabled =
meta_monitor_manager_native_set_privacy_screen_enabled;
manager_class->is_transform_handled = manager_class->is_transform_handled =
meta_monitor_manager_native_is_transform_handled; meta_monitor_manager_native_is_transform_handled;
manager_class->calculate_monitor_mode_scale = manager_class->calculate_monitor_mode_scale =

View File

@ -29,6 +29,7 @@
#include <string.h> #include <string.h>
#include "backends/meta-crtc.h" #include "backends/meta-crtc.h"
#include "backends/native/meta-kms.h"
#include "backends/native/meta-kms-connector.h" #include "backends/native/meta-kms-connector.h"
#include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms-mode.h" #include "backends/native/meta-kms-mode.h"
@ -96,6 +97,47 @@ meta_output_kms_set_underscan (MetaOutputKms *output_kms,
} }
} }
static MetaPrivacyScreenState
meta_output_kms_get_privacy_screen_state (MetaOutput *output)
{
MetaOutputKms *output_kms = META_OUTPUT_KMS (output);
const MetaKmsConnectorState *connector_state;
connector_state =
meta_kms_connector_get_current_state (output_kms->kms_connector);
return connector_state->privacy_screen_state;
}
static gboolean
meta_output_kms_set_privacy_screen_enabled (MetaOutput *output,
gboolean enabled,
GError **error)
{
MetaGpu *gpu;
MetaKms *kms;
MetaKmsDevice *kms_device;
MetaKmsUpdate *kms_update;
MetaOutputKms *output_kms = META_OUTPUT_KMS (output);
MetaKmsConnector *connector = meta_output_kms_get_kms_connector (output_kms);
if (!meta_kms_connector_is_privacy_screen_supported (connector))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"No privacy screen support");
return FALSE;
}
gpu = meta_output_get_gpu (META_OUTPUT (output_kms));
kms_device = meta_gpu_kms_get_kms_device (META_GPU_KMS (gpu));
kms = meta_kms_device_get_kms (kms_device);
kms_update = meta_kms_ensure_pending_update (kms, kms_device);
meta_kms_update_set_privacy_screen (kms_update, connector, enabled);
return TRUE;
}
uint32_t uint32_t
meta_output_kms_get_connector_id (MetaOutputKms *output_kms) meta_output_kms_get_connector_id (MetaOutputKms *output_kms)
{ {
@ -425,6 +467,12 @@ static void
meta_output_kms_class_init (MetaOutputKmsClass *klass) meta_output_kms_class_init (MetaOutputKmsClass *klass)
{ {
MetaOutputNativeClass *output_native_class = META_OUTPUT_NATIVE_CLASS (klass); MetaOutputNativeClass *output_native_class = META_OUTPUT_NATIVE_CLASS (klass);
MetaOutputClass *output_class = META_OUTPUT_CLASS (klass);
output_class->get_privacy_screen_state =
meta_output_kms_get_privacy_screen_state;
output_class->set_privacy_screen_enabled =
meta_output_kms_set_privacy_screen_enabled;
output_native_class->read_edid = meta_output_kms_read_edid; output_native_class->read_edid = meta_output_kms_read_edid;
} }

View File

@ -58,6 +58,7 @@
#include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms.h" #include "backends/native/meta-kms.h"
#include "backends/native/meta-onscreen-native.h" #include "backends/native/meta-onscreen-native.h"
#include "backends/native/meta-output-kms.h"
#include "backends/native/meta-render-device-gbm.h" #include "backends/native/meta-render-device-gbm.h"
#include "backends/native/meta-render-device-surfaceless.h" #include "backends/native/meta-render-device-surfaceless.h"
#include "backends/native/meta-renderer-native-private.h" #include "backends/native/meta-renderer-native-private.h"