our_dialog.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * Functions to arrange controls in a basically dialog-like window.
  3. *
  4. * The best method for doing this has varied wildly with versions of
  5. * GTK, hence the set of wrapper functions here.
  6. *
  7. * In GTK 1, a GtkDialog has an 'action_area' at the bottom, which is
  8. * a GtkHBox which stretches to cover the full width of the dialog. So
  9. * we can either add buttons or other widgets to that box directly, or
  10. * alternatively we can fill the hbox with some layout class of our
  11. * own such as a Columns widget.
  12. *
  13. * In GTK 2, the action area has become a GtkHButtonBox, and its
  14. * layout behaviour seems to be different and not what we want. So
  15. * instead we abandon the dialog's action area completely: we
  16. * gtk_widget_hide() it in the below code, and we also call
  17. * gtk_dialog_set_has_separator() to remove the separator above it. We
  18. * then insert our own action area into the end of the dialog's main
  19. * vbox, and add our own separator above that.
  20. *
  21. * In GTK 3, we typically don't even want to use GtkDialog at all,
  22. * because GTK 3 has become a lot more restrictive about what you can
  23. * sensibly use GtkDialog for - it deprecates direct access to the
  24. * action area in favour of making you provide nothing but
  25. * dialog-ending buttons in the form of (text, response code) pairs,
  26. * so you can't put any other kind of control in there, or fiddle with
  27. * alignment and positioning, or even have a button that _doesn't_ end
  28. * the dialog (e.g. 'View Licence' in our About box). So instead of
  29. * GtkDialog, we use a straight-up GtkWindow and have it contain a
  30. * vbox as its (unique) child widget; and we implement the action area
  31. * by adding a separator and another widget at the bottom of that
  32. * vbox.
  33. */
  34. #include <gtk/gtk.h>
  35. #include "putty.h"
  36. #include "gtkcompat.h"
  37. #include "gtkmisc.h"
  38. GtkWidget *our_dialog_new(void)
  39. {
  40. #if GTK_CHECK_VERSION(3,0,0)
  41. /*
  42. * See comment in our_dialog_set_action_area(): in GTK 3, we use
  43. * GtkWindow in place of GtkDialog for most purposes.
  44. */
  45. GtkWidget *w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  46. GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
  47. gtk_container_add(GTK_CONTAINER(w), vbox);
  48. gtk_widget_show(vbox);
  49. return w;
  50. #else
  51. return gtk_dialog_new();
  52. #endif
  53. }
  54. void our_dialog_set_action_area(GtkWindow *dlg, GtkWidget *w)
  55. {
  56. #if !GTK_CHECK_VERSION(2,0,0)
  57. gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),
  58. w, true, true, 0);
  59. #elif !GTK_CHECK_VERSION(3,0,0)
  60. GtkWidget *align;
  61. align = gtk_alignment_new(0, 0, 1, 1);
  62. gtk_container_add(GTK_CONTAINER(align), w);
  63. /*
  64. * The purpose of this GtkAlignment is to provide padding
  65. * around the buttons. The padding we use is twice the padding
  66. * used in our GtkColumns, because we nest two GtkColumns most
  67. * of the time (one separating the tree view from the main
  68. * controls, and another for the main controls themselves).
  69. */
  70. #if GTK_CHECK_VERSION(2,4,0)
  71. gtk_alignment_set_padding(GTK_ALIGNMENT(align), 8, 8, 8, 8);
  72. #endif
  73. gtk_widget_show(align);
  74. gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))),
  75. align, false, true, 0);
  76. w = gtk_hseparator_new();
  77. gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))),
  78. w, false, true, 0);
  79. gtk_widget_show(w);
  80. gtk_widget_hide(gtk_dialog_get_action_area(GTK_DIALOG(dlg)));
  81. g_object_set(G_OBJECT(dlg), "has-separator", true, (const char *)NULL);
  82. #else /* GTK 3 */
  83. /* GtkWindow is a GtkBin, hence contains exactly one child, which
  84. * here we always expect to be a vbox */
  85. GtkBox *vbox = GTK_BOX(gtk_bin_get_child(GTK_BIN(dlg)));
  86. GtkWidget *sep;
  87. g_object_set(G_OBJECT(w), "margin", 8, (const char *)NULL);
  88. gtk_box_pack_end(vbox, w, false, true, 0);
  89. sep = gtk_hseparator_new();
  90. gtk_box_pack_end(vbox, sep, false, true, 0);
  91. gtk_widget_show(sep);
  92. #endif
  93. }
  94. GtkBox *our_dialog_make_action_hbox(GtkWindow *dlg)
  95. {
  96. #if GTK_CHECK_VERSION(3,0,0)
  97. GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  98. our_dialog_set_action_area(dlg, hbox);
  99. g_object_set(G_OBJECT(hbox), "margin", 0, (const char *)NULL);
  100. g_object_set(G_OBJECT(hbox), "spacing", 8, (const char *)NULL);
  101. gtk_widget_show(hbox);
  102. return GTK_BOX(hbox);
  103. #else /* not GTK 3 */
  104. return GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dlg)));
  105. #endif
  106. }
  107. void our_dialog_add_to_content_area(GtkWindow *dlg, GtkWidget *w,
  108. bool expand, bool fill, guint padding)
  109. {
  110. #if GTK_CHECK_VERSION(3,0,0)
  111. /* GtkWindow is a GtkBin, hence contains exactly one child, which
  112. * here we always expect to be a vbox */
  113. GtkBox *vbox = GTK_BOX(gtk_bin_get_child(GTK_BIN(dlg)));
  114. gtk_box_pack_start(vbox, w, expand, fill, padding);
  115. #else
  116. gtk_box_pack_start(
  117. GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))),
  118. w, expand, fill, padding);
  119. #endif
  120. }