1 /*
2 roxterm - VTE/GTK terminal emulator with tabs
3 Copyright (C) 2004-2015 Tony Houghton <h@realh.co.uk>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "multitab-label.h"
21
22 G_DEFINE_TYPE (MultitabLabel, multitab_label, GTK_TYPE_EVENT_BOX);
23
24 #define PROP_TEXT 1
25 #define PROP_ATTENTION_COLOR 2
26
27 static void
multitab_label_set_property(GObject * object,guint prop,const GValue * value,GParamSpec * pspec)28 multitab_label_set_property (GObject *object, guint prop,
29 const GValue *value, GParamSpec *pspec)
30 {
31 const GdkRGBA *color;
32 MultitabLabel *self = MULTITAB_LABEL (object);
33
34 switch (prop)
35 {
36 case PROP_TEXT:
37 multitab_label_set_text (self, g_value_get_string (value));
38 break;
39 case PROP_ATTENTION_COLOR:
40 color = g_value_get_pointer (value);
41 multitab_label_set_attention_color (self, color);
42 break;
43 default:
44 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop, pspec);
45 break;
46 }
47 }
48
49 static void
multitab_label_get_property(GObject * object,guint prop,GValue * value,GParamSpec * pspec)50 multitab_label_get_property (GObject *object, guint prop,
51 GValue *value, GParamSpec *pspec)
52 {
53 MultitabLabel *self = MULTITAB_LABEL (object);
54
55 switch (prop)
56 {
57 case PROP_TEXT:
58 g_value_set_string (value, multitab_label_get_text (self));
59 break;
60 case PROP_ATTENTION_COLOR:
61 g_value_set_pointer (value, &self->attention_color);
62 break;
63 default:
64 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop, pspec);
65 break;
66 }
67 }
68
69 static gboolean
multitab_label_draw(GtkWidget * widget,cairo_t * cr)70 multitab_label_draw (GtkWidget *widget, cairo_t *cr)
71 {
72 MultitabLabel *self = MULTITAB_LABEL (widget);
73 if (self->attention)
74 {
75 cairo_set_source_rgb(cr, self->attention_color.red,
76 self->attention_color.green,
77 self->attention_color.blue);
78 cairo_paint(cr);
79 }
80 return GTK_WIDGET_CLASS (multitab_label_parent_class)->draw (widget, cr);
81 }
82
83 static gboolean
multitab_label_toggle_attention(gpointer data)84 multitab_label_toggle_attention (gpointer data)
85 {
86 MultitabLabel *self = MULTITAB_LABEL (data);
87
88 self->attention = !self->attention;
89 gtk_widget_queue_draw (GTK_WIDGET (data));
90 return TRUE;
91 }
92
93 static void
multitab_label_destroy(GtkWidget * w)94 multitab_label_destroy (GtkWidget *w)
95 {
96 multitab_label_cancel_attention (MULTITAB_LABEL (w));
97 GTK_WIDGET_CLASS (multitab_label_parent_class)->destroy (w);
98 }
99
100
101 #define MULTITAB_LABEL_FIXED_WIDTH 200
102
103 static void
multitab_label_modify_width(MultitabLabel * self,gint * minimum_width,gint * natural_width)104 multitab_label_modify_width(MultitabLabel *self,
105 gint *minimum_width, gint *natural_width)
106 {
107 if (self->single)
108 {
109 if (*minimum_width < MULTITAB_LABEL_FIXED_WIDTH)
110 *minimum_width = MULTITAB_LABEL_FIXED_WIDTH;
111 *natural_width = MAX(*natural_width, MULTITAB_LABEL_FIXED_WIDTH);
112 }
113 }
114
115
116 static void
multitab_label_get_preferred_width(GtkWidget * widget,gint * minimum_width,gint * natural_width)117 multitab_label_get_preferred_width (GtkWidget *widget,
118 gint *minimum_width, gint *natural_width)
119 {
120 MultitabLabel *self = MULTITAB_LABEL (widget);
121
122 GTK_WIDGET_CLASS (multitab_label_parent_class)->get_preferred_width
123 (widget, minimum_width, natural_width);
124 multitab_label_modify_width (self, minimum_width, natural_width);
125 }
126
127 static void
multitab_label_get_preferred_width_for_height(GtkWidget * widget,gint height,gint * minimum_width,gint * natural_width)128 multitab_label_get_preferred_width_for_height (GtkWidget *widget,
129 gint height, gint *minimum_width, gint *natural_width)
130 {
131 MultitabLabel *self = MULTITAB_LABEL (widget);
132
133 GTK_WIDGET_CLASS
134 (multitab_label_parent_class)->get_preferred_width_for_height
135 (widget, height, minimum_width, natural_width);
136 multitab_label_modify_width (self, minimum_width, natural_width);
137 }
138
139 static void
multitab_label_class_init(MultitabLabelClass * klass)140 multitab_label_class_init(MultitabLabelClass *klass)
141 {
142 GObjectClass *oclass = G_OBJECT_CLASS (klass);
143 GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass);
144 GParamSpec *pspec;
145
146 /* Make sure theme doesn't override our colour with a gradient or image */
147 static const char *style =
148 "MultitabLabel {\n"
149 "background-image : none;\n"
150 "}";
151
152 klass->style_provider = gtk_css_provider_new ();
153 gtk_css_provider_load_from_data (klass->style_provider,
154 style, -1, NULL);
155
156 wclass->destroy = multitab_label_destroy;
157 wclass->draw = multitab_label_draw;
158 wclass->get_preferred_width = multitab_label_get_preferred_width;
159 wclass->get_preferred_width_for_height =
160 multitab_label_get_preferred_width_for_height;
161 gtk_widget_class_set_css_name (wclass, "multitab-label");
162
163 oclass->set_property = multitab_label_set_property;
164 oclass->get_property = multitab_label_get_property;
165
166 pspec = g_param_spec_string ("text",
167 "Text", "Text displayed in the label",
168 "",
169 G_PARAM_READWRITE);
170 g_object_class_install_property (oclass, PROP_TEXT, pspec);
171
172 pspec = g_param_spec_pointer ("attention-color",
173 "Attention Color", "Color to flash to draw attention",
174 G_PARAM_READWRITE);
175 g_object_class_install_property (oclass, PROP_ATTENTION_COLOR, pspec);
176
177 }
178
179 static void
multitab_label_init(MultitabLabel * self)180 multitab_label_init(MultitabLabel *self)
181 {
182 GtkWidget *label = gtk_label_new ("");
183 GtkWidget *w = GTK_WIDGET(self);
184 static GdkRGBA amber;
185 static gboolean parsed_amber = FALSE;
186
187 self->single = FALSE;
188 self->parent = NULL;
189 #if MULTITAB_LABEL_GTK3_SIZE_KLUDGE
190 self->best_width = NULL;
191 #endif
192 gtk_style_context_add_provider (gtk_widget_get_style_context (w),
193 GTK_STYLE_PROVIDER (MULTITAB_LABEL_GET_CLASS
194 (self)->style_provider),
195 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
196 if (!parsed_amber)
197 {
198 gdk_rgba_parse(&amber, "#ffc450");
199 parsed_amber = TRUE;
200 }
201 gtk_event_box_set_visible_window (GTK_EVENT_BOX (self), FALSE);
202 multitab_label_set_attention_color (self, &amber);
203 self->label = GTK_LABEL (label);
204 gtk_label_set_ellipsize (self->label, PANGO_ELLIPSIZE_MIDDLE);
205 gtk_widget_show (label);
206 gtk_container_add (GTK_CONTAINER (self), label);
207 }
208
209 GtkWidget *
multitab_label_new(GtkWidget * parent,const char * text,int * best_width)210 multitab_label_new (GtkWidget *parent, const char *text, int *best_width)
211 {
212 MultitabLabel *self = (MultitabLabel *)
213 g_object_new (MULTITAB_TYPE_LABEL, NULL);
214
215 self->parent = parent;
216 if (text)
217 multitab_label_set_text (self, text);
218 self->best_width = best_width;
219 return GTK_WIDGET (self);
220 }
221
222 void
multitab_label_set_parent(MultitabLabel * self,GtkWidget * parent,int * best_width)223 multitab_label_set_parent (MultitabLabel *self,
224 GtkWidget *parent, int *best_width)
225 {
226 self->parent = parent;
227 self->best_width = best_width;
228 }
229
230 void
multitab_label_set_text(MultitabLabel * self,const char * text)231 multitab_label_set_text (MultitabLabel *self, const char *text)
232 {
233 gtk_label_set_text (self->label, text);
234 }
235
236 const char *
multitab_label_get_text(MultitabLabel * self)237 multitab_label_get_text (MultitabLabel *self)
238 {
239 return gtk_label_get_text (self->label);
240 }
241
242 void
multitab_label_draw_attention(MultitabLabel * self)243 multitab_label_draw_attention (MultitabLabel *self)
244 {
245 multitab_label_cancel_attention (self);
246 multitab_label_toggle_attention (self);
247 self->timeout_tag = g_timeout_add (500,
248 multitab_label_toggle_attention, self);
249 }
250
251 void
multitab_label_cancel_attention(MultitabLabel * self)252 multitab_label_cancel_attention (MultitabLabel *self)
253 {
254 if (self->timeout_tag)
255 {
256 g_source_remove (self->timeout_tag);
257 self->timeout_tag = 0;
258 }
259 if (self->attention)
260 {
261 multitab_label_toggle_attention (self);
262 }
263 }
264
265 void
multitab_label_set_attention_color(MultitabLabel * self,const GdkRGBA * color)266 multitab_label_set_attention_color (MultitabLabel *self,
267 const GdkRGBA *color)
268 {
269 self->attention_color = *color;
270 }
271
272 const GdkRGBA *
multitab_label_get_attention_color(MultitabLabel * self)273 multitab_label_get_attention_color (MultitabLabel *self)
274 {
275 return &self->attention_color;
276 }
277
278 void
multitab_label_set_single(MultitabLabel * self,gboolean single)279 multitab_label_set_single (MultitabLabel *self, gboolean single)
280 {
281
282 if (single != self->single)
283 {
284 self->single = single;
285 #if GTK_CHECK_VERSION(3, 0, 0)
286 if (self->label)
287 g_object_set(self->label, "hexpand", !single, NULL);
288 #endif
289 gtk_widget_queue_resize (GTK_WIDGET (self));
290 }
291 }
292
293 void
multitab_label_set_current(MultitabLabel * label,gboolean current)294 multitab_label_set_current(MultitabLabel *label, gboolean current)
295 {
296 gtk_widget_set_sensitive(GTK_WIDGET(label->label), current);
297 }
298