/* $Id: display_plugin.c 24641 2007-01-20 15:44:58Z benny $ */
/*-
 * Copyright (c) 2003-2006 Benedikt Meurer <benny@xfce.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; You may only use version 2 of the License,
 * you have no option to use any other version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include <X11/Xproto.h>
#ifdef USE_XRANDR
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xrender.h>
#endif
#ifdef USE_XF86VM
#include <X11/extensions/xf86vmode.h>
#endif

#include <gdk/gdkx.h>
#include <libxfce4mcs/mcs-manager.h>
#include <libxfcegui4/libxfcegui4.h>
#include <xfce-mcs-manager/manager-plugin.h>

/* this seems to be a sane value */
#define	BORDER		6

/* */
#define GAMMA_MIN	0.1
#define GAMMA_MAX	10.0

/* */
#define	RCDIR		"mcs_settings"
#define	OLDRCDIR	"settings"
#define	CHANNEL		"display"
#define	RCFILE		"display.xml"
#define DEFAULT_RES     -1

/* */
#define CONFIRM_TIMEOUT 15

/* */
enum
{
    NAME_COLUMN,
    SIZE_COLUMN,
    RATE_COLUMN,
    N_COLUMNS
};

/* settings */
static int sizeIndex = DEFAULT_RES;
static int rateIndex = DEFAULT_RES;
static int redValue = 100;
static int greenValue = 100;
static int blueValue = 100;
static gboolean syncGamma = TRUE;
#ifdef USE_XRANDR
static int default_size = 0;
static int default_rate = 0;
#endif

/* supported extensions */
static gboolean haveXrandr = FALSE;
static gboolean haveXxf86vm = FALSE;

/* */
typedef struct _Itf Itf;
struct _Itf {
    McsPlugin *plugin;

    GtkWidget *dialog;
    
    GtkWidget *treeview;
    GtkListStore *store;

    GtkWidget *rscale;
    GtkWidget *gscale;
    GtkWidget *bscale;

    GtkWidget *synctoggle;

    int original_size;
    int original_rate;

    int original_rgamma;
    int original_ggamma;
    int original_bgamma;

    gboolean original_sync;
};

/* static prototypes */
static void run_dialog (McsPlugin *);
static gboolean save_settings (McsPlugin * plugin);

#ifdef USE_XRANDR
/* */
static void
change_size_and_rate (XRRScreenConfiguration * sc, int size, int rate)
{
    Rotation current_rotation;
    int current_rate;
    int current_size;

    gdk_error_trap_push ();

    current_rate = XRRConfigCurrentRate (sc);
    current_size = XRRConfigCurrentConfiguration (sc, &current_rotation);

    if (gdk_error_trap_pop ())
      {
        g_warning ("display_plugin: Unable to query current display resolution");
        return;
      }

    if (size == current_size && rate == current_rate)
    {
        /* nothing to do here */
        return;
    }

    gdk_error_trap_push ();

    XRRSetScreenConfigAndRate (GDK_DISPLAY (), sc, GDK_ROOT_WINDOW (), (SizeID) size,
                               current_rotation, rate, CurrentTime);
    XSync (GDK_DISPLAY (), False);

    if (gdk_error_trap_pop ())
      {
        g_warning ("display_plugin: Unable to configure display resolution");
        return;
      }
}

static gboolean
confirm_timeout_cb (gpointer user_data)
{
    gint timeout;
    GtkWidget *msgdlg = user_data;

    timeout = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (msgdlg), "timeout"));

    if (!--timeout)
    {
        gtk_dialog_response (GTK_DIALOG (msgdlg), GTK_RESPONSE_NO);
        return FALSE;
    }

    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdlg),
                                              _("Old settings will be restored in %d seconds"),
                                              timeout);
    g_object_set_data (G_OBJECT (msgdlg), "timeout", GINT_TO_POINTER (timeout));

    return TRUE;
}

