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