Statistics
| Revision:

root / src / alertpanel.c @ 2164

History | View | Annotate | Download (11.2 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2006 Hiroyuki Yamamoto
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
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#include "defs.h"
25
26
#include <glib.h>
27
#include <glib/gi18n.h>
28
#include <gtk/gtk.h>
29
#include <gdk/gdkkeysyms.h>
30
31
#include "alertpanel.h"
32
#include "mainwindow.h"
33
#include "manage_window.h"
34
#include "utils.h"
35
#include "gtkutils.h"
36
#include "inc.h"
37
#include "prefs_common.h"
38
39
#define ALERT_PANEL_WIDTH        380
40
#define TITLE_HEIGHT                72
41
#define MESSAGE_HEIGHT                62
42
43
static gboolean alertpanel_is_open = FALSE;
44
static AlertValue value;
45
46
static GtkWidget *dialog;
47
48
static void alertpanel_show                (void);
49
static void alertpanel_create                (const gchar        *title,
50
                                         const gchar        *message,
51
                                         AlertType         type,
52
                                         AlertValue      default_value,
53
                                         gboolean         can_disable,
54
                                         const gchar        *button1_label,
55
                                         const gchar        *button2_label,
56
                                         const gchar        *button3_label);
57
58
static void alertpanel_button_toggled        (GtkToggleButton        *button,
59
                                         gpointer                 data);
60
static void alertpanel_button_clicked        (GtkWidget                *widget,
61
                                         gpointer                 data);
62
static gint alertpanel_deleted                (GtkWidget                *widget,
63
                                         GdkEventAny                *event,
64
                                         gpointer                 data);
65
static gboolean alertpanel_close        (GtkWidget                *widget,
66
                                         GdkEventAny                *event,
67
                                         gpointer                 data);
68
static gint alertpanel_focus_out        (GtkWidget                *widget,
69
                                         GdkEventFocus                *event,
70
                                         gpointer                 data);
71
72
AlertValue alertpanel_full(const gchar *title, const gchar *message,
73
                           AlertType type, AlertValue default_value,
74
                           gboolean can_disable,
75
                           const gchar *button1_label,
76
                           const gchar *button2_label,
77
                           const gchar *button3_label)
78
{
79
        if (alertpanel_is_open)
80
                return -1;
81
        else
82
                alertpanel_is_open = TRUE;
83
84
        alertpanel_create(title, message, type, default_value, can_disable,
85
                          button1_label, button2_label, button3_label);
86
        alertpanel_show();
87
88
        debug_print("return value = %d\n", value);
89
        return value;
90
}
91
92
AlertValue alertpanel(const gchar *title,
93
                      const gchar *message,
94
                      const gchar *button1_label,
95
                      const gchar *button2_label,
96
                      const gchar *button3_label)
97
{
98
        return alertpanel_full(title, message, ALERT_QUESTION, G_ALERTDEFAULT,
99
                               FALSE,
100
                               button1_label, button2_label, button3_label);
101
}
102
103
void alertpanel_message(const gchar *title, const gchar *message,
104
                        AlertType type)
105
{
106
        if (alertpanel_is_open)
107
                return;
108
        else
109
                alertpanel_is_open = TRUE;
110
111
        alertpanel_create(title, message, type, G_ALERTDEFAULT, FALSE,
112
                          NULL, NULL, NULL);
113
        alertpanel_show();
114
}
115
116
AlertValue alertpanel_message_with_disable(const gchar *title,
117
                                           const gchar *message,
118
                                           AlertType type)
119
{
120
        if (alertpanel_is_open)
121
                return 0;
122
        else
123
                alertpanel_is_open = TRUE;
124
125
        alertpanel_create(title, message, type, G_ALERTDEFAULT, TRUE,
126
                          NULL, NULL, NULL);
127
        alertpanel_show();
128
129
        return value;
130
}
131
132
void alertpanel_notice(const gchar *format, ...)
133
{
134
        va_list args;
135
        gchar buf[256];
136
137
        va_start(args, format);
138
        g_vsnprintf(buf, sizeof(buf), format, args);
139
        va_end(args);
140
        strretchomp(buf);
141
142
        alertpanel_message(_("Notice"), buf, ALERT_NOTICE);
143
}
144
145
void alertpanel_warning(const gchar *format, ...)
146
{
147
        va_list args;
148
        gchar buf[256];
149
150
        va_start(args, format);
151
        g_vsnprintf(buf, sizeof(buf), format, args);
152
        va_end(args);
153
        strretchomp(buf);
154
155
        alertpanel_message(_("Warning"), buf, ALERT_WARNING);
156
}
157
158
void alertpanel_error(const gchar *format, ...)
159
{
160
        va_list args;
161
        gchar buf[256];
162
163
        va_start(args, format);
164
        g_vsnprintf(buf, sizeof(buf), format, args);
165
        va_end(args);
166
        strretchomp(buf);
167
168
        alertpanel_message(_("Error"), buf, ALERT_ERROR);
169
}
170
171
static void alertpanel_show(void)
172
{
173
        gint x, y, w, h, sx, sy;
174
        value = G_ALERTWAIT;
175
176
        inc_lock();
177
178
        sx = gdk_screen_width();
179
        sy = gdk_screen_height();
180
        gdk_window_get_origin(dialog->window, &x, &y);
181
        w = dialog->allocation.width;
182
        h = dialog->allocation.height;
183
        if (x < 0 || y < 0 || x + w > sx || y + h > sy) {
184
                debug_print("sx, sy,  x, y,  w, h = %d, %d,  %d, %d,  %d, %d\n",
185
                            sx, sy, x, y, w, h);
186
                debug_print("alert dialog position out of range\n");
187
                gtk_window_set_position(GTK_WINDOW(dialog),
188
                                        GTK_WIN_POS_CENTER_ALWAYS);
189
        }
190
191
        while ((value & G_ALERT_VALUE_MASK) == G_ALERTWAIT)
192
                gtk_main_iteration();
193
194
        gtk_widget_destroy(dialog);
195
        GTK_EVENTS_FLUSH();
196
197
        alertpanel_is_open = FALSE;
198
        inc_unlock();
199
}
200
201
static void alertpanel_create(const gchar *title,
202
                              const gchar *message,
203
                              AlertType    type,
204
                              AlertValue   default_value,
205
                              gboolean           can_disable,
206
                              const gchar *button1_label,
207
                              const gchar *button2_label,
208
                              const gchar *button3_label)
209
{
210
        static PangoFontDescription *font_desc;
211
        GtkWidget *image;
212
        GtkWidget *label;
213
        GtkWidget *hbox;
214
        GtkWidget *vbox;
215
        GtkWidget *disable_chkbtn;
216
        GtkWidget *confirm_area;
217
        GtkWidget *button1;
218
        GtkWidget *button2;
219
        GtkWidget *button3;
220
        const gchar *label2;
221
        const gchar *label3;
222
223
        debug_print(_("Creating alert panel dialog...\n"));
224
225
        dialog = gtk_dialog_new();
226
        gtk_window_set_title(GTK_WINDOW(dialog), title);
227
        gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE);
228
        gtk_window_set_position(GTK_WINDOW(dialog),
229
                                GTK_WIN_POS_CENTER_ON_PARENT);
230
        gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
231
        manage_window_set_transient(GTK_WINDOW(dialog));
232
        gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
233
        gtk_widget_realize(dialog);
234
        g_signal_connect(G_OBJECT(dialog), "delete_event",
235
                         G_CALLBACK(alertpanel_deleted),
236
                         (gpointer)G_ALERTCANCEL);
237
        g_signal_connect(G_OBJECT(dialog), "key_press_event",
238
                         G_CALLBACK(alertpanel_close),
239
                         (gpointer)G_ALERTCANCEL);
240
        g_signal_connect(G_OBJECT(dialog), "focus_out_event",
241
                         G_CALLBACK(alertpanel_focus_out), NULL);
242
243
        /* for title icon, label and message */
244
        hbox = gtk_hbox_new(FALSE, 12);
245
        gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
246
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
247
                           hbox, FALSE, FALSE, 0);