static gboolean
confirm_display_mode (GtkWidget * parent)
{
    GtkWidget *msgdlg;
    gint response;
    guint timeout_id;

    msgdlg = gtk_message_dialog_new (GTK_WINDOW (parent),
                                     GTK_DIALOG_MODAL |
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_QUESTION,
                                     GTK_BUTTONS_YES_NO,
                                     _("Display settings have been changed.\n"
                                       "Would you like to keep these settings?"));

    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdlg),
                                              _("Previous settings will be restored in %d seconds"),
                                              CONFIRM_TIMEOUT);

    gtk_window_set_position (GTK_WINDOW (msgdlg), GTK_WIN_POS_CENTER_ALWAYS);

    g_object_set_data (G_OBJECT (msgdlg), "timeout", GINT_TO_POINTER (CONFIRM_TIMEOUT));
    timeout_id = g_timeout_add (1000, confirm_timeout_cb, msgdlg);

    response = gtk_dialog_run (GTK_DIALOG (msgdlg));

    g_source_remove (timeout_id);
    gtk_widget_destroy (msgdlg);
    
    return response == GTK_RESPONSE_YES;
}
#endif

#ifdef USE_XF86VM
/*
 */
static void
change_gamma (double red, double green, double blue)
{
    XF86VidModeGamma gamma;

    gamma.red = red / 100.0;
    gamma.green = green / 100.0;
    gamma.blue = blue / 100.0;

    gdk_error_trap_push ();

    XF86VidModeSetGamma (GDK_DISPLAY (), DefaultScreen (GDK_DISPLAY ()), &gamma);

    if (gdk_error_trap_pop ())
      {
        g_warning ("display_plugin: Unable to configure display gamma correction");
        return;
      }
}
#endif

/*
 */
McsPluginInitResult
mcs_plugin_init (McsPlugin * plugin)
{
#ifdef USE_XRANDR
    XRRScreenConfiguration *sc;
#endif
    McsSetting *setting;
    gchar *rcfile, *path;
#if defined(USE_XF86VM) || defined(USE_XRANDR)
    int major;
    int minor;
#endif

    xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");

    /* read settings channel from file */
    path = g_build_filename ("xfce4", RCDIR, RCFILE, NULL);
    rcfile = xfce_resource_lookup (XFCE_RESOURCE_CONFIG, path);

    if (!rcfile)
    {
        rcfile = xfce_get_userfile(OLDRCDIR, RCFILE, NULL);
    }

    if (g_file_test (rcfile, G_FILE_TEST_EXISTS))
    {
        mcs_manager_add_channel_from_file(plugin->manager, CHANNEL, 
                                          rcfile);
    }
    else
    {
        mcs_manager_add_channel(plugin->manager, CHANNEL);
    }
    
    g_free(path);
    g_free(rcfile);

    if ((setting = mcs_manager_setting_lookup (plugin->manager, "XDisplay/size", CHANNEL)) != NULL)
    {
        sizeIndex = setting->data.v_int;
    }
    else
    {
        mcs_manager_set_int (plugin->manager, "XDisplay/size", CHANNEL, sizeIndex);
    }

    if ((setting = mcs_manager_setting_lookup (plugin->manager, "XDisplay/rate", CHANNEL)) != NULL)
    {
        rateIndex = setting->data.v_int;
    }
    else
    {
        mcs_manager_set_int (plugin->manager, "XDisplay/rate", CHANNEL, rateIndex);
    }

    if ((setting = mcs_manager_setting_lookup (plugin->manager, "XDisplay/rgamma", CHANNEL)) != NULL)
    {
        redValue = setting->data.v_int;
    }
    else
    {
        mcs_manager_set_int (plugin->manager, "XDisplay/rgamma", CHANNEL, redValue);
    }

    if ((setting = mcs_manager_setting_lookup (plugin->manager, "XDisplay/ggamma", CHANNEL)) != NULL)
    {
        greenValue = setting->data.v_int;
    }
    else
    {
        mcs_manager_set_int (plugin->manager, "XDisplay/ggamma", CHANNEL, greenValue);
    }

    if ((setting = mcs_manager_setting_lookup (plugin->manager, "XDisplay/bgamma", CHANNEL)) != NULL)
    {
        blueValue = setting->data.v_int;
    }
    else
    {
        mcs_manager_set_int (plugin->manager, "XDisplay/bgamma", CHANNEL, blueValue);
    }

    if ((setting = mcs_manager_setting_lookup (plugin->manager, "XDisplay/syncGamma", CHANNEL)) != NULL)
    {
        syncGamma = setting->data.v_int;
    }
    else
    {
        mcs_manager_set_int (plugin->manager, "XDisplay/syncGamma", CHANNEL, syncGamma);
    }

#ifdef USE_XRANDR
    if (XRRQueryVersion (GDK_DISPLAY (), &major, &minor))
    {
        if ((sc = XRRGetScreenInfo (GDK_DISPLAY (), GDK_ROOT_WINDOW ())))
        {
            Rotation current_rotation;
            
            gdk_error_trap_push ();
            
            /* Save default values */
            default_size = XRRConfigCurrentConfiguration (sc, &current_rotation);
            default_rate = XRRConfigCurrentRate (sc);

            if (!gdk_error_trap_pop ())
            {
                if (sizeIndex >= 0 && rateIndex >= 0)
                {
                    /* restore resolution and rate */
                    change_size_and_rate (sc, sizeIndex, rateIndex);
                }
                else {
                    sizeIndex = default_size;
                    rateIndex = default_rate;
                }

                /* remember that we can use the Xrandr extension */
                haveXrandr = TRUE;
            }
            
            XRRFreeScreenConfigInfo (sc);
        }
    }
#endif

#ifdef USE_XF86VM
    if (XF86VidModeQueryVersion (GDK_DISPLAY (), &major, &minor))
    {

        /* sync the gamma settings */
        if (syncGamma)
        {
            redValue = greenValue = blueValue = (redValue + greenValue + blueValue) / 3;
        }

        /* restore gamma settings */
        change_gamma (redValue, greenValue, blueValue);

        /* remember that we can use the XF86VidMode extension */
        haveXxf86vm = TRUE;
    }
#endif

    plugin->plugin_name = g_strdup ("display");
    /* the button label in the xfce-mcs-manager dialog */
    plugin->caption = g_strdup (Q_ ("Button Label|Display"));
    plugin->run_dialog = run_dialog;
    plugin->icon = xfce_themed_icon_load ("xfce4-display", 48);
    if (G_LIKELY (plugin->icon != NULL))
      g_object_set_data_full (G_OBJECT (plugin->icon), "mcs-plugin-icon-name", g_strdup ("xfce4-display"), g_free);

#if 0    
    /* I fail to see why we need to save the options here, during startup... */
    save_settings (plugin);
#endif

    return (MCS_PLUGIN_INIT_OK);
}

