2 * gtkdlg.c - GTK implementation of the PuTTY configuration box.
13 * + `last focused' for nasty sessionsaver hack
14 * + set focus into a sensible control to start with
15 * + perhaps we need uc->primary as the right widget to
20 * - must return a value from the dialog box!
22 * - font selection hiccup: the default `fixed' is not
23 * automatically translated into its expanded XLFD form when the
24 * font selector is started. It should be.
27 * + can't we _somehow_ have less leading between radio buttons?
28 * + wrapping text widgets, the horror, the horror
29 * + labels and their associated edit boxes don't line up
40 #define PUTTY_DO_GLOBALS /* actually _define_ globals */
51 int privdata_needs_free
;
52 GtkWidget
**buttons
; int nbuttons
; /* for radio buttons */
53 GtkWidget
*entry
; /* for editbox, combobox, filesel, fontsel */
54 GtkWidget
*list
; /* for combobox, listbox */
55 GtkWidget
*menu
; /* for optionmenu (==droplist) */
56 GtkWidget
*optmenu
; /* also for optionmenu */
57 GtkWidget
*text
; /* for text */
61 tree234
*byctrl
, *bywidget
;
63 struct { unsigned char r
, g
, b
, ok
; } coloursel_result
; /* 0-255 */
64 /* `flags' are set to indicate when a GTK signal handler is being called
65 * due to automatic processing and should not flag a user event. */
68 #define FLAG_UPDATING_COMBO_LIST 1
73 static void listitem_button(GtkWidget
*item
, GdkEventButton
*event
,
75 static void menuitem_activate(GtkMenuItem
*item
, gpointer data
);
76 static void coloursel_ok(GtkButton
*button
, gpointer data
);
77 static void coloursel_cancel(GtkButton
*button
, gpointer data
);
79 static int uctrl_cmp_byctrl(void *av
, void *bv
)
81 struct uctrl
*a
= (struct uctrl
*)av
;
82 struct uctrl
*b
= (struct uctrl
*)bv
;
83 if (a
->ctrl
< b
->ctrl
)
85 else if (a
->ctrl
> b
->ctrl
)
90 static int uctrl_cmp_byctrl_find(void *av
, void *bv
)
92 union control
*a
= (union control
*)av
;
93 struct uctrl
*b
= (struct uctrl
*)bv
;
101 static int uctrl_cmp_bywidget(void *av
, void *bv
)
103 struct uctrl
*a
= (struct uctrl
*)av
;
104 struct uctrl
*b
= (struct uctrl
*)bv
;
105 if (a
->toplevel
< b
->toplevel
)
107 else if (a
->toplevel
> b
->toplevel
)
112 static int uctrl_cmp_bywidget_find(void *av
, void *bv
)
114 GtkWidget
*a
= (GtkWidget
*)av
;
115 struct uctrl
*b
= (struct uctrl
*)bv
;
118 else if (a
> b
->toplevel
)
123 static void dlg_init(struct dlgparam
*dp
)
125 dp
->byctrl
= newtree234(uctrl_cmp_byctrl
);
126 dp
->bywidget
= newtree234(uctrl_cmp_bywidget
);
127 dp
->coloursel_result
.ok
= FALSE
;
130 static void dlg_cleanup(struct dlgparam
*dp
)
134 freetree234(dp
->byctrl
); /* doesn't free the uctrls inside */
135 while ( (uc
= index234(dp
->bywidget
, 0)) != NULL
) {
136 del234(dp
->bywidget
, uc
);
137 if (uc
->privdata_needs_free
)
142 freetree234(dp
->bywidget
);
145 static void dlg_add_uctrl(struct dlgparam
*dp
, struct uctrl
*uc
)
147 add234(dp
->byctrl
, uc
);
148 add234(dp
->bywidget
, uc
);
151 static struct uctrl
*dlg_find_byctrl(struct dlgparam
*dp
, union control
*ctrl
)
153 return find234(dp
->byctrl
, ctrl
, uctrl_cmp_byctrl_find
);
156 static struct uctrl
*dlg_find_bywidget(struct dlgparam
*dp
, GtkWidget
*w
)
158 struct uctrl
*ret
= NULL
;
160 ret
= find234(dp
->bywidget
, w
, uctrl_cmp_bywidget_find
);
168 void *dlg_get_privdata(union control
*ctrl
, void *dlg
)
170 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
171 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
175 void dlg_set_privdata(union control
*ctrl
, void *dlg
, void *ptr
)
177 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
178 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
180 uc
->privdata_needs_free
= FALSE
;
183 void *dlg_alloc_privdata(union control
*ctrl
, void *dlg
, size_t size
)
185 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
186 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
187 uc
->privdata
= smalloc(size
);
188 uc
->privdata_needs_free
= FALSE
;
192 union control
*dlg_last_focused(void *dlg
)
194 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
195 return NULL
; /* FIXME */
198 void dlg_radiobutton_set(union control
*ctrl
, void *dlg
, int which
)
200 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
201 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
202 assert(uc
->ctrl
->generic
.type
== CTRL_RADIO
);
203 assert(uc
->buttons
!= NULL
);
204 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc
->buttons
[which
]), TRUE
);
207 int dlg_radiobutton_get(union control
*ctrl
, void *dlg
)
209 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
210 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
213 assert(uc
->ctrl
->generic
.type
== CTRL_RADIO
);
214 assert(uc
->buttons
!= NULL
);
215 for (i
= 0; i
< uc
->nbuttons
; i
++)
216 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc
->buttons
[i
])))
218 return 0; /* got to return something */
221 void dlg_checkbox_set(union control
*ctrl
, void *dlg
, int checked
)
223 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
224 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
225 assert(uc
->ctrl
->generic
.type
== CTRL_CHECKBOX
);
226 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc
->toplevel
), checked
);
229 int dlg_checkbox_get(union control
*ctrl
, void *dlg
)
231 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
232 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
233 assert(uc
->ctrl
->generic
.type
== CTRL_CHECKBOX
);
234 return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc
->toplevel
));
237 void dlg_editbox_set(union control
*ctrl
, void *dlg
, char const *text
)
239 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
240 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
241 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
);
242 assert(uc
->entry
!= NULL
);
243 gtk_entry_set_text(GTK_ENTRY(uc
->entry
), text
);
246 void dlg_editbox_get(union control
*ctrl
, void *dlg
, char *buffer
, int length
)
248 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
249 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
250 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
);
251 assert(uc
->entry
!= NULL
);
252 strncpy(buffer
, gtk_entry_get_text(GTK_ENTRY(uc
->entry
)),
254 buffer
[length
-1] = '\0';
257 static void container_remove_and_destroy(GtkWidget
*w
, gpointer data
)
259 GtkContainer
*cont
= GTK_CONTAINER(data
);
260 /* gtk_container_remove will unref the widget for us; we need not. */
261 gtk_container_remove(cont
, w
);
264 /* The `listbox' functions can also apply to combo boxes. */
265 void dlg_listbox_clear(union control
*ctrl
, void *dlg
)
267 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
268 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
271 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
||
272 uc
->ctrl
->generic
.type
== CTRL_LISTBOX
);
273 assert(uc
->menu
!= NULL
|| uc
->list
!= NULL
);
275 cont
= (uc
->menu ?
GTK_CONTAINER(uc
->menu
) : GTK_CONTAINER(uc
->list
));
277 gtk_container_foreach(cont
, container_remove_and_destroy
, cont
);
280 void dlg_listbox_del(union control
*ctrl
, void *dlg
, int index
)
282 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
283 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
285 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
||
286 uc
->ctrl
->generic
.type
== CTRL_LISTBOX
);
287 assert(uc
->menu
!= NULL
|| uc
->list
!= NULL
);
291 (GTK_CONTAINER(uc
->menu
),
292 g_list_nth_data(GTK_MENU_SHELL(uc
->menu
)->children
, index
));
294 gtk_list_clear_items(GTK_LIST(uc
->list
), index
, index
+1);
298 void dlg_listbox_add(union control
*ctrl
, void *dlg
, char const *text
)
300 dlg_listbox_addwithindex(ctrl
, dlg
, text
, 0);
304 * Each listbox entry may have a numeric id associated with it.
305 * Note that some front ends only permit a string to be stored at
306 * each position, which means that _if_ you put two identical
307 * strings in any listbox then you MUST not assign them different
308 * IDs and expect to get meaningful results back.
310 void dlg_listbox_addwithindex(union control
*ctrl
, void *dlg
,
311 char const *text
, int id
)
313 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
314 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
316 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
||
317 uc
->ctrl
->generic
.type
== CTRL_LISTBOX
);
318 assert(uc
->menu
!= NULL
|| uc
->list
!= NULL
);
320 dp
->flags
|= FLAG_UPDATING_COMBO_LIST
;
324 * List item in a drop-down (but non-combo) list. Tabs are
325 * ignored; we just provide a standard menu item with the
328 GtkWidget
*menuitem
= gtk_menu_item_new_with_label(text
);
330 gtk_container_add(GTK_CONTAINER(uc
->menu
), menuitem
);
331 gtk_widget_show(menuitem
);
333 gtk_object_set_data(GTK_OBJECT(menuitem
), "user-data", (gpointer
)id
);
334 gtk_signal_connect(GTK_OBJECT(menuitem
), "activate",
335 GTK_SIGNAL_FUNC(menuitem_activate
), dp
);
336 } else if (!uc
->entry
) {
338 * List item in a non-combo-box list box. We make all of
339 * these Columns containing GtkLabels. This allows us to do
340 * the nasty force_left hack irrespective of whether there
341 * are tabs in the thing.
343 GtkWidget
*listitem
= gtk_list_item_new();
344 GtkWidget
*cols
= columns_new(0);
348 /* Count the tabs in the text, and hence determine # of columns. */
350 for (i
= 0; text
[i
]; i
++)
355 (uc
->ctrl
->listbox
.ncols ? uc
->ctrl
->listbox
.ncols
: 1));
356 percents
= smalloc(ncols
* sizeof(gint
));
357 percents
[ncols
-1] = 100;
358 for (i
= 0; i
< ncols
-1; i
++) {
359 percents
[i
] = uc
->ctrl
->listbox
.percentages
[i
];
360 percents
[ncols
-1] -= percents
[i
];
362 columns_set_cols(COLUMNS(cols
), ncols
, percents
);
365 for (i
= 0; i
< ncols
; i
++) {
366 int len
= strcspn(text
, "\t");
367 char *dup
= dupprintf("%.*s", len
, text
);
372 label
= gtk_label_new(dup
);
375 columns_add(COLUMNS(cols
), label
, i
, 1);
376 columns_force_left_align(COLUMNS(cols
), label
);
377 gtk_widget_show(label
);
379 gtk_container_add(GTK_CONTAINER(listitem
), cols
);
380 gtk_widget_show(cols
);
381 gtk_container_add(GTK_CONTAINER(uc
->list
), listitem
);
382 gtk_widget_show(listitem
);
384 gtk_signal_connect(GTK_OBJECT(listitem
), "button_press_event",
385 GTK_SIGNAL_FUNC(listitem_button
), dp
);
386 gtk_object_set_data(GTK_OBJECT(listitem
), "user-data", (gpointer
)id
);
389 * List item in a combo-box list, which means the sensible
390 * thing to do is make it a perfectly normal label. Hence
391 * tabs are disregarded.
393 GtkWidget
*listitem
= gtk_list_item_new_with_label(text
);
395 gtk_container_add(GTK_CONTAINER(uc
->list
), listitem
);
396 gtk_widget_show(listitem
);
398 gtk_object_set_data(GTK_OBJECT(listitem
), "user-data", (gpointer
)id
);
401 dp
->flags
&= ~FLAG_UPDATING_COMBO_LIST
;
404 int dlg_listbox_getid(union control
*ctrl
, void *dlg
, int index
)
406 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
407 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
411 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
||
412 uc
->ctrl
->generic
.type
== CTRL_LISTBOX
);
413 assert(uc
->menu
!= NULL
|| uc
->list
!= NULL
);
415 children
= gtk_container_children(GTK_CONTAINER(uc
->menu ? uc
->menu
:
417 item
= GTK_OBJECT(g_list_nth_data(children
, index
));
419 return (int)gtk_object_get_data(GTK_OBJECT(item
), "user-data");
422 /* dlg_listbox_index returns <0 if no single element is selected. */
423 int dlg_listbox_index(union control
*ctrl
, void *dlg
)
425 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
426 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
428 GtkWidget
*item
, *activeitem
;
432 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
||
433 uc
->ctrl
->generic
.type
== CTRL_LISTBOX
);
434 assert(uc
->menu
!= NULL
|| uc
->list
!= NULL
);
437 activeitem
= gtk_menu_get_active(GTK_MENU(uc
->menu
));
439 children
= gtk_container_children(GTK_CONTAINER(uc
->menu ? uc
->menu
:
441 for (i
= 0; children
!=NULL
&& (item
= GTK_WIDGET(children
->data
))!=NULL
;
442 i
++, children
= children
->next
) {
443 if (uc
->menu ? activeitem
== item
:
444 GTK_WIDGET_STATE(item
) == GTK_STATE_SELECTED
) {
454 int dlg_listbox_issel(union control
*ctrl
, void *dlg
, int index
)
456 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
457 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
459 GtkWidget
*item
, *activeitem
;
461 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
||
462 uc
->ctrl
->generic
.type
== CTRL_LISTBOX
);
463 assert(uc
->menu
!= NULL
|| uc
->list
!= NULL
);
465 children
= gtk_container_children(GTK_CONTAINER(uc
->menu ? uc
->menu
:
467 item
= GTK_WIDGET(g_list_nth_data(children
, index
));
470 activeitem
= gtk_menu_get_active(GTK_MENU(uc
->menu
));
471 return item
== activeitem
;
473 return GTK_WIDGET_STATE(item
) == GTK_STATE_SELECTED
;
477 void dlg_listbox_select(union control
*ctrl
, void *dlg
, int index
)
479 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
480 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
482 assert(uc
->ctrl
->generic
.type
== CTRL_EDITBOX
||
483 uc
->ctrl
->generic
.type
== CTRL_LISTBOX
);
484 assert(uc
->optmenu
!= NULL
|| uc
->list
!= NULL
);
487 gtk_option_menu_set_history(GTK_OPTION_MENU(uc
->optmenu
), index
);
489 gtk_list_select_item(GTK_LIST(uc
->list
), index
);
493 void dlg_text_set(union control
*ctrl
, void *dlg
, char const *text
)
495 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
496 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
498 assert(uc
->ctrl
->generic
.type
== CTRL_TEXT
);
499 assert(uc
->text
!= NULL
);
501 gtk_label_set_text(GTK_LABEL(uc
->text
), text
);
504 void dlg_filesel_set(union control
*ctrl
, void *dlg
, Filename fn
)
506 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
507 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
508 assert(uc
->ctrl
->generic
.type
== CTRL_FILESELECT
);
509 assert(uc
->entry
!= NULL
);
510 gtk_entry_set_text(GTK_ENTRY(uc
->entry
), fn
.path
);
513 void dlg_filesel_get(union control
*ctrl
, void *dlg
, Filename
*fn
)
515 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
516 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
517 assert(uc
->ctrl
->generic
.type
== CTRL_FILESELECT
);
518 assert(uc
->entry
!= NULL
);
519 strncpy(fn
->path
, gtk_entry_get_text(GTK_ENTRY(uc
->entry
)),
521 fn
->path
[lenof(fn
->path
)-1] = '\0';
524 void dlg_fontsel_set(union control
*ctrl
, void *dlg
, FontSpec fs
)
526 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
527 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
528 assert(uc
->ctrl
->generic
.type
== CTRL_FONTSELECT
);
529 assert(uc
->entry
!= NULL
);
530 gtk_entry_set_text(GTK_ENTRY(uc
->entry
), fs
.name
);
533 void dlg_fontsel_get(union control
*ctrl
, void *dlg
, FontSpec
*fs
)
535 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
536 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
537 assert(uc
->ctrl
->generic
.type
== CTRL_FONTSELECT
);
538 assert(uc
->entry
!= NULL
);
539 strncpy(fs
->name
, gtk_entry_get_text(GTK_ENTRY(uc
->entry
)),
541 fs
->name
[lenof(fs
->name
)-1] = '\0';
545 * Bracketing a large set of updates in these two functions will
546 * cause the front end (if possible) to delay updating the screen
547 * until it's all complete, thus avoiding flicker.
549 void dlg_update_start(union control
*ctrl
, void *dlg
)
552 * Apparently we can't do this at all in GTK. GtkCList supports
553 * freeze and thaw, but not GtkList. Bah.
557 void dlg_update_done(union control
*ctrl
, void *dlg
)
560 * Apparently we can't do this at all in GTK. GtkCList supports
561 * freeze and thaw, but not GtkList. Bah.
565 void dlg_set_focus(union control
*ctrl
, void *dlg
)
567 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
572 * During event processing, you might well want to give an error
573 * indication to the user. dlg_beep() is a quick and easy generic
574 * error; dlg_error() puts up a message-box or equivalent.
576 void dlg_beep(void *dlg
)
581 void dlg_error_msg(void *dlg
, char *msg
)
583 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
588 * This function signals to the front end that the dialog's
589 * processing is completed, and passes an integer value (typically
592 void dlg_end(void *dlg
, int value
)
594 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
596 /* FIXME: don't forget to faff about with returning a value */
599 void dlg_refresh(union control
*ctrl
, void *dlg
)
601 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
605 if (ctrl
->generic
.handler
!= NULL
)
606 ctrl
->generic
.handler(ctrl
, dp
, dp
->data
, EVENT_REFRESH
);
610 for (i
= 0; (uc
= index234(dp
->byctrl
, i
)) != NULL
; i
++) {
611 assert(uc
->ctrl
!= NULL
);
612 if (uc
->ctrl
->generic
.handler
!= NULL
)
613 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
,
614 dp
->data
, EVENT_REFRESH
);
619 void dlg_coloursel_start(union control
*ctrl
, void *dlg
, int r
, int g
, int b
)
621 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
622 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
);
625 GtkWidget
*coloursel
=
626 gtk_color_selection_dialog_new("Select a colour");
627 GtkColorSelectionDialog
*ccs
= GTK_COLOR_SELECTION_DIALOG(coloursel
);
629 dp
->coloursel_result
.ok
= FALSE
;
631 gtk_window_set_modal(GTK_WINDOW(coloursel
), TRUE
);
632 gtk_color_selection_set_opacity(GTK_COLOR_SELECTION(ccs
->colorsel
), FALSE
);
633 cvals
[0] = r
/ 255.0;
634 cvals
[1] = g
/ 255.0;
635 cvals
[2] = b
/ 255.0;
636 cvals
[3] = 1.0; /* fully opaque! */
637 gtk_color_selection_set_color(GTK_COLOR_SELECTION(ccs
->colorsel
), cvals
);
639 gtk_object_set_data(GTK_OBJECT(ccs
->ok_button
), "user-data",
640 (gpointer
)coloursel
);
641 gtk_object_set_data(GTK_OBJECT(ccs
->cancel_button
), "user-data",
642 (gpointer
)coloursel
);
643 gtk_object_set_data(GTK_OBJECT(coloursel
), "user-data", (gpointer
)uc
);
644 gtk_signal_connect(GTK_OBJECT(ccs
->ok_button
), "clicked",
645 GTK_SIGNAL_FUNC(coloursel_ok
), (gpointer
)dp
);
646 gtk_signal_connect(GTK_OBJECT(ccs
->cancel_button
), "clicked",
647 GTK_SIGNAL_FUNC(coloursel_cancel
), (gpointer
)dp
);
648 gtk_signal_connect_object(GTK_OBJECT(ccs
->ok_button
), "clicked",
649 GTK_SIGNAL_FUNC(gtk_widget_destroy
),
650 (gpointer
)coloursel
);
651 gtk_signal_connect_object(GTK_OBJECT(ccs
->cancel_button
), "clicked",
652 GTK_SIGNAL_FUNC(gtk_widget_destroy
),
653 (gpointer
)coloursel
);
654 gtk_widget_show(coloursel
);
657 int dlg_coloursel_results(union control
*ctrl
, void *dlg
,
658 int *r
, int *g
, int *b
)
660 struct dlgparam
*dp
= (struct dlgparam
*)dlg
;
661 if (dp
->coloursel_result
.ok
) {
662 *r
= dp
->coloursel_result
.r
;
663 *g
= dp
->coloursel_result
.g
;
664 *b
= dp
->coloursel_result
.b
;
670 /* ----------------------------------------------------------------------
671 * Signal handlers while the dialog box is active.
674 static void button_clicked(GtkButton
*button
, gpointer data
)
676 struct dlgparam
*dp
= (struct dlgparam
*)data
;
677 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(button
));
678 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_ACTION
);
681 static void button_toggled(GtkToggleButton
*tb
, gpointer data
)
683 struct dlgparam
*dp
= (struct dlgparam
*)data
;
684 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(tb
));
685 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_VALCHANGE
);
688 static void editbox_changed(GtkEditable
*ed
, gpointer data
)
690 struct dlgparam
*dp
= (struct dlgparam
*)data
;
691 if (!(dp
->flags
& FLAG_UPDATING_COMBO_LIST
)) {
692 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(ed
));
693 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_VALCHANGE
);
697 static void editbox_lostfocus(GtkWidget
*ed
, GdkEventFocus
*event
,
700 struct dlgparam
*dp
= (struct dlgparam
*)data
;
701 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(ed
));
702 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_REFRESH
);
705 static void listitem_button(GtkWidget
*item
, GdkEventButton
*event
,
708 struct dlgparam
*dp
= (struct dlgparam
*)data
;
709 if (event
->type
== GDK_2BUTTON_PRESS
||
710 event
->type
== GDK_3BUTTON_PRESS
) {
711 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(item
));
712 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_ACTION
);
716 static void list_selchange(GtkList
*list
, gpointer data
)
718 struct dlgparam
*dp
= (struct dlgparam
*)data
;
719 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(list
));
720 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_SELCHANGE
);
723 static void menuitem_activate(GtkMenuItem
*item
, gpointer data
)
725 struct dlgparam
*dp
= (struct dlgparam
*)data
;
726 GtkWidget
*menushell
= GTK_WIDGET(item
)->parent
;
727 gpointer optmenu
= gtk_object_get_data(GTK_OBJECT(menushell
), "user-data");
728 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(optmenu
));
729 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_SELCHANGE
);
732 static void draglist_move(struct dlgparam
*dp
, struct uctrl
*uc
, int direction
)
734 int index
= dlg_listbox_index(uc
->ctrl
, dp
);
735 GList
*children
= gtk_container_children(GTK_CONTAINER(uc
->list
));
739 (index
== 0 && direction
< 0) ||
740 (index
== g_list_length(children
)-1 && direction
> 0)) {
745 child
= g_list_nth_data(children
, index
);
746 gtk_widget_ref(child
);
747 gtk_list_clear_items(GTK_LIST(uc
->list
), index
, index
+1);
749 children
= g_list_append(children
, child
);
750 gtk_list_insert_items(GTK_LIST(uc
->list
), children
, index
+ direction
);
751 gtk_list_select_item(GTK_LIST(uc
->list
), index
+ direction
);
752 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_VALCHANGE
);
755 static void draglist_up(GtkButton
*button
, gpointer data
)
757 struct dlgparam
*dp
= (struct dlgparam
*)data
;
758 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(button
));
759 draglist_move(dp
, uc
, -1);
762 static void draglist_down(GtkButton
*button
, gpointer data
)
764 struct dlgparam
*dp
= (struct dlgparam
*)data
;
765 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(button
));
766 draglist_move(dp
, uc
, +1);
769 static void filesel_ok(GtkButton
*button
, gpointer data
)
771 struct dlgparam
*dp
= (struct dlgparam
*)data
;
772 gpointer filesel
= gtk_object_get_data(GTK_OBJECT(button
), "user-data");
773 struct uctrl
*uc
= gtk_object_get_data(GTK_OBJECT(filesel
), "user-data");
774 char *name
= gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel
));
775 gtk_entry_set_text(GTK_ENTRY(uc
->entry
), name
);
778 static void fontsel_ok(GtkButton
*button
, gpointer data
)
780 struct dlgparam
*dp
= (struct dlgparam
*)data
;
781 gpointer fontsel
= gtk_object_get_data(GTK_OBJECT(button
), "user-data");
782 struct uctrl
*uc
= gtk_object_get_data(GTK_OBJECT(fontsel
), "user-data");
783 char *name
= gtk_font_selection_dialog_get_font_name
784 (GTK_FONT_SELECTION_DIALOG(fontsel
));
785 gtk_entry_set_text(GTK_ENTRY(uc
->entry
), name
);
788 static void coloursel_ok(GtkButton
*button
, gpointer data
)
790 struct dlgparam
*dp
= (struct dlgparam
*)data
;
791 gpointer coloursel
= gtk_object_get_data(GTK_OBJECT(button
), "user-data");
792 struct uctrl
*uc
= gtk_object_get_data(GTK_OBJECT(coloursel
), "user-data");
794 gtk_color_selection_get_color
795 (GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(coloursel
)->colorsel
),
797 dp
->coloursel_result
.r
= (int) (255 * cvals
[0]);
798 dp
->coloursel_result
.g
= (int) (255 * cvals
[1]);
799 dp
->coloursel_result
.b
= (int) (255 * cvals
[2]);
800 dp
->coloursel_result
.ok
= TRUE
;
801 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_CALLBACK
);
804 static void coloursel_cancel(GtkButton
*button
, gpointer data
)
806 struct dlgparam
*dp
= (struct dlgparam
*)data
;
807 gpointer coloursel
= gtk_object_get_data(GTK_OBJECT(button
), "user-data");
808 struct uctrl
*uc
= gtk_object_get_data(GTK_OBJECT(coloursel
), "user-data");
809 dp
->coloursel_result
.ok
= FALSE
;
810 uc
->ctrl
->generic
.handler(uc
->ctrl
, dp
, dp
->data
, EVENT_CALLBACK
);
813 static void filefont_clicked(GtkButton
*button
, gpointer data
)
815 struct dlgparam
*dp
= (struct dlgparam
*)data
;
816 struct uctrl
*uc
= dlg_find_bywidget(dp
, GTK_WIDGET(button
));
818 if (uc
->ctrl
->generic
.type
== CTRL_FILESELECT
) {
820 gtk_file_selection_new(uc
->ctrl
->fileselect
.title
);
821 gtk_window_set_modal(GTK_WINDOW(filesel
), TRUE
);
823 (GTK_OBJECT(GTK_FILE_SELECTION(filesel
)->ok_button
), "user-data",
825 gtk_object_set_data(GTK_OBJECT(filesel
), "user-data", (gpointer
)uc
);
827 (GTK_OBJECT(GTK_FILE_SELECTION(filesel
)->ok_button
), "clicked",
828 GTK_SIGNAL_FUNC(filesel_ok
), (gpointer
)dp
);
829 gtk_signal_connect_object
830 (GTK_OBJECT(GTK_FILE_SELECTION(filesel
)->ok_button
), "clicked",
831 GTK_SIGNAL_FUNC(gtk_widget_destroy
), (gpointer
)filesel
);
832 gtk_signal_connect_object
833 (GTK_OBJECT(GTK_FILE_SELECTION(filesel
)->cancel_button
), "clicked",
834 GTK_SIGNAL_FUNC(gtk_widget_destroy
), (gpointer
)filesel
);
835 gtk_widget_show(filesel
);
838 if (uc
->ctrl
->generic
.type
== CTRL_FONTSELECT
) {
839 gchar
*spacings
[] = { "c", "m", NULL
};
841 gtk_font_selection_dialog_new("Select a font");
842 gtk_window_set_modal(GTK_WINDOW(fontsel
), TRUE
);
843 gtk_font_selection_dialog_set_filter
844 (GTK_FONT_SELECTION_DIALOG(fontsel
),
845 GTK_FONT_FILTER_BASE
, GTK_FONT_ALL
,
846 NULL
, NULL
, NULL
, NULL
, spacings
, NULL
);
847 gtk_font_selection_dialog_set_font_name
848 (GTK_FONT_SELECTION_DIALOG(fontsel
),
849 gtk_entry_get_text(GTK_ENTRY(uc
->entry
)));
851 (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel
)->ok_button
),
852 "user-data", (gpointer
)fontsel
);
853 gtk_object_set_data(GTK_OBJECT(fontsel
), "user-data", (gpointer
)uc
);
855 (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel
)->ok_button
),
856 "clicked", GTK_SIGNAL_FUNC(fontsel_ok
), (gpointer
)dp
);
857 gtk_signal_connect_object
858 (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel
)->ok_button
),
859 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy
),
861 gtk_signal_connect_object
862 (GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontsel
)->cancel_button
),
863 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy
),
865 gtk_widget_show(fontsel
);
869 /* ----------------------------------------------------------------------
870 * This function does the main layout work: it reads a controlset,
871 * it creates the relevant GTK controls, and returns a GtkWidget
872 * containing the result. (This widget might be a title of some
873 * sort, it might be a Columns containing many controls, or it
874 * might be a GtkFrame containing a Columns; whatever it is, it's
875 * definitely a GtkWidget and should probably be added to a
878 GtkWidget
*layout_ctrls(struct dlgparam
*dp
, struct controlset
*s
,
885 if (!s
->boxname
&& s
->boxtitle
) {
886 /* This controlset is a panel title. */
887 return gtk_label_new(s
->boxtitle
);
891 * Otherwise, we expect to be laying out actual controls, so
892 * we'll start by creating a Columns for the purpose.
894 cols
= COLUMNS(columns_new(4));
895 ret
= GTK_WIDGET(cols
);
896 gtk_widget_show(ret
);
899 * Create a containing frame if we have a box name.
902 ret
= gtk_frame_new(s
->boxtitle
); /* NULL is valid here */
903 gtk_container_set_border_width(GTK_CONTAINER(cols
), 4);
904 gtk_container_add(GTK_CONTAINER(ret
), GTK_WIDGET(cols
));
905 gtk_widget_show(ret
);
909 * Now iterate through the controls themselves, create them,
910 * and add them to the Columns.
912 for (i
= 0; i
< s
->ncontrols
; i
++) {
913 union control
*ctrl
= s
->ctrls
[i
];
919 uc
.privdata_needs_free
= FALSE
;
921 uc
.entry
= uc
.list
= uc
.menu
= uc
.optmenu
= uc
.text
= NULL
;
923 switch (ctrl
->generic
.type
) {
926 static const int simplecols
[1] = { 100 };
927 columns_set_cols(cols
, ctrl
->columns
.ncols
,
928 (ctrl
->columns
.percentages ?
929 ctrl
->columns
.percentages
: simplecols
));
931 continue; /* no actual control created */
934 struct uctrl
*uc
= dlg_find_byctrl(dp
, ctrl
->tabdelay
.ctrl
);
936 columns_taborder_last(cols
, uc
->toplevel
);
938 continue; /* no actual control created */
940 w
= gtk_button_new_with_label(ctrl
->generic
.label
);
941 gtk_signal_connect(GTK_OBJECT(w
), "clicked",
942 GTK_SIGNAL_FUNC(button_clicked
), dp
);
945 w
= gtk_check_button_new_with_label(ctrl
->generic
.label
);
946 gtk_signal_connect(GTK_OBJECT(w
), "toggled",
947 GTK_SIGNAL_FUNC(button_toggled
), dp
);
951 * Radio buttons get to go inside their own Columns, no
955 gint i
, *percentages
;
959 if (ctrl
->generic
.label
) {
960 GtkWidget
*label
= gtk_label_new(ctrl
->generic
.label
);
961 columns_add(COLUMNS(w
), label
, 0, 1);
962 columns_force_left_align(COLUMNS(w
), label
);
963 gtk_widget_show(label
);
965 percentages
= g_new(gint
, ctrl
->radio
.ncolumns
);
966 for (i
= 0; i
< ctrl
->radio
.ncolumns
; i
++) {
968 ((100 * (i
+1) / ctrl
->radio
.ncolumns
) -
969 100 * i
/ ctrl
->radio
.ncolumns
);
971 columns_set_cols(COLUMNS(w
), ctrl
->radio
.ncolumns
,
976 uc
.nbuttons
= ctrl
->radio
.nbuttons
;
977 uc
.buttons
= smalloc(uc
.nbuttons
* sizeof(GtkWidget
*));
979 for (i
= 0; i
< ctrl
->radio
.nbuttons
; i
++) {
983 b
= (gtk_radio_button_new_with_label
984 (group
, ctrl
->radio
.buttons
[i
]));
986 group
= gtk_radio_button_group(GTK_RADIO_BUTTON(b
));
987 colstart
= i
% ctrl
->radio
.ncolumns
;
988 columns_add(COLUMNS(w
), b
, colstart
,
989 (i
== ctrl
->radio
.nbuttons
-1 ?
990 ctrl
->radio
.ncolumns
- colstart
: 1));
992 gtk_signal_connect(GTK_OBJECT(b
), "toggled",
993 GTK_SIGNAL_FUNC(button_toggled
), dp
);
998 if (ctrl
->editbox
.has_list
) {
1000 gtk_combo_set_value_in_list(GTK_COMBO(w
), FALSE
, TRUE
);
1001 uc
.entry
= GTK_COMBO(w
)->entry
;
1002 uc
.list
= GTK_COMBO(w
)->list
;
1004 w
= gtk_entry_new();
1005 if (ctrl
->editbox
.password
)
1006 gtk_entry_set_visibility(GTK_ENTRY(w
), FALSE
);
1009 gtk_signal_connect(GTK_OBJECT(uc
.entry
), "changed",
1010 GTK_SIGNAL_FUNC(editbox_changed
), dp
);
1012 * Edit boxes, for some strange reason, have a minimum
1013 * width of 150 in GTK 1.2. We don't want this - we'd
1014 * rather the edit boxes acquired their natural width
1015 * from the column layout of the rest of the box.
1019 gtk_widget_size_request(w
, &req
);
1020 gtk_widget_set_usize(w
, 10, req
.height
);
1022 if (ctrl
->generic
.label
) {
1023 GtkWidget
*label
, *container
;
1025 label
= gtk_label_new(ctrl
->generic
.label
);
1027 container
= columns_new(4);
1028 if (ctrl
->editbox
.percentwidth
== 100) {
1029 columns_add(COLUMNS(container
), label
, 0, 1);
1030 columns_force_left_align(COLUMNS(container
), label
);
1031 columns_add(COLUMNS(container
), w
, 0, 1);
1033 gint percentages
[2];
1034 percentages
[1] = ctrl
->editbox
.percentwidth
;
1035 percentages
[0] = 100 - ctrl
->editbox
.percentwidth
;
1036 columns_set_cols(COLUMNS(container
), 2, percentages
);
1037 columns_add(COLUMNS(container
), label
, 0, 1);
1038 columns_force_left_align(COLUMNS(container
), label
);
1039 columns_add(COLUMNS(container
), w
, 1, 1);
1041 gtk_widget_show(label
);
1046 gtk_signal_connect(GTK_OBJECT(uc
.entry
), "focus_out_event",
1047 GTK_SIGNAL_FUNC(editbox_lostfocus
), dp
);
1049 case CTRL_FILESELECT
:
1050 case CTRL_FONTSELECT
:
1055 (ctrl
->generic
.type
== CTRL_FILESELECT ?
1056 "Browse..." : "Change...");
1058 gint percentages
[] = { 75, 25 };
1060 columns_set_cols(COLUMNS(w
), 2, percentages
);
1062 if (ctrl
->generic
.label
) {
1063 ww
= gtk_label_new(ctrl
->generic
.label
);
1064 columns_add(COLUMNS(w
), ww
, 0, 2);
1065 columns_force_left_align(COLUMNS(w
), ww
);
1066 gtk_widget_show(ww
);
1069 uc
.entry
= ww
= gtk_entry_new();
1070 gtk_widget_size_request(ww
, &req
);
1071 gtk_widget_set_usize(ww
, 10, req
.height
);
1072 columns_add(COLUMNS(w
), ww
, 0, 1);
1073 gtk_widget_show(ww
);
1075 ww
= gtk_button_new_with_label(browsebtn
);
1076 columns_add(COLUMNS(w
), ww
, 1, 1);
1077 gtk_widget_show(ww
);
1079 gtk_signal_connect(GTK_OBJECT(uc
.entry
), "changed",
1080 GTK_SIGNAL_FUNC(editbox_changed
), dp
);
1081 gtk_signal_connect(GTK_OBJECT(ww
), "clicked",
1082 GTK_SIGNAL_FUNC(filefont_clicked
), dp
);
1086 if (ctrl
->listbox
.height
== 0) {
1087 uc
.optmenu
= w
= gtk_option_menu_new();
1088 uc
.menu
= gtk_menu_new();
1089 gtk_option_menu_set_menu(GTK_OPTION_MENU(w
), uc
.menu
);
1090 gtk_object_set_data(GTK_OBJECT(uc
.menu
), "user-data",
1091 (gpointer
)uc
.optmenu
);
1093 uc
.list
= gtk_list_new();
1094 gtk_list_set_selection_mode(GTK_LIST(uc
.list
),
1095 (ctrl
->listbox
.multisel ?
1096 GTK_SELECTION_MULTIPLE
:
1097 GTK_SELECTION_SINGLE
));
1098 w
= gtk_scrolled_window_new(NULL
, NULL
);
1099 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(w
),
1101 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w
),
1103 GTK_POLICY_AUTOMATIC
);
1104 gtk_widget_show(uc
.list
);
1105 gtk_signal_connect(GTK_OBJECT(uc
.list
), "selection-changed",
1106 GTK_SIGNAL_FUNC(list_selchange
), dp
);
1109 * Adjust the height of the scrolled window to the
1110 * minimum given by the height parameter.
1112 * This piece of guesswork is a horrid hack based
1113 * on looking inside the GTK 1.2 sources
1114 * (specifically gtkviewport.c, which appears to be
1115 * the widget which provides the border around the
1116 * scrolling area). Anyone lets me know how I can
1117 * do this in a way which isn't at risk from GTK
1118 * upgrades, I'd be grateful.
1121 int edge
= GTK_WIDGET(uc
.list
)->style
->klass
->ythickness
;
1122 gtk_widget_set_usize(w
, 10,
1123 2*edge
+ (ctrl
->listbox
.height
*
1127 if (ctrl
->listbox
.draglist
) {
1129 * GTK doesn't appear to make it easy to
1130 * implement a proper draggable list; so
1131 * instead I'm just going to have to put an Up
1132 * and a Down button to the right of the actual
1133 * list box. Ah well.
1135 GtkWidget
*cols
, *button
;
1136 static const gint percentages
[2] = { 80, 20 };
1138 cols
= columns_new(4);
1139 columns_set_cols(COLUMNS(cols
), 2, percentages
);
1140 columns_add(COLUMNS(cols
), w
, 0, 1);
1142 button
= gtk_button_new_with_label("Up");
1143 columns_add(COLUMNS(cols
), button
, 1, 1);
1144 gtk_widget_show(button
);
1145 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
1146 GTK_SIGNAL_FUNC(draglist_up
), dp
);
1147 button
= gtk_button_new_with_label("Down");
1148 columns_add(COLUMNS(cols
), button
, 1, 1);
1149 gtk_widget_show(button
);
1150 gtk_signal_connect(GTK_OBJECT(button
), "clicked",
1151 GTK_SIGNAL_FUNC(draglist_down
), dp
);
1157 if (ctrl
->generic
.label
) {
1158 GtkWidget
*label
, *container
;
1160 label
= gtk_label_new(ctrl
->generic
.label
);
1162 container
= columns_new(4);
1163 if (ctrl
->listbox
.percentwidth
== 100) {
1164 columns_add(COLUMNS(container
), label
, 0, 1);
1165 columns_force_left_align(COLUMNS(container
), label
);
1166 columns_add(COLUMNS(container
), w
, 0, 1);
1168 gint percentages
[2];
1169 percentages
[1] = ctrl
->listbox
.percentwidth
;
1170 percentages
[0] = 100 - ctrl
->listbox
.percentwidth
;
1171 columns_set_cols(COLUMNS(container
), 2, percentages
);
1172 columns_add(COLUMNS(container
), label
, 0, 1);
1173 columns_force_left_align(COLUMNS(container
), label
);
1174 columns_add(COLUMNS(container
), w
, 1, 1);
1176 gtk_widget_show(label
);
1183 uc
.text
= w
= gtk_label_new(ctrl
->generic
.label
);
1184 gtk_label_set_line_wrap(GTK_LABEL(w
), TRUE
);
1185 /* FIXME: deal with wrapping! */
1189 struct uctrl
*ucptr
;
1191 columns_add(cols
, w
,
1192 COLUMN_START(ctrl
->generic
.column
),
1193 COLUMN_SPAN(ctrl
->generic
.column
));
1196 ucptr
= smalloc(sizeof(struct uctrl
));
1197 *ucptr
= uc
; /* structure copy */
1198 ucptr
->toplevel
= w
;
1199 dlg_add_uctrl(dp
, ucptr
);
1208 GtkWidget
*panel
, *treeitem
;
1211 static void treeitem_sel(GtkItem
*item
, gpointer data
)
1213 struct selparam
*sp
= (struct selparam
*)data
;
1215 panels_switch_to(sp
->panels
, sp
->panel
);
1218 void destroy(GtkWidget
*widget
, gpointer data
)
1223 void do_config_box(void)
1225 GtkWidget
*window
, *hbox
, *vbox
, *cols
, *label
,
1226 *tree
, *treescroll
, *panels
, *panelvbox
;
1227 int index
, level
, listitemheight
;
1228 struct controlbox
*ctrlbox
;
1230 GtkTreeItem
*treeitemlevels
[8];
1231 GtkTree
*treelevels
[8];
1236 struct selparam
*selparams
= NULL
;
1237 int nselparams
= 0, selparamsize
= 0;
1239 do_defaults(NULL
, &cfg
);
1244 GtkWidget
*listitem
= gtk_list_item_new_with_label("foo");
1246 gtk_widget_size_request(listitem
, &req
);
1247 listitemheight
= req
.height
;
1248 gtk_widget_unref(listitem
);
1253 ctrlbox
= ctrl_new_box();
1254 setup_config_box(ctrlbox
, &sl
, FALSE
, 0);
1255 unix_setup_config_box(ctrlbox
, FALSE
);
1257 window
= gtk_dialog_new();
1258 hbox
= gtk_hbox_new(FALSE
, 4);
1259 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window
)->vbox
), hbox
, TRUE
, TRUE
, 0);
1260 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 10);
1261 gtk_widget_show(hbox
);
1262 vbox
= gtk_vbox_new(FALSE
, 4);
1263 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, FALSE
, FALSE
, 0);
1264 gtk_widget_show(vbox
);
1265 cols
= columns_new(4);
1266 gtk_box_pack_start(GTK_BOX(vbox
), cols
, FALSE
, FALSE
, 0);
1267 gtk_widget_show(cols
);
1268 label
= gtk_label_new("Category:");
1269 columns_add(COLUMNS(cols
), label
, 0, 1);
1270 columns_force_left_align(COLUMNS(cols
), label
);
1271 gtk_widget_show(label
);
1272 treescroll
= gtk_scrolled_window_new(NULL
, NULL
);
1273 tree
= gtk_tree_new();
1274 gtk_tree_set_view_mode(GTK_TREE(tree
), GTK_TREE_VIEW_ITEM
);
1275 gtk_tree_set_selection_mode(GTK_TREE(tree
), GTK_SELECTION_BROWSE
);
1276 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(treescroll
),
1278 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(treescroll
),
1280 GTK_POLICY_AUTOMATIC
);
1281 gtk_widget_show(tree
);
1282 gtk_widget_show(treescroll
);
1283 gtk_box_pack_start(GTK_BOX(vbox
), treescroll
, TRUE
, TRUE
, 0);
1284 panels
= panels_new();
1285 gtk_box_pack_start(GTK_BOX(hbox
), panels
, TRUE
, TRUE
, 0);
1286 gtk_widget_show(panels
);
1291 for (index
= 0; index
< ctrlbox
->nctrlsets
; index
++) {
1292 struct controlset
*s
= ctrlbox
->ctrlsets
[index
];
1293 GtkWidget
*w
= layout_ctrls(&dp
, s
, listitemheight
);
1295 if (!*s
->pathname
) {
1296 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window
)->action_area
),
1299 int j
= path ?
ctrl_path_compare(s
->pathname
, path
) : 0;
1300 if (j
!= INT_MAX
) { /* add to treeview, start new panel */
1302 GtkWidget
*treeitem
;
1306 * We expect never to find an implicit path
1307 * component. For example, we expect never to see
1308 * A/B/C followed by A/D/E, because that would
1309 * _implicitly_ create A/D. All our path prefixes
1310 * are expected to contain actual controls and be
1311 * selectable in the treeview; so we would expect
1312 * to see A/D _explicitly_ before encountering
1315 assert(j
== ctrl_path_elements(s
->pathname
) - 1);
1317 c
= strrchr(s
->pathname
, '/');
1323 treeitem
= gtk_tree_item_new_with_label(c
);
1324 assert(j
-1 < level
);
1326 if (!treelevels
[j
-1]) {
1327 treelevels
[j
-1] = GTK_TREE(gtk_tree_new());
1328 gtk_tree_item_set_subtree
1329 (treeitemlevels
[j
-1],
1330 GTK_WIDGET(treelevels
[j
-1]));
1331 gtk_tree_item_expand(treeitemlevels
[j
-1]);
1333 gtk_tree_append(treelevels
[j
-1], treeitem
);
1335 gtk_tree_append(GTK_TREE(tree
), treeitem
);
1337 treeitemlevels
[j
] = GTK_TREE_ITEM(treeitem
);
1338 treelevels
[j
] = NULL
;
1341 gtk_widget_show(treeitem
);
1345 first
= (panelvbox
== NULL
);
1347 panelvbox
= gtk_vbox_new(FALSE
, 4);
1348 gtk_container_add(GTK_CONTAINER(panels
), panelvbox
);
1350 panels_switch_to(PANELS(panels
), panelvbox
);
1351 gtk_tree_select_child(GTK_TREE(tree
), treeitem
);
1354 if (nselparams
>= selparamsize
) {
1356 selparams
= srealloc(selparams
,
1357 selparamsize
* sizeof(*selparams
));
1359 selparams
[nselparams
].panels
= PANELS(panels
);
1360 selparams
[nselparams
].panel
= panelvbox
;
1361 selparams
[nselparams
].treeitem
= treeitem
;
1366 gtk_box_pack_start(GTK_BOX(panelvbox
), w
, FALSE
, FALSE
, 0);
1371 for (index
= 0; index
< nselparams
; index
++) {
1372 gtk_signal_connect(GTK_OBJECT(selparams
[index
].treeitem
), "select",
1373 GTK_SIGNAL_FUNC(treeitem_sel
),
1378 dlg_refresh(NULL
, &dp
);
1380 gtk_widget_show(window
);
1382 gtk_signal_connect(GTK_OBJECT(window
), "destroy",
1383 GTK_SIGNAL_FUNC(destroy
), NULL
);
1391 /* ======================================================================
1392 * Below here is a stub main program which allows the dialog box
1393 * code to be compiled and tested with a minimal amount of the rest
1399 /* Compile command for testing:
1401 gcc -g -o gtkdlg gtk{dlg,cols,panel}.c ../{config,dialog,settings}.c \
1402 ../{misc,tree234,be_none}.c ux{store,misc,print,cfg}.c \
1403 -I. -I.. -I../charset -DTESTMODE `gtk-config --cflags --libs`
1406 void modalfatalbox(char *p
, ...)
1409 fprintf(stderr
, "FATAL ERROR: ");
1411 vfprintf(stderr
, p
, ap
);
1413 fputc('\n', stderr
);
1417 char *cp_name(int codepage
)
1419 return (codepage
== 123 ?
"testing123" :
1420 codepage
== 234 ?
"testing234" :
1421 codepage
== 345 ?
"testing345" :
1425 char *cp_enumerate(int index
)
1427 return (index
== 0 ?
"testing123" :
1428 index
== 1 ?
"testing234" :
1432 int decode_codepage(char *cp_name
)
1434 return (!strcmp(cp_name
, "testing123") ?
123 :
1435 !strcmp(cp_name
, "testing234") ?
234 :
1436 !strcmp(cp_name
, "testing345") ?
345 :
1440 struct printer_enum_tag
{ int dummy
; } printer_test
;
1442 printer_enum
*printer_start_enum(int *nprinters_ptr
) {
1444 return &printer_test
;
1446 char *printer_get_name(printer_enum
*pe
, int i
) {
1447 return (i
==0 ?
"lpr" : i
==1 ?
"lpr -Pfoobar" : NULL
);
1449 void printer_finish_enum(printer_enum
*pe
) { }
1451 char *platform_default_s(const char *name
)
1456 int platform_default_i(const char *name
, int def
)
1461 FontSpec
platform_default_fontspec(const char *name
)
1464 if (!strcmp(name
, "Font"))
1465 strcpy(ret
.name
, "fixed");
1471 Filename
platform_default_filename(const char *name
)
1474 if (!strcmp(name
, "LogFileName"))
1475 strcpy(ret
.path
, "putty.log");
1481 char *x_get_default(const char *key
)
1486 int main(int argc
, char **argv
)
1488 gtk_init(&argc
, &argv
);