fe_gtk.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * cdebconf - An implementation of the Debian Configuration Management
00004  *            System
00005  *
00006  * $Id$
00007  *
00008  * cdebconf is (c) 2000-2007 Randolph Chung and others under the following
00009  * license.
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  *
00015  * 1. Redistributions of source code must retain the above copyright
00016  * notice, this list of conditions and the following disclaimer.
00017  *
00018  * 2. Redistributions in binary form must reproduce the above copyright
00019  * notice, this list of conditions and the following disclaimer in the
00020  * documentation and/or other materials provided with the distribution.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
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 /* DI_UDEB */
00066 
00084 char * fe_gtk_get_text(struct frontend * fe, const char * template,
00085                        const char * fallback)
00086 {
00087     /* XXX: add macro? */
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 /* no one cares what value is returned */;
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 /* documented in fe_gtk.h */
00132 void fe_gtk_force_quit(struct frontend * fe)
00133 {
00134     if (-1 == kill(0 /* myself */, 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     /* Exit any running GO in order to cleanup. */
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     /* There is no safe way to free the mutex: this function can be called
00167      * as part as a signal handler while the mutex is actually held in
00168      * go.c:wait_answer().
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 /* key destroy function (strings) */,
00207         (GDestroyNotify) plugin_delete /* value destroy function (plugin) */);
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 /* DI_UDEB */
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 /* documented in fe_gtk.h */
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 /* documented in fe_gtk.h */
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 /* documented in fe_gtk.h */
00283 void fe_gtk_set_answer_ok(struct frontend * fe)
00284 {
00285     fe_gtk_set_answer(fe, DC_OK);
00286 }
00287 
00288 /* documented in fe_gtk.h */
00289 void fe_gtk_set_answer_notok(struct frontend * fe)
00290 {
00291     fe_gtk_set_answer(fe, DC_NOTOK);
00292 }
00293 
00294 /* documented in fe_gtk.h */
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 /* no data */,
00315         TRUE /* joinable thread */, &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     /* INFO(INFO_DEBUG, "GTK_DI - gtk_initialize() called"); */
00334     if (!g_thread_supported()) {
00335        g_thread_init(NULL /* default thread functions */);
00336        gdk_threads_init();
00337     } else {
00338         g_critical("Threads not supported by th glib.");
00339         return DC_NOTOK;
00340     }
00341     gtk_init(NULL /* no argc */, NULL /* no argv */);
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 /* DI_UDEB */
00359 
00360     /* XXX: here? */
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 /* Only for non d-i frontend */
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     /* see go.c */
00426     go: fe_gtk_go,
00427     /* see progress.c */
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 /* vim: et sw=4 si
00436  */

Generated on Sat Jul 7 23:41:41 2007 for fe_gtk by  doxygen 1.5.1