/*
 */
static gboolean
save_settings (McsPlugin * plugin)
{
    gboolean result = FALSE;
    gchar *rcfile, *path;

    path = g_build_filename ("xfce4", RCDIR, RCFILE, NULL);
    rcfile = xfce_resource_save_location (XFCE_RESOURCE_CONFIG, path, TRUE);
    if (G_LIKELY (rcfile != NULL))
    {
        result = mcs_manager_save_channel_to_file (plugin->manager, CHANNEL, rcfile);
        g_free(rcfile);
    }
    g_free(path);

    return (result);
}

#ifdef USE_XRANDR
/*
 */
static void
changedCB (GtkTreeSelection * selection, Itf * itf)
{
    XRRScreenConfiguration *sc;
    GtkTreeModel *store;
    GtkTreeIter iter;
    int newsize, newrate;
    gboolean is_default;
    /* If new resolution is rejected, we get called
     * again while restoring the old resolution */
    static guint recursion_count = 0;

    if (!gtk_tree_selection_get_selected (selection, &store, &iter))
        return;

    recursion_count++;

    gtk_tree_model_get (store, &iter,
                        SIZE_COLUMN, &newsize,
                        RATE_COLUMN, &newrate,
                        -1);

    /* apply settings */
    sc = XRRGetScreenInfo (GDK_DISPLAY (), GDK_ROOT_WINDOW ());
    change_size_and_rate (sc, newsize, newrate);
    XRRFreeScreenConfigInfo (sc);

    if (recursion_count > 1)
    {
        recursion_count--;
        return;
    }

    is_default = ( newsize == default_size && newrate == default_rate );

    if (!is_default &&
        !(newsize == itf->original_size && newrate == itf->original_rate))
    {
        if (!confirm_display_mode (itf->dialog))
        {
            /* Restore previous */
            if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
            {
                do {
                    gtk_tree_model_get (store, &iter,
                                        RATE_COLUMN, &newrate,
                                        SIZE_COLUMN, &newsize,
                                        -1);

                    if (newrate == rateIndex && newsize == sizeIndex)
                    {
                        gtk_tree_selection_select_iter (selection, &iter);
                        break;
                    }
                } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
            }
        }
    }

    if (newsize != sizeIndex || newrate != rateIndex) {
        sizeIndex = newsize;
        rateIndex = newrate;
        
        mcs_manager_set_int (itf->plugin->manager, "XDisplay/rate", CHANNEL,
                             is_default ? DEFAULT_RES : newrate);
        mcs_manager_set_int (itf->plugin->manager, "XDisplay/size", CHANNEL,
                             is_default ? DEFAULT_RES : newsize);
        mcs_manager_notify (itf->plugin->manager, CHANNEL);
        save_settings (itf->plugin);
    }

    recursion_count--;
}
#endif

