XRRSetScreenConfigAndRate 实例

#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"

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

/* settings */
static int sizeIndex = 0;
static int rateIndex = 0;
static int redValue = 100;
static int greenValue = 100;
static int blueValue = 100;
static gboolean syncGamma = TRUE;

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

/* */
static GtkWidget *dialog = NULL;
static GtkWidget *rscale = NULL;
static GtkWidget *gscale = NULL;
static GtkWidget *bscale = NULL;

/* 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;
      }
}
#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))
    {
        /* restore resolution and rate */
        if ((sc = XRRGetScreenInfo (GDK_DISPLAY (), GDK_ROOT_WINDOW ())))
        {
            change_size_and_rate (sc, sizeIndex, rateIndex);
            XRRFreeScreenConfigInfo (sc);
        }

        /* remember that we can use the Xrandr extension */
        haveXrandr = TRUE;
    }
#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");
    plugin->caption = g_strdup (_("Display"));
    plugin->run_dialog = run_dialog;
    plugin->icon = xfce_themed_icon_load ("xfce4-display", 48);

    save_settings (plugin);

    return (MCS_PLUGIN_INIT_OK);
}

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

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

    return (result);
}

#ifdef USE_XRANDR
/*
 */
static void
changedCB (GtkTreeSelection * selection, McsPlugin * plugin)
{
    XRRScreenConfiguration *sc;
    GtkTreeModel *store;
    GtkTreeIter iter;

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

    gtk_tree_model_get (store, &iter, RATE_COLUMN, &rateIndex, SIZE_COLUMN, &sizeIndex, -1);

    /* apply settings */
    sc = XRRGetScreenInfo (GDK_DISPLAY (), GDK_ROOT_WINDOW ());
    change_size_and_rate (sc, sizeIndex, rateIndex);
    XRRFreeScreenConfigInfo (sc);

    /* and remember the settings */
    mcs_manager_set_int (plugin->manager, "XDisplay/rate", CHANNEL, rateIndex);
    mcs_manager_set_int (plugin->manager, "XDisplay/size", CHANNEL, sizeIndex);
    mcs_manager_notify (plugin->manager, CHANNEL);
    save_settings (plugin);
}
#endif

#ifdef USE_XF86VM
/*
 */
static void
redChangedCB (GtkRange * range, McsPlugin * plugin)
{
    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 (gscale), value);

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

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

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

/*
 */
static void
greenChangedCB (GtkRange * range, McsPlugin * plugin)
{
    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 (rscale), value);

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

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

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

/*
 */
static void
blueChangedCB (GtkRange * range, McsPlugin * plugin)
{
    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 (rscale), value);

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

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

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

/*
 */
static void
syncGammaChangedCB (GtkToggleButton * button, McsPlugin * plugin)
{
    gint value;

    syncGamma = gtk_toggle_button_get_active (button);

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

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

#endif /* !USE_XF86VM */

/*
 */
static void
responseCB (GtkWidget * widget, gint response, McsPlugin * plugin)
{
    switch (response)
    {
        case GTK_RESPONSE_CANCEL:
            /* revert settings */
            gtk_range_set_value (GTK_RANGE (rscale), 1.0);
            gtk_range_set_value (GTK_RANGE (gscale), 1.0);
            gtk_range_set_value (GTK_RANGE (bscale), 1.0);
            break;

        default:
            gtk_widget_destroy (dialog);
            dialog = NULL;
    }
}

/*
 */
static void
run_dialog (McsPlugin * plugin)
{
    GtkTreeSelection *selection;
    GtkListStore *store;
    GtkWidget *revert;
    GtkWidget *close;
    GtkWidget *header;
    GtkWidget *hbox;
    GtkWidget *align;
    GtkWidget *frame;
    GtkWidget *vbox;
    GtkWidget *treeview;
    GtkWidget *scrollwin;
    GtkWidget *table;
    GtkWidget *rlabel;
    GtkWidget *glabel;
    GtkWidget *blabel;
    GtkWidget *checkbox;

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

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

    dialog = gtk_dialog_new_with_buttons (_("Display Preferences"), NULL, GTK_DIALOG_NO_SEPARATOR, NULL);

    /* 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_icon (GTK_WINDOW (dialog), plugin->icon);
    gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
    gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

    g_signal_connect_swapped (dialog, "response", G_CALLBACK (responseCB), plugin);

    header = xfce_create_header (plugin->icon, _("Display Preferences"));
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), header, FALSE, TRUE, 0);

    /* */
    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 */
    frame = xfce_framebox_new (_("Resolution"), TRUE);
    gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);

    vbox = gtk_vbox_new (FALSE, BORDER);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER);
    xfce_framebox_add (XFCE_FRAMEBOX (frame), vbox);

    /* 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 */
    store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);

    /* create tree view */
    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;

        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);

        /* fill store */
        for (i = 0; i < nsizes; i++)
        {
            GtkTreeIter iter;
            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]);

                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)
                {
                    GtkTreePath *path;

                    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), plugin);
#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 */
    frame = xfce_framebox_new (_("Gamma correction"), TRUE);
    gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);

    vbox = gtk_vbox_new (FALSE, BORDER);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER);
    xfce_framebox_add (XFCE_FRAMEBOX (frame), vbox);

    /* */
    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);
    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);
    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);
    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);

    /* */
    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)
    {
        g_signal_connect (G_OBJECT (rscale), "value-changed", G_CALLBACK (redChangedCB), plugin);
        g_signal_connect (G_OBJECT (gscale), "value-changed", G_CALLBACK (greenChangedCB), plugin);
        g_signal_connect (G_OBJECT (bscale), "value-changed", G_CALLBACK (blueChangedCB), plugin);
        g_signal_connect (G_OBJECT (checkbox), "toggled", G_CALLBACK (syncGammaChangedCB), plugin);
    }
    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);
    }


    /* */
    xfce_gtk_window_center_on_monitor_with_pointer (GTK_WINDOW (dialog));
    gtk_widget_show_all (dialog);
}

你可能感兴趣的:(manager,tree,table,dialog,border,gtk)