diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2011-01-07 21:04:07 +1000 |
---|---|---|
committer | Bastien Nocera <hadess@hadess.net> | 2011-08-26 11:35:27 +0100 |
commit | 7b213472f199333d08ba3840cd2e2b6475d62961 (patch) | |
tree | 409b4e928bf91cb8a4aa97d77af668a1e6f47e7b /panels/wacom/cc-wacom-panel.c | |
parent | a999160bf7db5aa6a4ac05628c8003abec31c8c1 (diff) | |
download | gnome-control-center-7b213472f199333d08ba3840cd2e2b6475d62961.tar.gz |
wacom: add a wacom control panel.
https://bugzilla.gnome.org/show_bug.cgi?id=640981
Diffstat (limited to 'panels/wacom/cc-wacom-panel.c')
-rw-r--r-- | panels/wacom/cc-wacom-panel.c | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/panels/wacom/cc-wacom-panel.c b/panels/wacom/cc-wacom-panel.c new file mode 100644 index 000000000..5d0478cef --- /dev/null +++ b/panels/wacom/cc-wacom-panel.c @@ -0,0 +1,434 @@ +/* + * Copyright © 2011 Red Hat, Inc. + * + * 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; either version 2 of the License, or + * (at your option) any later 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Peter Hutterer <peter.hutterer@redhat.com> + * + */ + +#include <config.h> + +#include "cc-wacom-panel.h" +#include <gtk/gtk.h> + +#include <string.h> + +#define WID(x) (GtkWidget *) gtk_builder_get_object (dialog, x) + +G_DEFINE_DYNAMIC_TYPE (CcWacomPanel, cc_wacom_panel, CC_TYPE_PANEL) + +#define WACOM_PANEL_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_WACOM_PANEL, CcWacomPanelPrivate)) + +struct _CcWacomPanelPrivate +{ + GtkBuilder *builder; + GSettings *wacom_settings; + GSettings *stylus_settings; + GSettings *eraser_settings; + /* The UI doesn't support cursor/pad at the moment */ +}; + +/* Button combo box storage columns */ +enum { + BUTTONNUMBER_COLUMN, + BUTTONNAME_COLUMN, + N_BUTTONCOLUMNS +}; + +/* Tablet mode combo box storage columns */ +enum { + MODENUMBER_COLUMN, + MODELABEL_COLUMN, + N_MODECOLUMNS +}; + +/* Tablet mode options - keep in sync with .ui */ +enum { + MODE_ABSOLUTE, /* stylus + eraser absolute */ + MODE_RELATIVE, /* stylus + eraser relative */ +}; + +/* GSettings stores pressurecurve as 4 values like the driver. We map slider + * scale to these values given the array below. These settings were taken from + * wacomcpl, where they've been around for years. + */ +#define N_PRESSURE_CURVES 7 +static const gint32 PRESSURE_CURVES[N_PRESSURE_CURVES][4] = { + { 0, 75, 25, 100 }, /* soft */ + { 0, 50, 50, 100 }, + { 0, 25, 75, 100 }, + { 0, 0, 100, 100 }, /* neutral */ + { 25, 0, 100, 75 }, + { 50, 0, 100, 50 }, + { 75, 0, 100, 25 } /* firm */ +}; + +static void +set_pressurecurve (GtkRange *range, GSettings *settings) +{ + gint slider_val = gtk_range_get_value (range); + GVariant *values[4], + *array; + int i; + + for (i = 0; i < 4; i++) + values[i] = g_variant_new_int32 (PRESSURE_CURVES[slider_val][i]); + + array = g_variant_new_array (G_VARIANT_TYPE_INT32, values, 4); + + g_settings_set_value (settings, "pressurecurve", array); + + g_variant_unref (array); +} + +static void +tip_feel_value_changed_cb (GtkRange *range, gpointer user_data) +{ + set_pressurecurve (range, CC_WACOM_PANEL(user_data)->priv->stylus_settings); +} + +static void +eraser_feel_value_changed_cb (GtkRange *range, gpointer user_data) +{ + set_pressurecurve (range, CC_WACOM_PANEL(user_data)->priv->eraser_settings); +} + +static void +set_feel_from_gsettings (GtkAdjustment *adjustment, GSettings *settings) +{ + GVariant *variant; + const gint32 *values; + gsize nvalues; + int i; + + variant = g_settings_get_value (settings, "pressurecurve"); + values = g_variant_get_fixed_array (variant, &nvalues, sizeof (gint32)); + + if (nvalues != 4) { + g_warning ("Invalid pressure curve format, expected 4 values (got %ld)", nvalues); + return; + } + + for (i = 0; i < N_PRESSURE_CURVES; i++) { + if (memcmp (PRESSURE_CURVES[i], values, sizeof (gint32) * 4) == 0) { + gtk_adjustment_set_value (adjustment, i); + break; + } + } +} + +static void +tabletmode_changed_cb (GtkComboBox *combo, gpointer user_data) +{ + CcWacomPanelPrivate *priv = CC_WACOM_PANEL(user_data)->priv; + GtkBuilder *dialog = GTK_BUILDER (priv->builder); + GtkListStore *liststore; + GtkTreeIter iter; + gint mode; + + if (!gtk_combo_box_get_active_iter (combo, &iter)) + return; + + liststore = GTK_LIST_STORE (WID ("liststore-tabletmode")); + gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter, + MODENUMBER_COLUMN, &mode, + -1); + switch (mode) + { + case MODE_ABSOLUTE: + g_settings_set_boolean (priv->stylus_settings, "is-absolute", TRUE); + g_settings_set_boolean (priv->eraser_settings, "is-absolute", TRUE); + break; + case MODE_RELATIVE: + g_settings_set_boolean (priv->stylus_settings, "is-absolute", FALSE); + g_settings_set_boolean (priv->eraser_settings, "is-absolute", FALSE); + break; + default: + g_warning ("Ignoring unknown tablet mode %d.\n", mode); + break; + } +} + +static void +set_mode_from_gsettings (GtkComboBox *combo, CcWacomPanel *panel) +{ + CcWacomPanelPrivate *priv = CC_WACOM_PANEL(panel)->priv; + gboolean stylus_is_absolute, + eraser_is_absolute; + + stylus_is_absolute = g_settings_get_boolean (priv->stylus_settings, "is-absolute"); + eraser_is_absolute = g_settings_get_boolean (priv->eraser_settings, "is-absolute"); + + /* this must be kept in sync with the .ui file */ + if (stylus_is_absolute && eraser_is_absolute) + gtk_combo_box_set_active (combo, MODE_ABSOLUTE); + else if (!stylus_is_absolute && !eraser_is_absolute) + gtk_combo_box_set_active (combo, MODE_RELATIVE); + else + gtk_combo_box_set_active (combo, -1); +} + +static void +set_button_mapping_from_gsettings (GtkComboBox *combo, GSettings* settings, gint current_button) +{ + GVariant *current; + gsize nvalues; + const gint *values; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean valid; + + current = g_settings_get_value (settings, "buttonmapping"); + values = g_variant_get_fixed_array (current, &nvalues, sizeof (gint32)); + model = gtk_combo_box_get_model (combo); + valid = gtk_tree_model_get_iter_first (model, &iter); + + while (valid) { + gint button; + + gtk_tree_model_get (model, &iter, + BUTTONNUMBER_COLUMN, &button, + -1); + + /* Currently button values match logical X buttons. If we + * introduce things like double-click, this code must + * change. Recommendation: use negative buttons numbers for + * special ones. + */ + + /* 0 vs 1-indexed array/button numbers */ + if (button == values[current_button - 1]) { + gtk_combo_box_set_active_iter (combo, &iter); + break; + } + + valid = gtk_tree_model_iter_next (model, &iter); + } +} + +static void +map_button (GSettings *settings, int button2, int button3) +{ + GVariant *current; /* current mapping */ + GVariant *array; /* new mapping */ + GVariant **tmp; + gsize nvalues; + const gint *values; + gint i; + + current = g_settings_get_value (settings, "buttonmapping"); + values = g_variant_get_fixed_array (current, &nvalues, sizeof (gint32)); + + tmp = g_malloc (nvalues * sizeof (GVariant*)); + for (i = 0; i < nvalues; i++) { + if (i == 1) /* zero indexed array vs one-indexed buttons */ + tmp[i] = g_variant_new_int32 (button2); + else if (i == 2) + tmp[i] = g_variant_new_int32 (button3); + else + tmp[i] = g_variant_new_int32 (values[i]); + } + + array = g_variant_new_array (G_VARIANT_TYPE_INT32, tmp, nvalues); + g_settings_set_value (settings, "buttonmapping", array); + + g_free (tmp); + g_variant_unref (array); +} + +static void +button_changed_cb (GtkComboBox *combo, gpointer user_data) +{ + CcWacomPanelPrivate *priv = CC_WACOM_PANEL(user_data)->priv; + GtkBuilder *dialog = priv->builder; + GtkTreeIter iter; + GtkListStore *liststore; + gint mapping_b2, + mapping_b3; + + if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (WID ("combo-bottombutton")), &iter)) + return; + + liststore = GTK_LIST_STORE (WID ("liststore-buttons")); + gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter, + BUTTONNUMBER_COLUMN, &mapping_b2, + -1); + + if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (WID ("combo-topbutton")), &iter)) + return; + + gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter, + BUTTONNUMBER_COLUMN, &mapping_b3, + -1); + + map_button (priv->stylus_settings, mapping_b2, mapping_b3); +} + +static void +combobox_text_cellrenderer (GtkComboBox *combo, int name_column) +{ + GtkCellRenderer *renderer; + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, + "text", BUTTONNAME_COLUMN, NULL); +} + +static void +gnome_wacom_properties_init (CcWacomPanel *panel) +{ + CcWacomPanelPrivate *priv = CC_WACOM_PANEL(panel)->priv; + GtkBuilder *dialog = priv->builder; + GtkComboBox *combo; + + priv->wacom_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.wacom"); + priv->stylus_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.wacom.stylus"); + priv->eraser_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.wacom.eraser"); + + g_signal_connect (WID ("scale-tip-feel"), "value-changed", + G_CALLBACK (tip_feel_value_changed_cb), panel); + g_signal_connect (WID ("scale-eraser-feel"), "value-changed", + G_CALLBACK (eraser_feel_value_changed_cb), panel); + + combo = GTK_COMBO_BOX (WID ("combo-topbutton")); + combobox_text_cellrenderer (combo, BUTTONNAME_COLUMN); + g_signal_connect (G_OBJECT (combo), "changed", + G_CALLBACK (button_changed_cb), panel); + + combo = GTK_COMBO_BOX (WID ("combo-bottombutton")); + combobox_text_cellrenderer (combo, BUTTONNAME_COLUMN); + g_signal_connect (G_OBJECT (combo), "changed", + G_CALLBACK (button_changed_cb), panel); + + combo = GTK_COMBO_BOX (WID ("combo-tabletmode")); + combobox_text_cellrenderer (combo, MODELABEL_COLUMN); + g_signal_connect (G_OBJECT (combo), "changed", + G_CALLBACK (tabletmode_changed_cb), panel); + + set_button_mapping_from_gsettings (GTK_COMBO_BOX (WID ("combo-topbutton")), priv->stylus_settings, 3); + set_button_mapping_from_gsettings (GTK_COMBO_BOX (WID ("combo-bottombutton")), priv->stylus_settings, 2); + set_mode_from_gsettings (GTK_COMBO_BOX (WID ("combo-tabletmode")), panel); + set_feel_from_gsettings (GTK_ADJUSTMENT (WID ("adjustment-tip-feel")), priv->stylus_settings); + set_feel_from_gsettings (GTK_ADJUSTMENT (WID ("adjustment-eraser-feel")), priv->eraser_settings); + + gtk_image_set_from_file (GTK_IMAGE (WID ("image-tablet")), PIXMAP_DIR "/wacom-tablet.png"); + gtk_image_set_from_file (GTK_IMAGE (WID ("image-stylus")), PIXMAP_DIR "/wacom-stylus.png"); +} + +/* Boilerplate code goes below */ + +static void +cc_wacom_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_wacom_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_wacom_panel_dispose (GObject *object) +{ + CcWacomPanelPrivate *priv = CC_WACOM_PANEL (object)->priv; + + if (priv->builder) + { + g_object_unref (priv->builder); + priv->builder = NULL; + } + + G_OBJECT_CLASS (cc_wacom_panel_parent_class)->dispose (object); +} + +static void +cc_wacom_panel_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_wacom_panel_parent_class)->finalize (object); +} + +static void +cc_wacom_panel_class_init (CcWacomPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (CcWacomPanelPrivate)); + + object_class->get_property = cc_wacom_panel_get_property; + object_class->set_property = cc_wacom_panel_set_property; + object_class->dispose = cc_wacom_panel_dispose; + object_class->finalize = cc_wacom_panel_finalize; +} + +static void +cc_wacom_panel_class_finalize (CcWacomPanelClass *klass) +{ +} + +static void +cc_wacom_panel_init (CcWacomPanel *self) +{ + CcWacomPanelPrivate *priv; + GtkWidget *grid; + GError *error = NULL; + + priv = self->priv = WACOM_PANEL_PRIVATE (self); + + priv->builder = gtk_builder_new (); + + gtk_builder_add_from_file (priv->builder, + GNOMECC_UI_DIR "/gnome-wacom-properties.ui", + &error); + if (error != NULL) + { + g_warning ("Error loading UI file: %s", error->message); + g_object_unref (priv->builder); + return; + } + + gnome_wacom_properties_init (self); + + grid = (GtkWidget*) gtk_builder_get_object (priv->builder, "main-grid"); + + gtk_widget_reparent (grid, GTK_WIDGET (self)); +} + +void +cc_wacom_panel_register (GIOModule *module) +{ + cc_wacom_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, + CC_TYPE_WACOM_PANEL, "wacom", 0); +} + |