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