ui.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 "ui.h"
00041 
00042 #include <gdk/gdkkeysyms.h>
00043 #include <gtk/gtk.h>
00044 
00045 #include "frontend.h"
00046 #include "question.h"
00047 
00048 #include "fe_gtk.h"
00049 #include "fe_data.h"
00050 #include "descriptions.h"
00051 #ifdef DI_UDEB
00052 # include "di.h"
00053 #endif
00054 
00055 /* documented in fe_gtk.h */
00056 void fe_gtk_add_common_layout(struct frontend * fe, struct question * question,
00057                               GtkWidget * container, GtkWidget * widget)
00058 {
00059     GtkWidget * description_box;
00060     GtkWidget * hpadbox;
00061     GtkWidget * vpadbox;
00062     gboolean is_single;
00063 
00064     is_single = IS_QUESTION_SINGLE(question);
00065 
00066     description_box = fe_gtk_create_description(fe, question);
00067 
00068     vpadbox = gtk_vbox_new(FALSE /* don't make children equal */,
00069                            DEFAULT_PADDING);
00070     gtk_box_pack_start(GTK_BOX(vpadbox), description_box,
00071                        FALSE /* don't expand */, FALSE /* don't fill */,
00072                        0 /* padding */);
00073     gtk_box_pack_start(GTK_BOX(vpadbox), widget, is_single /* expand? */,
00074                        is_single /* fill? */, 0 /* padding */);
00075     hpadbox = gtk_hbox_new(FALSE /* don't make children equal */,
00076                            DEFAULT_PADDING);
00077     gtk_box_pack_start(GTK_BOX(hpadbox), vpadbox, TRUE /* expand */,
00078                        TRUE /* fill */, QUESTIONBOX_HPADDING);
00079     gtk_box_pack_start(GTK_BOX(container), hpadbox, is_single /* expand? */,
00080                        is_single /* fill? */, QUESTIONBOX_VPADDING);
00081 }
00082 
00094 static gboolean handle_exposed_banner(GtkWidget * widget,
00095                                       GdkEventExpose * event,
00096                                       struct frontend * fe)
00097 {
00098     struct frontend_data * fe_data = fe->data;
00099     GdkScreen * screen;
00100     PangoFontDescription * font;
00101     PangoLayout * layout;
00102     gint text_width;
00103     gint text_height;
00104     gchar * message;
00105     char * text;
00106 
00107     if (NULL != fe->info) {
00108         text = q_get_description(fe->info);
00109         message = g_strdup_printf(
00110             "<b><span foreground=\"#ffffff\">%s</span></b>", text);
00111         layout = gtk_widget_create_pango_layout(
00112             widget, NULL /* no text for the layout */);
00113         pango_layout_set_markup(layout, message, -1 /* until '\0' */);
00114         font = pango_font_description_from_string("Sans 12");
00115         pango_layout_set_font_description(layout, font);
00116         pango_layout_get_pixel_size(layout, &text_width, &text_height);
00117         screen = gtk_window_get_screen(GTK_WINDOW(fe_data->window));
00118         /* XXX: damn magic numbers */
00119         gdk_draw_layout(widget->window, gdk_gc_new(widget->window),
00120             gdk_screen_get_width(screen) - text_width - 4
00121             - DEFAULT_PADDING * 2, 4, layout);
00122         g_object_unref(layout);
00123         pango_font_description_free(font);
00124         g_free(message);
00125         g_free(text);
00126     }
00127     return FALSE;
00128 }
00129 
00139 static void create_banner(struct frontend * fe, GtkWidget * container)
00140 {
00141     GtkWidget * banner;
00142     GtkWidget * logo;
00143     GdkColor bg;
00144 
00145     /* XXX: check NULL! */
00146     banner = gtk_event_box_new();
00147     logo = gtk_image_new_from_file(LOGO_IMAGE_PATH);
00148     gtk_misc_set_alignment(GTK_MISC(logo), 0 /* top */, 0 /* left */);
00149     gtk_misc_set_padding(GTK_MISC(logo), 0, 0);
00150     (void) gdk_color_parse(LOGO_BACKGROUND_COLOR, &bg);
00151     gtk_widget_modify_bg(banner, GTK_STATE_NORMAL, &bg);
00152     gtk_container_add(GTK_CONTAINER(banner), logo);
00153 
00154     g_signal_connect_after(G_OBJECT(banner), "expose_event",
00155                            G_CALLBACK(handle_exposed_banner), fe);
00156 
00157     gtk_box_pack_start(GTK_BOX(container), banner,
00158                        FALSE /* don't expand */, FALSE /* don't fill */,
00159                        0 /* padding */);
00160 }
00161 
00167 static void create_label_title(struct frontend * fe, GtkWidget * container)
00168 {
00169     struct frontend_data * fe_data = fe->data;
00170     GtkWidget * label_title;
00171 
00172     /* check NULL! */
00173     label_title = gtk_label_new(NULL /* no label */);
00174 
00175     gtk_misc_set_alignment(GTK_MISC(label_title), 0 /* left */, 0 /* top */);
00176 
00177     g_object_ref(G_OBJECT(label_title));
00178     fe_data->title = label_title;
00179 
00180     fe_gtk_center_widget(&label_title, 0 /* no horizontal padding */,
00181                          0 /* no vertical padding */);
00182     gtk_box_pack_start(GTK_BOX(container), label_title,
00183                        FALSE /* expand */, FALSE /* fill */, DEFAULT_PADDING);
00184 }
00185 
00191 static void create_target_box(struct frontend * fe, GtkWidget * container)
00192 {
00193     struct frontend_data * fe_data = fe->data;
00194     GtkWidget * target_box;
00195 
00196     /* This is the box were question(s) will be displayed */
00197     target_box = gtk_vbox_new(FALSE /* don't make children equal */,
00198                              0 /* padding */);
00199 
00200     gtk_box_pack_start(GTK_BOX(container), target_box, TRUE /* expand */,
00201                        TRUE /* fill */, DEFAULT_PADDING);
00202 
00203     g_object_ref(G_OBJECT(target_box));
00204     fe_data->target_box = target_box;
00205 }
00206 
00212 static void create_action_box(struct frontend * fe, GtkWidget * container)
00213 {
00214     struct frontend_data * fe_data = fe->data;
00215     GtkWidget * action_box;
00216 
00217     g_assert(NULL == fe_data->action_box);
00218 
00219     /* check NULL! */
00220     action_box = gtk_hbutton_box_new();
00221 
00222     gtk_button_box_set_layout(GTK_BUTTON_BOX(action_box), GTK_BUTTONBOX_END);
00223     gtk_box_set_spacing(GTK_BOX(action_box), DEFAULT_PADDING);
00224 
00225     gtk_box_pack_start(GTK_BOX(container), action_box,
00226                        FALSE /* don't expand */, FALSE /* don't fill */,
00227                        DEFAULT_PADDING);
00228 
00229     g_object_ref(G_OBJECT(action_box));
00230     fe_data->action_box = action_box;
00231 }
00232 
00241 static void create_main_widgets(struct frontend * fe, GtkWidget * window)
00242 {
00243     GtkWidget * outer_box;
00244     GtkWidget * v_mainbox;
00245     GtkWidget * h_mainbox;
00246 
00247     /* check NULL! */
00248     outer_box = gtk_vbox_new(FALSE /* don't make children equal */,
00249                              0 /* padding */);
00250     create_banner(fe, outer_box);
00251     /* check NULL! */
00252     v_mainbox = gtk_vbox_new(FALSE /* don't make children equal */,
00253                              0 /* padding */);
00254     /* check NULL! */
00255     h_mainbox = gtk_hbox_new(FALSE /* don't make children equal */,
00256                              0 /* padding */);
00257     create_label_title(fe, v_mainbox);
00258     create_target_box(fe, v_mainbox);
00259     create_action_box(fe, v_mainbox);
00260     gtk_box_pack_start(GTK_BOX(h_mainbox), v_mainbox, TRUE /* expand */,
00261                        TRUE /* fill */, DEFAULT_PADDING);
00262     gtk_box_pack_start(GTK_BOX(outer_box), h_mainbox, TRUE /* expand */,
00263                        TRUE /* fill */, 0 /* padding */);
00264     gtk_container_add(GTK_CONTAINER(window), outer_box);
00265 }
00266 
00276 static void handle_closed_main_window(struct frontend * fe,
00277                                       GtkWidget * window)
00278 {
00279     struct frontend_data * fe_data = fe->data;
00280 
00281     fe_data->window = NULL;
00282     g_object_unref(G_OBJECT(window));
00283     fe_gtk_force_quit(fe);
00284 }
00285 
00294 gboolean fe_gtk_create_main_window(struct frontend * fe)
00295 {
00296     struct frontend_data * fe_data = fe->data;
00297     GtkWidget * window;
00298 
00299     g_assert(NULL != fe_data);
00300     g_assert(NULL == fe_data->window);
00301     if (NULL == (window = gtk_window_new(GTK_WINDOW_TOPLEVEL))) {
00302         g_critical("gtk_window_new failed.");
00303         return FALSE;
00304     }
00305     gtk_window_set_resizable(GTK_WINDOW(window), TRUE /* resizable */);
00306     gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
00307     gtk_window_set_decorated(GTK_WINDOW(window), TRUE /* resizable */);
00308     create_main_widgets(fe, window);
00309 
00310     /* XXX: we might want to unconnect this signal in case of normal
00311      * shutdown... */
00312     g_signal_connect_swapped(window, "destroy",
00313                              G_CALLBACK(handle_closed_main_window), fe);
00314 
00315     g_object_ref(G_OBJECT(window));
00316     fe_data->window = window;
00317 
00318     return TRUE;
00319 }
00320 
00325 struct shortcut {
00327     GtkWidget * window;
00329     gulong handler_id;
00330 };
00331 
00340 static void remove_shortcut(GtkObject * widget, struct shortcut * shortcut)
00341 {
00342     g_signal_handler_disconnect(G_OBJECT(shortcut->window),
00343                                 shortcut->handler_id);
00344     g_free(shortcut);
00345 }
00346 
00347 /* documented in fe_gtk.h */
00348 void fe_gtk_add_global_key_handler(struct frontend * fe, GtkWidget * widget,
00349                                    GCallback key_event_handler)
00350 {
00351     struct frontend_data * fe_data = fe->data;
00352     struct shortcut * shortcut;
00353 
00354     /* XXX: check NULL! */
00355     shortcut = g_malloc0(sizeof (struct shortcut));
00356     shortcut->window = fe_data->window;
00357     shortcut->handler_id = g_signal_connect_after(
00358         fe_data->window, "key_press_event", key_event_handler, fe);
00359     g_signal_connect(G_OBJECT(widget), "destroy",
00360                      G_CALLBACK(remove_shortcut), shortcut);
00361 }
00362 
00367 void fe_gtk_destroy_main_window(struct frontend * fe)
00368 {
00369     struct frontend_data * fe_data = fe->data;
00370     GtkWidget * window = fe_data->window;
00371 
00372     if (NULL != window) {
00373         fe_data->window = NULL;
00374         g_object_unref(G_OBJECT(window));
00375         gtk_widget_destroy(window);
00376     }
00377 }
00378 
00379 /* documented in fe_gtk.h */
00380 void fe_gtk_center_widget(GtkWidget ** widget, guint horizontal_padding,
00381                           guint vertical_padding)
00382 {
00383     GtkWidget * vbox;
00384     GtkWidget * hbox;
00385 
00386     /* XXX: check NULL! */
00387     vbox = gtk_vbox_new(FALSE /* don't make children equal */,
00388                         0 /* padding */);
00389     /* XXX: check NULL! */
00390     hbox = gtk_hbox_new(FALSE /* don't make children equal */,
00391                         0 /* padding */);
00392     gtk_box_pack_start(GTK_BOX(vbox), *widget, TRUE /* expand */,
00393                        TRUE /* fill */, vertical_padding);
00394     gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE /* expand */, TRUE /* fill */,
00395                        horizontal_padding);
00396     *widget = hbox;
00397 }
00398 
00405 static GtkWidget * create_dialog_action_box(struct frontend * fe,
00406                                             GtkWidget * dialog)
00407 {
00408     GtkWidget * action_box;
00409     GtkWidget * close_button;
00410     char * label;
00411 
00412     /* check NULL! */
00413     action_box = gtk_hbutton_box_new();
00414     gtk_button_box_set_layout(GTK_BUTTON_BOX(action_box), GTK_BUTTONBOX_END);
00415 
00416     label = fe_gtk_get_text(fe, "debconf/button-continue", "Continue");
00417     /* check NULL! */
00418     close_button = gtk_button_new_with_label(label);
00419     g_free(label);
00420 
00421     g_signal_connect_swapped(G_OBJECT(close_button), "clicked",
00422                              G_CALLBACK(gtk_widget_destroy), dialog);
00423 
00424     gtk_box_pack_end(GTK_BOX(action_box), close_button,
00425                      TRUE /* expand */, TRUE /* fill */, DEFAULT_PADDING);
00426     return action_box;
00427 }
00428 
00434 static GtkWidget * create_dialog_title_label(const gchar * title)
00435 {
00436     GtkWidget * label;
00437     gchar * markup;
00438 
00439     /* check NULL! */
00440     label = gtk_label_new(NULL /* no text */);
00441     gtk_misc_set_alignment(GTK_MISC(label), 0 /* left aligned */,
00442                            0 /* top aligned */);
00443 
00444     markup = g_strdup_printf("<b>%s</b>", title);
00445     gtk_label_set_markup(GTK_LABEL(label), markup);
00446     g_free(markup);
00447 
00448     return label;
00449 }
00450 
00451 /* documented in fe_gtk.h */
00452 gboolean fe_gtk_run_message_dialog(struct frontend * fe, const gchar * title,
00453                                    const gchar * message)
00454 {
00455     struct frontend_data * fe_data = fe->data;
00456     GtkWidget * dialog;
00457     GtkWidget * vbox;
00458     GtkWidget * frame;
00459 
00460     /* XXX: check NULL! */
00461     dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00462     gtk_window_set_modal(GTK_WINDOW(dialog), TRUE /* modal */);
00463     gtk_window_set_transient_for(GTK_WINDOW(dialog),
00464                                  GTK_WINDOW(fe_data->window));
00465     gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE /* not resizable */);
00466     gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
00467     gtk_window_set_decorated(GTK_WINDOW(dialog), FALSE /* no decoration */);
00468     gtk_container_set_border_width(GTK_CONTAINER(dialog), 0 /* no border */);
00469 
00470     /* XXX: check NULL! */
00471     vbox = gtk_vbox_new(FALSE /* don't make children equal */,
00472                         DEFAULT_PADDING);
00473     gtk_box_pack_start(GTK_BOX(vbox), create_dialog_title_label(title),
00474                        FALSE /* don't expand */, FALSE /* don't fill */,
00475                        0 /* no padding */);
00476     gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(message),
00477                        FALSE /* don't expand */, FALSE /* don't fill */,
00478                        DEFAULT_PADDING);
00479     gtk_box_pack_start(GTK_BOX(vbox), gtk_hseparator_new(),
00480                        FALSE /* don't expand */, FALSE /* don't fill */,
00481                        0 /* no padding */);
00482     gtk_box_pack_start(GTK_BOX(vbox), create_dialog_action_box(fe, dialog),
00483                        FALSE /* don't expand */, FALSE /* don't fill */,
00484                        0 /* no padding */);
00485     fe_gtk_center_widget(&vbox, DEFAULT_PADDING, DEFAULT_PADDING);
00486 
00487     frame = gtk_frame_new(NULL /* no label */);
00488     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
00489     gtk_container_add(GTK_CONTAINER(frame), vbox);
00490     gtk_container_add(GTK_CONTAINER(dialog), frame);
00491 
00492     gtk_widget_show_all(dialog);
00493     return TRUE;
00494 }
00495 
00496 /* documented in fe_gtk.h. */
00497 void fe_gtk_set_buttons_sensitive(struct frontend * fe, gboolean sensitive)
00498 {
00499     struct frontend_data * fe_data = fe->data;
00500     GList * child;
00501 
00502     child = gtk_container_get_children(GTK_CONTAINER(fe_data->action_box));
00503     while (NULL != child) {
00504         gtk_widget_set_sensitive(GTK_WIDGET(child->data), sensitive);
00505         child = g_list_next(child);
00506     }
00507 }
00508 
00513 void fe_gtk_show_buttons(struct frontend * fe)
00514 {
00515     struct frontend_data * fe_data = fe->data;
00516 
00517     gtk_widget_show_all(fe_data->action_box);
00518 }
00519 
00520 /* documented in fe_gtk.h */
00521 void fe_gtk_add_button(struct frontend * fe, GtkWidget * button)
00522 {
00523     struct frontend_data * fe_data = fe->data;
00524     GtkWidget * action_box = fe_data->action_box;
00525     GList * focus_chain;
00526 
00527     gtk_box_pack_start(GTK_BOX(action_box), button,
00528                        TRUE /* expand */, TRUE /* fill */, DEFAULT_PADDING);
00529     gtk_container_get_focus_chain(GTK_CONTAINER(action_box), &focus_chain);
00530     focus_chain = g_list_append(focus_chain, button);
00531     gtk_container_set_focus_chain(GTK_CONTAINER(action_box), focus_chain);
00532     g_list_free(focus_chain);
00533 }
00534 
00535 /* documented in fe_gtk.h */
00536 void fe_gtk_set_button_secondary(struct frontend * fe, GtkWidget * button,
00537                                  gboolean secondary)
00538 {
00539     struct frontend_data * fe_data = fe->data;
00540 
00541     gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(fe_data->action_box),
00542                                        button, secondary);
00543 }
00544 
00549 void fe_gtk_update_frontend_title(struct frontend * fe)
00550 {
00551     struct frontend_data * fe_data = fe->data;
00552     gchar * tmp;
00553 
00554     tmp = g_strdup_printf("<b>%s</b>", fe->title);
00555     gtk_label_set_markup(GTK_LABEL(fe_data->title), tmp);
00556     g_free(tmp);
00557 }
00558 
00564 void fe_gtk_show_target_box(struct frontend * fe)
00565 {
00566     struct frontend_data * fe_data = fe->data;
00567 
00568     gtk_widget_show_all(fe_data->target_box);
00569 }
00570 
00576 void fe_gtk_empty_target_box(struct frontend * fe)
00577 {
00578     struct frontend_data * fe_data = fe->data;
00579 
00580     gtk_container_forall(GTK_CONTAINER(fe_data->target_box),
00581                          (GtkCallback) gtk_widget_destroy, NULL /* no data */);
00582 }
00583 
00584 /* vim: et sw=4 si
00585  */

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