Commit 8f462124 authored by Giovanni Campagna's avatar Giovanni Campagna Committed by Giovanni Campagna
Browse files

MonitorManager: add support for persistent monitor configurations

Add a new object, MetaMonitorConfig, that takes care of converting
between the logical configurations stored in monitors.xml and
the HW resources exposed by MonitorManager.
This commit includes loading and saving of configurations, but
still missing is the actual CRTC assignments and a default
configuration when none is found in the file.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
parent e039add2
......@@ -113,6 +113,7 @@ libmutter_la_SOURCES = \
core/main.c \
core/meta-xrandr-shared.h \
core/monitor.c \
core/monitor-config.c \
core/monitor-private.h \
core/mutter-Xatomtype.h \
core/place.c \
......
This diff is collapsed.
......@@ -177,10 +177,10 @@ void meta_monitor_manager_initialize (Display *display);
MetaMonitorManager *meta_monitor_manager_get (void);
MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
int *n_infos);
unsigned int *n_infos);
MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
int *n_outputs);
unsigned int *n_outputs);
int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
......@@ -191,6 +191,37 @@ void meta_monitor_manager_get_screen_size (MetaMonitorManager *
int *width,
int *height);
void meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
GVariant *crtcs,
GVariant *outputs);
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
#define META_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
#define META_IS_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_CONFIG))
#define META_IS_MONITOR_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_CONFIG))
#define META_MONITOR_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfigClass))
typedef struct _MetaMonitorConfigClass MetaMonitorConfigClass;
typedef struct _MetaMonitorConfig MetaMonitorConfig;
GType meta_monitor_config_get_type (void) G_GNUC_CONST;
MetaMonitorConfig *meta_monitor_config_new (void);
gboolean meta_monitor_config_match_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
gboolean meta_monitor_config_apply_stored (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_make_default (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_update_current (MetaMonitorConfig *config,
MetaMonitorManager *manager);
void meta_monitor_config_make_persistent (MetaMonitorConfig *config);
/* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */
static inline gboolean
......
......@@ -29,6 +29,7 @@
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#ifdef HAVE_RANDR
......@@ -99,6 +100,9 @@ struct _MetaMonitorManager
#endif
int dbus_name_id;
int persistent_timeout_id;
MetaMonitorConfig *config;
};
struct _MetaMonitorManagerClass
......@@ -124,6 +128,8 @@ static void meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface
G_DEFINE_TYPE_WITH_CODE (MetaMonitorManager, meta_monitor_manager, META_DBUS_TYPE_DISPLAY_CONFIG_SKELETON,
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_DISPLAY_CONFIG, meta_monitor_manager_display_config_init));
static void free_output_array (MetaOutput *old_outputs,
int n_old_outputs);
static void invalidate_logical_config (MetaMonitorManager *manager);
static void
......@@ -193,14 +199,14 @@ make_dummy_monitor_config (MetaMonitorManager *manager)
manager->outputs = g_new0 (MetaOutput, 3);
manager->n_outputs = 3;
manager->outputs[0].crtc = &manager->crtcs[0];
manager->outputs[0].crtc = 0;
manager->outputs[0].output_id = 6;
manager->outputs[0].name = g_strdup ("LVDS");
manager->outputs[0].vendor = g_strdup ("unknown");
manager->outputs[0].name = g_strdup ("HDMI");
manager->outputs[0].vendor = g_strdup ("MetaProducts Inc.");
manager->outputs[0].product = g_strdup ("unknown");
manager->outputs[0].serial = g_strdup ("");
manager->outputs[0].width_mm = 222;
manager->outputs[0].height_mm = 125;
manager->outputs[0].serial = g_strdup ("0xC0F01A");
manager->outputs[0].width_mm = 510;
manager->outputs[0].height_mm = 287;
manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
manager->outputs[0].preferred_mode = &manager->modes[0];
manager->outputs[0].n_modes = 3;
......@@ -215,14 +221,14 @@ make_dummy_monitor_config (MetaMonitorManager *manager)
manager->outputs[0].n_possible_clones = 0;
manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0);
manager->outputs[1].crtc = NULL;
manager->outputs[1].crtc = &manager->crtcs[0];
manager->outputs[1].output_id = 7;
manager->outputs[1].name = g_strdup ("HDMI");
manager->outputs[1].vendor = g_strdup ("unknown");
manager->outputs[1].name = g_strdup ("LVDS");
manager->outputs[1].vendor = g_strdup ("MetaProducts Inc.");
manager->outputs[1].product = g_strdup ("unknown");
manager->outputs[1].serial = g_strdup ("");
manager->outputs[1].width_mm = 510;
manager->outputs[1].height_mm = 287;
manager->outputs[1].serial = g_strdup ("0xC0FFEE");
manager->outputs[1].width_mm = 222;
manager->outputs[1].height_mm = 125;
manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
manager->outputs[1].preferred_mode = &manager->modes[0];
manager->outputs[1].n_modes = 3;
......@@ -240,9 +246,9 @@ make_dummy_monitor_config (MetaMonitorManager *manager)
manager->outputs[2].crtc = NULL;
manager->outputs[2].output_id = 8;
manager->outputs[2].name = g_strdup ("VGA");
manager->outputs[2].vendor = g_strdup ("unknown");
manager->outputs[2].vendor = g_strdup ("MetaProducts Inc.");
manager->outputs[2].product = g_strdup ("unknown");
manager->outputs[2].serial = g_strdup ("");
manager->outputs[2].serial = g_strdup ("0xC4FE");
manager->outputs[2].width_mm = 309;
manager->outputs[2].height_mm = 174;
manager->outputs[2].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
......@@ -332,6 +338,15 @@ wl_transform_from_xrandr_all (Rotation rotation)
return ret;
}
static int
compare_outputs (const void *one,
const void *two)
{
const MetaOutput *o_one = one, *o_two = two;
return strcmp (o_one->name, o_two->name);
}
static void
read_monitor_infos_from_xrandr (MetaMonitorManager *manager)
{
......@@ -531,6 +546,9 @@ read_monitor_infos_from_xrandr (MetaMonitorManager *manager)
manager->n_outputs = n_actual_outputs;
/* Sort the outputs for easier handling in MetaMonitorConfig */
qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
/* Now fix the clones */
for (i = 0; i < manager->n_outputs; i++)
{
......@@ -596,6 +614,8 @@ make_debug_config (MetaMonitorManager *manager)
static void
read_current_config (MetaMonitorManager *manager)
{
manager->serial++;
#ifdef HAVE_RANDR
if (manager->backend == META_BACKEND_XRANDR)
return read_monitor_infos_from_xrandr (manager);
......@@ -741,8 +761,39 @@ meta_monitor_manager_new (Display *display)
}
}
#endif
manager->config = meta_monitor_config_new ();
read_current_config (manager);
if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
/* Under XRandR, we don't rebuild our data structures until we see
the RRScreenNotify event, but at least at startup we want to have
the right configuration immediately.
The other backends keep the data structures always updated,
so this is not needed.
*/
if (manager->backend == META_BACKEND_XRANDR)
{
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
int n_old_outputs;
old_outputs = manager->outputs;
n_old_outputs = manager->n_outputs;
old_modes = manager->modes;
old_crtcs = manager->crtcs;
read_current_config (manager);
free_output_array (old_outputs, n_old_outputs);
g_free (old_modes);
g_free (old_crtcs);
}
make_logical_config (manager);
return manager;
}
......@@ -1339,6 +1390,32 @@ apply_config_dummy (MetaMonitorManager *manager,
invalidate_logical_config (manager);
}
void
meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
GVariant *crtcs,
GVariant *outputs)
{
GVariantIter crtc_iter, output_iter;
g_variant_iter_init (&crtc_iter, crtcs);
g_variant_iter_init (&output_iter, outputs);
if (manager->backend == META_BACKEND_XRANDR)
apply_config_xrandr (manager, &crtc_iter, &output_iter);
else
apply_config_dummy (manager, &crtc_iter, &output_iter);
}
static gboolean
save_config_timeout (gpointer user_data)
{
MetaMonitorManager *manager = user_data;
meta_monitor_config_make_persistent (manager->config);
return G_SOURCE_REMOVE;
}
static gboolean
meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleton,
GDBusMethodInvocation *invocation,
......@@ -1362,14 +1439,6 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
return TRUE;
}
if (persistent)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_NOT_SUPPORTED,
"Persistent configuration is not yet implemented");
return TRUE;
}
/* Validate all arguments */
g_variant_iter_init (&crtc_iter, crtcs);
while (g_variant_iter_loop (&crtc_iter, "(uiiiuaua{sv})",
......@@ -1493,13 +1562,25 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
}
}
g_variant_iter_init (&crtc_iter, crtcs);
g_variant_iter_init (&output_iter, outputs);
/* If we were in progress of making a persistent change and we see a
new request, it's likely that the old one failed in some way, so
don't save it.
*/
if (manager->persistent_timeout_id && persistent)
{
g_source_remove (manager->persistent_timeout_id);
manager->persistent_timeout_id = 0;
}
if (manager->backend == META_BACKEND_XRANDR)
apply_config_xrandr (manager, &crtc_iter, &output_iter);
else
apply_config_dummy (manager, &crtc_iter, &output_iter);
meta_monitor_manager_apply_configuration (manager, crtcs, outputs);
/* Update MetaMonitorConfig data structures immediately so that we
don't revert the change at the next XRandR event, then wait 20
seconds and save the change to disk
*/
meta_monitor_config_update_current (manager->config, manager);
if (persistent)
manager->persistent_timeout_id = g_timeout_add_seconds (20, save_config_timeout, manager);
meta_dbus_display_config_complete_apply_configuration (skeleton, invocation);
return TRUE;
......@@ -1576,7 +1657,7 @@ meta_monitor_manager_get (void)
MetaMonitorInfo *
meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
int *n_infos)
unsigned int *n_infos)
{
*n_infos = manager->n_monitor_infos;
return manager->monitor_infos;
......@@ -1584,7 +1665,7 @@ meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
MetaOutput *
meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
int *n_outputs)
unsigned int *n_outputs)
{
*n_outputs = manager->n_outputs;
return manager->outputs;
......@@ -1612,7 +1693,6 @@ invalidate_logical_config (MetaMonitorManager *manager)
old_monitor_infos = manager->monitor_infos;
manager->serial++;
make_logical_config (manager);
g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
......@@ -1626,7 +1706,6 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
{
MetaOutput *old_outputs;
MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes;
int n_old_outputs;
......@@ -1646,7 +1725,24 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
old_crtcs = manager->crtcs;
read_current_config (manager);
invalidate_logical_config (manager);
/* Check if the current intended configuration has the same outputs
as the new real one. If so, this was a result of an ApplyConfiguration
call (or a change from ourselves), and we can go straight to rebuild
the logical config and tell the outside world.
Otherwise, this event was caused by hotplug, so give a chance to
MetaMonitorConfig.
*/
if (meta_monitor_config_match_current (manager->config, manager))
{
invalidate_logical_config (manager);
}
else
{
if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager);
}
free_output_array (old_outputs, n_old_outputs);
g_free (old_modes);
......
......@@ -434,7 +434,7 @@ reload_monitor_infos (MetaScreen *screen)
manager = meta_monitor_manager_get ();
screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager,
&screen->n_monitor_infos);
(unsigned*)&screen->n_monitor_infos);
screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment