~ubuntu-branches/ubuntu/precise/gnome-control-center/precise-updates

« back to all changes in this revision

Viewing changes to panels/user-accounts/um-utils.c

Tags: upstream-3.0.1.1
ImportĀ upstreamĀ versionĀ 3.0.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright 2009-2010  Red Hat, Inc,
 
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 3 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
 * Written by: Matthias Clasen <mclasen@redhat.com>
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <math.h>
 
25
 
 
26
#include <glib.h>
 
27
#include <glib/gi18n.h>
 
28
 
 
29
#include "um-utils.h"
 
30
 
 
31
typedef struct {
 
32
        gchar *text;
 
33
        gchar *placeholder_str;
 
34
        GIcon *icon;
 
35
        gunichar placeholder;
 
36
        gulong query_id;
 
37
} IconShapeData;
 
38
 
 
39
static IconShapeData *
 
40
icon_shape_data_new (const gchar *text,
 
41
                     const gchar *placeholder,
 
42
                     GIcon       *icon)
 
43
{
 
44
        IconShapeData *data;
 
45
 
 
46
        data = g_new0 (IconShapeData, 1);
 
47
 
 
48
        data->text = g_strdup (text);
 
49
        data->placeholder_str = g_strdup (placeholder);
 
50
        data->placeholder = g_utf8_get_char_validated (placeholder, -1);
 
51
        data->icon = g_object_ref (icon);
 
52
 
 
53
        return data;
 
54
}
 
55
 
 
56
static void
 
57
icon_shape_data_free (gpointer user_data)
 
58
{
 
59
        IconShapeData *data = user_data;
 
60
 
 
61
        g_free (data->text);
 
62
        g_free (data->placeholder_str);
 
63
        g_object_unref (data->icon);
 
64
        g_free (data);
 
65
}
 
66
 
 
67
static void
 
68
icon_shape_renderer (cairo_t        *cr,
 
69
                     PangoAttrShape *attr,
 
70
                     gboolean        do_path,
 
71
                     gpointer        user_data)
 
72
{
 
73
        IconShapeData *data = user_data;
 
74
        gdouble x, y;
 
75
 
 
76
        cairo_get_current_point (cr, &x, &y);
 
77
        if (GPOINTER_TO_UINT (attr->data) == data->placeholder) {
 
78
                gdouble ascent;
 
79
                gdouble height;
 
80
                GdkPixbuf *pixbuf;
 
81
                GtkIconInfo *info;
 
82
 
 
83
                ascent = pango_units_to_double (attr->ink_rect.y);
 
84
                height = pango_units_to_double (attr->ink_rect.height);
 
85
                info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
 
86
                                                       data->icon,
 
87
                                                       (gint)height,
 
88
                                                       GTK_ICON_LOOKUP_FORCE_SIZE | GTK_ICON_LOOKUP_USE_BUILTIN);
 
89
                pixbuf = gtk_icon_info_load_icon (info, NULL);
 
90
                gtk_icon_info_free (info);
 
91
 
 
92
                cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
93
                cairo_reset_clip (cr);
 
94
                gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y + ascent);
 
95
                cairo_paint (cr);
 
96
                g_object_unref (pixbuf);
 
97
        }
 
98
}
 
99
 
 
100
static PangoAttrList *
 
101
create_shape_attr_list_for_layout (PangoLayout   *layout,
 
102
                                   IconShapeData *data)
 
103
{
 
104
        PangoAttrList *attrs;
 
105
        PangoFontMetrics *metrics;
 
106
        gint ascent, descent;
 
107
        PangoRectangle ink_rect, logical_rect;
 
108
        const gchar *p;
 
109
        const gchar *text;
 
110
        gint placeholder_len;
 
111
 
 
112
        /* Get font metrics and prepare fancy shape size */
 
113
        metrics = pango_context_get_metrics (pango_layout_get_context (layout),
 
114
                                             pango_layout_get_font_description (layout),
 
115
                                             NULL);
 
116
        ascent = pango_font_metrics_get_ascent (metrics);
 
117
        descent = pango_font_metrics_get_descent (metrics);
 
118
        pango_font_metrics_unref (metrics);
 
119
 
 
120
        logical_rect.x = 0;
 
121
        logical_rect.y = - ascent;
 
122
        logical_rect.width = ascent + descent;
 
123
        logical_rect.height = ascent + descent;
 
124
 
 
125
        ink_rect = logical_rect;
 
126
 
 
127
        attrs = pango_attr_list_new ();
 
128
        text = pango_layout_get_text (layout);
 
129
        placeholder_len = strlen (data->placeholder_str);
 
130
        for (p = text; (p = strstr (p, data->placeholder_str)); p += placeholder_len) {
 
131
                PangoAttribute *attr;
 
132
 
 
133
                attr = pango_attr_shape_new_with_data (&ink_rect,
 
134
                                                       &logical_rect,
 
135
                                                       GUINT_TO_POINTER (g_utf8_get_char (p)),
 
136
                                                       NULL, NULL);
 
137
 
 
138
                attr->start_index = p - text;
 
139
                attr->end_index = attr->start_index + placeholder_len;
 
140
 
 
141
                pango_attr_list_insert (attrs, attr);
 
142
        }
 
143
 
 
144
        return attrs;
 
145
}
 