#ifdef USE_XF86VM
/*
 */
static void
redChangedCB (GtkRange * range, Itf * itf)
{
    double value;

    value = gtk_range_get_value (range);

    redValue = (int) (value * 100);

    /* sync the other slides */
    if (syncGamma)
    {
        if (greenValue * 100.0 != value)
            gtk_range_set_value (GTK_RANGE (itf->gscale), value);

        if (blueValue * 100.0 != value)
            gtk_range_set_value (GTK_RANGE (itf->bscale), value);
    }

    /* apply settings */
    change_gamma (redValue, greenValue, blueValue);

    /* and remember the settings */
    mcs_manager_set_int (itf->plugin->manager, "XDisplay/rgamma", CHANNEL, redValue);
    mcs_manager_notify (itf->plugin->manager, CHANNEL);
    save_settings (itf->plugin);
}

/*
 */
static void
greenChangedCB (GtkRange * range, Itf * itf)
{
    double value;

    value = gtk_range_get_value (range);

    greenValue = (int) (value * 100);

    /* sync the other slides */
    if (syncGamma)
    {
        if (redValue * 100.0 != value)
            gtk_range_set_value (GTK_RANGE (itf->rscale), value);

        if (blueValue * 100.0 != value)
            gtk_range_set_value (GTK_RANGE (itf->bscale), value);
    }

    /* apply settings */
    change_gamma (redValue, greenValue, blueValue);

    /* and remember the settings */
    mcs_manager_set_int (itf->plugin->manager, "XDisplay/ggamma", CHANNEL, greenValue);
    mcs_manager_notify (itf->plugin->manager, CHANNEL);
    save_settings (itf->plugin);
}

/*
 */
static void
blueChangedCB (GtkRange * range, Itf * itf)
{
    double value;

    value = gtk_range_get_value (range);

    blueValue = (int) (value * 100);

    /* sync the other slides */
    if (syncGamma)
    {
        if (redValue * 100.0 != value)
            gtk_range_set_value (GTK_RANGE (itf->rscale), value);

        if (greenValue * 100.0 != value)
            gtk_range_set_value (GTK_RANGE (itf->gscale), value);
    }

    /* apply settings */
    change_gamma (redValue, greenValue, blueValue);

    /* and remember the settings */
    mcs_manager_set_int (itf->plugin->manager, "XDisplay/bgamma", CHANNEL, blueValue);
    mcs_manager_notify (itf->plugin->manager, CHANNEL);
    save_settings (itf->plugin);
}

/*
 */
static void
syncGammaChangedCB (GtkToggleButton * button, Itf * itf)
{
    gint value;

    syncGamma = gtk_toggle_button_get_active (button);

    if (syncGamma)
    {
        value = (redValue + greenValue + blueValue) / 3;
        gtk_range_set_value (GTK_RANGE (itf->rscale), value / 100.0);
        gtk_range_set_value (GTK_RANGE (itf->gscale), value / 100.0);
        gtk_range_set_value (GTK_RANGE (itf->bscale), value / 100.0);
    }

    mcs_manager_set_int (itf->plugin->manager, "XDisplay/syncGamma", CHANNEL, syncGamma);
    mcs_manager_notify (itf->plugin->manager, CHANNEL);
    save_settings (itf->plugin);
}

#endif /* !USE_XF86VM */

/*
 */