248
249
        /* title icon */
250
        switch (type) {
251
        case ALERT_QUESTION:
252
                image = gtk_image_new_from_stock
253
                        (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
254
                break;
255
        case ALERT_WARNING:
256
                image = gtk_image_new_from_stock
257
                        (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
258
                break;
259
        case ALERT_ERROR:
260
                image = gtk_image_new_from_stock
261
                        (GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG);
262
                break;
263
        case ALERT_NOTICE:
264
        default:
265
                image = gtk_image_new_from_stock
266
                        (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
267
                break;
268
        }
269
        gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.0);
270
        gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
271
272
        /* for title and message */
273
        vbox = gtk_vbox_new(FALSE, 12);
274
        gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
275
276
        label = gtk_label_new(title);
277
        gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
278
        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
279
        gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
280
        if (!font_desc) {
281
                gint size;
282
283
                size = pango_font_description_get_size
284
                        (label->style->font_desc);
285
                font_desc = pango_font_description_new();
286
                pango_font_description_set_weight
287
                        (font_desc, PANGO_WEIGHT_BOLD);
288
                pango_font_description_set_size
289
                        (font_desc, size * PANGO_SCALE_LARGE);
290
        }
291
        if (font_desc)
292
                gtk_widget_modify_font(label, font_desc);
293
294
        /* message label */
295
        label = gtk_label_new(message);
296
        gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
297
        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
298
        gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
299
        gtk_label_set_selectable(GTK_LABEL(label), TRUE);
300
        GTK_WIDGET_UNSET_FLAGS(label, GTK_CAN_FOCUS);
301
#ifdef G_OS_WIN32
302
        {
303
                GtkStyle *style;
304
                style = gtk_widget_get_style(dialog);
305
                gtk_widget_modify_base(label, GTK_STATE_ACTIVE,
306
                                       &style->base[GTK_STATE_SELECTED]);
307
                gtk_widget_modify_text(label, GTK_STATE_ACTIVE,
308
                                       &style->text[GTK_STATE_SELECTED]);
309
        }
310
#endif
311
312
        if (can_disable) {
313
                hbox = gtk_hbox_new(FALSE, 0);
314
                gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox,
315
                                   FALSE, FALSE, 0);
316
317
                disable_chkbtn = gtk_check_button_new_with_label
318
                        (_("Show this message next time"));
319
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(disable_chkbtn),
320
                                             TRUE);
321
                gtk_box_pack_start(GTK_BOX(hbox), disable_chkbtn,
322
                                   FALSE, FALSE, 12);
323
                g_signal_connect(G_OBJECT(disable_chkbtn), "toggled",
324
                                 G_CALLBACK(alertpanel_button_toggled),
325
                                 GUINT_TO_POINTER(G_ALERTDISABLE));
326
        }
