2 * @file gtkplugin.c GTK+ Plugins support
8 * Pidgin is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
28 #include "gtkplugin.h"
29 #include "gtkpluginpref.h"
34 #include "pidgintooltip.h"
38 #define PIDGIN_RESPONSE_CONFIGURE 98121
40 static void plugin_toggled_stage_two(PurplePlugin
*plug
, GtkTreeModel
*model
,
41 GtkTreeIter
*iter
, gboolean unload
);
43 static GtkWidget
*expander
= NULL
;
44 static GtkWidget
*plugin_dialog
= NULL
;
46 static GtkLabel
*plugin_name
= NULL
;
47 static GtkTextBuffer
*plugin_desc
= NULL
;
48 static GtkLabel
*plugin_error
= NULL
;
49 static GtkLabel
*plugin_author
= NULL
;
50 static GtkLabel
*plugin_website
= NULL
;
51 static gchar
*plugin_website_uri
= NULL
;
52 static GtkLabel
*plugin_filename
= NULL
;
54 static GtkWidget
*pref_button
= NULL
;
55 static GHashTable
*plugin_pref_dialogs
= NULL
;
58 pidgin_plugin_get_config_frame(PurplePlugin
*plugin
)
60 GtkWidget
*config
= NULL
;
62 g_return_val_if_fail(plugin
!= NULL
, NULL
);
64 if (PIDGIN_IS_PIDGIN_PLUGIN(plugin
) && plugin
->info
->ui_info
65 && PIDGIN_PLUGIN_UI_INFO(plugin
)->get_config_frame
)
67 PidginPluginUiInfo
*ui_info
;
69 ui_info
= PIDGIN_PLUGIN_UI_INFO(plugin
);
71 config
= ui_info
->get_config_frame(plugin
);
73 if (plugin
->info
->prefs_info
74 && plugin
->info
->prefs_info
->get_plugin_pref_frame
)
76 purple_debug_warning("gtkplugin",
77 "Plugin %s contains both, ui_info and "
78 "prefs_info preferences; prefs_info will be "
79 "ignored.", plugin
->info
->name
);
83 if (config
== NULL
&& plugin
->info
->prefs_info
84 && plugin
->info
->prefs_info
->get_plugin_pref_frame
)
86 PurplePluginPrefFrame
*frame
;
88 frame
= plugin
->info
->prefs_info
->get_plugin_pref_frame(plugin
);
90 config
= pidgin_plugin_pref_create_frame(frame
);
92 plugin
->info
->prefs_info
->frame
= frame
;
99 pidgin_plugins_save(void)
101 purple_plugins_save_loaded(PIDGIN_PREFS_ROOT
"/plugins/loaded");
105 update_plugin_list(void *data
)
107 GtkListStore
*ls
= GTK_LIST_STORE(data
);
112 gtk_list_store_clear(ls
);
113 purple_plugins_probe(G_MODULE_SUFFIX
);
115 for (probes
= purple_plugins_get_all();
117 probes
= probes
->next
)
125 if (plug
->info
->type
== PURPLE_PLUGIN_LOADER
) {
127 for (cur
= PURPLE_PLUGIN_LOADER_INFO(plug
)->exts
; cur
!= NULL
;
129 purple_plugins_probe(cur
->data
);
131 } else if (plug
->info
->type
!= PURPLE_PLUGIN_STANDARD
||
132 (plug
->info
->flags
& PURPLE_PLUGIN_FLAG_INVISIBLE
)) {
136 gtk_list_store_append (ls
, &iter
);
138 if (plug
->info
->name
) {
139 name
= g_markup_escape_text(_(plug
->info
->name
), -1);
141 char *tmp
= g_path_get_basename(plug
->path
);
142 name
= g_markup_escape_text(tmp
, -1);
145 version
= g_markup_escape_text(purple_plugin_get_version(plug
), -1);
146 summary
= g_markup_escape_text(purple_plugin_get_summary(plug
), -1);
148 desc
= g_strdup_printf("<b>%s</b> %s\n%s", name
,
155 gtk_list_store_set(ls
, &iter
,
156 0, purple_plugin_is_loaded(plug
),
159 3, purple_plugin_is_unloadable(plug
),
165 static void plugin_loading_common(PurplePlugin
*plugin
, GtkTreeView
*view
, gboolean loaded
)
168 GtkTreeModel
*model
= gtk_tree_view_get_model(view
);
170 if (gtk_tree_model_get_iter_first(model
, &iter
)) {
173 GtkTreeSelection
*sel
;
175 gtk_tree_model_get(model
, &iter
, 2, &plug
, -1);
180 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, 0, loaded
, -1);
182 /* If the loaded/unloaded plugin is the selected row,
183 * update the pref_button. */
184 sel
= gtk_tree_view_get_selection(view
);
185 if (gtk_tree_selection_get_selected(sel
, &model
, &iter
))
187 gtk_tree_model_get(model
, &iter
, 2, &plug
, -1);
190 gtk_widget_set_sensitive(pref_button
,
192 && ((PIDGIN_IS_PIDGIN_PLUGIN(plug
) && plug
->info
->ui_info
193 && PIDGIN_PLUGIN_UI_INFO(plug
)->get_config_frame
)
194 || (plug
->info
->prefs_info
195 && plug
->info
->prefs_info
->get_plugin_pref_frame
)));
200 } while (gtk_tree_model_iter_next(model
, &iter
));
204 static void plugin_load_cb(PurplePlugin
*plugin
, gpointer data
)
206 GtkTreeView
*view
= (GtkTreeView
*)data
;
207 plugin_loading_common(plugin
, view
, TRUE
);
210 static void plugin_unload_cb(PurplePlugin
*plugin
, gpointer data
)
212 GtkTreeView
*view
= (GtkTreeView
*)data
;
213 plugin_loading_common(plugin
, view
, FALSE
);
216 static void pref_dialog_response_cb(GtkWidget
*d
, int response
, PurplePlugin
*plug
)
219 case GTK_RESPONSE_CLOSE
:
220 case GTK_RESPONSE_DELETE_EVENT
:
221 g_hash_table_remove(plugin_pref_dialogs
, plug
);
222 if (g_hash_table_size(plugin_pref_dialogs
) == 0) {
223 g_hash_table_destroy(plugin_pref_dialogs
);
224 plugin_pref_dialogs
= NULL
;
226 gtk_widget_destroy(d
);
228 if (plug
->info
->prefs_info
&& plug
->info
->prefs_info
->frame
) {
229 purple_plugin_pref_frame_destroy(plug
->info
->prefs_info
->frame
);
230 plug
->info
->prefs_info
->frame
= NULL
;
237 static void plugin_unload_confirm_cb(gpointer
*data
)
239 PurplePlugin
*plugin
= (PurplePlugin
*)data
[0];
240 GtkTreeModel
*model
= (GtkTreeModel
*)data
[1];
241 GtkTreeIter
*iter
= (GtkTreeIter
*)data
[2];
243 plugin_toggled_stage_two(plugin
, model
, iter
, TRUE
);
248 static void plugin_toggled(GtkCellRendererToggle
*cell
, gchar
*pth
, gpointer data
)
250 GtkTreeModel
*model
= (GtkTreeModel
*)data
;
251 GtkTreeIter
*iter
= g_new(GtkTreeIter
, 1);
252 GtkTreePath
*path
= gtk_tree_path_new_from_string(pth
);
254 GtkWidget
*dialog
= NULL
;
256 gtk_tree_model_get_iter(model
, iter
, path
);
257 gtk_tree_path_free(path
);
258 gtk_tree_model_get(model
, iter
, 2, &plug
, -1);
260 /* Apparently, GTK+ won't honor the sensitive flag on cell renderers for booleans. */
261 if (purple_plugin_is_unloadable(plug
))
267 if (!purple_plugin_is_loaded(plug
))
269 pidgin_set_cursor(plugin_dialog
, GDK_WATCH
);
271 purple_plugin_load(plug
);
272 plugin_toggled_stage_two(plug
, model
, iter
, FALSE
);
274 pidgin_clear_cursor(plugin_dialog
);
278 if (plugin_pref_dialogs
!= NULL
&&
279 (dialog
= g_hash_table_lookup(plugin_pref_dialogs
, plug
)))
280 pref_dialog_response_cb(dialog
, GTK_RESPONSE_DELETE_EVENT
, plug
);
282 if (plug
->dependent_plugins
!= NULL
)
284 GString
*tmp
= g_string_new(_("The following plugins will be unloaded."));
288 for (l
= plug
->dependent_plugins
; l
!= NULL
; l
= l
->next
)
290 const char *dep_name
= (const char *)l
->data
;
291 PurplePlugin
*dep_plugin
= purple_plugins_find_with_id(dep_name
);
292 g_return_if_fail(dep_plugin
!= NULL
);
294 g_string_append_printf(tmp
, "\n\t%s\n", purple_plugin_get_name(dep_plugin
));
297 cb_data
= g_new(gpointer
, 3);
302 purple_request_action(plugin_dialog
, NULL
,
303 _("Multiple plugins will be unloaded."),
307 _("Unload Plugins"), G_CALLBACK(plugin_unload_confirm_cb
),
308 _("Cancel"), g_free
);
309 g_string_free(tmp
, TRUE
);
312 plugin_toggled_stage_two(plug
, model
, iter
, TRUE
);
316 static void plugin_toggled_stage_two(PurplePlugin
*plug
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gboolean unload
)
320 pidgin_set_cursor(plugin_dialog
, GDK_WATCH
);
322 if (!purple_plugin_unload(plug
))
324 const char *primary
= _("Could not unload plugin");
325 const char *reload
= _("The plugin could not be unloaded now, but will be disabled at the next startup.");
329 purple_notify_warning(NULL
, NULL
, primary
, reload
);
333 char *tmp
= g_strdup_printf("%s\n\n%s", reload
, plug
->error
);
334 purple_notify_warning(NULL
, NULL
, primary
, tmp
);
338 purple_plugin_disable(plug
);
341 pidgin_clear_cursor(plugin_dialog
);
344 gtk_widget_set_sensitive(pref_button
,
345 purple_plugin_is_loaded(plug
)
346 && ((PIDGIN_IS_PIDGIN_PLUGIN(plug
) && plug
->info
->ui_info
347 && PIDGIN_PLUGIN_UI_INFO(plug
)->get_config_frame
)
348 || (plug
->info
->prefs_info
349 && plug
->info
->prefs_info
->get_plugin_pref_frame
)));
351 if (plug
->error
!= NULL
)
353 gchar
*name
= g_markup_escape_text(purple_plugin_get_name(plug
), -1);
355 gchar
*error
= g_markup_escape_text(plug
->error
, -1);
358 text
= g_strdup_printf(
359 "<b>%s</b> %s\n<span weight=\"bold\" color=\"red\"%s</span>",
360 purple_plugin_get_name(plug
), purple_plugin_get_version(plug
), error
);
361 gtk_list_store_set(GTK_LIST_STORE (model
), iter
,
366 text
= g_strdup_printf(
367 "<span weight=\"bold\" color=\"red\">%s</span>",
369 gtk_label_set_markup(plugin_error
, text
);
376 gtk_list_store_set(GTK_LIST_STORE (model
), iter
,
377 0, purple_plugin_is_loaded(plug
),
381 pidgin_plugins_save();
384 static gboolean
ensure_plugin_visible(void *data
)
386 GtkTreeSelection
*sel
= GTK_TREE_SELECTION(data
);
387 GtkTreeView
*tv
= gtk_tree_selection_get_tree_view(sel
);
388 GtkTreeModel
*model
= gtk_tree_view_get_model(tv
);
391 if (!gtk_tree_selection_get_selected (sel
, &model
, &iter
))
393 path
= gtk_tree_model_get_path(model
, &iter
);
394 gtk_tree_view_scroll_to_cell(gtk_tree_selection_get_tree_view(sel
), path
, NULL
, FALSE
, 0, 0);
395 gtk_tree_path_free(path
);
399 static void prefs_plugin_sel (GtkTreeSelection
*sel
, GtkTreeModel
*model
)
401 gchar
*buf
, *tmp
, *name
, *version
;
406 if (!gtk_tree_selection_get_selected (sel
, &model
, &iter
))
408 gtk_widget_set_sensitive(pref_button
, FALSE
);
410 /* Collapse and disable the expander widget */
411 gtk_expander_set_expanded(GTK_EXPANDER(expander
), FALSE
);
412 gtk_widget_set_sensitive(expander
, FALSE
);
417 gtk_widget_set_sensitive(expander
, TRUE
);
420 gtk_tree_model_get_value (model
, &iter
, 2, &val
);
421 plug
= g_value_get_pointer(&val
);
423 name
= g_markup_escape_text(purple_plugin_get_name(plug
), -1);
424 version
= g_markup_escape_text(purple_plugin_get_version(plug
), -1);
425 buf
= g_strdup_printf(
426 "<span size=\"larger\" weight=\"bold\">%s</span> "
427 "<span size=\"smaller\">%s</span>",
429 gtk_label_set_markup(plugin_name
, buf
);
434 gtk_text_buffer_set_text(plugin_desc
, purple_plugin_get_description(plug
), -1);
435 gtk_label_set_text(plugin_author
, purple_plugin_get_author(plug
));
436 gtk_label_set_text(plugin_filename
, plug
->path
);
438 g_free(plugin_website_uri
);
439 plugin_website_uri
= g_strdup(purple_plugin_get_homepage(plug
));
440 if (plugin_website_uri
)
442 tmp
= g_markup_escape_text(plugin_website_uri
, -1);
443 buf
= g_strdup_printf("<span underline=\"single\" "
444 "foreground=\"blue\">%s</span>", tmp
);
445 gtk_label_set_markup(plugin_website
, buf
);
451 gtk_label_set_text(plugin_website
, NULL
);
454 if (plug
->error
== NULL
)
456 gtk_label_set_text(plugin_error
, NULL
);
460 tmp
= g_markup_escape_text(plug
->error
, -1);
461 buf
= g_strdup_printf(
462 _("<span foreground=\"red\" weight=\"bold\">"
464 "Check the plugin website for an update."
467 gtk_label_set_markup(plugin_error
, buf
);
472 gtk_widget_set_sensitive(pref_button
,
473 purple_plugin_is_loaded(plug
)
474 && ((PIDGIN_IS_PIDGIN_PLUGIN(plug
) && plug
->info
->ui_info
475 && PIDGIN_PLUGIN_UI_INFO(plug
)->get_config_frame
)
476 || (plug
->info
->prefs_info
477 && plug
->info
->prefs_info
->get_plugin_pref_frame
)));
479 /* Make sure the selected plugin is still visible */
480 g_idle_add(ensure_plugin_visible
, sel
);
485 static void plugin_dialog_response_cb(GtkWidget
*d
, int response
, GtkTreeSelection
*sel
)
488 GtkWidget
*dialog
, *box
;
494 case GTK_RESPONSE_CLOSE
:
495 case GTK_RESPONSE_DELETE_EVENT
:
496 purple_request_close_with_handle(plugin_dialog
);
497 purple_signals_disconnect_by_handle(plugin_dialog
);
498 gtk_widget_destroy(d
);
499 if (plugin_pref_dialogs
!= NULL
) {
500 g_hash_table_destroy(plugin_pref_dialogs
);
501 plugin_pref_dialogs
= NULL
;
503 plugin_dialog
= NULL
;
505 case PIDGIN_RESPONSE_CONFIGURE
:
506 if (! gtk_tree_selection_get_selected (sel
, &model
, &iter
))
509 gtk_tree_model_get_value(model
, &iter
, 2, &val
);
510 plug
= g_value_get_pointer(&val
);
513 if (plugin_pref_dialogs
!= NULL
&&
514 g_hash_table_lookup(plugin_pref_dialogs
, plug
))
516 box
= pidgin_plugin_get_config_frame(plug
);
520 dialog
= gtk_dialog_new_with_buttons(PIDGIN_ALERT_TITLE
, GTK_WINDOW(d
),
521 GTK_DIALOG_NO_SEPARATOR
| GTK_DIALOG_DESTROY_WITH_PARENT
,
522 GTK_STOCK_CLOSE
, GTK_RESPONSE_CLOSE
,
524 if (plugin_pref_dialogs
== NULL
)
525 plugin_pref_dialogs
= g_hash_table_new(NULL
, NULL
);
527 g_hash_table_insert(plugin_pref_dialogs
, plug
, dialog
);
529 g_signal_connect(G_OBJECT(dialog
), "response", G_CALLBACK(pref_dialog_response_cb
), plug
);
530 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
),
531 pidgin_make_scrollable(box
, GTK_POLICY_AUTOMATIC
,
532 GTK_POLICY_AUTOMATIC
, GTK_SHADOW_IN
, 400, 400));
533 gtk_window_set_role(GTK_WINDOW(dialog
), "plugin_config");
534 gtk_window_set_title(GTK_WINDOW(dialog
), _(purple_plugin_get_name(plug
)));
535 gtk_widget_show_all(dialog
);
542 show_plugin_prefs_cb(GtkTreeView
*view
, GtkTreePath
*path
, GtkTreeViewColumn
*column
, GtkWidget
*dialog
)
544 GtkTreeSelection
*sel
;
546 PurplePlugin
*plugin
;
549 sel
= gtk_tree_view_get_selection(view
);
551 if (!gtk_tree_selection_get_selected(sel
, &model
, &iter
))
554 gtk_tree_model_get(model
, &iter
, 2, &plugin
, -1);
556 if (!purple_plugin_is_loaded(plugin
))
559 /* Now show the pref-dialog for the plugin */
560 plugin_dialog_response_cb(dialog
, PIDGIN_RESPONSE_CONFIGURE
, sel
);
564 pidgin_plugins_paint_tooltip(GtkWidget
*tipwindow
, gpointer data
)
566 PangoLayout
*layout
= g_object_get_data(G_OBJECT(tipwindow
), "tooltip-plugin");
567 gtk_paint_layout(tipwindow
->style
, tipwindow
->window
, GTK_STATE_NORMAL
, FALSE
,
568 NULL
, tipwindow
, "tooltip",
574 pidgin_plugins_create_tooltip(GtkWidget
*tipwindow
, GtkTreePath
*path
,
575 gpointer data
, int *w
, int *h
)
578 GtkTreeView
*treeview
= GTK_TREE_VIEW(data
);
579 PurplePlugin
*plugin
= NULL
;
580 GtkTreeModel
*model
= gtk_tree_view_get_model(treeview
);
583 char *markup
, *name
, *desc
, *author
;
585 if (!gtk_tree_model_get_iter(model
, &iter
, path
))
588 gtk_tree_model_get(model
, &iter
, 2, &plugin
, -1);
590 markup
= g_strdup_printf("<span size='x-large' weight='bold'>%s</span>\n<b>%s:</b> %s\n<b>%s:</b> %s",
591 name
= g_markup_escape_text(purple_plugin_get_name(plugin
), -1),
592 _("Description"), desc
= g_markup_escape_text(purple_plugin_get_description(plugin
), -1),
593 _("Author"), author
= g_markup_escape_text(purple_plugin_get_author(plugin
), -1));
595 layout
= gtk_widget_create_pango_layout(tipwindow
, NULL
);
596 pango_layout_set_markup(layout
, markup
, -1);
597 pango_layout_set_wrap(layout
, PANGO_WRAP_WORD
);
598 pango_layout_set_width(layout
, 600000);
599 pango_layout_get_size(layout
, &width
, &height
);
600 g_object_set_data_full(G_OBJECT(tipwindow
), "tooltip-plugin", layout
, g_object_unref
);
603 *w
= PANGO_PIXELS(width
) + 12;
605 *h
= PANGO_PIXELS(height
) + 12;
616 website_button_motion_cb(GtkWidget
*button
, GdkEventCrossing
*event
,
619 if (plugin_website_uri
) {
620 pidgin_set_cursor(button
, GDK_HAND2
);
627 website_button_clicked_cb(GtkButton
*button
, GdkEventButton
*event
,
630 if (plugin_website_uri
) {
631 purple_notify_uri(NULL
, plugin_website_uri
);
640 GtkBox
*vbox
= GTK_BOX(gtk_vbox_new(FALSE
, 3));
641 GtkSizeGroup
*sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
642 GtkWidget
*label
, *view
, *website_button
;
644 plugin_name
= GTK_LABEL(gtk_label_new(NULL
));
645 gtk_misc_set_alignment(GTK_MISC(plugin_name
), 0, 0);
646 gtk_label_set_line_wrap(plugin_name
, FALSE
);
647 gtk_label_set_selectable(plugin_name
, TRUE
);
648 gtk_box_pack_start(vbox
, GTK_WIDGET(plugin_name
), FALSE
, FALSE
, 0);
650 view
= gtk_text_view_new();
651 plugin_desc
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(view
));
652 g_object_set(view
, "wrap-mode", GTK_WRAP_WORD
,
654 "left-margin", PIDGIN_HIG_CAT_SPACE
,
655 "right-margin", PIDGIN_HIG_CAT_SPACE
,
657 gtk_box_pack_start(vbox
, view
, TRUE
, TRUE
, 0);
659 plugin_error
= GTK_LABEL(gtk_label_new(NULL
));
660 gtk_misc_set_alignment(GTK_MISC(plugin_error
), 0, 0);
661 gtk_label_set_line_wrap(plugin_error
, FALSE
);
662 gtk_label_set_selectable(plugin_error
, TRUE
);
663 gtk_box_pack_start(vbox
, GTK_WIDGET(plugin_error
), FALSE
, FALSE
, 0);
665 plugin_author
= GTK_LABEL(gtk_label_new(NULL
));
666 gtk_label_set_line_wrap(plugin_author
, FALSE
);
667 gtk_misc_set_alignment(GTK_MISC(plugin_author
), 0, 0);
668 gtk_label_set_selectable(plugin_author
, TRUE
);
669 pidgin_add_widget_to_vbox(vbox
, "", sg
,
670 GTK_WIDGET(plugin_author
), TRUE
, &label
);
671 gtk_label_set_markup(GTK_LABEL(label
), _("<b>Written by:</b>"));
672 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
674 website_button
= gtk_event_box_new();
675 gtk_event_box_set_visible_window(GTK_EVENT_BOX(website_button
), FALSE
);
677 plugin_website
= GTK_LABEL(gtk_label_new(NULL
));
678 g_object_set(G_OBJECT(plugin_website
),
679 "ellipsize", PANGO_ELLIPSIZE_MIDDLE
, NULL
);
680 gtk_misc_set_alignment(GTK_MISC(plugin_website
), 0, 0);
681 gtk_container_add(GTK_CONTAINER(website_button
),
682 GTK_WIDGET(plugin_website
));
683 g_signal_connect(website_button
, "button-release-event",
684 G_CALLBACK(website_button_clicked_cb
), NULL
);
685 g_signal_connect(website_button
, "enter-notify-event",
686 G_CALLBACK(website_button_motion_cb
), NULL
);
687 g_signal_connect(website_button
, "leave-notify-event",
688 G_CALLBACK(pidgin_clear_cursor
), NULL
);
690 pidgin_add_widget_to_vbox(vbox
, "", sg
, website_button
, TRUE
, &label
);
691 gtk_label_set_markup(GTK_LABEL(label
), _("<b>Web site:</b>"));
692 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
694 plugin_filename
= GTK_LABEL(gtk_label_new(NULL
));
695 gtk_label_set_line_wrap(plugin_filename
, FALSE
);
696 gtk_misc_set_alignment(GTK_MISC(plugin_filename
), 0, 0);
697 gtk_label_set_selectable(plugin_filename
, TRUE
);
698 pidgin_add_widget_to_vbox(vbox
, "", sg
,
699 GTK_WIDGET(plugin_filename
), TRUE
, &label
);
700 gtk_label_set_markup(GTK_LABEL(label
), _("<b>Filename:</b>"));
701 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
705 return GTK_WIDGET(vbox
);
709 void pidgin_plugin_dialog_show()
711 GtkWidget
*event_view
;
713 GtkCellRenderer
*rend
, *rendt
;
714 GtkTreeViewColumn
*col
;
715 GtkTreeSelection
*sel
;
717 if (plugin_dialog
!= NULL
) {
718 gtk_window_present(GTK_WINDOW(plugin_dialog
));
722 plugin_dialog
= gtk_dialog_new_with_buttons(_("Plugins"),
724 GTK_DIALOG_NO_SEPARATOR
,
726 pref_button
= gtk_dialog_add_button(GTK_DIALOG(plugin_dialog
),
727 _("Configure Pl_ugin"), PIDGIN_RESPONSE_CONFIGURE
);
728 gtk_dialog_add_button(GTK_DIALOG(plugin_dialog
),
729 GTK_STOCK_CLOSE
, GTK_RESPONSE_CLOSE
);
730 gtk_widget_set_sensitive(pref_button
, FALSE
);
731 gtk_window_set_role(GTK_WINDOW(plugin_dialog
), "plugins");
733 ls
= gtk_list_store_new(4, G_TYPE_BOOLEAN
, G_TYPE_STRING
, G_TYPE_POINTER
, G_TYPE_BOOLEAN
);
734 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls
),
735 1, GTK_SORT_ASCENDING
);
737 update_plugin_list(ls
);
739 event_view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls
));
741 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(event_view
), TRUE
);
743 g_signal_connect(G_OBJECT(event_view
), "row-activated",
744 G_CALLBACK(show_plugin_prefs_cb
), plugin_dialog
);
746 purple_signal_connect(purple_plugins_get_handle(), "plugin-load", plugin_dialog
,
747 PURPLE_CALLBACK(plugin_load_cb
), event_view
);
748 purple_signal_connect(purple_plugins_get_handle(), "plugin-unload", plugin_dialog
,
749 PURPLE_CALLBACK(plugin_unload_cb
), event_view
);
751 rend
= gtk_cell_renderer_toggle_new();
752 sel
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_view
));
754 col
= gtk_tree_view_column_new_with_attributes (_("Enabled"),
758 gtk_tree_view_append_column (GTK_TREE_VIEW(event_view
), col
);
759 gtk_tree_view_column_set_sort_column_id(col
, 0);
760 g_signal_connect(G_OBJECT(rend
), "toggled",
761 G_CALLBACK(plugin_toggled
), ls
);
763 rendt
= gtk_cell_renderer_text_new();
765 "foreground", "#c0c0c0",
767 col
= gtk_tree_view_column_new_with_attributes (_("Name"),
772 gtk_tree_view_column_set_expand (col
, TRUE
);
773 g_object_set(rendt
, "ellipsize", PANGO_ELLIPSIZE_END
, NULL
);
774 gtk_tree_view_append_column (GTK_TREE_VIEW(event_view
), col
);
775 gtk_tree_view_column_set_sort_column_id(col
, 1);
776 g_object_unref(G_OBJECT(ls
));
777 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(plugin_dialog
)->vbox
),
778 pidgin_make_scrollable(event_view
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
, GTK_SHADOW_IN
, -1, -1),
780 gtk_tree_view_set_search_column(GTK_TREE_VIEW(event_view
), 1);
781 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(event_view
),
782 pidgin_tree_view_search_equal_func
, NULL
, NULL
);
784 pidgin_tooltip_setup_for_treeview(event_view
, event_view
,
785 pidgin_plugins_create_tooltip
,
786 pidgin_plugins_paint_tooltip
);
789 expander
= gtk_expander_new(_("<b>Plugin Details</b>"));
790 gtk_expander_set_use_markup(GTK_EXPANDER(expander
), TRUE
);
791 gtk_widget_set_sensitive(expander
, FALSE
);
792 gtk_container_add(GTK_CONTAINER(expander
), create_details());
793 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(plugin_dialog
)->vbox
), expander
,
797 g_signal_connect (G_OBJECT (sel
), "changed", G_CALLBACK (prefs_plugin_sel
), NULL
);
798 g_signal_connect(G_OBJECT(plugin_dialog
), "response", G_CALLBACK(plugin_dialog_response_cb
), sel
);
799 gtk_window_set_default_size(GTK_WINDOW(plugin_dialog
), 430, 530);
801 pidgin_auto_parent_window(plugin_dialog
);
803 gtk_widget_show_all(plugin_dialog
);