static void
responseCB (GtkWidget * widget, gint response, Itf * itf)
{
    switch (response)
    {
        case GTK_RESPONSE_CANCEL:
            {
                /* revert settings */
                if (haveXrandr)
                {
#ifdef USE_XRANDR
                    GtkTreeIter iter;

                    if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (itf->store), &iter))
                    {
                        gint size, rate;

                        do {
                            gtk_tree_model_get (GTK_TREE_MODEL (itf->store), &iter,
                                                SIZE_COLUMN, &size,
                                                RATE_COLUMN, &rate,
                                                -1 );

                            if (size == itf->original_size && rate == itf->original_rate)
                            {
                                GtkTreePath *path;
                                
                                path = gtk_tree_model_get_path (GTK_TREE_MODEL (itf->store), &iter);
                                gtk_tree_view_set_cursor (GTK_TREE_VIEW (itf->treeview), path,
                                                          0, FALSE);
                                gtk_tree_path_free (path);
                            }
                        } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (itf->store), &iter));
                    }
#endif /* !USE_XRANDR */
                }

                if (haveXxf86vm)
                {
#ifdef USE_XF86VM
                    gint rgamma, ggamma, bgamma;

                    rgamma = itf->original_rgamma;
                    ggamma = itf->original_ggamma;
                    bgamma = itf->original_bgamma;

                    if (itf->original_sync)
                    {
                        rgamma = ggamma = bgamma = (rgamma + ggamma + bgamma) / 3;
                    }

                    gtk_range_set_value (GTK_RANGE (itf->rscale), rgamma / 100);
                    gtk_range_set_value (GTK_RANGE (itf->gscale), ggamma / 100);
                    gtk_range_set_value (GTK_RANGE (itf->bscale), bgamma / 100);
                    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (itf->synctoggle),
                                                  itf->original_sync);
#endif /* !USE_XF86VM */
                }
            }
            break;

        default:
            gtk_widget_destroy (itf->dialog);
    }
}

/*
 */