327
328
        /* for button(s) */
329
        if (!button1_label)
330
                button1_label = GTK_STOCK_OK;
331
        label2 = button2_label;
332
        label3 = button3_label;
333
        if (label2 && *label2 == '+') label2++;
334
        if (label3 && *label3 == '+') label3++;
335
336
        gtkut_stock_button_set_create(&confirm_area,
337
                                      &button1, button1_label,
338
                                      button2_label ? &button2 : NULL, label2,
339
                                      button3_label ? &button3 : NULL, label3);
340
341
        gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->action_area),
342
                         confirm_area, FALSE, FALSE, 0);
343
        gtk_container_set_border_width(GTK_CONTAINER(confirm_area), 5);
344
        gtk_widget_grab_default(button1);
345
        gtk_widget_grab_focus(button1);
346
        if (button2_label &&
347
            (default_value == G_ALERTALTERNATE || *button2_label == '+')) {
348
                gtk_widget_grab_default(button2);
349
                gtk_widget_grab_focus(button2);
350
        }
351
        if (button3_label &&
352
            (default_value == G_ALERTOTHER || *button3_label == '+')) {
353
                gtk_widget_grab_default(button3);
354
                gtk_widget_grab_focus(button3);
355
        }
356
357
        g_signal_connect(G_OBJECT(button1), "clicked",
358
                         G_CALLBACK(alertpanel_button_clicked),
359
                         GUINT_TO_POINTER(G_ALERTDEFAULT));
360
        if (button2_label)
361
                g_signal_connect(G_OBJECT(button2), "clicked",
362
                                 G_CALLBACK(alertpanel_button_clicked),
363
                                 GUINT_TO_POINTER(G_ALERTALTERNATE));
364
        if (button3_label)
365
                g_signal_connect(G_OBJECT(button3), "clicked",
366
                                 G_CALLBACK(alertpanel_button_clicked),
367
                                 GUINT_TO_POINTER(G_ALERTOTHER));
368
369
        gtk_widget_show_all(dialog);
370
}
371
372
static void alertpanel_button_toggled(GtkToggleButton *button,
373
                                      gpointer data)
374
{
375
        if (gtk_toggle_button_get_active(button))
376
                value &= ~GPOINTER_TO_UINT(data);
377
        else
378
                value |= GPOINTER_TO_UINT(data);
379
}
380
381
static void alertpanel_button_clicked(GtkWidget *widget, gpointer data)
382
{
383
        value = (value & ~G_ALERT_VALUE_MASK) | (AlertValue)data;
384
}
385
386
static gint alertpanel_deleted(GtkWidget *widget, GdkEventAny *event,
387
                               gpointer data)
388
{
389
        value = (value & ~G_ALERT_VALUE_MASK) | (AlertValue)data;
390
        return TRUE;
391
}
392
393
static gboolean alertpanel_close(GtkWidget *widget, GdkEventAny *event,
394
                                 gpointer data)
395
{
396
        if (event->type == GDK_KEY_PRESS)
397
                if (((GdkEventKey *)event)->keyval != GDK_Escape)
398
                        return FALSE;
399
400
        value = (value & ~G_ALERT_VALUE_MASK) | (AlertValue)data;
401
        return FALSE;
402
}
403
404
405
static gint alertpanel_focus_out(GtkWidget *widget, GdkEventFocus *event,
406
                                 gpointer data)
407
{
408
#ifdef G_OS_WIN32
409
        gtk_window_present(GTK_WINDOW(widget));
410
#endif
411
        return FALSE;
412
}