00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00040 #include "go.h"
00041
00042 #include <string.h>
00043 #include <gtk/gtk.h>
00044 #include <gdk/gdkkeysyms.h>
00045
00046 #include "frontend.h"
00047 #include "question.h"
00048 #include "template.h"
00049 #include "plugin.h"
00050 #include "database.h"
00051
00052 #include "fe_gtk.h"
00053 #include "fe_data.h"
00054 #include "ui.h"
00055 #include "handlers.h"
00056 #include "select_handlers.h"
00057 #include "progress.h"
00058 #ifdef DI_UDEB
00059 # include "di.h"
00060 #endif
00061
00066 struct setter {
00071 setter_function func;
00072
00074 struct question * question;
00075
00077 void * user_data;
00078
00080 struct setter * next;
00081 };
00082
00092 void fe_gtk_register_setter(struct frontend * fe, setter_function func,
00093 struct question * question, void * user_data)
00094 {
00095 struct frontend_data * fe_data = fe->data;
00096 struct setter * setter;
00097
00098
00099 setter = g_malloc0(sizeof (struct setter));
00100 setter->func = func;
00101 setter->question = question;
00102 setter->user_data = user_data;
00103 setter->next = fe_data->setters;
00104 fe_data->setters = setter;
00105 }
00106
00111 static void call_setters(struct frontend * fe)
00112 {
00113 struct frontend_data * fe_data = fe->data;
00114 struct setter * setter;
00115
00116 setter = fe_data->setters;
00117 while (NULL != setter) {
00118 (*setter->func)(setter->question, setter->user_data);
00119 setter = setter->next;
00120 }
00121 }
00122
00127 static void free_setters(struct frontend_data * fe_data)
00128 {
00129 struct setter * setter;
00130 struct setter * previous;
00131
00132 setter = fe_data->setters;
00133 while (NULL != setter) {
00134 previous = setter;
00135 setter = setter->next;
00136 g_free(previous);
00137 }
00138 fe_data->setters = NULL;
00139 }
00140
00148 static gboolean handle_goback_key(GtkWidget * widget, GdkEventKey * key,
00149 struct frontend * fe)
00150 {
00151 if (GDK_Escape == key->keyval) {
00152 fe_gtk_set_answer_goback(fe);
00153 return TRUE;
00154 }
00155 return FALSE;
00156 }
00157
00164 static void create_goback_button(struct frontend * fe)
00165 {
00166 GtkWidget * button;
00167 char * label;
00168
00169 label = fe_gtk_get_text(fe, "debconf/button-goback", "Go Back");
00170
00171 button = gtk_button_new_with_label(label);
00172 g_free(label);
00173
00174 g_signal_connect_swapped(G_OBJECT(button), "clicked",
00175 G_CALLBACK(fe_gtk_set_answer_goback), fe);
00176
00177 fe_gtk_add_button(fe, button);
00178 fe_gtk_set_button_secondary(fe, button, TRUE);
00179 fe_gtk_add_global_key_handler(fe, button, G_CALLBACK(handle_goback_key));
00180 }
00181
00182
00183 GtkWidget * fe_gtk_create_continue_button(struct frontend * fe)
00184 {
00185 GtkWidget * button;
00186 char * label;
00187
00188
00189 label = fe_gtk_get_text(fe, "debconf/button-continue", "Continue");
00190 button = gtk_button_new_with_label(label);
00191 g_free(label);
00192
00193 g_signal_connect_swapped(G_OBJECT(button), "clicked",
00194 G_CALLBACK(fe_gtk_set_answer_ok), fe);
00195 fe_gtk_add_button(fe, button);
00196 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
00197 gtk_widget_grab_default(GTK_WIDGET(button));
00198
00199 return button;
00200 }
00201
00209 static void create_default_buttons_if_needed(struct frontend * fe)
00210 {
00211 struct frontend_data * fe_data = fe->data;
00212 GtkContainer * action_box = GTK_CONTAINER(fe_data->action_box);
00213
00214 if (NULL == gtk_container_get_children(action_box)) {
00215 (void) fe_gtk_create_continue_button(fe);
00216 }
00217 }
00218
00223 static void destroy_buttons(struct frontend * fe)
00224 {
00225 struct frontend_data * fe_data = fe->data;
00226 GtkContainer * action_box = GTK_CONTAINER(fe_data->action_box);
00227
00228 gtk_container_foreach(action_box, (GtkCallback) gtk_widget_destroy,
00229 NULL );
00230 }
00231
00234 static const struct {
00236 const char * type;
00238 fe_gtk_handler handler;
00239 } question_handlers[] = {
00240 { "boolean", fe_gtk_handle_boolean },
00241 { "multiselect", fe_gtk_handle_multiselect },
00242 { "note", fe_gtk_handle_note },
00243 { "password", fe_gtk_handle_password },
00244 { "select", fe_gtk_handle_select },
00245 { "string", fe_gtk_handle_string },
00246 { "error", fe_gtk_handle_note },
00247 { "text", fe_gtk_handle_text },
00248 { "", NULL },
00249 };
00250
00256 static fe_gtk_handler find_internal_handler(const char * type)
00257 {
00258 int i;
00259
00260 for (i = 0; NULL != question_handlers[i].handler; i++) {
00261 if (0 == strcmp(type, question_handlers[i].type)) {
00262 return question_handlers[i].handler;
00263 }
00264 }
00265 return NULL;
00266 }
00267
00277 static fe_gtk_handler find_external_handler(struct frontend * fe,
00278 const char * type)
00279 {
00280 struct frontend_data * fe_data = fe->data;
00281 struct plugin * plugin;
00282
00283
00284 plugin = g_hash_table_lookup(fe_data->plugins, type);
00285 if (NULL == plugin) {
00286
00287 if (NULL == (plugin = plugin_find(fe, type))) {
00288 g_warning("No plugin for %s", type);
00289 return NULL;
00290 }
00291
00292 g_hash_table_insert(fe_data->plugins, g_strdup(type), plugin);
00293 }
00294 return (fe_gtk_handler) plugin->handler;
00295 }
00296
00302 static void update_question_database(struct frontend * fe)
00303 {
00304 struct question * question;
00305
00306 question = fe->questions;
00307 while (NULL != question) {
00308 fe->qdb->methods.set(fe->qdb, question);
00309 question = question->next;
00310 }
00311 }
00312
00322 static gboolean call_question_handlers(struct frontend * fe,
00323 GtkWidget * question_box)
00324 {
00325 struct question * question;
00326 fe_gtk_handler handler;
00327
00328 question = fe->questions;
00329 while (NULL != question) {
00330 handler = find_internal_handler(question->template->type);
00331 if (NULL == handler) {
00332 handler = find_external_handler(fe, question->template->type);
00333 }
00334 if (NULL == handler) {
00335 return FALSE;
00336 }
00337 if (DC_OK != handler(fe, question, question_box)) {
00338 g_warning("tag \"%s\" failed to display!", question->tag);
00339
00340 }
00341 question = question->next;
00342 }
00343 return TRUE;
00344 }
00345
00367 static GtkWidget * create_question_box(struct frontend * fe,
00368 GtkWidget * container)
00369 {
00370 GtkWidget * question_box;
00371 GtkWidget * question_box_scroll = NULL;
00372
00373
00374 question_box = gtk_vbox_new(FALSE ,
00375 0 );
00376
00377 if (IS_QUESTION_SINGLE(fe->questions)) {
00378 gtk_box_pack_start(GTK_BOX(container), question_box,
00379 TRUE , TRUE ,
00380 0 );
00381 } else {
00382 question_box_scroll = gtk_scrolled_window_new(
00383 NULL ,
00384 NULL );
00385 gtk_scrolled_window_add_with_viewport(
00386 GTK_SCROLLED_WINDOW(question_box_scroll), question_box);
00387 gtk_scrolled_window_set_policy(
00388 GTK_SCROLLED_WINDOW(question_box_scroll),
00389 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
00390 gtk_scrolled_window_set_shadow_type(
00391 GTK_SCROLLED_WINDOW(question_box_scroll), GTK_SHADOW_NONE);
00392 gtk_box_pack_start(GTK_BOX(container), question_box_scroll,
00393 TRUE , TRUE ,
00394 DEFAULT_PADDING);
00395 }
00396 return question_box;
00397 }
00398
00405 static void wait_answer(struct frontend * fe)
00406 {
00407 struct frontend_data * fe_data = fe->data;
00408
00409 g_mutex_lock(fe_data->answer_mutex);
00410 while (DC_NO_ANSWER == fe_data->answer) {
00411 g_cond_wait(fe_data->answer_cond, fe_data->answer_mutex);
00412 }
00413 g_mutex_unlock(fe_data->answer_mutex);
00414 }
00415
00438 int fe_gtk_go(struct frontend * fe)
00439 {
00440 struct frontend_data * fe_data = fe->data;
00441 GtkWidget * question_box;
00442
00443 if (NULL == fe->questions) {
00444 return DC_OK;
00445 }
00446
00447 fe_gtk_set_answer(fe, DC_NO_ANSWER);
00448
00449 gdk_threads_enter();
00450 #ifdef DI_UDEB
00451
00452 fe_gtk_di_run_dialog(fe);
00453 #endif
00454 if (NULL != fe_data->progress_data) {
00455 fe_gtk_hide_progress(fe);
00456 }
00457 question_box = create_question_box(fe, fe_data->target_box);
00458 if (!call_question_handlers(fe, question_box)) {
00459
00460 fe_gtk_set_answer(fe, DC_NOTIMPL);
00461 goto end;
00462 }
00463 create_default_buttons_if_needed(fe);
00464 if (CAN_GO_BACK(fe)) {
00465 create_goback_button(fe);
00466 }
00467 fe_gtk_show_target_box(fe);
00468 fe_gtk_show_buttons(fe);
00469 gdk_threads_leave();
00470
00471
00472 wait_answer(fe);
00473
00474 if (DC_NOTOK == fe_data->answer) {
00475 goto end;
00476 }
00477
00478 gdk_threads_enter();
00479 fe_gtk_set_buttons_sensitive(fe, FALSE);
00480 if (DC_OK == fe_data->answer) {
00481 call_setters(fe);
00482 update_question_database(fe);
00483 }
00484 fe_gtk_empty_target_box(fe);
00485 destroy_buttons(fe);
00486 gdk_threads_leave();
00487
00488 end:
00489 free_setters(fe_data);
00490 return fe_data->answer;
00491 }
00492
00493
00494
00495