~charlesk/ido/lp-921065

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
 * Copyright 2010 Canonical, Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of either or both of the following licenses:
 *
 * 1) the GNU Lesser General Public License version 3, as published by the
 * Free Software Foundation; and/or
 * 2) the GNU Lesser General Public License version 2.1, as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the applicable version of the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of both the GNU Lesser General Public
 * License version 3 and version 2.1 along with this program.  If not, see
 * <http://www.gnu.org/licenses/>
 *
 * Authors:
 *    Cody Russell <crussell@canonical.com>
 */

#include "idorange.h"
#include "idotypebuiltins.h"
#include "config.h"

struct _IdoRangePrivate
{
  IdoRangeStyle style;
};

static void ido_range_constructed    (GObject          *object);
static void ido_range_set_property   (GObject          *object,
                                      guint             prop_id,
                                      const GValue     *value,
                                      GParamSpec       *pspec);
static void ido_range_get_property   (GObject          *object,
                                      guint             prop_id,
                                      GValue           *value,
                                      GParamSpec       *pspec);
#ifdef USE_GTK3
static void ido_range_grab_notify    (GtkWidget        *widget,
                                      gboolean          was_grabbed);
#endif

#define IDO_RANGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDO_TYPE_RANGE, IdoRangePrivate))

G_DEFINE_TYPE (IdoRange, ido_range, GTK_TYPE_SCALE)

enum {
  PROP_0,
  PROP_STYLE
};

static void
ido_range_class_init (IdoRangeClass *class)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);

  gobject_class->constructed  = ido_range_constructed;
  gobject_class->set_property = ido_range_set_property;
  gobject_class->get_property = ido_range_get_property;

#ifdef USE_GTK3
  widget_class->grab_notify = ido_range_grab_notify;
#endif

  g_object_class_install_property (gobject_class,
                                   PROP_STYLE,
                                   g_param_spec_enum ("range-style",
                                                      "Range style",
                                                      "The style of the range",
                                                      IDO_TYPE_RANGE_STYLE,
                                                      IDO_RANGE_STYLE_SMALL,
                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("knob-width",
                                                             "The knob width",
                                                             "The knob width",
                                                             G_MININT,
                                                             G_MAXINT,
                                                             8,
                                                             G_PARAM_READABLE));

  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("knob-height",
                                                             "The knob height",
                                                             "The knob height",
                                                             G_MININT,
                                                             G_MAXINT,
                                                             8,
                                                             G_PARAM_READABLE));

  g_type_class_add_private (class, sizeof (IdoRangePrivate));
}

static void
ido_range_get_property (GObject      *object,
                        guint         prop_id,
                        GValue       *value,
                        GParamSpec   *pspec)
{
  IdoRangePrivate *priv = IDO_RANGE (object)->priv;

  switch (prop_id)
    {
    case PROP_STYLE:
      g_value_set_enum (value, priv->style);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
ido_range_set_property (GObject      *object,
                        guint         prop_id,
                        const GValue *value,
                        GParamSpec   *pspec)
{
  IdoRangePrivate *priv = IDO_RANGE (object)->priv;

  switch (prop_id)
    {
    case PROP_STYLE:
      priv->style = g_value_get_enum (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

#ifdef USE_GTK3
static void
ido_range_grab_notify (GtkWidget *widget, gboolean was_grabbed)
{
  /*
   * FIXME: workaround for lp bug #865122.
   * Without this handler, GtkRange will call remove_grab which results
   * in an infinite loop of grab_notifies.
   *
   * The widget will still work properly, because grab-broken-event will get
   * properly fired and internal state of GtkRange will be properly updated.
   */
}
#endif

static void
ido_range_constructed (GObject *object)
{
  IdoRange *range = IDO_RANGE (object);
  IdoRangeStyle style;
  char buf[1024];

  g_object_get (range,
                "range-style", &style,
                NULL);

  g_snprintf (buf, sizeof (buf), "idorange-%p", range);
  gtk_widget_set_name (GTK_WIDGET (range), buf);

  if (style == IDO_RANGE_STYLE_SMALL)
    {
      gint width, height;

      gtk_widget_style_get (GTK_WIDGET (range),
                            "knob-width", &width,
                            "knob-height", &height,
                            NULL);

#ifndef USE_GTK3
      g_snprintf (buf, sizeof (buf),
                  "style \"ido-range\" {\n"
                  "  GtkRange::slider-width = %d\n"
                  "  GtkScale::slider-length = %d\n"
                  "} widget \"*.idorange-%p\" style \"ido-range\"\n",
                  width, height, range);
      gtk_rc_parse_string (buf);
#endif
    }

  gtk_range_set_slider_size_fixed (GTK_RANGE (range), TRUE);
}

static void
ido_range_init (IdoRange *range)
{
  range->priv = IDO_RANGE_GET_PRIVATE (range);
}

/**
 * ido_range_new:
 * @adj: A #GtkAdjustment providing the range values
 * @style: The range style
 *
 * Creates a new #IdoRange widget.
 **/
GtkWidget *
ido_range_new (GObject *adj,
               IdoRangeStyle  style)
{
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adj), NULL);

  return g_object_new (IDO_TYPE_RANGE,
                       "orientation", GTK_ORIENTATION_HORIZONTAL,
                       "adjustment",  adj,
                       "range-style", style,
                       NULL);
}