[gnome-flashback] monitor-manager: implement ApplyMonitorsConfig
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] monitor-manager: implement ApplyMonitorsConfig
- Date: Thu, 21 Sep 2017 00:09:29 +0000 (UTC)
commit 40bcefadbb548a92195f75a3f37bf8a84f129896
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Thu Sep 21 02:55:54 2017 +0300
monitor-manager: implement ApplyMonitorsConfig
backends/gf-backend-private.h | 5 +-
backends/gf-backend.c | 10 +
backends/gf-monitor-manager.c | 561 ++++++++++++++++++++++++++++++++++++++++-
3 files changed, 572 insertions(+), 4 deletions(-)
---
diff --git a/backends/gf-backend-private.h b/backends/gf-backend-private.h
index 83497bf..9aab10b 100644
--- a/backends/gf-backend-private.h
+++ b/backends/gf-backend-private.h
@@ -28,6 +28,7 @@
#include "gf-backend.h"
#include "gf-monitor-manager-private.h"
+#include "gf-orientation-manager-private.h"
#include "gf-settings-private.h"
G_BEGIN_DECLS
@@ -41,7 +42,9 @@ struct _GfBackendClass
GfMonitorManager * (* create_monitor_manager) (GfBackend *backend);
};
-GfSettings *gf_backend_get_settings (GfBackend *backend);
+GfOrientationManager *gf_backend_get_orientation_manager (GfBackend *backend);
+
+GfSettings *gf_backend_get_settings (GfBackend *backend);
G_END_DECLS
diff --git a/backends/gf-backend.c b/backends/gf-backend.c
index 6281418..8faa617 100644
--- a/backends/gf-backend.c
+++ b/backends/gf-backend.c
@@ -183,6 +183,16 @@ gf_backend_get_monitor_manager (GfBackend *backend)
return priv->monitor_manager;
}
+GfOrientationManager *
+gf_backend_get_orientation_manager (GfBackend *backend)
+{
+ GfBackendPrivate *priv;
+
+ priv = gf_backend_get_instance_private (backend);
+
+ return priv->orientation_manager;
+}
+
GfSettings *
gf_backend_get_settings (GfBackend *backend)
{
diff --git a/backends/gf-monitor-manager.c b/backends/gf-monitor-manager.c
index a7b3a31..333cae0 100644
--- a/backends/gf-monitor-manager.c
+++ b/backends/gf-monitor-manager.c
@@ -80,6 +80,35 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GfMonitorManager, gf_monitor_manager, GF_DBUS_
G_IMPLEMENT_INTERFACE (GF_DBUS_TYPE_DISPLAY_CONFIG,
gf_monitor_manager_display_config_init))
static void
+power_save_mode_changed (GfMonitorManager *manager,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GfMonitorManagerClass *manager_class;
+ GfDBusDisplayConfig *display_config;
+ gint mode;
+
+ manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
+ display_config = GF_DBUS_DISPLAY_CONFIG (manager);
+ mode = gf_dbus_display_config_get_power_save_mode (display_config);
+
+ if (mode == GF_POWER_SAVE_UNSUPPORTED)
+ return;
+
+ /* If DPMS is unsupported, force the property back. */
+ if (manager->power_save_mode == GF_POWER_SAVE_UNSUPPORTED)
+ {
+ gf_dbus_display_config_set_power_save_mode (display_config, GF_POWER_SAVE_UNSUPPORTED);
+ return;
+ }
+
+ if (manager_class->set_power_save_mode)
+ manager_class->set_power_save_mode (manager, mode);
+
+ manager->power_save_mode = mode;
+}
+
+static void
gf_monitor_manager_update_monitor_modes_derived (GfMonitorManager *manager)
{
GList *l;
@@ -407,6 +436,375 @@ gf_monitor_manager_apply_monitors_config (GfMonitorManager *manager,
return TRUE;
}
+static void
+orientation_changed (GfOrientationManager *orientation_manager,
+ GfMonitorManager *manager)
+{
+ GfMonitorTransform transform;
+ GError *error = NULL;
+ GfMonitorsConfig *config;
+
+ switch (gf_orientation_manager_get_orientation (orientation_manager))
+ {
+ case GF_ORIENTATION_NORMAL:
+ transform = GF_MONITOR_TRANSFORM_NORMAL;
+ break;
+ case GF_ORIENTATION_BOTTOM_UP:
+ transform = GF_MONITOR_TRANSFORM_180;
+ break;
+ case GF_ORIENTATION_LEFT_UP:
+ transform = GF_MONITOR_TRANSFORM_90;
+ break;
+ case GF_ORIENTATION_RIGHT_UP:
+ transform = GF_MONITOR_TRANSFORM_270;
+ break;
+
+ case GF_ORIENTATION_UNDEFINED:
+ default:
+ return;
+ }
+
+ config = gf_monitor_config_manager_create_for_orientation (manager->config_manager,
+ transform);
+
+ if (!config)
+ return;
+
+ if (!gf_monitor_manager_apply_monitors_config (manager, config,
+ GF_MONITORS_CONFIG_METHOD_TEMPORARY,
+ &error))
+ {
+ g_warning ("Failed to use orientation monitor configuration: %s",
+ error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (config);
+}
+
+static void
+cancel_persistent_confirmation (GfMonitorManager *manager)
+{
+}
+
+static void
+request_persistent_confirmation (GfMonitorManager *manager)
+{
+}
+
+static gboolean
+find_monitor_mode_scale (GfMonitorManager *manager,
+ GfLogicalMonitorLayoutMode layout_mode,
+ GfMonitorConfig *monitor_config,
+ gfloat scale,
+ gfloat *out_scale,
+ GError **error)
+{
+ GfMonitorSpec *monitor_spec;
+ GfMonitor *monitor;
+ GfMonitorModeSpec *monitor_mode_spec;
+ GfMonitorMode *monitor_mode;
+ gfloat *supported_scales;
+ gint n_supported_scales;
+ gint i;
+
+ monitor_spec = monitor_config->monitor_spec;
+ monitor = gf_monitor_manager_get_monitor_from_spec (manager, monitor_spec);
+
+ if (!monitor)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Monitor not found");
+
+ return FALSE;
+ }
+
+ monitor_mode_spec = monitor_config->mode_spec;
+ monitor_mode = gf_monitor_get_mode_from_spec (monitor, monitor_mode_spec);
+
+ if (!monitor_mode)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Monitor mode not found");
+
+ return FALSE;
+ }
+
+ supported_scales = gf_monitor_manager_calculate_supported_scales (manager, layout_mode,
+ monitor, monitor_mode,
+ &n_supported_scales);
+
+ for (i = 0; i < n_supported_scales; i++)
+ {
+ gfloat supported_scale = supported_scales[i];
+
+ if (fabsf (supported_scale - scale) < FLT_EPSILON)
+ {
+ *out_scale = supported_scale;
+ g_free (supported_scales);
+ return TRUE;
+ }
+ }
+
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Scale %g not valid for resolution %dx%d",
+ scale,
+ monitor_mode_spec->width,
+ monitor_mode_spec->height);
+
+ g_free (supported_scales);
+ return FALSE;
+}
+
+static gboolean
+derive_logical_monitor_size (GfMonitorConfig *monitor_config,
+ gint *out_width,
+ gint *out_height,
+ gfloat scale,
+ GfMonitorTransform transform,
+ GfLogicalMonitorLayoutMode layout_mode,
+ GError **error)
+{
+ gint width, height;
+
+ if (gf_monitor_transform_is_rotated (transform))
+ {
+ width = monitor_config->mode_spec->height;
+ height = monitor_config->mode_spec->width;
+ }
+ else
+ {
+ width = monitor_config->mode_spec->width;
+ height = monitor_config->mode_spec->height;
+ }
+
+ switch (layout_mode)
+ {
+ case GF_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
+ width = roundf (width / scale);
+ height = roundf (height / scale);
+ break;
+
+ case GF_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
+ default:
+ break;
+ }
+
+ *out_width = width;
+ *out_height = height;
+
+ return TRUE;
+}
+
+static GfMonitor *
+find_monitor_from_connector (GfMonitorManager *manager,
+ gchar *connector)
+{
+ GList *monitors;
+ GList *l;
+
+ if (!connector)
+ return NULL;
+
+ monitors = gf_monitor_manager_get_monitors (manager);
+ for (l = monitors; l; l = l->next)
+ {
+ GfMonitor *monitor = l->data;
+ GfMonitorSpec *monitor_spec = gf_monitor_get_spec (monitor);
+
+ if (g_str_equal (connector, monitor_spec->connector))
+ return monitor;
+ }
+
+ return NULL;
+}
+
+static GfMonitorConfig *
+create_monitor_config_from_variant (GfMonitorManager *manager,
+ GVariant *monitor_config_variant,
+ GError **error)
+{
+ gchar *connector;
+ gchar *mode_id;
+ GVariant *properties_variant;
+ GfMonitor *monitor;
+ GfMonitorMode *monitor_mode;
+ gboolean enable_underscanning;
+ GfMonitorSpec *monitor_spec;
+ GfMonitorModeSpec *monitor_mode_spec;
+ GfMonitorConfig *monitor_config;
+
+ connector = NULL;
+ mode_id = NULL;
+ properties_variant = NULL;
+
+ g_variant_get (monitor_config_variant, "(ss@a{sv})",
+ &connector, &mode_id, &properties_variant);
+
+ monitor = find_monitor_from_connector (manager, connector);
+ if (!monitor)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Invalid connector '%s' specified", connector);
+
+ g_variant_unref (properties_variant);
+ g_free (connector);
+ g_free (mode_id);
+
+ return NULL;
+ }
+
+ monitor_mode = gf_monitor_get_mode_from_id (monitor, mode_id);
+ if (!monitor_mode)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Invalid mode '%s' specified", mode_id);
+
+ g_variant_unref (properties_variant);
+ g_free (connector);
+ g_free (mode_id);
+
+ return NULL;
+ }
+
+ enable_underscanning = FALSE;
+ g_variant_lookup (properties_variant, "underscanning", "b", &enable_underscanning);
+
+ g_variant_unref (properties_variant);
+ g_free (connector);
+ g_free (mode_id);
+
+ monitor_spec = gf_monitor_spec_clone (gf_monitor_get_spec (monitor));
+
+ monitor_mode_spec = g_new0 (GfMonitorModeSpec, 1);
+ *monitor_mode_spec = *gf_monitor_mode_get_spec (monitor_mode);
+
+ monitor_config = g_new0 (GfMonitorConfig, 1);
+ *monitor_config = (GfMonitorConfig) {
+ .monitor_spec = monitor_spec,
+ .mode_spec = monitor_mode_spec,
+ .enable_underscanning = enable_underscanning
+ };
+
+ return monitor_config;
+}
+
+#define MONITOR_CONFIG_FORMAT "(ssa{sv})"
+#define MONITOR_CONFIGS_FORMAT "a" MONITOR_CONFIG_FORMAT
+#define LOGICAL_MONITOR_CONFIG_FORMAT "(iidub" MONITOR_CONFIGS_FORMAT ")"
+
+static GfLogicalMonitorConfig *
+create_logical_monitor_config_from_variant (GfMonitorManager *manager,
+ GVariant *logical_monitor_config_variant,
+ GfLogicalMonitorLayoutMode layout_mode,
+ GError **error)
+{
+ GfLogicalMonitorConfig *logical_monitor_config;
+ gint x, y, width, height;
+ gdouble scale_d;
+ gfloat scale;
+ GfMonitorTransform transform;
+ gboolean is_primary;
+ GVariantIter *monitor_configs_iter;
+ GList *monitor_configs = NULL;
+ GfMonitorConfig *monitor_config;
+
+ g_variant_get (logical_monitor_config_variant, LOGICAL_MONITOR_CONFIG_FORMAT,
+ &x, &y, &scale_d, &transform, &is_primary, &monitor_configs_iter);
+
+ scale = (gfloat) scale_d;
+
+ while (TRUE)
+ {
+ GVariant *monitor_config_variant;
+
+ monitor_config_variant = g_variant_iter_next_value (monitor_configs_iter);
+
+ if (!monitor_config_variant)
+ break;
+
+ monitor_config = create_monitor_config_from_variant (manager,
+ monitor_config_variant,
+ error);
+
+ if (!monitor_config)
+ goto err;
+
+ if (!gf_verify_monitor_config (monitor_config, error))
+ {
+ gf_monitor_config_free (monitor_config);
+ goto err;
+ }
+
+ monitor_configs = g_list_append (monitor_configs, monitor_config);
+ }
+ g_variant_iter_free (monitor_configs_iter);
+
+ if (!monitor_configs)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Empty logical monitor");
+ goto err;
+ }
+
+ monitor_config = monitor_configs->data;
+ if (!find_monitor_mode_scale (manager, layout_mode, monitor_config,
+ scale, &scale, error))
+ goto err;
+
+ if (!derive_logical_monitor_size (monitor_config, &width, &height,
+ scale, transform, layout_mode, error))
+ goto err;
+
+ logical_monitor_config = g_new0 (GfLogicalMonitorConfig, 1);
+ *logical_monitor_config = (GfLogicalMonitorConfig) {
+ .layout = {
+ .x = x,
+ .y = y,
+ .width = width,
+ .height = height
+ },
+ .transform = transform,
+ .scale = scale,
+ .is_primary = is_primary,
+ .monitor_configs = monitor_configs
+ };
+
+ if (!gf_verify_logical_monitor_config (logical_monitor_config, layout_mode,
+ manager, error))
+ {
+ gf_logical_monitor_config_free (logical_monitor_config);
+ return NULL;
+ }
+
+ return logical_monitor_config;
+
+err:
+ g_list_free_full (monitor_configs, (GDestroyNotify) gf_monitor_config_free);
+ return NULL;
+}
+
+#undef MONITOR_MODE_SPEC_FORMAT
+#undef MONITOR_CONFIG_FORMAT
+#undef MONITOR_CONFIGS_FORMAT
+#undef LOGICAL_MONITOR_CONFIG_FORMAT
+
+static gboolean
+is_valid_layout_mode (GfLogicalMonitorLayoutMode layout_mode)
+{
+ switch (layout_mode)
+ {
+ case GF_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
+ case GF_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
static const gdouble known_diagonals[] =
{
12.1,
@@ -1198,9 +1596,141 @@ gf_monitor_manager_handle_apply_monitors_config (GfDBusDisplayConfig *skeleton
GVariant *logical_monitor_configs_variant,
GVariant *properties_variant)
{
- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
- G_DBUS_ERROR_FAILED,
- "Not implemented");
+ GfMonitorManager *manager;
+ GfMonitorManagerCapability capabilities;
+ GVariant *layout_mode_variant;
+ GfLogicalMonitorLayoutMode layout_mode;
+ GVariantIter configs_iter;
+ GList *logical_monitor_configs;
+ GError *error;
+ GfMonitorsConfig *config;
+
+ manager = GF_MONITOR_MANAGER (skeleton);
+
+ if (serial != manager->serial)
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ "The requested configuration is based on stale information");
+ return TRUE;
+ }
+
+ capabilities = gf_monitor_manager_get_capabilities (manager);
+ layout_mode_variant = NULL;
+ logical_monitor_configs = NULL;
+ error = NULL;
+
+ if (properties_variant)
+ {
+ layout_mode_variant = g_variant_lookup_value (properties_variant,
+ "layout-mode",
+ G_VARIANT_TYPE ("u"));
+ }
+
+ if (layout_mode_variant &&
+ capabilities & GF_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE)
+ {
+ g_variant_get (layout_mode_variant, "u", &layout_mode);
+ }
+ else if (!layout_mode_variant)
+ {
+ layout_mode = gf_monitor_manager_get_default_layout_mode (manager);
+ }
+ else
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Can't set layout mode");
+ return TRUE;
+ }
+
+ if (!is_valid_layout_mode (layout_mode))
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ "Invalid layout mode specified");
+ return TRUE;
+ }
+
+ g_variant_iter_init (&configs_iter, logical_monitor_configs_variant);
+
+ while (TRUE)
+ {
+ GVariant *config_variant;
+ GfLogicalMonitorConfig *logical_monitor_config;
+
+ config_variant = g_variant_iter_next_value (&configs_iter);
+ if (!config_variant)
+ break;
+
+ logical_monitor_config = create_logical_monitor_config_from_variant (manager,
+ config_variant,
+ layout_mode,
+ &error);
+
+ if (!logical_monitor_config)
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "%s", error->message);
+
+ g_error_free (error);
+ g_list_free_full (logical_monitor_configs,
+ (GDestroyNotify) gf_logical_monitor_config_free);
+
+ return TRUE;
+ }
+
+ logical_monitor_configs = g_list_append (logical_monitor_configs,
+ logical_monitor_config);
+ }
+
+ config = gf_monitors_config_new (logical_monitor_configs, layout_mode,
+ GF_MONITORS_CONFIG_FLAG_NONE);
+
+ if (!gf_verify_monitors_config (config, manager, &error))
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "%s", error->message);
+
+ g_error_free (error);
+ g_object_unref (config);
+
+ return TRUE;
+ }
+
+ if (!gf_monitor_manager_is_config_applicable (manager, config, &error))
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "%s", error->message);
+
+ g_error_free (error);
+ g_object_unref (config);
+
+ return TRUE;
+ }
+
+ if (method != GF_MONITORS_CONFIG_METHOD_VERIFY)
+ cancel_persistent_confirmation (manager);
+
+ if (!gf_monitor_manager_apply_monitors_config (manager, config, method, &error))
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "%s", error->message);
+
+ g_error_free (error);
+ g_object_unref (config);
+
+ return TRUE;
+ }
+
+ if (method == GF_MONITORS_CONFIG_METHOD_PERSISTENT)
+ request_persistent_confirmation (manager);
+
+ gf_dbus_display_config_complete_apply_monitors_config (skeleton, invocation);
return TRUE;
}
@@ -1285,6 +1815,7 @@ gf_monitor_manager_constructed (GObject *object)
GfMonitorManager *manager;
GfMonitorManagerClass *manager_class;
GfMonitorManagerPrivate *priv;
+ GfOrientationManager *orientation_manager;
manager = GF_MONITOR_MANAGER (object);
manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
@@ -1300,6 +1831,13 @@ gf_monitor_manager_constructed (GObject *object)
G_CALLBACK (lid_is_closed_changed), manager, 0);
}
+ g_signal_connect_object (manager, "notify::power-save-mode",
+ G_CALLBACK (power_save_mode_changed), manager, 0);
+
+ orientation_manager = gf_backend_get_orientation_manager (priv->backend);
+ g_signal_connect_object (orientation_manager, "orientation-changed",
+ G_CALLBACK (orientation_changed), manager, 0);
+
manager->config_manager = gf_monitor_config_manager_new (manager);
gf_monitor_manager_read_current_state (manager);
@@ -1342,6 +1880,22 @@ gf_monitor_manager_dispose (GObject *object)
}
static void
+gf_monitor_manager_finalize (GObject *object)
+{
+ GfMonitorManager *manager;
+
+ manager = GF_MONITOR_MANAGER (object);
+
+ free_output_array (manager->outputs, manager->n_outputs);
+ free_mode_array (manager->modes, manager->n_modes);
+ free_crtc_array (manager->crtcs, manager->n_crtcs);
+
+ g_list_free_full (manager->logical_monitors, g_object_unref);
+
+ G_OBJECT_CLASS (gf_monitor_manager_parent_class)->finalize (object);
+}
+
+static void
gf_monitor_manager_get_property (GObject *object,
guint property_id,
GValue *value,
@@ -1423,6 +1977,7 @@ gf_monitor_manager_class_init (GfMonitorManagerClass *manager_class)
object_class->constructed = gf_monitor_manager_constructed;
object_class->dispose = gf_monitor_manager_dispose;
+ object_class->finalize = gf_monitor_manager_finalize;
object_class->get_property = gf_monitor_manager_get_property;
object_class->set_property = gf_monitor_manager_set_property;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]