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 <syslog.h>
00041 #include <glib.h>
00042 #include <gtk/gtk.h>
00043 #include <signal.h>
00044 #include <string.h>
00045 #include <errno.h>
00046
00047 #include "common.h"
00048 #include "template.h"
00049 #include "question.h"
00050 #include "frontend.h"
00051 #include "database.h"
00052 #include "plugin.h"
00053 #include "strutl.h"
00054
00055 #include "fe_gtk.h"
00056 #include "fe_data.h"
00057 #include "handlers.h"
00058 #include "select_handlers.h"
00059 #include "descriptions.h"
00060 #include "progress.h"
00061 #include "go.h"
00062 #include "ui.h"
00063 #ifdef DI_UDEB
00064 # include "di.h"
00065 #endif
00066
00084 char * fe_gtk_get_text(struct frontend * fe, const char * template,
00085 const char * fallback)
00086 {
00087
00088 struct question * question = fe->qdb->methods.get(fe->qdb, template);
00089
00090 return question ? q_get_description(question) : g_strdup(fallback);
00091 }
00092
00101 static void * handle_gtk_events(void * dummy)
00102 {
00103 gdk_threads_enter();
00104 gtk_main();
00105 gdk_threads_leave();
00106
00107 return NULL ;
00108 }
00109
00116 gboolean fe_gtk_is_first_question(struct question * question)
00117 {
00118 struct question * crawl;
00119
00120 crawl = question;
00121
00122 while (NULL != crawl->prev) {
00123 if (0 != strcmp(crawl->prev->template->type, "note")) {
00124 return FALSE;
00125 }
00126 crawl = crawl->prev;
00127 }
00128 return TRUE;
00129 }
00130
00131
00132 void fe_gtk_force_quit(struct frontend * fe)
00133 {
00134 if (-1 == kill(0 , SIGTERM)) {
00135 g_critical("kill failed: %s", strerror(errno));
00136 }
00137 }
00138
00143 static void destroy_frontend_data(struct frontend * fe)
00144 {
00145 struct frontend_data * fe_data = fe->data;
00146
00147 if (NULL == fe_data) {
00148 return;
00149 }
00150 fe_gtk_progress_stop(fe);
00151
00152 fe_gtk_set_answer_notok(fe);
00153 fe->data = NULL;
00154 if (NULL != fe_data->window) {
00155 g_object_unref(G_OBJECT(fe_data->window));
00156 }
00157 if (NULL != fe_data->title) {
00158 g_object_unref(G_OBJECT(fe_data->title));
00159 }
00160 if (NULL != fe_data->target_box) {
00161 g_object_unref(G_OBJECT(fe_data->target_box));
00162 }
00163 if (NULL != fe_data->action_box) {
00164 g_object_unref(G_OBJECT(fe_data->action_box));
00165 }
00166
00167
00168
00169
00170 if (NULL == fe_data->plugins) {
00171 g_hash_table_destroy(fe_data->plugins);
00172 }
00173 g_free(fe_data);
00174 }
00175
00184 static gboolean create_frontend_data(struct frontend * fe)
00185 {
00186 struct frontend_data * fe_data;
00187
00188 g_assert(NULL == fe->data);
00189
00190 if (NULL == (fe->data = g_malloc0(sizeof (struct frontend_data)))) {
00191 g_critical("Unable to allocate frontend_data.");
00192 return FALSE;
00193 }
00194
00195 fe_data = fe->data;
00196
00197 if (NULL == (fe_data->answer_cond = g_cond_new())) {
00198 g_critical("g_cond_new failed.");
00199 goto failed;
00200 }
00201 if (NULL == (fe_data->answer_mutex = g_mutex_new())) {
00202 g_critical("g_mutex_new failed.");
00203 goto failed;
00204 }
00205 fe_data->plugins = g_hash_table_new_full(
00206 g_str_hash, g_str_equal, g_free ,
00207 (GDestroyNotify) plugin_delete );
00208 if (NULL == fe_data->plugins) {
00209 g_critical("g_hash_table_new_full failed.");
00210 goto failed;
00211 }
00212
00213 fe->data = fe_data;
00214
00215 return TRUE;
00216
00217 failed:
00218 destroy_frontend_data(fe);
00219 return FALSE;
00220 }
00221
00226 static int fe_gtk_shutdown(struct frontend * fe)
00227 {
00228 struct frontend_data * fe_data = fe->data;
00229
00230 if (NULL != fe_data->event_listener) {
00231 gtk_main_quit();
00232 if (g_thread_self() != fe_data->event_listener) {
00233 (void) g_thread_join(fe_data->event_listener);
00234 }
00235 fe_data->event_listener = NULL;
00236 }
00237 fe_gtk_destroy_main_window(fe);
00238 #ifdef DI_UDEB
00239 fe_gtk_di_shutdown(fe);
00240 #endif
00241 destroy_frontend_data(fe);
00242
00243 return DC_OK;
00244 }
00245
00250 static void show_main_window(struct frontend * fe)
00251 {
00252 struct frontend_data * fe_data = fe->data;
00253
00254 g_assert(NULL != fe_data->window);
00255
00256 gtk_widget_show_all(fe_data->window);
00257 }
00258
00259
00260 int fe_gtk_get_answer(struct frontend * fe)
00261 {
00262 struct frontend_data * fe_data = fe->data;
00263 int answer;
00264
00265 g_mutex_lock(fe_data->answer_mutex);
00266 answer = fe_data->answer;
00267 g_mutex_unlock(fe_data->answer_mutex);
00268 return answer;
00269 }
00270
00271
00272 void fe_gtk_set_answer(struct frontend * fe, int answer)
00273 {
00274 struct frontend_data * fe_data = fe->data;
00275
00276 g_mutex_lock(fe_data->answer_mutex);
00277 fe_data->answer = answer;
00278 g_cond_broadcast(fe_data->answer_cond);
00279 g_mutex_unlock(fe_data->answer_mutex);
00280 }
00281
00282
00283 void fe_gtk_set_answer_ok(struct frontend * fe)
00284 {
00285 fe_gtk_set_answer(fe, DC_OK);
00286 }
00287
00288
00289 void fe_gtk_set_answer_notok(struct frontend * fe)
00290 {
00291 fe_gtk_set_answer(fe, DC_NOTOK);
00292 }
00293
00294
00295 void fe_gtk_set_answer_goback(struct frontend * fe)
00296 {
00297 fe_gtk_set_answer(fe, DC_GOBACK);
00298 }
00299
00306 static gboolean create_event_listener_thread(struct frontend * fe)
00307 {
00308 struct frontend_data * fe_data = fe->data;
00309 GError * error;
00310
00311 g_assert(NULL == fe_data->event_listener);
00312
00313 fe_data->event_listener = g_thread_create(
00314 (GThreadFunc) handle_gtk_events, NULL ,
00315 TRUE , &error);
00316 if (NULL == fe_data->event_listener) {
00317 g_critical("g_thread_create failed: %s", error->message);
00318 g_error_free(error);
00319 return FALSE;
00320 }
00321 return TRUE;
00322 }
00323
00331 static int fe_gtk_initialize(struct frontend * fe, struct configuration * conf)
00332 {
00333
00334 if (!g_thread_supported()) {
00335 g_thread_init(NULL );
00336 gdk_threads_init();
00337 } else {
00338 g_critical("Threads not supported by th glib.");
00339 return DC_NOTOK;
00340 }
00341 gtk_init(NULL , NULL );
00342
00343 if (!create_frontend_data(fe)) {
00344 g_critical("create_frontend_data failed.");
00345 goto failed;
00346 }
00347 if (!fe_gtk_create_main_window(fe)) {
00348 g_critical("fe_gtk_create_main_window failed.");
00349 goto failed;
00350 }
00351 fe->interactive = TRUE;
00352
00353 #ifdef DI_UDEB
00354 if (!fe_gtk_di_setup(fe)) {
00355 g_critical("fe_gtk_di_setup failed.");
00356 goto failed;
00357 }
00358 #endif
00359
00360
00361 show_main_window(fe);
00362
00363 if (!create_event_listener_thread(fe)) {
00364 g_critical("create_event_listener_thread failed.");
00365 goto failed;
00366 }
00367
00368 return DC_OK;
00369
00370 failed:
00371 fe_gtk_shutdown(fe);
00372 return DC_NOTOK;
00373 }
00374
00384 static void fe_gtk_set_title(struct frontend * fe, const char * title)
00385 {
00386 g_free(fe->title);
00387 fe->title = g_strdup(title);
00388 #ifndef DI_UDEB
00389 gdk_threads_enter();
00390 fe_gtk_update_frontend_title(fe);
00391 gdk_threads_leave();
00392 #endif
00393 }
00394
00401 static bool fe_gtk_can_go_back(struct frontend * fe,
00402 struct question * question)
00403 {
00404 return DCF_CAPB_BACKUP == (fe->capability & DCF_CAPB_BACKUP);
00405 }
00406
00412 static unsigned long fe_gtk_query_capability(struct frontend * fe)
00413 {
00414 return DCF_CAPB_BACKUP;
00415 }
00416
00419 struct frontend_module debconf_frontend_module = {
00420 initialize: fe_gtk_initialize,
00421 shutdown: fe_gtk_shutdown,
00422 can_go_back: fe_gtk_can_go_back,
00423 query_capability: fe_gtk_query_capability,
00424 set_title: fe_gtk_set_title,
00425
00426 go: fe_gtk_go,
00427
00428 can_cancel_progress: fe_gtk_can_cancel_progress,
00429 progress_start: fe_gtk_progress_start,
00430 progress_info: fe_gtk_progress_info,
00431 progress_set: fe_gtk_progress_set,
00432 progress_stop: fe_gtk_progress_stop,
00433 };
00434
00435
00436