146
 
 
147
static gboolean
 
148
query_unlock_tooltip (GtkWidget  *widget,
 
149
                      gint        x,
 
150
                      gint        y,
 
151
                      gboolean    keyboard_tooltip,
 
152
                      GtkTooltip *tooltip,
 
153
                      gpointer    user_data)
 
154
{
 
155
        GtkWidget *label;
 
156
        PangoLayout *layout;
 
157
        PangoAttrList *attrs;
 
158
        IconShapeData *data;
 
159
 
 
160
        data = g_object_get_data (G_OBJECT (widget), "icon-shape-data");
 
161
        label = g_object_get_data (G_OBJECT (widget), "tooltip-label");
 
162
        if (label == NULL) {
 
163
                label = gtk_label_new (data->text);
 
164
                g_object_ref_sink (label);
 
165
                g_object_set_data_full (G_OBJECT (widget),
 
166
                                        "tooltip-label", label, g_object_unref);
 
167
        }
 
168
 
 
169
        layout = gtk_label_get_layout (GTK_LABEL (label));
 
170
        pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout),
 
171
                                                icon_shape_renderer,
 
172
                                                data, NULL);
 
173
 
 
174
        attrs = create_shape_attr_list_for_layout (layout, data);
 
175
        gtk_label_set_attributes (GTK_LABEL (label), attrs);
 
176
        pango_attr_list_unref (attrs);
 
177
 
 
178
        gtk_tooltip_set_custom (tooltip, label);
 
179
 
 
180
        return TRUE;
 
181
}
 
182
 
 
183
void
 
184
setup_tooltip_with_embedded_icon (GtkWidget   *widget,
 
185
                                  const gchar *text,
 
186
                                  const gchar *placeholder,
 
187
                                  GIcon       *icon)
 
188
{
 
189
        IconShapeData *data;
 
190
 
 
191
        data = g_object_get_data (G_OBJECT (widget), "icon-shape-data");
 
192
        if (data) {
 
193
                gtk_widget_set_has_tooltip (widget, FALSE);
 
194
                g_signal_handler_disconnect (widget, data->query_id);
 
195
                g_object_set_data (G_OBJECT (widget), "icon-shape-data", NULL);
 
196
                g_object_set_data (G_OBJECT (widget), "tooltip-label", NULL);
 
197
        }
 
198
 
 
199
        if (!placeholder) {
 
200
                gtk_widget_set_tooltip_text (widget, text);
 
201
                return;
 
202
        }
 
203
 
 
204
        data = icon_shape_data_new (text, placeholder, icon);
 
205
        g_object_set_data_full (G_OBJECT (widget),
 
206
                                "icon-shape-data",
 
207
                                data,
 
208
                                icon_shape_data_free);
 
209
 
 
210
        gtk_widget_set_has_tooltip (widget, TRUE);
 
211
        data->query_id = g_signal_connect (widget, "query-tooltip",
 
212
                                           G_CALLBACK (query_unlock_tooltip), NULL);
 
213
 
 
214
}
 
215
 
 
216
gboolean
 
217
show_tooltip_now (GtkWidget *widget,
 
218
                  GdkEvent  *event)
 
219
{
 
220
        GtkSettings *settings;
 
221
        gint timeout;
 
222
 
 
223
        settings = gtk_widget_get_settings (widget);
 
224
 
 
225
        g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL);
 
226
        g_object_set (settings, "gtk-tooltip-timeout", 1, NULL);
 
