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
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
23 #include "glibcompat.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
;
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
);
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
),
55 (GBaseFinalizeFunc
) NULL
,
56 (GClassInitFunc
) pidgin_mini_dialog_class_intern_init
,
57 (GClassFinalizeFunc
) NULL
,
58 NULL
, /* class_data */
59 sizeof (PidginMiniDialog
),
61 (GInstanceInitFunc
) pidgin_mini_dialog_init
,
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
;
76 PROP_ENABLE_DESCRIPTION_MARKUP
,
79 } HazeConnectionProperties
;
81 static GParamSpec
*properties
[LAST_PROPERTY
];
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
,
103 "description", description
,
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
);
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
);
128 pidgin_mini_dialog_set_title(PidginMiniDialog
*mini_dialog
,
131 g_object_set(G_OBJECT(mini_dialog
), "title", title
, NULL
);
135 pidgin_mini_dialog_set_description(PidginMiniDialog
*mini_dialog
,
136 const char *description
)
138 g_object_set(G_OBJECT(mini_dialog
), "description", description
, NULL
);
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
);
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
);
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
;
170 gboolean close_dialog_after_click
;
174 pidgin_mini_dialog_get_num_children(PidginMiniDialog
*mini_dialog
)
178 tmp
= gtk_container_get_children(GTK_CONTAINER(mini_dialog
->contents
));
179 len
= g_list_length(tmp
);
185 idle_destroy_cb(GtkWidget
*mini_dialog
)
187 gtk_widget_destroy(mini_dialog
);
192 mini_dialog_button_clicked_cb(GtkButton
*button
,
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
);
214 mini_dialog_button_destroy_cb(GtkButton
*button
,
217 struct _mini_dialog_button_clicked_cb_data
*data
= user_data
;
222 mini_dialog_add_button(PidginMiniDialog
*self
,
224 PidginMiniDialogCallback clicked_cb
,
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
);
234 g_strdup_printf("<span size=\"smaller\">%s</span>", text
);
236 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label
), 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
));
256 pidgin_mini_dialog_add_button(PidginMiniDialog
*self
,
258 PidginMiniDialogCallback clicked_cb
,
261 mini_dialog_add_button(self
, text
, clicked_cb
, user_data
, TRUE
);
265 pidgin_mini_dialog_add_non_closing_button(PidginMiniDialog
*self
,
267 PidginMiniDialogCallback clicked_cb
,
270 mini_dialog_add_button(self
, text
, clicked_cb
, user_data
, FALSE
);
274 pidgin_mini_dialog_get_property(GObject
*object
,
279 PidginMiniDialog
*self
= PIDGIN_MINI_DIALOG(object
);
280 PidginMiniDialogPrivate
*priv
= PIDGIN_MINI_DIALOG_GET_PRIVATE(self
);
282 switch (property_id
) {
284 g_value_set_string(value
, gtk_label_get_text(priv
->title
));
286 case PROP_DESCRIPTION
:
287 g_value_set_string(value
, gtk_label_get_text(priv
->desc
));
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
);
296 case PROP_CUSTOM_ICON
:
297 g_value_set_object(value
, gtk_image_get_pixbuf(priv
->icon
));
299 case PROP_ENABLE_DESCRIPTION_MARKUP
:
300 g_value_set_boolean(value
, priv
->enable_description_markup
);
303 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
308 mini_dialog_set_title(PidginMiniDialog
*self
,
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
);
321 g_free(title_markup
);
323 g_object_notify_by_pspec(G_OBJECT(self
), properties
[PROP_TITLE
]);
327 mini_dialog_set_description(PidginMiniDialog
*self
,
328 const char *description
)
330 PidginMiniDialogPrivate
*priv
= PIDGIN_MINI_DIALOG_GET_PRIVATE(self
);
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
);
342 gtk_widget_show(GTK_WIDGET(priv
->desc
));
343 g_object_set(G_OBJECT(priv
->desc
), "no-show-all", FALSE
, NULL
);
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
]);
359 pidgin_mini_dialog_set_property(GObject
*object
,
364 PidginMiniDialog
*self
= PIDGIN_MINI_DIALOG(object
);
365 PidginMiniDialogPrivate
*priv
= PIDGIN_MINI_DIALOG_GET_PRIVATE(self
);
367 switch (property_id
) {
369 mini_dialog_set_title(self
, g_value_get_string(value
));
371 case PROP_DESCRIPTION
:
372 mini_dialog_set_description(self
, g_value_get_string(value
));
375 gtk_image_set_from_icon_name(priv
->icon
,
376 g_value_get_string(value
),
377 GTK_ICON_SIZE_SMALL_TOOLBAR
);
379 case PROP_CUSTOM_ICON
:
380 gtk_image_set_from_pixbuf(priv
->icon
, g_value_get_object(value
));
382 case PROP_ENABLE_DESCRIPTION_MARKUP
:
383 priv
->enable_description_markup
= g_value_get_boolean(value
);
386 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
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
);
402 purple_prefs_disconnect_by_handle(self
);
404 G_OBJECT_CLASS (pidgin_mini_dialog_parent_class
)->finalize (object
);
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",
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",
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",
428 "String specifying the GtkIconTheme name of the dialog's icon",
430 G_PARAM_STATIC_STRINGS
| G_PARAM_READWRITE
);
432 properties
[PROP_CUSTOM_ICON
] = g_param_spec_object("custom-icon",
434 "Pixbuf to use as the dialog's icon",
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
);
448 pidgin_mini_dialog_init(PidginMiniDialog
*self
)
450 GtkBox
*self_box
= GTK_BOX(self
);
452 PidginMiniDialogPrivate
*priv
= g_new0(PidginMiniDialogPrivate
, 1);
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
));