Index: xfce4-settings-4.11.99/dialogs/display-settings/main.c =================================================================== --- xfce4-settings-4.11.99.orig/dialogs/display-settings/main.c +++ xfce4-settings-4.11.99/dialogs/display-settings/main.c @@ -95,7 +95,22 @@ static const XfceRelation relation_names { XFCE_RANDR_PLACEMENT_LEFT, N_("Left of") } }; +enum +{ + GAMMARED, + GAMMAGREEN, + GAMMABLUE, + GAMMABRIGHT, + N_GAMMA_VALUES +}; +static const gchar * gamma_widgets_names[] = +{ + "randr-gamma-red", + "randr-gamma-green", + "randr-gamma-blue", + "randr-gamma-bright" +}; /* Xrandr rotation name conversion */ static const XfceRotation rotation_names[] = @@ -665,6 +678,79 @@ display_setting_rotations_populate (GtkB builder); } +static void +display_setting_gamma_changed (GtkRange *slider, + GtkBuilder *builder) +{ + int whichgammavalue; + gdouble value; + gdouble * pval; + XfceGamma oldGamma; + gboolean changed = TRUE; + + /* backup old values */ + memcpy(&oldGamma, &xfce_randr->gamma[active_output], sizeof(oldGamma)); + + /* set new values */ + whichgammavalue = (int)gtk_object_get_data(GTK_OBJECT(slider), "whichgammavalue"); + value = gtk_range_get_value(GTK_RANGE(slider)); + switch (whichgammavalue) { + case GAMMARED: pval = &xfce_randr->gamma[active_output].red; break; + case GAMMAGREEN: pval = &xfce_randr->gamma[active_output].green; break; + case GAMMABLUE: pval = &xfce_randr->gamma[active_output].blue; break; + case GAMMABRIGHT: pval = &xfce_randr->gamma[active_output].bright; break; + } + + if (*pval != value) + *pval = value; + else + changed = FALSE; + + if (changed) { + /* Apply the changes */ + xfce_randr_save_output (xfce_randr, "Default", display_channel, + active_output, FALSE); + xfce_randr_apply (xfce_randr, "Default", display_channel); +#ifdef CONFIRMATION_ON_GAMMA_CHANGE //for gamma settings we do not ask for confirmation + /* Ask user confirmation */ + if (!display_setting_timed_confirmation (builder)) + { + //restore old values + memcpy(&xfce_randr->gamma[active_output], &oldGamma, sizeof(oldGamma)); + xfce_randr_save_output (xfce_randr, "Default", display_channel, + active_output, FALSE); + xfce_randr_apply (xfce_randr, "Default", display_channel); + } +#endif + } +} + +static void +display_setting_gamma_populate (GtkBuilder *builder) +{ + GObject * scale; + int which_gamma_value; + gdouble val; + + //loop through all four gamma values + for (which_gamma_value = 0; which_gamma_value < N_GAMMA_VALUES; ++which_gamma_value) { + //get gtk widget + scale = gtk_builder_get_object (builder, gamma_widgets_names[which_gamma_value]); + //disconnect changed signal to avoid user confirmation + g_object_disconnect (scale, "any_signal::value-changed", display_setting_gamma_changed, builder, NULL); + //set value + switch (which_gamma_value) { + case GAMMARED: val = xfce_randr->gamma[active_output].red ; break; + case GAMMAGREEN: val = xfce_randr->gamma[active_output].green ; break; + case GAMMABLUE: val = xfce_randr->gamma[active_output].blue ; break; + case GAMMABRIGHT: val = xfce_randr->gamma[active_output].bright; break; + } + + gtk_range_set_value(GTK_RANGE(scale), val); + //and reconnect changed signal + g_signal_connect (scale, "value-changed", G_CALLBACK (display_setting_gamma_changed), builder); + } +} static void @@ -1320,6 +1406,7 @@ display_settings_treeview_selection_chan display_setting_resolutions_populate (builder); display_setting_refresh_rates_populate (builder); display_setting_rotations_populate (builder); + display_setting_gamma_populate(builder); display_setting_reflections_populate (builder); /* redraw the two (old active, new active) popups */ @@ -1445,7 +1532,9 @@ display_settings_dialog_response (GtkDia static GtkWidget * display_settings_dialog_new (GtkBuilder *builder) { + GObject *scale; + int which_gamma_value; GObject *treeview; GtkCellRenderer *renderer; GtkTreeSelection *selection; GObject *combobox; @@ -1521,6 +1610,12 @@ display_settings_dialog_new (GtkBuilder xfconf_g_property_bind (display_channel, "/Notify", G_TYPE_BOOLEAN, check, "active"); + for (which_gamma_value = 0; which_gamma_value < N_GAMMA_VALUES; ++which_gamma_value) { + scale = gtk_builder_get_object (builder, gamma_widgets_names[which_gamma_value]); + gtk_object_set_data(GTK_OBJECT(scale), "whichgammavalue", (gpointer) which_gamma_value); + g_signal_connect (G_OBJECT (scale), "value-changed", G_CALLBACK (display_setting_gamma_changed), builder); + } + /* Populate the treeview */ display_settings_treeview_populate (builder); Index: xfce4-settings-4.11.99/dialogs/display-settings/xfce-randr.c =================================================================== --- xfce4-settings-4.11.99.orig/dialogs/display-settings/xfce-randr.c +++ xfce4-settings-4.11.99/dialogs/display-settings/xfce-randr.c @@ -30,6 +30,8 @@ #include #include +#include +#include #include "xfce-randr.h" #include "edid.h" @@ -93,7 +95,113 @@ xfce_randr_get_safe_rotations (XfceRandr return rot; } +/* Returns the index of the last value in an array < 0xffff */ +static int +find_last_non_clamped(CARD16 array[], int size) { + int i; + for (i = size - 1; i > 0; i--) { + if (array[i] < 0xffff) + return i; + } + return 0; +} +static void +xfce_randr_get_save_gamma( XfceRandr * randr, + Display * xdisplay, + guint num_output) { + int size, middle, last_best, last_red, last_green, last_blue; + double i1, v1, i2, v2, bright; + CARD16 *best_array; + XRRCrtcGamma * xr_gamma; + + randr->gamma[num_output].red = 0.0; + randr->gamma[num_output].green = 0.0; + randr->gamma[num_output].blue = 0.0; + randr->gamma[num_output].bright = 0.0; + + if (randr->priv->output_info[num_output]->crtc) { + size = XRRGetCrtcGammaSize(xdisplay, randr->priv->output_info[num_output]->crtc); + if (size) { + xr_gamma = XRRGetCrtcGamma(xdisplay, randr->priv->output_info[num_output]->crtc); + if (xr_gamma) { + /* Taken from xrandr.c @ xrandr-1.3.5, but modified in the following way: + * - we want to have the Zero-Value (not 1) to be the neutral default settings + * - if a positive value is set for a color, we want to see more of this color on screen + * + * so we modify the values (x) from xrandr to values (y) from xfce4-display-settings: + * colors: x = 1 - y <---> y = 1 - x + * brightness: x = y + 1 <---> y = x - 1 + * */ + /* + * Here is a bit tricky because gamma is a whole curve for each + * color. So, typically, we need to represent 3 * 256 values as 3 + 1 + * values. Therefore, we approximate the gamma curve (v) by supposing + * it always follows the way we set it: a power function (i^g) + * multiplied by a brightness (b). + * v = i^g * b + * so g = (ln(v) - ln(b))/ln(i) + * and b can be found using two points (v1,i1) and (v2, i2): + * b = e^((ln(v2)*ln(i1) - ln(v1)*ln(i2))/ln(i1/i2)) + * For the best resolution, we select i2 at the highest place not + * clamped and i1 at i2/2. Note that if i2 = 1 (as in most normal + * cases), then b = v2. + */ + last_red = find_last_non_clamped(xr_gamma->red, size); + last_green = find_last_non_clamped(xr_gamma->green, size); + last_blue = find_last_non_clamped(xr_gamma->blue, size); + best_array = xr_gamma->red; + last_best = last_red; + if (last_green > last_best) { + last_best = last_green; + best_array = xr_gamma->green; + } + if (last_blue > last_best) { + last_best = last_blue; + best_array = xr_gamma->blue; + } + if (last_best == 0) + last_best = 1; + + middle = last_best / 2; + i1 = (double)(middle + 1) / size; + v1 = (double)(best_array[middle]) / 65535; + i2 = (double)(last_best + 1) / size; + v2 = (double)(best_array[last_best]) / 65535; + if (v2 < 0.0001) { /* The screen is black */ + randr->gamma[num_output].red = 0.0; + randr->gamma[num_output].green = 0.0; + randr->gamma[num_output].blue = 0.0; + randr->gamma[num_output].bright = 0.0; + } else { + if ((last_best + 1) == size) + bright = v2; + else + bright = exp((log(v2)*log(i1) - log(v1)*log(i2))/log(i1/i2)); + + randr->gamma[num_output].red = (log((double)(xr_gamma->red[last_red / 2]) / bright + / 65535) / log((double)((last_red / 2) + 1) / size)); + randr->gamma[num_output].red = round(100.5 - (randr->gamma[num_output].red * 100)) / 100; //round to 2 digits + if (fabs(randr->gamma[num_output].red) < 0.01) randr->gamma[num_output].red = 0.0; //sometimes we get here e.g. -0.000000 + + randr->gamma[num_output].green = (log((double)(xr_gamma->green[last_green / 2]) / bright + / 65535) / log((double)((last_green / 2) + 1) / size)); + randr->gamma[num_output].green = round(100.5 - (randr->gamma[num_output].green * 100)) / 100; + if (fabs(randr->gamma[num_output].green) < 0.01) randr->gamma[num_output].green = 0.0; + + randr->gamma[num_output].blue = (log((double)(xr_gamma->blue[last_blue / 2]) / bright + / 65535) / log((double)((last_blue / 2) + 1) / size)); + randr->gamma[num_output].blue = round(100.5 - (randr->gamma[num_output].blue * 100)) / 100; + if (fabs(randr->gamma[num_output].blue) < 0.01) randr->gamma[num_output].blue = 0.0; + + randr->gamma[num_output].bright = bright - 1; + randr->gamma[num_output].bright = round(randr->gamma[num_output].bright * 100) / 100; + } + XRRFreeGamma(xr_gamma); + } + } + } +} static XfceRRMode * xfce_randr_list_supported_modes (XRRScreenResources *resources, @@ -135,7 +243,7 @@ xfce_randr_list_supported_modes (XRRScre static void -xfce_randr_guess_relations (XfceRandr *randr) +xfce_randr_guess_relations (XfceRandr *randr, Display * xdisplay) { guint n, m; @@ -180,6 +288,7 @@ xfce_randr_guess_relations (XfceRandr *r break; } } + xfce_randr_get_save_gamma(randr, xdisplay, m); } } @@ -284,6 +393,7 @@ xfce_randr_populate (XfceRandr *randr, randr->relation = g_new0 (XfceOutputRelation, randr->noutput); randr->related_to = g_new0 (guint, randr->noutput); randr->status = g_new0 (XfceOutputStatus, randr->noutput); + randr->gamma = g_new0 (XfceGamma, randr->noutput); randr->friendly_name = g_new0 (gchar *, randr->noutput); /* walk the connected outputs */ @@ -324,7 +434,7 @@ xfce_randr_populate (XfceRandr *randr, } /* calculate relations from positions */ - xfce_randr_guess_relations (randr); + xfce_randr_guess_relations (randr, xdisplay); } @@ -403,6 +513,7 @@ xfce_randr_cleanup (XfceRandr *randr) /* free the settings */ g_free (randr->friendly_name); + g_free (randr->gamma); g_free (randr->mode); g_free (randr->priv->modes); g_free (randr->rotation); @@ -550,6 +661,20 @@ xfce_randr_save_output (XfceRandr *r g_snprintf (property, sizeof (property), "/%s/%s/Position/Y", scheme, randr->priv->output_info[output]->name); xfconf_channel_set_int (channel, property, MAX (randr->priv->position[output].y, 0)); + + /* save gamma values */ + g_snprintf (property, sizeof (property), "/%s/%s/Gamma/Red", scheme, + randr->priv->output_info[output]->name); + xfconf_channel_set_double (channel, property, randr->gamma[output].red); + g_snprintf (property, sizeof (property), "/%s/%s/Gamma/Green", scheme, + randr->priv->output_info[output]->name); + xfconf_channel_set_double (channel, property, randr->gamma[output].green); + g_snprintf (property, sizeof (property), "/%s/%s/Gamma/Blue", scheme, + randr->priv->output_info[output]->name); + xfconf_channel_set_double (channel, property, randr->gamma[output].blue); + g_snprintf (property, sizeof (property), "/%s/%s/Gamma/Brightness", scheme, + randr->priv->output_info[output]->name); + xfconf_channel_set_double (channel, property, randr->gamma[output].bright); } Index: xfce4-settings-4.11.99/dialogs/display-settings/xfce-randr.h =================================================================== --- xfce4-settings-4.11.99.orig/dialogs/display-settings/xfce-randr.h +++ xfce4-settings-4.11.99/dialogs/display-settings/xfce-randr.h @@ -39,6 +39,7 @@ typedef struct _XfceRandrPrivate XfceR typedef struct _XfceRRMode XfceRRMode; typedef enum _XfceOutputStatus XfceOutputStatus; typedef enum _XfceOutputRelation XfceOutputRelation; +typedef struct _XfceGamma XfceGamma; enum _XfceOutputStatus { @@ -63,6 +64,14 @@ struct _XfceRRMode gdouble rate; }; +struct _XfceGamma +{ + gdouble red; + gdouble green; + gdouble blue; + gdouble bright; +}; + struct _XfceRandr { /* number of connected outputs */ @@ -76,6 +85,7 @@ struct _XfceRandr guint *related_to; XfceOutputStatus *status; gchar **friendly_name; + XfceGamma *gamma; /* implementation details */ XfceRandrPrivate *priv; Index: xfce4-settings-4.11.99/xfsettingsd/displays.c =================================================================== --- xfce4-settings-4.11.99.orig/xfsettingsd/displays.c +++ xfce4-settings-4.11.99/xfsettingsd/displays.c @@ -28,6 +28,10 @@ #include #endif +#ifdef HAVE_STDLIB_H +#include +#endif + #include #include #include @@ -61,9 +65,16 @@ #define RRATE_PROP OUTPUT_FMT "/RefreshRate" #define POSX_PROP OUTPUT_FMT "/Position/X" #define POSY_PROP OUTPUT_FMT "/Position/Y" +#define GAMMA_RED_PROP OUTPUT_FMT "/Gamma/Red" +#define GAMMA_GREEN_PROP OUTPUT_FMT "/Gamma/Green" +#define GAMMA_BLUE_PROP OUTPUT_FMT "/Gamma/Blue" +#define GAMMA_BRIGHT_PROP OUTPUT_FMT "/Gamma/Brightness" #define NOTIFY_PROP "/Notify" - +static inline double dmin (double x, double y) +{ + return x < y ? x : y; +} /* wrappers to avoid querying too often */ typedef struct _XfceRRCrtc XfceRRCrtc; @@ -174,6 +185,10 @@ struct _XfceRRCrtc gint npossible; RROutput *possible; gint changed; + gdouble brightness; + gdouble gamma_red; + gdouble gamma_green; + gdouble gamma_blue; }; struct _XfceRROutput @@ -560,7 +575,7 @@ xfce_displays_helper_load_from_xfconf (X GValue *value; const gchar *str_value; gchar property[512]; - gdouble output_rate, rate; + gdouble output_rate, rate, g_red, g_green, g_blue, bright; RRMode valid_mode; Rotation rot; gint x, y, n, m, int_value; @@ -763,6 +778,61 @@ xfce_displays_helper_load_from_xfconf (X crtc->changed = TRUE; } + /* gamma correction */ + /* We use the nearly the same values as xrandr 1.3.5 except the following: + * - we want to have the Zero-Value (not 1) to be the neutral default settings + * - if a positive value is set for a color, we want to see more of this color on screen + * + * so we modify the values (x) from xrandr to values (y) from xfce4-display-settings: + * colors: x = 1 - y <---> y = 1 - x + * brightness: x = y + 1 <---> y = x - 1 + * */ + + g_snprintf (property, sizeof (property), GAMMA_RED_PROP, scheme, + output->info->name); + value = g_hash_table_lookup (saved_outputs, property); + if (G_VALUE_HOLDS_DOUBLE (value)) + g_red = 1.0 - g_value_get_double (value); + else + g_red = 1.0; + + g_snprintf (property, sizeof (property), GAMMA_GREEN_PROP, scheme, + output->info->name); + value = g_hash_table_lookup (saved_outputs, property); + if (G_VALUE_HOLDS_DOUBLE (value)) + g_green = 1.0 - g_value_get_double (value); + else + g_green = 1.0; + + g_snprintf (property, sizeof (property), GAMMA_BLUE_PROP, scheme, + output->info->name); + value = g_hash_table_lookup (saved_outputs, property); + if (G_VALUE_HOLDS_DOUBLE (value)) + g_blue = 1.0 - g_value_get_double (value); + else + g_blue = 1.0; + + g_snprintf (property, sizeof (property), GAMMA_BRIGHT_PROP, scheme, + output->info->name); + value = g_hash_table_lookup (saved_outputs, property); + if (G_VALUE_HOLDS_DOUBLE (value)) + bright = 1.0 + g_value_get_double (value); + else + bright = 1.0; + + if ( crtc->gamma_red != g_red + || crtc->gamma_green != g_green + || crtc->gamma_blue != g_blue + || crtc->brightness != bright) + { + crtc->gamma_red = g_red; + crtc->gamma_green = g_green; + crtc->gamma_blue = g_blue; + crtc->brightness = bright; + crtc->changed = TRUE; + } + + xfce_displays_helper_set_outputs (crtc, output); return active; @@ -1127,6 +1197,24 @@ xfce_displays_helper_apply_crtc (XfceRRC CurrentTime, crtc->x, crtc->y, crtc->mode, crtc->rotation, crtc->outputs, crtc->noutput); + if (ret == RRSetConfigSuccess) { + int i,size; + XRRCrtcGamma * xr_gamma; + size = XRRGetCrtcGammaSize(helper->xdisplay, crtc->id); + if (size) { + xr_gamma = XRRAllocGamma(size); + if (xr_gamma) { + for (i=0; ired[i] = dmin( pow( (double) i/ (double)(size - 1), crtc->gamma_red) * crtc->brightness, 1.0) * 65535.0; + xr_gamma->green[i] = dmin( pow( (double) i/ (double)(size - 1), crtc->gamma_green) * crtc->brightness, 1.0) * 65535.0; + xr_gamma->blue[i] = dmin( pow( (double) i/ (double)(size - 1), crtc->gamma_blue) * crtc->brightness, 1.0) * 65535.0; + } + XRRSetCrtcGamma(helper->xdisplay, crtc->id, xr_gamma); + free(xr_gamma); + } + } + } + if (ret == RRSetConfigSuccess) crtc->changed = FALSE; else Index: xfce4-settings-4.11.99/dialogs/display-settings/display-dialog.glade =================================================================== --- xfce4-settings-4.11.99.orig/dialogs/display-settings/display-dialog.glade +++ xfce4-settings-4.11.99/dialogs/display-settings/display-dialog.glade @@ -3,6 +3,30 @@ + + -1 + 1 + 0.01 + 0.050000000000000003 + + + -1 + 1 + 0.01 + 0.050000000000000003 + + + -1 + 1 + 0.01 + 0.050000000000000003 + + + -1 + 1 + 0.01 + 0.050000000000000003 + False Display @@ -18,241 +42,412 @@ False 2 - + True False - 12 - 12 - - 200 - True - True - automatic - automatic - etched-in - - - True - True - False - False - False - - - - - True - True - 0 - - - - + True False - 7 - 2 - 12 - 6 - - - False - - - 1 - 2 - 6 - 7 - GTK_FILL - - - - - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - False - 0 - Ref_lection: - True - - - 6 - 7 - GTK_FILL - GTK_FILL - - - - - True - False - 0 - Ro_tation: - True - - - 5 - 6 - GTK_FILL - GTK_FILL - - - - - True - False - 0 - Refresh _rate: - True - - - 4 - 5 - GTK_FILL - GTK_FILL - - - - - True - False - 0 - R_esolution: - True - - - 3 - 4 - GTK_FILL - GTK_FILL - - + 12 + 12 - - True - False - 0 - P_osition: - True - - - 2 - 3 - GTK_FILL - GTK_FILL - - - - - _Use this output + + 200 True True - False - False - True - True - - - 2 - GTK_FILL - GTK_FILL - - - - - _Mirror displays - True - True - False - False - True - True + automatic + automatic + etched-in + + + True + True + False + False + False + + - 2 - 1 - 2 - GTK_FILL - GTK_FILL + True + True + 0 - + True False + 7 + 2 + 12 + 6 + + + False + + + 1 + 2 + 6 + 7 + GTK_FILL + + + + + True + False + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + True + False + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + False + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + False + 0 + Ref_lection: + True + + + 6 + 7 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Ro_tation: + True + + + 5 + 6 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Refresh _rate: + True + + + 4 + 5 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + R_esolution: + True + + + 3 + 4 + GTK_FILL + GTK_FILL + + - + True False + 0 + P_osition: + True + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + _Use this output + False + True + True + False + True + True - True - True - 0 + 2 + GTK_FILL + GTK_FILL - + + _Mirror displays + False + True + True + False + True + True + + + 2 + 1 + 2 + GTK_FILL + GTK_FILL + + + + True False + + + True + False + + + True + True + 0 + + + + + True + False + + + True + True + 1 + + - True - True - 1 + 1 + 2 + 2 + 3 + GTK_FILL - 1 - 2 - 2 - 3 - GTK_FILL + True + True + 1 True True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 4 + 2 + + + True + False + 0 + Re_d: + True + randr-gamma-red + + + GTK_FILL + + + + + True + False + 0 + Gree_n: + True + randr-gamma-green + + + 1 + 2 + GTK_FILL + + + + + True + False + 0 + _Blue: + True + randr-gamma-blue + + + 2 + 3 + GTK_FILL + + + + + True + False + 0 + Br_ightness: + True + randr-gamma-bright + + + 3 + 4 + GTK_FILL + + + + + True + True + discontinuous + adjustment1 + 1 + 2 + right + + + 1 + 2 + + + + + True + True + discontinuous + adjustment2 + 2 + 2 + right + + + 1 + 2 + 1 + 2 + + + + + True + True + discontinuous + adjustment3 + 2 + 2 + right + + + 1 + 2 + 2 + 3 + + + + + True + True + discontinuous + adjustment4 + 2 + 2 + right + + + 1 + 2 + 3 + 4 + + + + + + + + + True + False + <b>Gamma correction</b> + True + + + + + True + True 1 @@ -304,7 +499,7 @@ False True end - 0 + 1