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
This commit is contained in:
Giovanni Campagna 2013-07-24 15:35:47 +02:00 committed by Giovanni Campagna
parent 91d193e5e8
commit 12cd4c216b
5 changed files with 1205 additions and 36 deletions

View File

@ -113,6 +113,7 @@ libmutter_la_SOURCES = \
core/main.c \ core/main.c \
core/meta-xrandr-shared.h \ core/meta-xrandr-shared.h \
core/monitor.c \ core/monitor.c \
core/monitor-config.c \
core/monitor-private.h \ core/monitor-private.h \
core/mutter-Xatomtype.h \ core/mutter-Xatomtype.h \
core/place.c \ core/place.c \

1041
src/core/monitor-config.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -177,10 +177,10 @@ void meta_monitor_manager_initialize (Display *display);
MetaMonitorManager *meta_monitor_manager_get (void); MetaMonitorManager *meta_monitor_manager_get (void);
MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager, MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
int *n_infos); unsigned int *n_infos);
MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager, MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
int *n_outputs); unsigned int *n_outputs);
int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager); int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
@ -191,6 +191,37 @@ void meta_monitor_manager_get_screen_size (MetaMonitorManager *
int *width, int *width,
int *height); 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 /* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */ This is true for the odd transforms in the enum */
static inline gboolean static inline gboolean

View File

