xrandr: use "hotplug_mode_update" property

Use the "hotplug_mode_update" connector property indicating that the
screen settings should be updated: get a new preferred mode on hotplug
events to handle dynamic guest resizing (where you resize the host
window and the guest resizes with it).

https://bugzilla.gnome.org/show_bug.cgi?id=711216
This commit is contained in:
Marc-André Lureau 2013-10-31 14:37:44 +01:00
parent 21c46852cd
commit ca5d115715
4 changed files with 82 additions and 20 deletions

View File

@ -817,6 +817,22 @@ meta_monitor_config_match_current (MetaMonitorConfig *self,
return ok; return ok;
} }
gboolean
meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
{
MetaOutput *outputs;
unsigned n_outputs;
unsigned int i;
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
for (i = 0; i < n_outputs; i++)
if (outputs[i].hotplug_mode_update)
return TRUE;
return FALSE;
}
static MetaConfiguration * static MetaConfiguration *
meta_monitor_config_get_stored (MetaMonitorConfig *self, meta_monitor_config_get_stored (MetaMonitorConfig *self,
MetaOutput *outputs, MetaOutput *outputs,

View File

@ -116,6 +116,9 @@ struct _MetaOutput
*/ */
gboolean is_primary; gboolean is_primary;
gboolean is_presentation; gboolean is_presentation;
/* get a new preferred mode on hotplug events, to handle dynamic guest resizing */
gboolean hotplug_mode_update;
}; };
struct _MetaCRTC struct _MetaCRTC
@ -383,6 +386,7 @@ void meta_output_info_free (MetaOutputInfo *info);
void meta_monitor_manager_free_output_array (MetaOutput *old_outputs, void meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
int n_old_outputs); int n_old_outputs);
gboolean meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager);
/* 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 */

View File

@ -311,6 +311,29 @@ read_output_edid (MetaMonitorManagerXrandr *manager_xrandr,
return NULL; return NULL;
} }
static gboolean
output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
XID output_id)
{
MetaDisplay *display = meta_get_display ();
XRRPropertyInfo *info;
gboolean result = FALSE;
meta_error_trap_push (display);
info = XRRQueryOutputProperty (manager_xrandr->xdisplay, output_id,
display->atom_hotplug_mode_update);
meta_error_trap_pop (display);
if (info)
{
result = TRUE;
XFree (info);
}
return result;
}
static void static void
meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager) meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
{ {
@ -484,6 +507,8 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
meta_output->width_mm = output->mm_width; meta_output->width_mm = output->mm_width;
meta_output->height_mm = output->mm_height; meta_output->height_mm = output->mm_height;
meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
meta_output->hotplug_mode_update =
output_get_hotplug_mode_update (manager_xrandr, meta_output->output_id);
meta_output->n_modes = output->nmode; meta_output->n_modes = output->nmode;
meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes); meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);
@ -971,6 +996,16 @@ meta_monitor_manager_xrandr_set_crtc_gamma (MetaMonitorManager *manager,
XRRFreeGamma (gamma); XRRFreeGamma (gamma);
} }
static void
meta_monitor_manager_xrandr_rebuild_derived (MetaMonitorManager *manager)
{
/* This will be a no-op if the change was from our side, as
we already called it in the DBus method handler */
meta_monitor_config_update_current (manager->config, manager);
meta_monitor_manager_rebuild_derived (manager);
}
static gboolean static gboolean
meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager, meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
XEvent *event) XEvent *event)
@ -980,6 +1015,7 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
MetaCRTC *old_crtcs; MetaCRTC *old_crtcs;
MetaMonitorMode *old_modes; MetaMonitorMode *old_modes;
int n_old_outputs; int n_old_outputs;
gboolean new_config;
if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify) if ((event->type - manager_xrandr->rr_event_base) != RRScreenChangeNotify)
return FALSE; return FALSE;
@ -995,31 +1031,36 @@ meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManager *manager,
manager->serial++; manager->serial++;
meta_monitor_manager_xrandr_read_current (manager); meta_monitor_manager_xrandr_read_current (manager);
/* Check if the current intended configuration has the same outputs new_config = manager_xrandr->resources->timestamp >=
as the new real one, or if the event is a result of an XRandR call. manager_xrandr->resources->configTimestamp;
If so, we can go straight to rebuild the logical config and tell if (meta_monitor_manager_has_hotplug_mode_update (manager))
the outside world.
Otherwise, this event was caused by hotplug, so give a chance to
MetaMonitorConfig.
Note that we need to check both the timestamps and the list of
outputs, because the X server might emit spurious events with
new configTimestamps (bug 702804), and the driver may have
changed the EDID for some other reason (old broken qxl and vbox
drivers...).
*/
if (manager_xrandr->resources->timestamp >= manager_xrandr->resources->configTimestamp ||
meta_monitor_config_match_current (manager->config, manager))
{ {
/* This will be a no-op if the change was from our side, as /* Check if the current intended configuration is a result of an
we already called it in the DBus method handler */ XRandR call. Otherwise, hotplug_mode_update tells us to get
meta_monitor_config_update_current (manager->config, manager); a new preferred mode on hotplug events to handle dynamic
guest resizing. */
meta_monitor_manager_rebuild_derived (manager); if (new_config)
meta_monitor_manager_xrandr_rebuild_derived (manager);
else
meta_monitor_config_make_default (manager->config, manager);
} }
else else
{ {
if (!meta_monitor_config_apply_stored (manager->config, manager)) /* Check if the current intended configuration has the same outputs
as the new real one, or if the event is a result of an XRandR call.
If so, 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.
Note that we need to check both the timestamps and the list of
outputs, because the X server might emit spurious events with new
configTimestamps (bug 702804), and the driver may have changed
the EDID for some other reason (old qxl and vbox drivers). */
if (new_config || meta_monitor_config_match_current (manager->config, manager))
meta_monitor_manager_xrandr_rebuild_derived (manager);
else if (!meta_monitor_config_apply_stored (manager->config, manager))
meta_monitor_config_make_default (manager->config, manager); meta_monitor_config_make_default (manager->config, manager);
} }

View File

@ -81,6 +81,7 @@ item(TIMESTAMP)
item(VERSION) item(VERSION)
item(ATOM_PAIR) item(ATOM_PAIR)
item(BACKLIGHT) item(BACKLIGHT)
item(hotplug_mode_update)
/* Oddities: These are used, and we need atoms for them, /* Oddities: These are used, and we need atoms for them,
* but when we need all _NET_WM hints (i.e. when we're making * but when we need all _NET_WM hints (i.e. when we're making