]> code.delx.au - gnu-emacs/blob - src/emacsgtkfixed.c
6795155831ede005203aefa0a8e50dfc18d7e7b0
[gnu-emacs] / src / emacsgtkfixed.c
1 /* A Gtk Widget that inherits GtkFixed, but can be shrunk.
2 This file is only use when compiling with Gtk+ 3.
3
4 Copyright (C) 2011-2016 Free Software Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20
21 #include <config.h>
22
23 #include "lisp.h"
24 #include "frame.h"
25 #include "xterm.h"
26 #include "xwidget.h"
27 #include "emacsgtkfixed.h"
28
29 /* Silence a bogus diagnostic; see GNOME bug 683906. */
30 #if 4 < __GNUC__ + (7 <= __GNUC_MINOR__)
31 # pragma GCC diagnostic push
32 # pragma GCC diagnostic ignored "-Wunused-local-typedefs"
33 #endif
34
35 typedef struct _EmacsFixed EmacsFixed;
36 typedef struct _EmacsFixedPrivate EmacsFixedPrivate;
37 typedef struct _EmacsFixedClass EmacsFixedClass;
38
39 struct _EmacsFixedPrivate
40 {
41 struct frame *f;
42 };
43
44
45 static void emacs_fixed_get_preferred_width (GtkWidget *widget,
46 gint *minimum,
47 gint *natural);
48 static void emacs_fixed_get_preferred_height (GtkWidget *widget,
49 gint *minimum,
50 gint *natural);
51 static GType emacs_fixed_get_type (void);
52 G_DEFINE_TYPE (EmacsFixed, emacs_fixed, GTK_TYPE_FIXED)
53
54 static EmacsFixed *
55 EMACS_FIXED (GtkWidget *widget)
56 {
57 return G_TYPE_CHECK_INSTANCE_CAST (widget, emacs_fixed_get_type (),
58 EmacsFixed);
59 }
60
61 #ifdef HAVE_XWIDGETS
62
63 static EmacsFixedClass *
64 EMACS_FIXED_GET_CLASS (GtkWidget *widget)
65 {
66 return G_TYPE_INSTANCE_GET_CLASS (widget, emacs_fixed_get_type (),
67 EmacsFixedClass);
68 }
69
70 struct GtkFixedPrivateL
71 {
72 GList *children;
73 };
74
75 static void
76 emacs_fixed_gtk_widget_size_allocate (GtkWidget *widget,
77 GtkAllocation *allocation)
78 {
79 /* For xwidgets.
80
81 This basically re-implements the base class method and adds an
82 additional case for an xwidget view.
83
84 It would be nicer if the bse class method could be called first,
85 and the the xview modification only would remain here. It wasn't
86 possible to solve it that way yet. */
87 EmacsFixedClass *klass;
88 GtkWidgetClass *parent_class;
89 struct GtkFixedPrivateL *priv;
90
91 klass = EMACS_FIXED_GET_CLASS (widget);
92 parent_class = g_type_class_peek_parent (klass);
93 parent_class->size_allocate (widget, allocation);
94
95 priv = G_TYPE_INSTANCE_GET_PRIVATE (widget, GTK_TYPE_FIXED,
96 struct GtkFixedPrivateL);
97
98 gtk_widget_set_allocation (widget, allocation);
99
100 if (gtk_widget_get_has_window (widget))
101 {
102 if (gtk_widget_get_realized (widget))
103 gdk_window_move_resize (gtk_widget_get_window (widget),
104 allocation->x,
105 allocation->y,
106 allocation->width,
107 allocation->height);
108 }
109
110 for (GList *children = priv->children; children; children = children->next)
111 {
112 GtkFixedChild *child = children->data;
113
114 if (!gtk_widget_get_visible (child->widget))
115 continue;
116
117 GtkRequisition child_requisition;
118 gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
119
120 GtkAllocation child_allocation;
121 child_allocation.x = child->x;
122 child_allocation.y = child->y;
123
124 if (!gtk_widget_get_has_window (widget))
125 {
126 child_allocation.x += allocation->x;
127 child_allocation.y += allocation->y;
128 }
129
130 child_allocation.width = child_requisition.width;
131 child_allocation.height = child_requisition.height;
132
133 struct xwidget_view *xv
134 = g_object_get_data (G_OBJECT (child->widget), XG_XWIDGET_VIEW);
135 if (xv)
136 {
137 child_allocation.width = xv->clip_right;
138 child_allocation.height = xv->clip_bottom - xv->clip_top;
139 }
140
141 gtk_widget_size_allocate (child->widget, &child_allocation);
142 }
143 }
144
145 #endif /* HAVE_XWIDGETS */
146
147 static void
148 emacs_fixed_class_init (EmacsFixedClass *klass)
149 {
150 GtkWidgetClass *widget_class;
151
152 widget_class = (GtkWidgetClass*) klass;
153
154 widget_class->get_preferred_width = emacs_fixed_get_preferred_width;
155 widget_class->get_preferred_height = emacs_fixed_get_preferred_height;
156 #ifdef HAVE_XWIDGETS
157 widget_class->size_allocate = emacs_fixed_gtk_widget_size_allocate;
158 #endif
159 g_type_class_add_private (klass, sizeof (EmacsFixedPrivate));
160 }
161
162 static void
163 emacs_fixed_init (EmacsFixed *fixed)
164 {
165 fixed->priv = G_TYPE_INSTANCE_GET_PRIVATE (fixed, emacs_fixed_get_type (),
166 EmacsFixedPrivate);
167 fixed->priv->f = 0;
168 }
169
170 GtkWidget *
171 emacs_fixed_new (struct frame *f)
172 {
173 EmacsFixed *fixed = g_object_new (emacs_fixed_get_type (), NULL);
174 EmacsFixedPrivate *priv = fixed->priv;
175 priv->f = f;
176 return GTK_WIDGET (fixed);
177 }
178
179 static void
180 emacs_fixed_get_preferred_width (GtkWidget *widget,
181 gint *minimum,
182 gint *natural)
183 {
184 EmacsFixed *fixed = EMACS_FIXED (widget);
185 EmacsFixedPrivate *priv = fixed->priv;
186 int w = priv->f->output_data.x->size_hints.min_width;
187 if (minimum) *minimum = w;
188 if (natural) *natural = w;
189 }
190
191 static void
192 emacs_fixed_get_preferred_height (GtkWidget *widget,
193 gint *minimum,
194 gint *natural)
195 {
196 EmacsFixed *fixed = EMACS_FIXED (widget);
197 EmacsFixedPrivate *priv = fixed->priv;
198 int h = priv->f->output_data.x->size_hints.min_height;
199 if (minimum) *minimum = h;
200 if (natural) *natural = h;
201 }
202
203
204 /* Override the X function so we can intercept Gtk+ 3 calls.
205 Use our values for min_width/height so that KDE don't freak out
206 (Bug#8919), and so users can resize our frames as they wish. */
207
208 void
209 XSetWMSizeHints (Display* d,
210 Window w,
211 XSizeHints* hints,
212 Atom prop)
213 {
214 struct x_display_info *dpyinfo = x_display_info_for_display (d);
215 struct frame *f = x_top_window_to_frame (dpyinfo, w);
216 long data[18];
217 data[0] = hints->flags;
218 data[1] = hints->x;
219 data[2] = hints->y;
220 data[3] = hints->width;
221 data[4] = hints->height;
222 data[5] = hints->min_width;
223 data[6] = hints->min_height;
224 data[7] = hints->max_width;
225 data[8] = hints->max_height;
226 data[9] = hints->width_inc;
227 data[10] = hints->height_inc;
228 data[11] = hints->min_aspect.x;
229 data[12] = hints->min_aspect.y;
230 data[13] = hints->max_aspect.x;
231 data[14] = hints->max_aspect.y;
232 data[15] = hints->base_width;
233 data[16] = hints->base_height;
234 data[17] = hints->win_gravity;
235
236 if ((hints->flags & PMinSize) && f)
237 {
238 int w = f->output_data.x->size_hints.min_width;
239 int h = f->output_data.x->size_hints.min_height;
240 data[5] = w;
241 data[6] = h;
242 }
243
244 XChangeProperty (d, w, prop, XA_WM_SIZE_HINTS, 32, PropModeReplace,
245 (unsigned char *) data, 18);
246 }
247
248 /* Override this X11 function.
249 This function is in the same X11 file as the one above. So we must
250 provide it also. */
251
252 void
253 XSetWMNormalHints (Display *d, Window w, XSizeHints *hints)
254 {
255 XSetWMSizeHints (d, w, hints, XA_WM_NORMAL_HINTS);
256 }