static void
run_dialog (McsPlugin * plugin)
{
    GtkTreeSelection *selection;
    GtkListStore *store;
    GtkWidget *revert;
    GtkWidget *close;
    GtkWidget *hbox;
    GtkWidget *align;
    GtkWidget *frame;
    GtkWidget *vbox;
    GtkWidget *treeview;
    GtkWidget *scrollwin;
    GtkWidget *table;
    GtkWidget *rlabel;
    GtkWidget *glabel;
    GtkWidget *blabel;
    GtkWidget *checkbox;
    GtkWidget *dialog;
    GtkWidget *rscale;
    GtkWidget *gscale;
    GtkWidget *bscale;
    static Itf *itf = NULL;

    if (itf != NULL)
    {
        gtk_window_present (GTK_WINDOW (itf->dialog));
        return;
    }

    xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");

    itf = g_new( Itf, 1 );

    itf->plugin = plugin;

    itf->dialog = dialog = xfce_titled_dialog_new_with_buttons (_("Display Preferences"), NULL, GTK_DIALOG_NO_SEPARATOR, NULL);
    gtk_window_set_icon_name (GTK_WINDOW (dialog), "xfce4-display");
    g_signal_connect_swapped (G_OBJECT (dialog), "destroy", G_CALLBACK (g_free), itf);
    g_signal_connect (G_OBJECT (dialog), "destroy", G_CALLBACK (gtk_widget_destroyed), &itf);

    /* action widgets */
    gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog)->action_area), GTK_BUTTONBOX_EDGE);

    revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
    gtk_dialog_add_action_widget (GTK_DIALOG (dialog), revert, GTK_RESPONSE_CANCEL);

    close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
    gtk_dialog_add_action_widget (GTK_DIALOG (dialog), close, GTK_RESPONSE_CLOSE);
    GTK_WIDGET_SET_FLAGS (close, GTK_CAN_DEFAULT);
    gtk_widget_grab_default (close);
    gtk_widget_grab_focus (close);

    gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
    gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

    g_signal_connect (dialog, "response", G_CALLBACK (responseCB), itf);

    /* */
    hbox = gtk_hbox_new (FALSE, BORDER);
    gtk_container_set_border_width (GTK_CONTAINER (hbox), BORDER);
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);

    /* */
    align = gtk_alignment_new (0, 0, 0, 0);
    gtk_widget_set_size_request (align, BORDER, BORDER);
    gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, TRUE, 0);

    /* resolution settings */
    vbox = gtk_vbox_new (FALSE, BORDER);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER);
    frame = xfce_create_framebox_with_content (_("Resolution"), vbox);
    gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);

    /* create the surrounding scrolled window */
    scrollwin = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_IN);
    gtk_box_pack_start (GTK_BOX (vbox), scrollwin, TRUE, TRUE, 0);

    /* create store */
    itf->store = store = gtk_list_store_new (N_COLUMNS,
                                             G_TYPE_STRING,
                                             G_TYPE_INT, G_TYPE_INT,
                                             G_TYPE_BOOLEAN);

    /* create tree view */
    itf->treeview = treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
    gtk_widget_set_size_request (treeview, -1, 200);
    gtk_container_add (GTK_CONTAINER (scrollwin), treeview);
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
    gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);

    /* create treeview columns */
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview),
        gtk_tree_view_column_new_with_attributes ("", gtk_cell_renderer_text_new (), "text", NAME_COLUMN, NULL));

    if (haveXrandr)
    {
#ifdef USE_XRANDR
        XRRScreenConfiguration *sc;
        Rotation current_rotation;
        XRRScreenSize *sizes;
        int nsizes, i, j;
        int current_rate;
        int current_size;
        GtkTreePath *path;
        GtkTreeIter iter;

        sc = XRRGetScreenInfo (GDK_DISPLAY (), GDK_ROOT_WINDOW ());

        /* XXX */
        g_assert (sc != NULL);

        sizes = XRRConfigSizes (sc, &nsizes);
        current_rate = XRRConfigCurrentRate (sc);
        current_size = XRRConfigCurrentConfiguration (sc, &current_rotation);

        /* Add default entry */
        gtk_list_store_append (store, &iter);
        gtk_list_store_set (store, &iter, NAME_COLUMN, "Default",
                            SIZE_COLUMN, default_size,
                            RATE_COLUMN, default_rate,
                            DEFAULT_RES);
        path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
        gtk_tree_view_set_cursor (GTK_TREE_VIEW (treeview), path, 0, FALSE);
        gtk_tree_path_free (path);

        /* fill store */
        for (i = 0; i < nsizes; i++)
        {
            gchar *buffer;
            short *rates;
            int nrates;

            /* query rates for this size */
            rates = XRRConfigRates (sc, i, &nrates);

            for (j = 0; j < nrates; j++)
            {
                buffer = g_strdup_printf (_("%dx%d@%d"), sizes[i].width, sizes[i].height, (int) rates[j]);

                if (i != default_size || rates[j] != default_rate)
                {
                    gtk_list_store_append (store, &iter);
                    gtk_list_store_set (store, &iter,
                                        NAME_COLUMN, buffer,
                                        SIZE_COLUMN, (int) i, RATE_COLUMN, (int) rates[j],
                                        -1);

                    if (i == current_size && rates[j] == current_rate)
                    {
                        path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
                        gtk_tree_view_set_cursor (GTK_TREE_VIEW (treeview), path, 0, FALSE);
                        gtk_tree_path_free (path);
                    }
                }

                g_free (buffer);
            }
        }

        /* no longer needed */
        XRRFreeScreenConfigInfo (sc);

        /* connect the changed callback */
        g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (changedCB), itf);

        /* Store values to revert to */
        itf->original_size = current_size;
        itf->original_rate = current_rate;
