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