227
        gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (widget));
 
228
        g_object_set (settings, "gtk-tooltip-timeout", timeout, NULL);
 
229
 
 
230
        return FALSE;
 
231
}
 
232
 
 
233
static gboolean
 
234
query_tooltip (GtkWidget  *widget,
 
235
               gint        x,
 
236
               gint        y,
 
237
               gboolean    keyboard_mode,
 
238
               GtkTooltip *tooltip,
 
239
               gpointer    user_data)
 
240
{
 
241
        gchar *tip;
 
242
 
 
243
        if (GTK_ENTRY_ICON_SECONDARY == gtk_entry_get_icon_at_pos (GTK_ENTRY (widget), x, y)) {
 
244
                tip = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget),
 
245
                                                       GTK_ENTRY_ICON_SECONDARY);
 
246
                gtk_tooltip_set_text (tooltip, tip);
 
247
                g_free (tip);
 
248
 
 
249
                return TRUE;
 
250
        }
 
251
        else {
 
252
                return FALSE;
 
253
        }
 
254
}
 
255
 
 
256
static void
 
257
icon_released (GtkEntry             *entry,
 
258
              GtkEntryIconPosition  pos,
 
259
              GdkEvent             *event,
 
260
              gpointer              user_data)
 
261
{
 
262
        GtkSettings *settings;
 
263
        gint timeout;
 
264
 
 
265
        settings = gtk_widget_get_settings (GTK_WIDGET (entry));
 
266
 
 
267
        g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL);
 
268
        g_object_set (settings, "gtk-tooltip-timeout", 1, NULL);
 
269
        gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (GTK_WIDGET (entry)));
 
270
        g_object_set (settings, "gtk-tooltip-timeout", timeout, NULL);
 
271
}
 
272
 
 
273
 
 
274
void
 
275
set_entry_validation_error (GtkEntry    *entry,
 
276
                            const gchar *text)
 
277
{
 
278
        g_object_set (entry, "caps-lock-warning", FALSE, NULL);
 
279
        gtk_entry_set_icon_from_stock (entry,
 
280
                                       GTK_ENTRY_ICON_SECONDARY,
 
281
                                       GTK_STOCK_DIALOG_ERROR);
 
282
        gtk_entry_set_icon_activatable (entry,
 
283
                                        GTK_ENTRY_ICON_SECONDARY,
 
284
                                        TRUE);
 
285
        g_signal_connect (entry, "icon-release",
 
286
                          G_CALLBACK (icon_released), FALSE);
 
287
        g_signal_connect (entry, "query-tooltip",
 
288
                          G_CALLBACK (query_tooltip), NULL);
 
289
        g_object_set (entry, "has-tooltip", TRUE, NULL);
 
290
        gtk_entry_set_icon_tooltip_text (entry,
 
291
                                         GTK_ENTRY_ICON_SECONDARY,
 
292
                                         text);
 
293
}
 
294
 
 
295
void
 
296
clear_entry_validation_error (GtkEntry *entry)
 
297
{
 
298
        gboolean warning;
 
299
 
 
300
        g_object_get (entry, "caps-lock-warning", &warning, NULL);
 
301
 
 
302
        if (warning)
 
303
                return;
 
304
 
 
305
        g_object_set (entry, "has-tooltip", FALSE, NULL);
 
306
        gtk_entry_set_icon_from_pixbuf (entry,
 
307
                                        GTK_ENTRY_ICON_SECONDARY,
 
308
                                        NULL);
 
309
        g_object_set (entry, "caps-lock-warning", TRUE, NULL);
 
310
}
 
311
 
 
312
void
 
313
popup_menu_below_button (GtkMenu   *menu,
 
314
                         gint      *x,
 
315
                         gint      *y,
 
316
                         gboolean  *push_in,
 
317
                         GtkWidget *button)
 
318
{
 
319
        GtkRequisition menu_req;
 
320
        GtkTextDirection direction;
 
321
        GtkAllocation allocation;
 
322
 
 
323
        gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &menu_req);
 
324
 
 
325
        direction = gtk_widget_get_direction (button);
 
326
 
 
327
        gdk_window_get_origin (gtk_widget_get_window (button), x, y);
 
328
        gtk_widget_get_allocation (button, &allocation);
 
329
        *x += allocation.x;
 
330
        *y += allocation.y + allocation.height;
 
