+static void window_destroy(GtkWidget *widget, gpointer data)
+{
+ gtk_main_quit();
+}
+
+static void msgbox_button_clicked(GtkButton *button, gpointer data)
+{
+ GtkWidget *window = GTK_WIDGET(data);
+ int v, *ip;
+
+ ip = (int *)gtk_object_get_data(GTK_OBJECT(window), "user-data");
+ v = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(button), "user-data"));
+ *ip = v;
+
+ gtk_widget_destroy(GTK_WIDGET(data));
+}
+
+static int win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+ GtkObject *cancelbutton = GTK_OBJECT(data);
+
+ /*
+ * `Escape' effectively clicks the cancel button
+ */
+ if (event->keyval == GDK_Escape) {
+ gtk_signal_emit_by_name(GTK_OBJECT(cancelbutton), "clicked");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+enum { MB_OK, MB_YESNO };
+
+int message_box(GtkWidget *parent, char *title, char *msg, int centre,
+ int type)
+{
+ GtkWidget *window, *hbox, *text, *button;
+ char *titles;
+ int i, def, cancel;
+
+ window = gtk_dialog_new();
+ text = gtk_label_new(msg);
+ gtk_misc_set_alignment(GTK_MISC(text), 0.0, 0.0);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), text, FALSE, FALSE, 20);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox),
+ hbox, FALSE, FALSE, 20);
+ gtk_widget_show(text);
+ gtk_widget_show(hbox);
+ gtk_window_set_title(GTK_WINDOW(window), title);
+ gtk_label_set_line_wrap(GTK_LABEL(text), TRUE);
+
+ if (type == MB_OK) {
+ titles = "OK\0";
+ def = cancel = 0;
+ } else {
+ assert(type == MB_YESNO);
+ titles = "Yes\0No\0";
+ def = 0;
+ cancel = 1;
+ }
+ i = 0;
+
+ while (*titles) {
+ button = gtk_button_new_with_label(titles);
+ gtk_box_pack_end(GTK_BOX(GTK_DIALOG(window)->action_area),
+ button, FALSE, FALSE, 0);
+ gtk_widget_show(button);
+ if (i == def) {
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_window_set_default(GTK_WINDOW(window), button);
+ }
+ if (i == cancel) {
+ gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+ GTK_SIGNAL_FUNC(win_key_press), button);
+ }
+ gtk_signal_connect(GTK_OBJECT(button), "clicked",
+ GTK_SIGNAL_FUNC(msgbox_button_clicked), window);
+ gtk_object_set_data(GTK_OBJECT(button), "user-data",
+ GINT_TO_POINTER(i));
+ titles += strlen(titles)+1;
+ i++;
+ }
+ gtk_object_set_data(GTK_OBJECT(window), "user-data",
+ GINT_TO_POINTER(&i));
+ gtk_signal_connect(GTK_OBJECT(window), "destroy",
+ GTK_SIGNAL_FUNC(window_destroy), NULL);
+ gtk_window_set_modal(GTK_WINDOW(window), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(parent));
+ /* set_transient_window_pos(parent, window); */
+ gtk_widget_show(window);
+ i = -1;
+ gtk_main();
+ return (type == MB_YESNO ? i == 0 : TRUE);
+}
+
+void error_box(GtkWidget *parent, char *msg)
+{
+ message_box(parent, "Error", msg, FALSE, MB_OK);
+}
+
+static void config_ok_button_clicked(GtkButton *button, gpointer data)
+{
+ frontend *fe = (frontend *)data;
+ char *err;
+
+ err = midend_set_config(fe->me, fe->cfg_which, fe->cfg);
+
+ if (err)
+ error_box(fe->cfgbox, err);
+ else {
+ fe->cfgret = TRUE;
+ gtk_widget_destroy(fe->cfgbox);
+ }
+}
+
+static void config_cancel_button_clicked(GtkButton *button, gpointer data)
+{
+ frontend *fe = (frontend *)data;
+
+ gtk_widget_destroy(fe->cfgbox);
+}
+
+static int editbox_key(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+ /*
+ * GtkEntry has a nasty habit of eating the Return key, which
+ * is unhelpful since it doesn't actually _do_ anything with it
+ * (it calls gtk_widget_activate, but our edit boxes never need
+ * activating). So I catch Return before GtkEntry sees it, and
+ * pass it straight on to the parent widget. Effect: hitting
+ * Return in an edit box will now activate the default button
+ * in the dialog just like it will everywhere else.
+ */
+ if (event->keyval == GDK_Return && widget->parent != NULL) {
+ gint return_val;
+ gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
+ gtk_signal_emit_by_name(GTK_OBJECT(widget->parent), "key_press_event",
+ event, &return_val);
+ return return_val;
+ }
+ return FALSE;
+}
+
+static void editbox_changed(GtkEditable *ed, gpointer data)
+{
+ config_item *i = (config_item *)data;
+
+ sfree(i->sval);
+ i->sval = dupstr(gtk_entry_get_text(GTK_ENTRY(ed)));
+}
+
+static void button_toggled(GtkToggleButton *tb, gpointer data)
+{
+ config_item *i = (config_item *)data;
+
+ i->ival = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb));
+}
+
+static void droplist_sel(GtkMenuItem *item, gpointer data)
+{
+ config_item *i = (config_item *)data;
+
+ i->ival = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(item),
+ "user-data"));
+}
+
+static int get_config(frontend *fe, int which)
+{
+ GtkWidget *w, *table, *cancel;
+ char *title;
+ config_item *i;
+ int y;
+
+ fe->cfg = midend_get_config(fe->me, which, &title);
+ fe->cfg_which = which;
+ fe->cfgret = FALSE;
+
+ fe->cfgbox = gtk_dialog_new();
+ gtk_window_set_title(GTK_WINDOW(fe->cfgbox), title);
+ sfree(title);
+
+ w = gtk_button_new_with_label("OK");
+ gtk_box_pack_end(GTK_BOX(GTK_DIALOG(fe->cfgbox)->action_area),
+ w, FALSE, FALSE, 0);
+ gtk_widget_show(w);
+ GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
+ gtk_window_set_default(GTK_WINDOW(fe->cfgbox), w);
+ gtk_signal_connect(GTK_OBJECT(w), "clicked",
+ GTK_SIGNAL_FUNC(config_ok_button_clicked), fe);
+
+ w = gtk_button_new_with_label("Cancel");
+ gtk_box_pack_end(GTK_BOX(GTK_DIALOG(fe->cfgbox)->action_area),
+ w, FALSE, FALSE, 0);
+ gtk_widget_show(w);
+ gtk_signal_connect(GTK_OBJECT(w), "clicked",
+ GTK_SIGNAL_FUNC(config_cancel_button_clicked), fe);
+ cancel = w;
+
+ table = gtk_table_new(1, 2, FALSE);
+ y = 0;
+ gtk_box_pack_end(GTK_BOX(GTK_DIALOG(fe->cfgbox)->vbox),
+ table, FALSE, FALSE, 0);
+ gtk_widget_show(table);
+
+ for (i = fe->cfg; i->type != C_END; i++) {
+ gtk_table_resize(GTK_TABLE(table), y+1, 2);
+
+ switch (i->type) {
+ case C_STRING:
+ /*
+ * Edit box with a label beside it.
+ */
+
+ w = gtk_label_new(i->name);
+ gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
+ gtk_table_attach(GTK_TABLE(table), w, 0, 1, y, y+1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ 3, 3);
+ gtk_widget_show(w);
+
+ w = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), w, 1, 2, y, y+1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ 3, 3);
+ gtk_entry_set_text(GTK_ENTRY(w), i->sval);
+ gtk_signal_connect(GTK_OBJECT(w), "changed",
+ GTK_SIGNAL_FUNC(editbox_changed), i);
+ gtk_signal_connect(GTK_OBJECT(w), "key_press_event",
+ GTK_SIGNAL_FUNC(editbox_key), NULL);
+ gtk_widget_show(w);
+
+ break;
+
+ case C_BOOLEAN:
+ /*
+ * Simple checkbox.
+ */
+ w = gtk_check_button_new_with_label(i->name);
+ gtk_signal_connect(GTK_OBJECT(w), "toggled",
+ GTK_SIGNAL_FUNC(button_toggled), i);
+ gtk_table_attach(GTK_TABLE(table), w, 0, 2, y, y+1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ 3, 3);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), i->ival);
+ gtk_widget_show(w);
+ break;
+
+ case C_CHOICES:
+ /*
+ * Drop-down list (GtkOptionMenu).
+ */
+
+ w = gtk_label_new(i->name);
+ gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
+ gtk_table_attach(GTK_TABLE(table), w, 0, 1, y, y+1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ 3, 3);
+ gtk_widget_show(w);
+
+ w = gtk_option_menu_new();
+ gtk_table_attach(GTK_TABLE(table), w, 1, 2, y, y+1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ 3, 3);
+ gtk_widget_show(w);
+
+ {
+ int c, val;
+ char *p, *q, *name;
+ GtkWidget *menuitem;
+ GtkWidget *menu = gtk_menu_new();
+
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(w), menu);
+
+ c = *i->sval;
+ p = i->sval+1;
+ val = 0;
+
+ while (*p) {
+ q = p;
+ while (*q && *q != c)
+ q++;
+
+ name = snewn(q-p+1, char);
+ strncpy(name, p, q-p);
+ name[q-p] = '\0';
+
+ if (*q) q++; /* eat delimiter */
+
+ menuitem = gtk_menu_item_new_with_label(name);
+ gtk_container_add(GTK_CONTAINER(menu), menuitem);
+ gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
+ GINT_TO_POINTER(val));
+ gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
+ GTK_SIGNAL_FUNC(droplist_sel), i);
+ gtk_widget_show(menuitem);
+
+ val++;
+
+ p = q;
+ }
+
+ gtk_option_menu_set_history(GTK_OPTION_MENU(w), i->ival);
+ }
+
+ break;
+ }
+
+ y++;
+ }
+
+ gtk_signal_connect(GTK_OBJECT(fe->cfgbox), "destroy",
+ GTK_SIGNAL_FUNC(window_destroy), NULL);
+ gtk_signal_connect(GTK_OBJECT(fe->cfgbox), "key_press_event",
+ GTK_SIGNAL_FUNC(win_key_press), cancel);
+ gtk_window_set_modal(GTK_WINDOW(fe->cfgbox), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(fe->cfgbox),
+ GTK_WINDOW(fe->window));
+ /* set_transient_window_pos(fe->window, fe->cfgbox); */
+ gtk_widget_show(fe->cfgbox);
+ gtk_main();
+
+ free_cfg(fe->cfg);
+
+ return fe->cfgret;
+}
+