+/* ----------------------------------------------------------------------
+ * Signal handlers while the dialog box is active.
+ */
+
+static gboolean widget_focus(GtkWidget *widget, GdkEventFocus *event,
+ gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, widget);
+ union control *focus;
+
+ if (uc && uc->ctrl)
+ focus = uc->ctrl;
+ else
+ focus = NULL;
+
+ if (focus != dp->currfocus) {
+ dp->lastfocus = dp->currfocus;
+ dp->currfocus = focus;
+ }
+
+ return FALSE;
+}
+
+static void button_clicked(GtkButton *button, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
+}
+
+static void button_toggled(GtkToggleButton *tb, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(tb));
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
+}
+
+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)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ if (!(dp->flags & FLAG_UPDATING_COMBO_LIST)) {
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(ed));
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
+ }
+}
+
+static void editbox_lostfocus(GtkWidget *ed, GdkEventFocus *event,
+ gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(ed));
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_REFRESH);
+}
+
+static int listitem_key(GtkWidget *item, GdkEventKey *event, gpointer data,
+ int multiple)
+{
+ GtkAdjustment *adj = GTK_ADJUSTMENT(data);
+
+ if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
+ event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
+ event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
+ event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down) {
+ /*
+ * Up, Down, PgUp or PgDn have been pressed on a ListItem
+ * in a list box. So, if the list box is single-selection:
+ *
+ * - if the list item in question isn't already selected,
+ * we simply select it.
+ * - otherwise, we find the next one (or next
+ * however-far-away) in whichever direction we're going,
+ * and select that.
+ * + in this case, we must also fiddle with the
+ * scrollbar to ensure the newly selected item is
+ * actually visible.
+ *
+ * If it's multiple-selection, we do all of the above
+ * except actually selecting anything, so we move the focus
+ * and fiddle the scrollbar to follow it.
+ */
+ GtkWidget *list = item->parent;
+
+ gtk_signal_emit_stop_by_name(GTK_OBJECT(item), "key_press_event");
+
+ if (!multiple &&
+ GTK_WIDGET_STATE(item) != GTK_STATE_SELECTED) {
+ gtk_list_select_child(GTK_LIST(list), item);
+ } else {
+ int direction =
+ (event->keyval==GDK_Up || event->keyval==GDK_KP_Up ||
+ event->keyval==GDK_Page_Up || event->keyval==GDK_KP_Page_Up)
+ ? -1 : +1;
+ int step =
+ (event->keyval==GDK_Page_Down ||
+ event->keyval==GDK_KP_Page_Down ||
+ event->keyval==GDK_Page_Up || event->keyval==GDK_KP_Page_Up)
+ ? 2 : 1;
+ int i, n;
+ GList *children, *chead;
+
+ chead = children = gtk_container_children(GTK_CONTAINER(list));
+
+ n = g_list_length(children);
+
+ if (step == 2) {
+ /*
+ * Figure out how many list items to a screenful,
+ * and adjust the step appropriately.
+ */
+ step = 0.5 + adj->page_size * n / (adj->upper - adj->lower);
+ step--; /* go by one less than that */
+ }
+
+ i = 0;
+ while (children != NULL) {
+ if (item == children->data)
+ break;
+ children = children->next;
+ i++;
+ }
+
+ while (step > 0) {
+ if (direction < 0 && i > 0)
+ children = children->prev, i--;
+ else if (direction > 0 && i < n-1)
+ children = children->next, i++;
+ step--;
+ }
+
+ if (children && children->data) {
+ if (!multiple)
+ gtk_list_select_child(GTK_LIST(list),
+ GTK_WIDGET(children->data));
+ gtk_widget_grab_focus(GTK_WIDGET(children->data));
+ gtk_adjustment_clamp_page
+ (adj,
+ adj->lower + (adj->upper-adj->lower) * i / n,
+ adj->lower + (adj->upper-adj->lower) * (i+1) / n);
+ }
+
+ g_list_free(chead);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int listitem_single_key(GtkWidget *item, GdkEventKey *event,
+ gpointer data)
+{
+ return listitem_key(item, event, data, FALSE);
+}
+
+static int listitem_multi_key(GtkWidget *item, GdkEventKey *event,
+ gpointer data)
+{
+ return listitem_key(item, event, data, TRUE);
+}
+
+static int listitem_button(GtkWidget *item, GdkEventButton *event,
+ gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ if (event->type == GDK_2BUTTON_PRESS ||
+ event->type == GDK_3BUTTON_PRESS) {
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(item));
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_ACTION);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void list_selchange(GtkList *list, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(list));
+ if (!uc) return;
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_SELCHANGE);
+}
+
+static void menuitem_activate(GtkMenuItem *item, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ GtkWidget *menushell = GTK_WIDGET(item)->parent;
+ gpointer optmenu = gtk_object_get_data(GTK_OBJECT(menushell), "user-data");
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(optmenu));
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_SELCHANGE);
+}
+
+static void draglist_move(struct dlgparam *dp, struct uctrl *uc, int direction)
+{
+ int index = dlg_listbox_index(uc->ctrl, dp);
+ GList *children = gtk_container_children(GTK_CONTAINER(uc->list));
+ GtkWidget *child;
+
+ if ((index < 0) ||
+ (index == 0 && direction < 0) ||
+ (index == g_list_length(children)-1 && direction > 0)) {
+ gdk_beep();
+ return;
+ }
+
+ child = g_list_nth_data(children, index);
+ gtk_widget_ref(child);
+ gtk_list_clear_items(GTK_LIST(uc->list), index, index+1);
+ g_list_free(children);
+
+ children = NULL;
+ children = g_list_append(children, child);
+ gtk_list_insert_items(GTK_LIST(uc->list), children, index + direction);
+ gtk_list_select_item(GTK_LIST(uc->list), index + direction);
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_VALCHANGE);
+}
+
+static void draglist_up(GtkButton *button, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
+ draglist_move(dp, uc, -1);
+}
+
+static void draglist_down(GtkButton *button, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
+ draglist_move(dp, uc, +1);
+}
+
+static void filesel_ok(GtkButton *button, gpointer data)
+{
+ /* struct dlgparam *dp = (struct dlgparam *)data; */
+ gpointer filesel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
+ struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(filesel), "user-data");
+ char *name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel));
+ gtk_entry_set_text(GTK_ENTRY(uc->entry), name);
+}
+
+static void fontsel_ok(GtkButton *button, gpointer data)
+{
+ /* struct dlgparam *dp = (struct dlgparam *)data; */
+ gpointer fontsel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
+ struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(fontsel), "user-data");
+ char *name = gtk_font_selection_dialog_get_font_name
+ (GTK_FONT_SELECTION_DIALOG(fontsel));
+ gtk_entry_set_text(GTK_ENTRY(uc->entry), name);
+}
+
+static void coloursel_ok(GtkButton *button, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ gpointer coloursel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
+ struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(coloursel), "user-data");
+ gdouble cvals[4];
+ gtk_color_selection_get_color
+ (GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(coloursel)->colorsel),
+ cvals);
+ dp->coloursel_result.r = (int) (255 * cvals[0]);
+ dp->coloursel_result.g = (int) (255 * cvals[1]);
+ dp->coloursel_result.b = (int) (255 * cvals[2]);
+ dp->coloursel_result.ok = TRUE;
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK);
+}
+
+static void coloursel_cancel(GtkButton *button, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ gpointer coloursel = gtk_object_get_data(GTK_OBJECT(button), "user-data");
+ struct uctrl *uc = gtk_object_get_data(GTK_OBJECT(coloursel), "user-data");
+ dp->coloursel_result.ok = FALSE;
+ uc->ctrl->generic.handler(uc->ctrl, dp, dp->data, EVENT_CALLBACK);
+}
+
+static void filefont_clicked(GtkButton *button, gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, GTK_WIDGET(button));
+
+ if (uc->ctrl->generic.type == CTRL_FILESELECT) {
+ GtkWidget *filesel =
+ gtk_file_selection_new(uc->ctrl->fileselect.title);
+ gtk_window_set_modal(GTK_WINDOW(filesel), TRUE);
+ gtk_object_set_data
+ (GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "user-data",
+ (gpointer)filesel);
+ gtk_object_set_data(GTK_OBJECT(filesel), "user-data", (gpointer)uc);
+ gtk_signal_connect
+ (GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
+ GTK_SIGNAL_FUNC(filesel_ok), (gpointer)dp);
+ gtk_signal_connect_object
+ (GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer)filesel);
+ gtk_signal_connect_object
+ (GTK_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button), "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer)filesel);
+ gtk_widget_show(filesel);
+ }
+
+ if (uc->ctrl->generic.type == CTRL_FONTSELECT) {
+ gchar *spacings[] = { "c", "m", NULL };
+ gchar *fontname = gtk_entry_get_text(GTK_ENTRY(uc->entry));
+ GtkWidget *fontsel =
+ gtk_font_selection_dialog_new("Select a font");
+ gtk_window_set_modal(GTK_WINDOW(fontsel), TRUE);
+ gtk_font_selection_dialog_set_filter
+ (GTK_FONT_SELECTION_DIALOG(fontsel),
+ GTK_FONT_FILTER_BASE, GTK_FONT_ALL,
+ NULL, NULL, NULL, NULL, spacings, NULL);
+ if (!gtk_font_selection_dialog_set_font_name
+ (GTK_FONT_SELECTION_DIALOG(fontsel), fontname)) {
+ /*
+ * If the font name wasn't found as it was, try opening
+ * it and extracting its FONT property. This should
+ * have the effect of mapping short aliases into true
+ * XLFDs.
+ */
+ GdkFont *font = gdk_font_load(fontname);
+ if (font) {
+ XFontStruct *xfs = GDK_FONT_XFONT(font);
+ Display *disp = GDK_FONT_XDISPLAY(font);
+ Atom fontprop = XInternAtom(disp, "FONT", False);
+ unsigned long ret;
+ if (XGetFontProperty(xfs, fontprop, &ret)) {
+ char *name = XGetAtomName(disp, (Atom)ret);
+ if (name)
+ gtk_font_selection_dialog_set_font_name
+ (GTK_FONT_SELECTION_DIALOG(fontsel), name);
+ }
+ gdk_font_unref(font);
+ }
+ }
+ gtk_object_set_data
+ (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
+ "user-data", (gpointer)fontsel);
+ gtk_object_set_data(GTK_OBJECT(fontsel), "user-data", (gpointer)uc);
+ gtk_signal_connect
+ (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
+ "clicked", GTK_SIGNAL_FUNC(fontsel_ok), (gpointer)dp);
+ gtk_signal_connect_object
+ (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->ok_button),
+ "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ (gpointer)fontsel);
+ gtk_signal_connect_object
+ (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel)->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ (gpointer)fontsel);
+ gtk_widget_show(fontsel);
+ }
+}
+
+static void label_sizealloc(GtkWidget *widget, GtkAllocation *alloc,
+ gpointer data)
+{
+ struct dlgparam *dp = (struct dlgparam *)data;
+ struct uctrl *uc = dlg_find_bywidget(dp, widget);
+
+ gtk_widget_set_usize(uc->text, alloc->width, -1);
+ gtk_label_set_text(GTK_LABEL(uc->text), uc->ctrl->generic.label);
+ gtk_signal_disconnect(GTK_OBJECT(uc->text), uc->textsig);
+}
+
+/* ----------------------------------------------------------------------