331
 
 
332
        if (direction == GTK_TEXT_DIR_LTR)
 
333
                *x += MAX (allocation.width - menu_req.width, 0);
 
334
        else if (menu_req.width > allocation.width)
 
335
                *x -= menu_req.width - allocation.width;
 
336
 
 
337
        *push_in = TRUE;
 
338
}
 
339
 
 
340
void
 
341
rounded_rectangle (cairo_t *cr,
 
342
                   gdouble  aspect,
 
343
                   gdouble  x,
 
344
                   gdouble  y,
 
345
                   gdouble  corner_radius,
 
346
                   gdouble  width,
 
347
                   gdouble  height)
 
348
{
 
349
        gdouble radius;
 
350
        gdouble degrees;
 
351
 
 
352
        radius = corner_radius / aspect;
 
353
        degrees = G_PI / 180.0;
 
354
 
 
355
        cairo_new_sub_path (cr);
 
356
        cairo_arc (cr,
 
357
                   x + width - radius,
 
358
                   y + radius,
 
359
                   radius,
 
360
                   -90 * degrees,
 
361
                   0 * degrees);
 
362
        cairo_arc (cr,
 
363
                   x + width - radius,
 
364
                   y + height - radius,
 
365
                   radius,
 
366
                   0 * degrees,
 
367
                   90 * degrees);
 
368
        cairo_arc (cr,
 
369
                   x + radius,
 
370
                   y + height - radius,
 
371
                   radius,
 
372
                   90 * degrees,
 
373
                   180 * degrees);
 
374
        cairo_arc (cr,
 
375
                   x + radius,
 
376
                   y + radius,
 
377
                   radius,
 
378
                   180 * degrees,
 
379
                   270 * degrees);
 
380
        cairo_close_path (cr);
 
381
}
 
382
 
 
383
void
 
384
down_arrow (GtkStyleContext *context,
 
385
            cairo_t         *cr,
 
386
            gint             x,
 
387
            gint             y,
 
388
            gint             width,
 
389
            gint             height)
 
390
{
 
391
        GtkStateFlags flags;
 
392
        GdkRGBA fg_color;
 
393
        GdkRGBA outline_color;
 
394
        gdouble vertical_overshoot;
 
395
        gint diameter;
 
396
        gdouble radius;
 
397
        gdouble x_double, y_double;
 
398
        gdouble angle;
 
399
        gint line_width;
 
400
 
 
401
        flags = gtk_style_context_get_state (context);
 
402
 
 
403
        gtk_style_context_get_color (context, flags, &fg_color);
 
404
        gtk_style_context_get_border_color (context, flags, &outline_color);
 
405
 
 
406
        line_width = 1;
 
407
        angle = G_PI / 2;
 
408
        vertical_overshoot = line_width / 2.0 * (1. / tan (G_PI / 8));
 
409
        if (line_width % 2 == 1)
 
410
                vertical_overshoot = ceil (0.5 + vertical_overshoot) - 0.5;
 
411
        else
 
412
                vertical_overshoot = ceil (vertical_overshoot);
 
413
        diameter = (gint) MAX (3, width - 2 * vertical_overshoot);
 
414
        diameter -= (1 - (diameter + line_width) % 2);
 
415
        radius = diameter / 2.;
 
416
        x_double = floor ((x + width / 2) - (radius + line_width) / 2.) + (radius + line_width) / 2.;
 
417
 
 
418
        y_double = (y + height / 2) - 0.5;
 
419
 
 
420
        cairo_save (cr);
 
421
 
 
422
        cairo_translate (cr, x_double, y_double);
 
423
        cairo_rotate (cr, angle);
 
424
 
 
425
        cairo_move_to (cr, - radius / 2., - radius);
 
426
        cairo_line_to (cr,   radius / 2.,   0);
 
427
        cairo_line_to (cr, - radius / 2.,   radius);
 
428
 
 
429
        cairo_close_path (cr);
 
430
 
 
431
        cairo_set_line_width (cr, line_width);
 
432
 
 
433
        gdk_cairo_set_source_rgba (cr, &fg_color);
 
434
 
 
435
        cairo_fill_preserve (cr);
 
436
 
 
437
        gdk_cairo_set_source_rgba (cr, &outline_color);
 
438
        cairo_stroke (cr);
 
439
 
 
440
        cairo_restore (cr);
 
441
}
 
442