#endif /* !USE_XRANDR */
    }
    else
    {
        /*
         * either no XRandr support compiled in, or no Xrandr
         * available for the display we are running on
         */
        gtk_widget_set_sensitive (treeview, FALSE);
    }

    /* treeview now keeps a reference on the backstore */
    g_object_unref (G_OBJECT (store));

    /* gamma settings */
    vbox = gtk_vbox_new (FALSE, BORDER);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER);
    frame = xfce_create_framebox_with_content (_("Gamma correction"), vbox);
    gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);

    /* */
    table = gtk_table_new (3, 3, FALSE);
    gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);

    /* Red */
    rlabel = gtk_label_new (_("Red"));
    gtk_table_attach (GTK_TABLE (table), rlabel, 0, 1, 0, 1, GTK_FILL, GTK_FILL, BORDER, BORDER);
    itf->rscale = rscale = gtk_vscale_new_with_range (GAMMA_MIN, GAMMA_MAX, 0.01);
    gtk_range_set_inverted (GTK_RANGE (rscale), TRUE);
    gtk_range_set_value (GTK_RANGE (rscale), redValue / 100.0);
    gtk_scale_set_digits (GTK_SCALE (rscale), 2);
    gtk_scale_set_draw_value (GTK_SCALE (rscale), TRUE);
    gtk_scale_set_value_pos (GTK_SCALE (rscale), GTK_POS_BOTTOM);
    gtk_table_attach (GTK_TABLE (table), rscale, 0, 1, 1, 2, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);

    /* Green */
    glabel = gtk_label_new (_("Green"));
    gtk_table_attach (GTK_TABLE (table), glabel, 1, 2, 0, 1, GTK_FILL, GTK_FILL, BORDER, BORDER);
    itf->gscale = gscale = gtk_vscale_new_with_range (GAMMA_MIN, GAMMA_MAX, 0.01);
    gtk_range_set_value (GTK_RANGE (gscale), greenValue / 100.0);
    gtk_range_set_inverted (GTK_RANGE (gscale), TRUE);
    gtk_scale_set_digits (GTK_SCALE (gscale), 2);
    gtk_scale_set_draw_value (GTK_SCALE (gscale), TRUE);
    gtk_scale_set_value_pos (GTK_SCALE (gscale), GTK_POS_BOTTOM);
    gtk_table_attach (GTK_TABLE (table), gscale, 1, 2, 1, 2, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);

    /* Blue */
    blabel = gtk_label_new (_("Blue"));
    gtk_table_attach (GTK_TABLE (table), blabel, 2, 3, 0, 1, GTK_FILL, GTK_FILL, BORDER, BORDER);
    itf->bscale = bscale = gtk_vscale_new_with_range (GAMMA_MIN, GAMMA_MAX, 0.01);
    gtk_range_set_value (GTK_RANGE (bscale), blueValue / 100.0);
    gtk_range_set_inverted (GTK_RANGE (bscale), TRUE);
    gtk_scale_set_digits (GTK_SCALE (bscale), 2);
    gtk_scale_set_draw_value (GTK_SCALE (bscale), TRUE);
    gtk_scale_set_value_pos (GTK_SCALE (bscale), GTK_POS_BOTTOM);
    gtk_table_attach (GTK_TABLE (table), bscale, 2, 3, 1, 2, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);

    /* */
    itf->synctoggle = checkbox = gtk_check_button_new_with_label (_("Sync sliders"));
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), syncGamma);
    gtk_table_attach (GTK_TABLE (table), checkbox, 0, 3, 2, 3, GTK_FILL, GTK_FILL, 0, BORDER);

#ifdef USE_XF86VM
    if (haveXxf86vm)
    {
        /* Store values to revert to */
        itf->original_rgamma = redValue;
        itf->original_ggamma = greenValue;
        itf->original_bgamma = blueValue;
        itf->original_sync = syncGamma;

        g_signal_connect (G_OBJECT (rscale), "value-changed", G_CALLBACK (redChangedCB), itf);
        g_signal_connect (G_OBJECT (gscale), "value-changed", G_CALLBACK (greenChangedCB), itf);
        g_signal_connect (G_OBJECT (bscale), "value-changed", G_CALLBACK (blueChangedCB), itf);
        g_signal_connect (G_OBJECT (checkbox), "toggled", G_CALLBACK (syncGammaChangedCB), itf);
    }
    else
#endif
    {
        gtk_widget_set_sensitive (rlabel, FALSE);
        gtk_widget_set_sensitive (rscale, FALSE);
        gtk_widget_set_sensitive (glabel, FALSE);
        gtk_widget_set_sensitive (gscale, FALSE);
        gtk_widget_set_sensitive (blabel, FALSE);
        gtk_widget_set_sensitive (bscale, FALSE);
        gtk_widget_set_sensitive (checkbox, FALSE);
    }


    /* */
    gtk_widget_realize (dialog);
    gdk_x11_window_set_user_time(GTK_WIDGET (dialog)->window, 
            gdk_x11_get_server_time (GTK_WIDGET (dialog)->window));
    gtk_widget_show_all (dialog);
}

/* */
MCS_PLUGIN_CHECK_INIT


syntax highlighted by Code2HTML, v. 0.9.1