@ -29,6 +29,7 @@
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <stdlib.h>
#include <clutter/clutter.h> #include <clutter/clutter.h>
#ifdef HAVE_RANDR #ifdef HAVE_RANDR
@ -99,6 +100,9 @@ struct _MetaMonitorManager
#endif #endif
int dbus_name_id; int dbus_name_id;
int persistent_timeout_id;
MetaMonitorConfig *config;
}; };
struct _MetaMonitorManagerClass 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_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)); 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 invalidate_logical_config (MetaMonitorManager *manager);
static void static void
@ -193,14 +199,14 @@ make_dummy_monitor_config (MetaMonitorManager *manager)
manager->outputs = g_new0 (MetaOutput, 3); manager->outputs = g_new0 (MetaOutput, 3);
manager->n_outputs = 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].output_id = 6;
manager->outputs[0].name = g_strdup ("LVDS"); manager->outputs[0].name = g_strdup ("HDMI");
manager->outputs[0].vendor = g_strdup ("unknown"); manager->outputs[0].vendor = g_strdup ("MetaProducts Inc.");
manager->outputs[0].product = g_strdup ("unknown"); manager->outputs[0].product = g_strdup ("unknown");
manager->outputs[0].serial = g_strdup (""); manager->outputs[0].serial = g_strdup ("0xC0F01A");
manager->outputs[0].width_mm = 222; manager->outputs[0].width_mm = 510;
manager->outputs[0].height_mm = 125; manager->outputs[0].height_mm = 287;
manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
manager->outputs[0].preferred_mode = &manager->modes[0]; manager->outputs[0].preferred_mode = &manager->modes[0];
manager->outputs[0].n_modes = 3; 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].n_possible_clones = 0;
manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 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].output_id = 7;
manager->outputs[1].name = g_strdup ("HDMI"); manager->outputs[1].name = g_strdup ("LVDS");
manager->outputs[1].vendor = g_strdup ("unknown"); manager->outputs[1].vendor = g_strdup ("MetaProducts Inc.");
manager->outputs[1].product = g_strdup ("unknown"); manager->outputs[1].product = g_strdup ("unknown");
manager->outputs[1].serial = g_strdup (""); manager->outputs[1].serial = g_strdup ("0xC0FFEE");
manager->outputs[1].width_mm = 510; manager->outputs[1].width_mm = 222;
manager->outputs[1].height_mm = 287; manager->outputs[1].height_mm = 125;
manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; manager->outputs[1].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
manager->outputs[1].preferred_mode = &manager->modes[0]; manager->outputs[1].preferred_mode = &manager->modes[0];
manager->outputs[1].n_modes = 3; manager->outputs[1].n_modes = 3;
@ -240,9 +246,9 @@ make_dummy_monitor_config (MetaMonitorManager *manager)
manager->outputs[2].crtc = NULL; manager->outputs[2].crtc = NULL;
manager->outputs[2].output_id = 8; manager->outputs[2].output_id = 8;
manager->outputs[2].name = g_strdup ("VGA"); 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].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].width_mm = 309;
manager->outputs[2].height_mm = 174; manager->outputs[2].height_mm = 174;
manager->outputs[2].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; manager->outputs[2].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
@ -332,6 +338,15 @@ wl_transform_from_xrandr_all (Rotation rotation)
return ret; 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 static void
read_monitor_infos_from_xrandr (MetaMonitorManager *manager) read_monitor_infos_from_xrandr (MetaMonitorManager *manager)
{ {
@ -531,6 +546,9 @@ read_monitor_infos_from_xrandr (MetaMonitorManager *manager)
manager->n_outputs = n_actual_outputs; 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 */ /* Now fix the clones */
for (i = 0; i < manager->n_outputs; i++) for (i = 0; i < manager->n_outputs; i++)
{ {
@ -596,6 +614,8 @@ make_debug_config (MetaMonitorManager *manager)
static void static void
read_current_config (MetaMonitorManager *manager) read_current_config (MetaMonitorManager *manager)
{ {
manager->serial++;
#ifdef HAVE_RANDR #ifdef HAVE_RANDR
if (manager->backend == META_BACKEND_XRANDR) if (manager->backend == META_BACKEND_XRANDR)
return read_monitor_infos_from_xrandr (manager); return read_monitor_infos_from_xrandr (manager);
@ -741,8 +761,39 @@ meta_monitor_manager_new (Display *display)
} }
} }
#endif #endif
manager->config = meta_monitor_config_new ();
read_current_config (manager); 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); make_logical_config (manager);
return manager; return manager;
} }
@ -1339,6 +1390,32 @@ apply_config_dummy (MetaMonitorManager *manager,
invalidate_logical_config (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 static gboolean
meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleton, meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleton,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
@ -1362,14 +1439,6 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
return TRUE; 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 */ /* Validate all arguments */
g_variant_iter_init (&crtc_iter, crtcs); g_variant_iter_init (&crtc_iter, crtcs);
while (g_variant_iter_loop (&crtc_iter, "(uiiiuaua{sv})", 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); /* If we were in progress of making a persistent change and we see a
g_variant_iter_init (&output_iter, outputs); 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) meta_monitor_manager_apply_configuration (manager, crtcs, outputs);
apply_config_xrandr (manager, &crtc_iter, &output_iter);
else /* Update MetaMonitorConfig data structures immediately so that we
apply_config_dummy (manager, &crtc_iter, &output_iter); 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); meta_dbus_display_config_complete_apply_configuration (skeleton, invocation);
return TRUE; return TRUE;
@ -1576,7 +1657,7 @@ meta_monitor_manager_get (void)
MetaMonitorInfo * MetaMonitorInfo *
meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager, meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
int *n_infos) unsigned int *n_infos)
{ {
*n_infos = manager->n_monitor_infos; *n_infos = manager->n_monitor_infos;
return manager->monitor_infos; return manager->monitor_infos;
@ -1584,7 +1665,7 @@ meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
MetaOutput * MetaOutput *
meta_monitor_manager_get_outputs (MetaMonitorManager *manager, meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
int *n_outputs) unsigned int *n_outputs)
{ {
*n_outputs = manager->n_outputs; *n_outputs = manager->n_outputs;
return manager->outputs; return manager->outputs;
@ -1612,7 +1693,6 @@ invalidate_logical_config (MetaMonitorManager *manager)
old_monitor_infos = manager->monitor_infos; old_monitor_infos = manager->monitor_infos;
manager->serial++;
make_logical_config (manager); make_logical_config (manager);
g_signal_emit (manager, signals[MONITORS_CHANGED], 0); g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
@ -1626,7 +1706,6 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
{ {
MetaOutput *old_outputs; MetaOutput *old_outputs;
MetaCRTC *old_crtcs; MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes; MetaMonitorMode *old_modes;
int n_old_outputs; int n_old_outputs;
@ -1646,7 +1725,24 @@ meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
old_crtcs = manager->crtcs; old_crtcs = manager->crtcs;
read_current_config (manager); read_current_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); 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); free_output_array (old_outputs, n_old_outputs);
g_free (old_modes); g_free (old_modes);

View File

@ -434,7 +434,7 @@ reload_monitor_infos (MetaScreen *screen)
manager = meta_monitor_manager_get (); manager = meta_monitor_manager_get ();
screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager, 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); screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager);
} }