Note with this patch, the previous patch is unnecessary: the configuration can be sent to all agents (gdm & user) the creation/deletion races will be ignored.<br><div class="gmail_extra"><br><br><div class="gmail_quote">
On Thu, Nov 22, 2012 at 4:08 PM, Marc-André Lureau <span dir="ltr"><<a href="mailto:marcandre.lureau@gmail.com" target="_blank">marcandre.lureau@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
The agent creates a unique mode vdagent-N per output, that is deleted<br>
when the custom resolution is changed. In order to be deleted, it<br>
can't be the current active crtc config.<br>
<br>
Now, the vdagent just sets the mode to NULL, but that causes a change<br>
of resolution probably due to gnome-settings-daemon (in RHEL6, it<br>
switches to max resultion 2560x1600 before switching back to custom<br>
resolution).<br>
<br>
We can avoid deleting current mode by creating a different mode,<br>
switching to it, and then deleting the previous mode. Also, we can<br>
ignore some Create/Delete races with other XRandR clients that may<br>
modify the mode simultaneously. This shouldn't be fatal, as long as<br>
the rest of the resolution switching can take place.<br>
---<br>
src/vdagent-x11-randr.c | 53 +++++++++++++++++++++++++++----------------------<br>
1 file changed, 29 insertions(+), 24 deletions(-)<br>
<br>
diff --git a/src/vdagent-x11-randr.c b/src/vdagent-x11-randr.c<br>
index 2ffd264..2c1819a 100644<br>
--- a/src/vdagent-x11-randr.c<br>
+++ b/src/vdagent-x11-randr.c<br>
@@ -47,13 +47,16 @@ static void arm_error_handler(struct vdagent_x11 *x11)<br>
old_error_handler = XSetErrorHandler(error_handler);<br>
}<br>
<br>
-static void check_error_handler(struct vdagent_x11 *x11)<br>
+static int check_error_handler(struct vdagent_x11 *x11)<br>
{<br>
+ int error;<br>
+<br>
XSync(x11->display, False);<br>
XSetErrorHandler(old_error_handler);<br>
- if (caught_error) {<br>
- x11->set_crtc_config_not_functional = 1;<br>
- }<br>
+ error = caught_error;<br>
+ caught_error = 0;<br>
+<br>
+ return error;<br>
}<br>
<br>
static XRRModeInfo *mode_from_id(struct vdagent_x11 *x11, int id)<br>
@@ -196,7 +199,7 @@ find_mode_by_size (struct vdagent_x11 *x11, int width, int height)<br>
return ret;<br>
}<br>
<br>
-static void delete_mode(struct vdagent_x11 *x11, int output_index)<br>
+static void delete_mode(struct vdagent_x11 *x11, int output_index, const char* name)<br>
{<br>
int m;<br>
XRRModeInfo *mode;<br>
@@ -204,7 +207,6 @@ static void delete_mode(struct vdagent_x11 *x11, int output_index)<br>
XRRCrtcInfo *crtc_info;<br>
RRCrtc crtc;<br>
int current_mode = -1;<br>
- char name[20];<br>
<br>
output_info = x11->randr.outputs[output_index];<br>
if (output_info->ncrtc != 1) {<br>
@@ -215,23 +217,22 @@ static void delete_mode(struct vdagent_x11 *x11, int output_index)<br>
crtc_info = crtc_from_id(x11, output_info->crtcs[0]);<br>
current_mode = crtc_info->mode;<br>
crtc = output_info->crtc;<br>
- snprintf(name, sizeof(name), "vdagent-%d", output_index);<br>
for (m = 0 ; m < x11->randr.res->nmode; ++m) {<br>
mode = &x11->randr.res->modes[m];<br>
if (strcmp(mode->name, name) == 0)<br>
break;<br>
}<br>
if (m < x11->randr.res->nmode) {<br>
- if (crtc && mode->id == current_mode) {<br>
- syslog(LOG_DEBUG,<br>
- "delete_mode of in use mode, setting crtc to NULL mode");<br>
- XRRSetCrtcConfig(x11->display, x11->randr.res, crtc,<br>
- CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0);<br>
- }<br>
+ arm_error_handler(x11);<br>
XRRDeleteOutputMode (x11->display, x11->randr.res->outputs[output_index],<br>
mode->id);<br>
XRRDestroyMode (x11->display, mode->id);<br>
+ // ignore race error, if mode is created by others<br>
+ check_error_handler(x11);<br>
}<br>
+<br>
+ /* silly to update everytime for more then one monitor */<br>
+ update_randr_res(x11);<br>
}<br>
<br>
static void set_reduced_cvt_mode(XRRModeInfo *mode, int width, int height)<br>
@@ -315,24 +316,21 @@ static XRRModeInfo *create_new_mode(struct vdagent_x11 *x11, int output_index,<br>
char modename[20];<br>
XRRModeInfo mode;<br>
<br>
- /* we may be using this mode from an old invocation - check first */<br>
- snprintf(modename, sizeof(modename), "vdagent-%d", output_index);<br>
- arm_error_handler(x11);<br>
- delete_mode(x11, output_index);<br>
- check_error_handler(x11);<br>
- if (x11->set_crtc_config_not_functional) {<br>
- return NULL;<br>
- }<br>
+ snprintf(modename, sizeof(modename), "%dx%d-%d", width, height, output_index);<br>
mode.hSkew = 0;<br>
<a href="http://mode.name" target="_blank">mode.name</a> = modename;<br>
mode.nameLength = strlen(<a href="http://mode.name" target="_blank">mode.name</a>);<br>
set_reduced_cvt_mode(&mode, width, height);<br>
mode.modeFlags = 0;<br>
<a href="http://mode.id" target="_blank">mode.id</a> = 0;<br>
-<br>
+ arm_error_handler(x11);<br>
XRRCreateMode (x11->display, x11->root_window, &mode);<br>
+ // ignore race error, if mode is created by others<br>
+ check_error_handler(x11);<br>
+<br>
/* silly to update everytime for more then one monitor */<br>
update_randr_res(x11);<br>
+<br>
return find_mode_by_name(x11, modename);<br>
}<br>
<br>
@@ -343,6 +341,7 @@ static int xrandr_add_and_set(struct vdagent_x11 *x11, int output, int x, int y,<br>
int xid;<br>
Status s;<br>
RROutput outputs[1];<br>
+ char modename[20];<br>
<br>
if (!x11->randr.res || output >= x11->randr.res->noutput || output < 0) {<br>
syslog(LOG_ERR, "%s: program error: missing RANDR or bad output",<br>
@@ -367,12 +366,17 @@ static int xrandr_add_and_set(struct vdagent_x11 *x11, int output, int x, int y,<br>
s = XRRSetCrtcConfig(x11->display, x11->randr.res, x11->randr.res->crtcs[output],<br>
CurrentTime, x, y, mode->id, RR_Rotate_0, outputs,<br>
1);<br>
+<br>
if (s != RRSetConfigSuccess) {<br>
syslog(LOG_ERR, "failed to XRRSetCrtcConfig");<br>
- delete_mode(x11, output);<br>
x11->set_crtc_config_not_functional = 1;<br>
return 0;<br>
}<br>
+<br>
+ /* clean the previous name, if any */<br>
+ snprintf(modename, sizeof(modename), "%dx%d-%d", x11->width, x11->height, output);<br>
+ delete_mode(x11, output, modename);<br>
+<br>
return 1;<br>
}<br>
<br>
@@ -695,7 +699,8 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,<br>
XRRSetScreenSize(x11->display, x11->root_window, primary_w, primary_h,<br>
DisplayWidthMM(x11->display, x11->screen),<br>
DisplayHeightMM(x11->display, x11->screen));<br>
- check_error_handler(x11);<br>
+<br>
+ x11->set_crtc_config_not_functional = check_error_handler(x11);<br>
}<br>
<br>
update:<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.7.11.7<br>
<br>
</font></span></blockquote></div><br><br clear="all"><br>-- <br>Marc-André Lureau<br>
</div>