Remove unused Meson option for enchant.
[pidgin-git.git] / pidgin / minidialog.c
blobd436aebb03b72b4d9c25b22748723e84a428bb0f
1 /* pidgin
3 * Pidgin is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 #include "internal.h"
23 #include "glibcompat.h"
25 #include <gtk/gtk.h>
27 #include "gtk3compat.h"
29 #include "libpurple/prefs.h"
31 #include "pidgin/minidialog.h"
32 #include "pidgin/pidgin.h"
34 static void pidgin_mini_dialog_init (PidginMiniDialog *self);
35 static void pidgin_mini_dialog_class_init (PidginMiniDialogClass *klass);
37 static gpointer pidgin_mini_dialog_parent_class = NULL;
39 static void
40 pidgin_mini_dialog_class_intern_init (gpointer klass)
42 pidgin_mini_dialog_parent_class = g_type_class_peek_parent (klass);
43 pidgin_mini_dialog_class_init ((PidginMiniDialogClass*) klass);
46 GType
47 pidgin_mini_dialog_get_type (void)
49 static GType g_define_type_id = 0;
50 if (g_define_type_id == 0)
52 static const GTypeInfo g_define_type_info = {
53 sizeof (PidginMiniDialogClass),
54 (GBaseInitFunc) NULL,
55 (GBaseFinalizeFunc) NULL,
56 (GClassInitFunc) pidgin_mini_dialog_class_intern_init,
57 (GClassFinalizeFunc) NULL,
58 NULL, /* class_data */
59 sizeof (PidginMiniDialog),
60 0, /* n_preallocs */
61 (GInstanceInitFunc) pidgin_mini_dialog_init,
62 NULL,
64 g_define_type_id = g_type_register_static(GTK_TYPE_BOX,
65 "PidginMiniDialog", &g_define_type_info, 0);
67 return g_define_type_id;
70 enum
72 PROP_TITLE = 1,
73 PROP_DESCRIPTION,
74 PROP_ICON_NAME,
75 PROP_CUSTOM_ICON,
76 PROP_ENABLE_DESCRIPTION_MARKUP,
78 LAST_PROPERTY
79 } HazeConnectionProperties;
81 static GParamSpec *properties[LAST_PROPERTY];
83 typedef struct
85 GtkImage *icon;
86 GtkBox *title_box;
87 GtkLabel *title;
88 GtkLabel *desc;
89 GtkBox *buttons;
90 gboolean enable_description_markup;
92 guint idle_destroy_cb_id;
93 } PidginMiniDialogPrivate;
95 #define PIDGIN_MINI_DIALOG_GET_PRIVATE(dialog) \
96 ((PidginMiniDialogPrivate *) ((dialog)->priv))
98 static PidginMiniDialog *
99 mini_dialog_new(const gchar *title, const gchar *description)
101 return g_object_new(PIDGIN_TYPE_MINI_DIALOG,
102 "title", title,
103 "description", description,
104 NULL);
107 PidginMiniDialog *
108 pidgin_mini_dialog_new(const gchar *title,
109 const gchar *description,
110 const gchar *icon_name)
112 PidginMiniDialog *mini_dialog = mini_dialog_new(title, description);
113 pidgin_mini_dialog_set_icon_name(mini_dialog, icon_name);
114 return mini_dialog;
117 PidginMiniDialog *
118 pidgin_mini_dialog_new_with_custom_icon(const gchar *title,
119 const gchar *description,
120 GdkPixbuf *custom_icon)
122 PidginMiniDialog *mini_dialog = mini_dialog_new(title, description);
123 pidgin_mini_dialog_set_custom_icon(mini_dialog, custom_icon);
124 return mini_dialog;
127 void
128 pidgin_mini_dialog_set_title(PidginMiniDialog *mini_dialog,
129 const char *title)
131 g_object_set(G_OBJECT(mini_dialog), "title", title, NULL);
134 void
135 pidgin_mini_dialog_set_description(PidginMiniDialog *mini_dialog,
136 const char *description)
138 g_object_set(G_OBJECT(mini_dialog), "description", description, NULL);
141 void
142 pidgin_mini_dialog_enable_description_markup(PidginMiniDialog *mini_dialog)
144 g_object_set(G_OBJECT(mini_dialog), "enable-description-markup", TRUE, NULL);
147 void pidgin_mini_dialog_set_link_callback(PidginMiniDialog *mini_dialog, GCallback cb, gpointer user_data)
149 g_signal_connect(PIDGIN_MINI_DIALOG_GET_PRIVATE(mini_dialog)->desc, "activate-link", cb, user_data);
152 void
153 pidgin_mini_dialog_set_icon_name(PidginMiniDialog *mini_dialog,
154 const char *icon_name)
156 g_object_set(G_OBJECT(mini_dialog), "icon-name", icon_name, NULL);
159 void
160 pidgin_mini_dialog_set_custom_icon(PidginMiniDialog *mini_dialog, GdkPixbuf *custom_icon)
162 g_object_set(G_OBJECT(mini_dialog), "custom-icon", custom_icon, NULL);
165 struct _mini_dialog_button_clicked_cb_data
167 PidginMiniDialog *mini_dialog;
168 PidginMiniDialogCallback callback;
169 gpointer user_data;
170 gboolean close_dialog_after_click;
173 guint
174 pidgin_mini_dialog_get_num_children(PidginMiniDialog *mini_dialog)
176 GList *tmp;
177 guint len;
178 tmp = gtk_container_get_children(GTK_CONTAINER(mini_dialog->contents));
179 len = g_list_length(tmp);
180 g_list_free(tmp);
181 return len;
184 static gboolean
185 idle_destroy_cb(GtkWidget *mini_dialog)
187 gtk_widget_destroy(mini_dialog);
188 return FALSE;
191 static void
192 mini_dialog_button_clicked_cb(GtkButton *button,
193 gpointer user_data)
195 struct _mini_dialog_button_clicked_cb_data *data = user_data;
196 PidginMiniDialogPrivate *priv =
197 PIDGIN_MINI_DIALOG_GET_PRIVATE(data->mini_dialog);
199 if (data->close_dialog_after_click) {
200 /* Set up the destruction callback before calling the clicked callback,
201 * so that if the mini-dialog gets destroyed during the clicked callback
202 * the idle_destroy_cb is correctly removed by _finalize.
204 priv->idle_destroy_cb_id =
205 g_idle_add((GSourceFunc) idle_destroy_cb, data->mini_dialog);
208 if (data->callback != NULL)
209 data->callback(data->mini_dialog, button, data->user_data);
213 static void
214 mini_dialog_button_destroy_cb(GtkButton *button,
215 gpointer user_data)
217 struct _mini_dialog_button_clicked_cb_data *data = user_data;
218 g_free(data);
221 static void
222 mini_dialog_add_button(PidginMiniDialog *self,
223 const char *text,
224 PidginMiniDialogCallback clicked_cb,
225 gpointer user_data,
226 gboolean close_dialog_after_click)
228 PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
229 struct _mini_dialog_button_clicked_cb_data *callback_data
230 = g_new0(struct _mini_dialog_button_clicked_cb_data, 1);
231 GtkWidget *button = gtk_button_new();
232 GtkWidget *label = gtk_label_new(NULL);
233 char *button_text =
234 g_strdup_printf("<span size=\"smaller\">%s</span>", text);
236 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), button_text);
237 g_free(button_text);
239 callback_data->mini_dialog = self;
240 callback_data->callback = clicked_cb;
241 callback_data->user_data = user_data;
242 callback_data->close_dialog_after_click = close_dialog_after_click;
243 g_signal_connect(G_OBJECT(button), "clicked",
244 (GCallback) mini_dialog_button_clicked_cb, callback_data);
245 g_signal_connect(G_OBJECT(button), "destroy",
246 (GCallback) mini_dialog_button_destroy_cb, callback_data);
248 gtk_container_add(GTK_CONTAINER(button), label);
250 gtk_box_pack_end(GTK_BOX(priv->buttons), button, FALSE, FALSE,
252 gtk_widget_show_all(GTK_WIDGET(button));
255 void
256 pidgin_mini_dialog_add_button(PidginMiniDialog *self,
257 const char *text,
258 PidginMiniDialogCallback clicked_cb,
259 gpointer user_data)
261 mini_dialog_add_button(self, text, clicked_cb, user_data, TRUE);
264 void
265 pidgin_mini_dialog_add_non_closing_button(PidginMiniDialog *self,
266 const char *text,
267 PidginMiniDialogCallback clicked_cb,
268 gpointer user_data)
270 mini_dialog_add_button(self, text, clicked_cb, user_data, FALSE);
273 static void
274 pidgin_mini_dialog_get_property(GObject *object,
275 guint property_id,
276 GValue *value,
277 GParamSpec *pspec)
279 PidginMiniDialog *self = PIDGIN_MINI_DIALOG(object);
280 PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
282 switch (property_id) {
283 case PROP_TITLE:
284 g_value_set_string(value, gtk_label_get_text(priv->title));
285 break;
286 case PROP_DESCRIPTION:
287 g_value_set_string(value, gtk_label_get_text(priv->desc));
288 break;
289 case PROP_ICON_NAME:
291 const gchar *icon_name = NULL;
292 gtk_image_get_icon_name(priv->icon, &icon_name, NULL);
293 g_value_set_string(value, icon_name);
294 break;
296 case PROP_CUSTOM_ICON:
297 g_value_set_object(value, gtk_image_get_pixbuf(priv->icon));
298 break;
299 case PROP_ENABLE_DESCRIPTION_MARKUP:
300 g_value_set_boolean(value, priv->enable_description_markup);
301 break;
302 default:
303 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
307 static void
308 mini_dialog_set_title(PidginMiniDialog *self,
309 const char *title)
311 PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
313 char *title_esc = g_markup_escape_text(title, -1);
314 char *title_markup = g_strdup_printf(
315 "<span weight=\"bold\" size=\"smaller\">%s</span>",
316 title_esc ? title_esc : "");
318 gtk_label_set_markup(priv->title, title_markup);
320 g_free(title_esc);
321 g_free(title_markup);
323 g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_TITLE]);
326 static void
327 mini_dialog_set_description(PidginMiniDialog *self,
328 const char *description)
330 PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
331 if(description)
333 char *desc_esc = priv->enable_description_markup ? g_strdup(description) : g_markup_escape_text(description, -1);
334 char *desc_markup = g_strdup_printf(
335 "<span size=\"smaller\">%s</span>", desc_esc);
337 gtk_label_set_markup(priv->desc, desc_markup);
339 g_free(desc_esc);
340 g_free(desc_markup);
342 gtk_widget_show(GTK_WIDGET(priv->desc));
343 g_object_set(G_OBJECT(priv->desc), "no-show-all", FALSE, NULL);
345 else
347 gtk_label_set_text(priv->desc, NULL);
348 gtk_widget_hide(GTK_WIDGET(priv->desc));
349 /* make calling show_all() on the minidialog not affect desc
350 * even though it's packed inside it.
352 g_object_set(G_OBJECT(priv->desc), "no-show-all", TRUE, NULL);
355 g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_DESCRIPTION]);
358 static void
359 pidgin_mini_dialog_set_property(GObject *object,
360 guint property_id,
361 const GValue *value,
362 GParamSpec *pspec)
364 PidginMiniDialog *self = PIDGIN_MINI_DIALOG(object);
365 PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
367 switch (property_id) {
368 case PROP_TITLE:
369 mini_dialog_set_title(self, g_value_get_string(value));
370 break;
371 case PROP_DESCRIPTION:
372 mini_dialog_set_description(self, g_value_get_string(value));
373 break;
374 case PROP_ICON_NAME:
375 gtk_image_set_from_icon_name(priv->icon,
376 g_value_get_string(value),
377 GTK_ICON_SIZE_SMALL_TOOLBAR);
378 break;
379 case PROP_CUSTOM_ICON:
380 gtk_image_set_from_pixbuf(priv->icon, g_value_get_object(value));
381 break;
382 case PROP_ENABLE_DESCRIPTION_MARKUP:
383 priv->enable_description_markup = g_value_get_boolean(value);
384 break;
385 default:
386 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
390 static void
391 pidgin_mini_dialog_finalize(GObject *object)
393 PidginMiniDialog *self = PIDGIN_MINI_DIALOG(object);
394 PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
396 if (priv->idle_destroy_cb_id)
397 g_source_remove(priv->idle_destroy_cb_id);
399 g_free(priv);
400 self->priv = NULL;
402 purple_prefs_disconnect_by_handle(self);
404 G_OBJECT_CLASS (pidgin_mini_dialog_parent_class)->finalize (object);
407 static void
408 pidgin_mini_dialog_class_init(PidginMiniDialogClass *klass)
410 GObjectClass *object_class = G_OBJECT_CLASS(klass);
412 object_class->get_property = pidgin_mini_dialog_get_property;
413 object_class->set_property = pidgin_mini_dialog_set_property;
414 object_class->finalize = pidgin_mini_dialog_finalize;
416 properties[PROP_TITLE] = g_param_spec_string("title",
417 "title",
418 "String specifying the mini-dialog's title", NULL,
419 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
421 properties[PROP_DESCRIPTION] = g_param_spec_string("description",
422 "description",
423 "Description text for the mini-dialog, if desired", NULL,
424 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
426 properties[PROP_ICON_NAME] = g_param_spec_string("icon-name",
427 "icon-name",
428 "String specifying the GtkIconTheme name of the dialog's icon",
429 NULL,
430 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
432 properties[PROP_CUSTOM_ICON] = g_param_spec_object("custom-icon",
433 "custom-icon",
434 "Pixbuf to use as the dialog's icon",
435 GDK_TYPE_PIXBUF,
436 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
438 properties[PROP_ENABLE_DESCRIPTION_MARKUP] =
439 g_param_spec_boolean("enable-description-markup",
440 "enable-description-markup",
441 "Use GMarkup in the description text", FALSE,
442 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
444 g_object_class_install_properties(object_class, LAST_PROPERTY, properties);
447 static void
448 pidgin_mini_dialog_init(PidginMiniDialog *self)
450 GtkBox *self_box = GTK_BOX(self);
452 PidginMiniDialogPrivate *priv = g_new0(PidginMiniDialogPrivate, 1);
453 self->priv = priv;
455 gtk_orientable_set_orientation(GTK_ORIENTABLE(self), GTK_ORIENTATION_VERTICAL);
457 gtk_container_set_border_width(GTK_CONTAINER(self), PIDGIN_HIG_BOX_SPACE);
459 priv->title_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PIDGIN_HIG_BOX_SPACE));
461 priv->icon = GTK_IMAGE(gtk_image_new());
462 gtk_widget_set_halign(GTK_WIDGET(priv->icon), GTK_ALIGN_START);
463 gtk_widget_set_valign(GTK_WIDGET(priv->icon), GTK_ALIGN_START);
465 priv->title = GTK_LABEL(gtk_label_new(NULL));
466 gtk_label_set_line_wrap(priv->title, TRUE);
467 gtk_label_set_selectable(priv->title, TRUE);
468 gtk_label_set_xalign(priv->title, 0);
469 gtk_label_set_yalign(priv->title, 0);
471 gtk_box_pack_start(priv->title_box, GTK_WIDGET(priv->icon), FALSE, FALSE, 0);
472 gtk_box_pack_start(priv->title_box, GTK_WIDGET(priv->title), TRUE, TRUE, 0);
474 priv->desc = GTK_LABEL(gtk_label_new(NULL));
475 gtk_label_set_line_wrap(priv->desc, TRUE);
476 gtk_label_set_xalign(priv->desc, 0);
477 gtk_label_set_yalign(priv->desc, 0);
478 gtk_label_set_selectable(priv->desc, TRUE);
479 /* make calling show_all() on the minidialog not affect desc even though
480 * it's packed inside it.
482 g_object_set(G_OBJECT(priv->desc), "no-show-all", TRUE, NULL);
484 self->contents = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
486 priv->buttons = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
488 gtk_box_pack_start(self_box, GTK_WIDGET(priv->title_box), FALSE, FALSE, 0);
489 gtk_box_pack_start(self_box, GTK_WIDGET(priv->desc), FALSE, FALSE, 0);
490 gtk_box_pack_start(self_box, GTK_WIDGET(self->contents), TRUE, TRUE, 0);
491 gtk_box_pack_start(self_box, GTK_WIDGET(priv->buttons), FALSE, FALSE, 0);
493 gtk_widget_show_all(GTK_WIDGET(self));