| 37 |
37 |
| 38 #include "gtk3compat.h" |
38 #include "gtk3compat.h" |
| 39 |
39 |
| 40 #define PIDGIN_RESPONSE_CONFIGURE 98121 |
40 #define PIDGIN_RESPONSE_CONFIGURE 98121 |
| 41 |
41 |
| |
42 typedef struct |
| |
43 { |
| |
44 enum |
| |
45 { |
| |
46 PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME, |
| |
47 PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST |
| |
48 } type; |
| |
49 |
| |
50 union |
| |
51 { |
| |
52 struct |
| |
53 { |
| |
54 GtkWidget *dialog; |
| |
55 PurplePluginPrefFrame *pref_frame; |
| |
56 } frame; |
| |
57 |
| |
58 gpointer request_handle; |
| |
59 } u; |
| |
60 } PidginPluginUiData; |
| |
61 |
| 42 static void plugin_toggled_stage_two(PurplePlugin *plug, GtkTreeModel *model, |
62 static void plugin_toggled_stage_two(PurplePlugin *plug, GtkTreeModel *model, |
| 43 GtkTreeIter *iter, gboolean unload); |
63 GtkTreeIter *iter, gboolean unload); |
| 44 |
64 |
| 45 static GtkWidget *expander = NULL; |
65 static GtkWidget *expander = NULL; |
| 46 static GtkWidget *plugin_dialog = NULL; |
66 static GtkWidget *plugin_dialog = NULL; |
| 52 static GtkLabel *plugin_website = NULL; |
72 static GtkLabel *plugin_website = NULL; |
| 53 static gchar *plugin_website_uri = NULL; |
73 static gchar *plugin_website_uri = NULL; |
| 54 static GtkLabel *plugin_filename = NULL; |
74 static GtkLabel *plugin_filename = NULL; |
| 55 |
75 |
| 56 static GtkWidget *pref_button = NULL; |
76 static GtkWidget *pref_button = NULL; |
| 57 static GHashTable *plugin_pref_dialogs = NULL; |
77 |
| 58 |
78 static gboolean |
| 59 GtkWidget * |
79 pidgin_plugin_has_prefs(PurplePlugin *plugin) |
| 60 pidgin_plugin_get_config_frame(PurplePlugin *plugin) |
80 { |
| |
81 PurplePluginUiInfo *pinfo; |
| |
82 |
| |
83 g_return_val_if_fail(plugin != NULL, FALSE); |
| |
84 |
| |
85 if (!purple_plugin_is_loaded(plugin)) |
| |
86 return FALSE; |
| |
87 |
| |
88 if (PIDGIN_IS_PIDGIN_PLUGIN(plugin) && plugin->info->ui_info && |
| |
89 PIDGIN_PLUGIN_UI_INFO(plugin)->get_config_frame) |
| |
90 { |
| |
91 return TRUE; |
| |
92 } |
| |
93 |
| |
94 pinfo = plugin->info->prefs_info; |
| |
95 |
| |
96 if (!pinfo) |
| |
97 return FALSE; |
| |
98 |
| |
99 return (pinfo->get_plugin_pref_frame || pinfo->get_plugin_pref_request); |
| |
100 } |
| |
101 |
| |
102 static GtkWidget * |
| |
103 pidgin_plugin_get_config_frame(PurplePlugin *plugin, |
| |
104 PurplePluginPrefFrame **purple_pref_frame) |
| 61 { |
105 { |
| 62 GtkWidget *config = NULL; |
106 GtkWidget *config = NULL; |
| 63 |
107 |
| 64 g_return_val_if_fail(plugin != NULL, NULL); |
108 g_return_val_if_fail(plugin != NULL, NULL); |
| 65 |
109 |
| 69 PidginPluginUiInfo *ui_info; |
113 PidginPluginUiInfo *ui_info; |
| 70 |
114 |
| 71 ui_info = PIDGIN_PLUGIN_UI_INFO(plugin); |
115 ui_info = PIDGIN_PLUGIN_UI_INFO(plugin); |
| 72 |
116 |
| 73 config = ui_info->get_config_frame(plugin); |
117 config = ui_info->get_config_frame(plugin); |
| 74 |
|
| 75 if (plugin->info->prefs_info |
|
| 76 && plugin->info->prefs_info->get_plugin_pref_frame) |
|
| 77 { |
|
| 78 purple_debug_warning("gtkplugin", |
|
| 79 "Plugin %s contains both, ui_info and " |
|
| 80 "prefs_info preferences; prefs_info will be " |
|
| 81 "ignored.", plugin->info->name); |
|
| 82 } |
|
| 83 } |
118 } |
| 84 |
119 |
| 85 if (config == NULL && plugin->info->prefs_info |
120 if (config == NULL && plugin->info->prefs_info |
| 86 && plugin->info->prefs_info->get_plugin_pref_frame) |
121 && plugin->info->prefs_info->get_plugin_pref_frame) |
| 87 { |
122 { |
| 89 |
124 |
| 90 frame = plugin->info->prefs_info->get_plugin_pref_frame(plugin); |
125 frame = plugin->info->prefs_info->get_plugin_pref_frame(plugin); |
| 91 |
126 |
| 92 config = pidgin_plugin_pref_create_frame(frame); |
127 config = pidgin_plugin_pref_create_frame(frame); |
| 93 |
128 |
| 94 plugin->ui_data = frame; |
129 *purple_pref_frame = frame; |
| 95 } |
130 } |
| 96 |
131 |
| 97 return config; |
132 return config; |
| |
133 } |
| |
134 |
| |
135 static void |
| |
136 pref_dialog_close(PurplePlugin *plugin) |
| |
137 { |
| |
138 PidginPluginUiData *ui_data; |
| |
139 |
| |
140 g_return_if_fail(plugin != NULL); |
| |
141 |
| |
142 ui_data = plugin->ui_data; |
| |
143 if (ui_data == NULL) |
| |
144 return; |
| |
145 |
| |
146 if (ui_data->type == PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST) { |
| |
147 purple_request_close(PURPLE_REQUEST_FIELDS, |
| |
148 ui_data->u.request_handle); |
| |
149 return; |
| |
150 } |
| |
151 |
| |
152 g_return_if_fail(ui_data->type == PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME); |
| |
153 |
| |
154 gtk_widget_destroy(ui_data->u.frame.dialog); |
| |
155 |
| |
156 if (ui_data->u.frame.pref_frame) |
| |
157 purple_plugin_pref_frame_destroy(ui_data->u.frame.pref_frame); |
| |
158 |
| |
159 g_free(ui_data); |
| |
160 plugin->ui_data = NULL; |
| |
161 } |
| |
162 |
| |
163 |
| |
164 static void |
| |
165 pref_dialog_response_cb(GtkWidget *dialog, int response, PurplePlugin *plugin) |
| |
166 { |
| |
167 if (response == GTK_RESPONSE_CLOSE || |
| |
168 response == GTK_RESPONSE_DELETE_EVENT) |
| |
169 { |
| |
170 pref_dialog_close(plugin); |
| |
171 } |
| |
172 } |
| |
173 |
| |
174 static void |
| |
175 pidgin_plugin_open_config(PurplePlugin *plugin, GtkWindow *parent) |
| |
176 { |
| |
177 PurplePluginUiInfo *pinfo; |
| |
178 PidginPluginUiData *ui_data; |
| |
179 gboolean has_purple_frame, has_purple_request, has_pidgin_frame; |
| |
180 gint prefs_count; |
| |
181 |
| |
182 g_return_if_fail(plugin != NULL); |
| |
183 |
| |
184 if (!pidgin_plugin_has_prefs(plugin)) { |
| |
185 purple_debug_warning("gtkplugin", "Plugin has no prefs"); |
| |
186 return; |
| |
187 } |
| |
188 |
| |
189 if (plugin->ui_data != NULL) |
| |
190 return; |
| |
191 |
| |
192 pinfo = plugin->info->prefs_info; |
| |
193 has_purple_frame = (pinfo->get_plugin_pref_frame != NULL); |
| |
194 has_purple_request = (pinfo->get_plugin_pref_request != NULL); |
| |
195 has_pidgin_frame = (PIDGIN_IS_PIDGIN_PLUGIN(plugin) && |
| |
196 plugin->info->ui_info && |
| |
197 PIDGIN_PLUGIN_UI_INFO(plugin)->get_config_frame); |
| |
198 |
| |
199 prefs_count = 0; |
| |
200 if (has_purple_frame) |
| |
201 prefs_count++; |
| |
202 if (has_purple_request) |
| |
203 prefs_count++; |
| |
204 if (has_pidgin_frame) |
| |
205 prefs_count++; |
| |
206 |
| |
207 if (prefs_count > 1) { |
| |
208 purple_debug_warning("gtkplugin", "Plugin %s contains more than" |
| |
209 " one prefs callback, some will be ignored.", |
| |
210 plugin->info->name); |
| |
211 } |
| |
212 g_return_if_fail(prefs_count > 0); |
| |
213 |
| |
214 plugin->ui_data = ui_data = g_new0(PidginPluginUiData, 1); |
| |
215 |
| |
216 /* Priority: pidgin frame > purple request > purple frame |
| |
217 * Purple frame could be replaced with purple request some day. |
| |
218 */ |
| |
219 if (has_purple_request && !has_pidgin_frame) { |
| |
220 ui_data->type = PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST; |
| |
221 ui_data->u.request_handle = |
| |
222 pinfo->get_plugin_pref_request(plugin); |
| |
223 purple_request_add_close_notify(ui_data->u.request_handle, |
| |
224 purple_callback_set_zero, &plugin->ui_data); |
| |
225 purple_request_add_close_notify(ui_data->u.request_handle, |
| |
226 g_free, ui_data); |
| |
227 } else { |
| |
228 GtkWidget *box, *dialog; |
| |
229 |
| |
230 ui_data->type = PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME; |
| |
231 |
| |
232 box = pidgin_plugin_get_config_frame(plugin, |
| |
233 &ui_data->u.frame.pref_frame); |
| |
234 if (box == NULL) { |
| |
235 purple_debug_error("gtkplugin", |
| |
236 "Failed to display prefs frame"); |
| |
237 g_free(ui_data); |
| |
238 plugin->ui_data = NULL; |
| |
239 return; |
| |
240 } |
| |
241 |
| |
242 ui_data->u.frame.dialog = dialog = gtk_dialog_new_with_buttons( |
| |
243 PIDGIN_ALERT_TITLE, parent, |
| |
244 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, |
| |
245 GTK_RESPONSE_CLOSE, NULL); |
| |
246 |
| |
247 g_signal_connect(G_OBJECT(dialog), "response", |
| |
248 G_CALLBACK(pref_dialog_response_cb), plugin); |
| |
249 gtk_container_add(GTK_CONTAINER( |
| |
250 gtk_dialog_get_content_area(GTK_DIALOG(dialog))), box); |
| |
251 gtk_window_set_role(GTK_WINDOW(dialog), "plugin_config"); |
| |
252 gtk_window_set_title(GTK_WINDOW(dialog), |
| |
253 _(purple_plugin_get_name(plugin))); |
| |
254 gtk_widget_show_all(dialog); |
| |
255 } |
| 98 } |
256 } |
| 99 |
257 |
| 100 void |
258 void |
| 101 pidgin_plugins_save(void) |
259 pidgin_plugins_save(void) |
| 102 { |
260 { |
| 211 |
365 |
| 212 static void plugin_unload_cb(PurplePlugin *plugin, gpointer data) |
366 static void plugin_unload_cb(PurplePlugin *plugin, gpointer data) |
| 213 { |
367 { |
| 214 GtkTreeView *view = (GtkTreeView *)data; |
368 GtkTreeView *view = (GtkTreeView *)data; |
| 215 plugin_loading_common(plugin, view, FALSE); |
369 plugin_loading_common(plugin, view, FALSE); |
| 216 } |
|
| 217 |
|
| 218 static void pref_dialog_response_cb(GtkWidget *d, int response, PurplePlugin *plug) |
|
| 219 { |
|
| 220 switch (response) { |
|
| 221 case GTK_RESPONSE_CLOSE: |
|
| 222 case GTK_RESPONSE_DELETE_EVENT: |
|
| 223 g_hash_table_remove(plugin_pref_dialogs, plug); |
|
| 224 if (g_hash_table_size(plugin_pref_dialogs) == 0) { |
|
| 225 g_hash_table_destroy(plugin_pref_dialogs); |
|
| 226 plugin_pref_dialogs = NULL; |
|
| 227 } |
|
| 228 gtk_widget_destroy(d); |
|
| 229 |
|
| 230 if (plug->info->prefs_info && plug->ui_data) { |
|
| 231 purple_plugin_pref_frame_destroy(plug->ui_data); |
|
| 232 plug->ui_data = NULL; |
|
| 233 } |
|
| 234 |
|
| 235 break; |
|
| 236 } |
|
| 237 } |
370 } |
| 238 |
371 |
| 239 static void plugin_unload_confirm_cb(gpointer *data) |
372 static void plugin_unload_confirm_cb(gpointer *data) |
| 240 { |
373 { |
| 241 PurplePlugin *plugin = (PurplePlugin *)data[0]; |
374 PurplePlugin *plugin = (PurplePlugin *)data[0]; |
| 251 { |
384 { |
| 252 GtkTreeModel *model = (GtkTreeModel *)data; |
385 GtkTreeModel *model = (GtkTreeModel *)data; |
| 253 GtkTreeIter *iter = g_new(GtkTreeIter, 1); |
386 GtkTreeIter *iter = g_new(GtkTreeIter, 1); |
| 254 GtkTreePath *path = gtk_tree_path_new_from_string(pth); |
387 GtkTreePath *path = gtk_tree_path_new_from_string(pth); |
| 255 PurplePlugin *plug; |
388 PurplePlugin *plug; |
| 256 GtkWidget *dialog = NULL; |
|
| 257 |
389 |
| 258 gtk_tree_model_get_iter(model, iter, path); |
390 gtk_tree_model_get_iter(model, iter, path); |
| 259 gtk_tree_path_free(path); |
391 gtk_tree_path_free(path); |
| 260 gtk_tree_model_get(model, iter, 2, &plug, -1); |
392 gtk_tree_model_get(model, iter, 2, &plug, -1); |
| 261 |
393 |
| 468 gtk_label_set_markup(plugin_error, buf); |
593 gtk_label_set_markup(plugin_error, buf); |
| 469 g_free(buf); |
594 g_free(buf); |
| 470 g_free(tmp); |
595 g_free(tmp); |
| 471 } |
596 } |
| 472 |
597 |
| 473 gtk_widget_set_sensitive(pref_button, |
598 gtk_widget_set_sensitive(pref_button, pidgin_plugin_has_prefs(plug)); |
| 474 purple_plugin_is_loaded(plug) |
|
| 475 && ((PIDGIN_IS_PIDGIN_PLUGIN(plug) && plug->info->ui_info |
|
| 476 && PIDGIN_PLUGIN_UI_INFO(plug)->get_config_frame) |
|
| 477 || (plug->info->prefs_info |
|
| 478 && plug->info->prefs_info->get_plugin_pref_frame))); |
|
| 479 |
599 |
| 480 /* Make sure the selected plugin is still visible */ |
600 /* Make sure the selected plugin is still visible */ |
| 481 g_idle_add(ensure_plugin_visible, sel); |
601 g_idle_add(ensure_plugin_visible, sel); |
| 482 |
602 |
| 483 g_value_unset(&val); |
603 g_value_unset(&val); |
| 484 } |
604 } |
| 485 |
605 |
| 486 static void plugin_dialog_response_cb(GtkWidget *d, int response, GtkTreeSelection *sel) |
606 static void plugin_dialog_response_cb(GtkWidget *d, int response, GtkTreeSelection *sel) |
| 487 { |
607 { |
| 488 PurplePlugin *plug; |
608 PurplePlugin *plugin; |
| 489 GtkWidget *dialog, *box; |
|
| 490 GtkTreeModel *model; |
609 GtkTreeModel *model; |
| 491 GValue val; |
610 GValue val; |
| 492 GtkTreeIter iter; |
611 GtkTreeIter iter; |
| |
612 GList *it; |
| 493 |
613 |
| 494 switch (response) { |
614 switch (response) { |
| 495 case GTK_RESPONSE_CLOSE: |
615 case GTK_RESPONSE_CLOSE: |
| 496 case GTK_RESPONSE_DELETE_EVENT: |
616 case GTK_RESPONSE_DELETE_EVENT: |
| 497 purple_request_close_with_handle(plugin_dialog); |
617 purple_request_close_with_handle(plugin_dialog); |
| 498 purple_signals_disconnect_by_handle(plugin_dialog); |
618 purple_signals_disconnect_by_handle(plugin_dialog); |
| |
619 for (it = purple_plugins_get_all(); it; it = g_list_next(it)) |
| |
620 pref_dialog_close(it->data); |
| 499 gtk_widget_destroy(d); |
621 gtk_widget_destroy(d); |
| 500 if (plugin_pref_dialogs != NULL) { |
|
| 501 g_hash_table_destroy(plugin_pref_dialogs); |
|
| 502 plugin_pref_dialogs = NULL; |
|
| 503 } |
|
| 504 plugin_dialog = NULL; |
622 plugin_dialog = NULL; |
| 505 break; |
623 break; |
| 506 case PIDGIN_RESPONSE_CONFIGURE: |
624 case PIDGIN_RESPONSE_CONFIGURE: |
| 507 if (! gtk_tree_selection_get_selected (sel, &model, &iter)) |
625 if (! gtk_tree_selection_get_selected (sel, &model, &iter)) |
| 508 return; |
626 return; |
| 509 val.g_type = 0; |
627 val.g_type = 0; |
| 510 gtk_tree_model_get_value(model, &iter, 2, &val); |
628 gtk_tree_model_get_value(model, &iter, 2, &val); |
| 511 plug = g_value_get_pointer(&val); |
629 plugin = g_value_get_pointer(&val); |
| 512 if (plug == NULL) |
630 g_value_unset(&val); |
| |
631 if (plugin == NULL) |
| 513 break; |
632 break; |
| 514 if (plugin_pref_dialogs != NULL && |
633 |
| 515 g_hash_table_lookup(plugin_pref_dialogs, plug)) |
634 pidgin_plugin_open_config(plugin, GTK_WINDOW(d)); |
| 516 break; |
635 |
| 517 box = pidgin_plugin_get_config_frame(plug); |
|
| 518 if (box == NULL) |
|
| 519 break; |
|
| 520 |
|
| 521 dialog = gtk_dialog_new_with_buttons(PIDGIN_ALERT_TITLE, GTK_WINDOW(d), |
|
| 522 GTK_DIALOG_DESTROY_WITH_PARENT, |
|
| 523 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, |
|
| 524 NULL); |
|
| 525 if (plugin_pref_dialogs == NULL) |
|
| 526 plugin_pref_dialogs = g_hash_table_new(NULL, NULL); |
|
| 527 |
|
| 528 g_hash_table_insert(plugin_pref_dialogs, plug, dialog); |
|
| 529 |
|
| 530 g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(pref_dialog_response_cb), plug); |
|
| 531 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), box); |
|
| 532 gtk_window_set_role(GTK_WINDOW(dialog), "plugin_config"); |
|
| 533 gtk_window_set_title(GTK_WINDOW(dialog), _(purple_plugin_get_name(plug))); |
|
| 534 gtk_widget_show_all(dialog); |
|
| 535 g_value_unset(&val); |
|
| 536 break; |
636 break; |
| 537 } |
637 } |
| 538 } |
638 } |
| 539 |
639 |
| 540 static void |
640 static void |