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 "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
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 ,
00069 DEFAULT_PADDING);
00070 gtk_box_pack_start(GTK_BOX(vpadbox), description_box,
00071 FALSE , FALSE ,
00072 0 );
00073 gtk_box_pack_start(GTK_BOX(vpadbox), widget, is_single ,
00074 is_single , 0 );
00075 hpadbox = gtk_hbox_new(FALSE ,
00076 DEFAULT_PADDING);
00077 gtk_box_pack_start(GTK_BOX(hpadbox), vpadbox, TRUE ,
00078 TRUE , QUESTIONBOX_HPADDING);
00079 gtk_box_pack_start(GTK_BOX(container), hpadbox, is_single ,
00080 is_single , 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 );
00113 pango_layout_set_markup(layout, message, -1 );
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
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
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 , 0 );
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 , FALSE ,
00159 0 );
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
00173 label_title = gtk_label_new(NULL );
00174
00175 gtk_misc_set_alignment(GTK_MISC(label_title), 0 , 0 );
00176
00177 g_object_ref(G_OBJECT(label_title));
00178 fe_data->title = label_title;
00179
00180 fe_gtk_center_widget(&label_title, 0 ,
00181 0 );
00182 gtk_box_pack_start(GTK_BOX(container), label_title,
00183 FALSE , FALSE , 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
00197 target_box = gtk_vbox_new(FALSE ,
00198 0 );
00199
00200 gtk_box_pack_start(GTK_BOX(container), target_box, TRUE ,
00201 TRUE , 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
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 , FALSE ,
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
00248 outer_box = gtk_vbox_new(FALSE ,
00249 0 );
00250 create_banner(fe, outer_box);
00251
00252 v_mainbox = gtk_vbox_new(FALSE ,
00253 0 );
00254
00255 h_mainbox = gtk_hbox_new(FALSE ,
00256 0 );
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 ,
00261 TRUE , DEFAULT_PADDING);
00262 gtk_box_pack_start(GTK_BOX(outer_box), h_mainbox, TRUE ,
00263 TRUE , 0 );
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 );
00306 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
00307 gtk_window_set_decorated(GTK_WINDOW(window), TRUE );
00308 create_main_widgets(fe, window);
00309
00310
00311
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
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
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
00380 void fe_gtk_center_widget(GtkWidget ** widget, guint horizontal_padding,
00381 guint vertical_padding)
00382 {
00383 GtkWidget * vbox;
00384 GtkWidget * hbox;
00385
00386
00387 vbox = gtk_vbox_new(FALSE ,
00388 0 );
00389
00390 hbox = gtk_hbox_new(FALSE ,
00391 0 );
00392 gtk_box_pack_start(GTK_BOX(vbox), *widget, TRUE ,
00393 TRUE , vertical_padding);
00394 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE , TRUE ,
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
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
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 , TRUE , 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
00440 label = gtk_label_new(NULL );
00441 gtk_misc_set_alignment(GTK_MISC(label), 0 ,
00442 0 );
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
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
00461 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00462 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE );
00463 gtk_window_set_transient_for(GTK_WINDOW(dialog),
00464 GTK_WINDOW(fe_data->window));
00465 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE );
00466 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
00467 gtk_window_set_decorated(GTK_WINDOW(dialog), FALSE );
00468 gtk_container_set_border_width(GTK_CONTAINER(dialog), 0 );
00469
00470
00471 vbox = gtk_vbox_new(FALSE ,
00472 DEFAULT_PADDING);
00473 gtk_box_pack_start(GTK_BOX(vbox), create_dialog_title_label(title),
00474 FALSE , FALSE ,
00475 0 );
00476 gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(message),
00477 FALSE , FALSE ,
00478 DEFAULT_PADDING);
00479 gtk_box_pack_start(GTK_BOX(vbox), gtk_hseparator_new(),
00480 FALSE , FALSE ,
00481 0 );
00482 gtk_box_pack_start(GTK_BOX(vbox), create_dialog_action_box(fe, dialog),
00483 FALSE , FALSE ,
00484 0 );
00485 fe_gtk_center_widget(&vbox, DEFAULT_PADDING, DEFAULT_PADDING);
00486
00487 frame = gtk_frame_new(NULL );
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
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
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 , TRUE , 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
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 );
00582 }
00583
00584
00585