1 /*
2  * ghbcompat.h
3  * Copyright (C) John Stebbins 2008-2021 <stebbins@stebbins>
4  *
5  * ghbcompat.h is free software.
6  *
7  * You may redistribute it and/or modify it under the terms of the
8  * GNU General Public License version 2, as published by the Free Software
9  * Foundation.
10  *
11  * ghbcompat.h is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with callbacks.h.  If not, write to:
18  *  The Free Software Foundation, Inc.,
19  *  51 Franklin Street, Fifth Floor
20  *  Boston, MA  02110-1301, USA.
21  */
22 
23 #if !defined(_GHB_COMPAT_H_)
24 #define _GHB_COMPAT_H_
25 
26 #include <gtk/gtk.h>
27 #include <gdk/gdk.h>
28 #include <string.h>
29 
30 #if defined(_WIN32)
31 #define GHB_UNSAFE_FILENAME_CHARS "/:<>\"\\|?*"
32 #else
33 #define GHB_UNSAFE_FILENAME_CHARS "/"
34 #endif
35 
36 #if GTK_CHECK_VERSION(3, 90, 0)
37 #define GHB_ICON_SIZE_BUTTON GTK_ICON_SIZE_NORMAL
38 #else
39 #define GHB_ICON_SIZE_BUTTON GTK_ICON_SIZE_BUTTON
40 #endif
41 
42 #if !GTK_CHECK_VERSION(3, 10, 0)
43 #define gtk_image_set_from_icon_name gtk_image_set_from_stock
44 #define GHB_PLAY_ICON "gtk-media-play"
45 #define GHB_PAUSE_ICON "gtk-media-pause"
46 #else
47 #define GHB_PLAY_ICON "media-playback-start"
48 #define GHB_PAUSE_ICON "media-playback-pause"
49 #endif
50 
51 #if !GTK_CHECK_VERSION(3, 10, 0)
52 #define GHB_STOCK_OPEN      GTK_STOCK_OPEN
53 #define GHB_STOCK_CANCEL    GTK_STOCK_CANCEL
54 #define GHB_STOCK_SAVE      GTK_STOCK_SAVE
55 #else
56 #define GHB_STOCK_OPEN      "_Open"
57 #define GHB_STOCK_CANCEL    "_Cancel"
58 #define GHB_STOCK_SAVE      "_Save"
59 #endif
60 
ghb_widget_get_preferred_width(GtkWidget * widget,gint * min_width,gint * natural_width)61 static inline void ghb_widget_get_preferred_width(
62     GtkWidget *widget, gint *min_width, gint * natural_width)
63 {
64 #if GTK_CHECK_VERSION(3, 90, 0)
65     GtkRequisition min_req, nat_req;
66 
67     gtk_widget_get_preferred_size(widget, &min_req, &nat_req);
68     if (min_width != NULL)
69     {
70         *min_width = min_req.width;
71     }
72     if (natural_width != NULL)
73     {
74         *natural_width = nat_req.width;
75     }
76 #else
77     gtk_widget_get_preferred_width(widget, min_width, natural_width);
78 #endif
79 }
80 
ghb_widget_get_preferred_height(GtkWidget * widget,gint * min_height,gint * natural_height)81 static inline void ghb_widget_get_preferred_height(
82     GtkWidget *widget, gint *min_height, gint * natural_height)
83 {
84 #if GTK_CHECK_VERSION(3, 90, 0)
85     GtkRequisition min_req, nat_req;
86 
87     gtk_widget_get_preferred_size(widget, &min_req, &nat_req);
88     if (min_height != NULL)
89     {
90         *min_height = min_req.height;
91     }
92     if (natural_height != NULL)
93     {
94         *natural_height = nat_req.height;
95     }
96 #else
97     gtk_widget_get_preferred_height(widget, min_height, natural_height);
98 #endif
99 }
100 
ghb_button_set_icon_name(GtkButton * button,const char * name)101 static inline void ghb_button_set_icon_name(GtkButton *button,
102                                             const char * name)
103 {
104 #if GTK_CHECK_VERSION(3, 90, 0)
105     gtk_button_set_icon_name(button, name);
106 #else
107     GtkImage *image;
108 
109     image = GTK_IMAGE(gtk_image_new_from_icon_name(name, GTK_ICON_SIZE_BUTTON));
110     gtk_button_set_image(button, GTK_WIDGET(image));
111 #endif
112 }
113 
ghb_get_expand_fill(GtkBox * box,GtkWidget * child,gboolean * expand,gboolean * fill)114 static inline void ghb_get_expand_fill(GtkBox * box, GtkWidget * child,
115                                        gboolean *expand, gboolean *fill)
116 {
117     if (gtk_orientable_get_orientation(GTK_ORIENTABLE(box)) ==
118         GTK_ORIENTATION_HORIZONTAL)
119     {
120         *expand = gtk_widget_get_hexpand(child);
121         *fill   = gtk_widget_get_halign(child) == GTK_ALIGN_FILL;
122     }
123     else
124     {
125         *expand = gtk_widget_get_vexpand(child);
126         *fill   = gtk_widget_get_valign(child) == GTK_ALIGN_FILL;
127     }
128 }
129 
ghb_box_append_child(GtkBox * box,GtkWidget * child)130 static inline void ghb_box_append_child(GtkBox * box, GtkWidget * child)
131 {
132 #if GTK_CHECK_VERSION(3, 90, 0)
133     GtkWidget * sibling = NULL;
134 
135     sibling = gtk_widget_get_last_child(GTK_WIDGET(box));
136     gtk_box_insert_child_after(box, child, sibling);
137 #else
138     gboolean expand, fill;
139 
140     ghb_get_expand_fill(box, child, &expand, &fill);
141     gtk_box_pack_start(box, child, expand, fill, 0);
142 #endif
143 }
144 
ghb_css_provider_load_from_data(GtkCssProvider * provider,const gchar * data,gssize length)145 static inline void ghb_css_provider_load_from_data(GtkCssProvider *provider,
146                                                    const gchar *data,
147                                                    gssize length)
148 {
149 #if GTK_CHECK_VERSION(3, 90, 0)
150     gtk_css_provider_load_from_data(provider, data, length);
151 #else
152     gtk_css_provider_load_from_data(provider, data, length, NULL);
153 #endif
154 }
155 
ghb_event_get_event_type(const GdkEvent * event)156 static inline GdkEventType ghb_event_get_event_type(const GdkEvent *event)
157 {
158 #if GTK_CHECK_VERSION(3, 10, 0)
159     return gdk_event_get_event_type(event);
160 #else
161     return event->type;
162 #endif
163 }
164 
ghb_event_get_keyval(const GdkEvent * event,guint * keyval)165 static inline gboolean ghb_event_get_keyval(const GdkEvent *event,
166                                             guint *keyval)
167 {
168 #if GTK_CHECK_VERSION(3, 2, 0)
169     return gdk_event_get_keyval(event, keyval);
170 #else
171     *keyval = ((GdkEventKey*)event)->keyval;
172     return TRUE;
173 #endif
174 }
175 
ghb_event_get_button(const GdkEvent * event,guint * button)176 static inline gboolean ghb_event_get_button(const GdkEvent *event,
177                                             guint *button)
178 {
179 #if GTK_CHECK_VERSION(3, 2, 0)
180     return gdk_event_get_button(event, button);
181 #else
182     *keyval = ((GdkEventButton*)event)->button;
183     return TRUE;
184 #endif
185 }
186 
ghb_widget_get_font(GtkWidget * widget)187 static inline PangoFontDescription* ghb_widget_get_font(GtkWidget *widget)
188 {
189     PangoFontDescription *font = NULL;
190 
191 #if GTK_CHECK_VERSION(3, 0, 0)
192     GtkStyleContext *style;
193 
194     style = gtk_widget_get_style_context(widget);
195 
196 #if GTK_CHECK_VERSION(3, 8, 0)
197     gtk_style_context_get(style, GTK_STATE_FLAG_NORMAL,
198                           "font", &font, NULL);
199 #else
200     font = gtk_style_context_get_font(style, GTK_STATE_FLAG_NORMAL);
201 #endif
202 #endif
203 
204     return font;
205 }
206 
207 #if GTK_CHECK_VERSION(3, 90, 0)
208 typedef GdkSurface      GhbSurface;
209 typedef GdkSurfaceHints GhbSurfaceHints;
210 
ghb_widget_get_surface(GtkWidget * widget)211 static inline GhbSurface * ghb_widget_get_surface(GtkWidget * widget)
212 {
213     return gtk_widget_get_surface(widget);
214 }
215 
216 static inline GdkMonitor *
ghb_display_get_monitor_at_surface(GdkDisplay * display,GhbSurface * surface)217 ghb_display_get_monitor_at_surface(GdkDisplay * display, GhbSurface * surface)
218 {
219     return gdk_display_get_monitor_at_surface(display, surface);
220 }
221 
222 static inline void
ghb_surface_set_geometry_hints(GhbSurface * surface,const GdkGeometry * geometry,GhbSurfaceHints geom_mask)223 ghb_surface_set_geometry_hints(GhbSurface * surface,
224                                const GdkGeometry * geometry,
225                                GhbSurfaceHints geom_mask)
226 {
227     gdk_surface_set_geometry_hints(surface, geometry, geom_mask);
228 }
229 #else
230 typedef GdkWindow       GhbSurface;
231 typedef GdkWindowHints  GhbSurfaceHints;
232 
ghb_widget_get_surface(GtkWidget * widget)233 static inline GhbSurface * ghb_widget_get_surface(GtkWidget * widget)
234 {
235     return gtk_widget_get_window(widget);
236 }
237 
238 static inline GdkMonitor *
ghb_display_get_monitor_at_surface(GdkDisplay * display,GhbSurface * surface)239 ghb_display_get_monitor_at_surface(GdkDisplay * display, GhbSurface * surface)
240 {
241     return gdk_display_get_monitor_at_window(display, surface);
242 }
243 
244 static inline void
ghb_surface_set_geometry_hints(GhbSurface * surface,const GdkGeometry * geometry,GhbSurfaceHints geom_mask)245 ghb_surface_set_geometry_hints(GhbSurface * surface,
246                                const GdkGeometry * geometry,
247                                GhbSurfaceHints geom_mask)
248 {
249     gdk_window_set_geometry_hints(surface, geometry, geom_mask);
250 }
251 #endif
252 
ghb_monitor_get_size(GtkWidget * widget,gint * w,gint * h)253 static inline void ghb_monitor_get_size(GtkWidget *widget, gint *w, gint *h)
254 {
255     *w = *h = 0;
256 
257 #if GTK_CHECK_VERSION(3, 22, 0)
258     GdkDisplay * display = gtk_widget_get_display(widget);
259     GhbSurface * surface = ghb_widget_get_surface(widget);
260     if (surface != NULL && display != NULL)
261     {
262         GdkMonitor * monitor;
263 
264         monitor = ghb_display_get_monitor_at_surface(display, surface);
265         if (monitor != NULL)
266         {
267             GdkRectangle rect;
268 
269             gdk_monitor_get_geometry(monitor, &rect);
270             *w = rect.width;
271             *h = rect.height;
272         }
273     }
274 #else
275     GdkScreen *ss;
276 
277     ss = gdk_screen_get_default();
278     if (ss != NULL)
279     {
280         *w = gdk_screen_get_width(ss);
281         *h = gdk_screen_get_height(ss);
282     }
283 #endif
284 }
285 
ghb_strv_contains(const char ** strv,const char * str)286 static inline gboolean ghb_strv_contains(const char ** strv, const char * str)
287 {
288 #if GLIB_CHECK_VERSION(2, 44, 0)
289     return g_strv_contains(strv, str);
290 #else
291     int ii;
292 
293     if (strv == NULL)
294     {
295         return FALSE;
296     }
297     for (ii = 0; strv[ii] != NULL; ii++)
298     {
299         if (!strcmp(strv[ii], str))
300         {
301             return TRUE;
302         }
303     }
304     return FALSE;
305 #endif
306 }
307 
308 #if GTK_CHECK_VERSION(3, 90, 0)
309 
310 #define ghb_editable_get_text(e) gtk_editable_get_text(GTK_EDITABLE(e))
311 #define ghb_editable_set_text(e,t) gtk_editable_set_text(GTK_EDITABLE(e), (t))
312 
313 #else
314 
315 #define ghb_editable_get_text(e) gtk_entry_get_text(GTK_ENTRY(e))
316 #define ghb_editable_set_text(e,t) gtk_entry_set_text(GTK_ENTRY(e), (t))
317 
318 #endif
319 
320 #if GTK_CHECK_VERSION(3, 90, 0)
321 static inline void
ghb_image_set_from_icon_name(GtkImage * image,const gchar * name,GtkIconSize size)322 ghb_image_set_from_icon_name(GtkImage * image, const gchar * name,
323                              GtkIconSize size)
324 {
325     gtk_image_set_from_icon_name(image, name);
326     gtk_image_set_icon_size(image, size);
327 }
328 
329 static inline GtkWidget *
ghb_image_new_from_icon_name(const gchar * name,GtkIconSize size)330 ghb_image_new_from_icon_name(const gchar * name, GtkIconSize size)
331 {
332     GtkWidget * image;
333 
334     image = gtk_image_new_from_icon_name(name);
335     gtk_image_set_icon_size(GTK_IMAGE(image), size);
336 
337     return image;
338 }
339 
340 static inline GtkWidget *
ghb_button_new_from_icon_name(const gchar * name)341 ghb_button_new_from_icon_name(const gchar * name)
342 {
343     return gtk_button_new_from_icon_name(name);
344 }
345 
346 static inline GtkWidget *
ghb_scale_button_new(gdouble min,gdouble max,gdouble step,const gchar ** icons)347 ghb_scale_button_new(gdouble min, gdouble max, gdouble step,
348                      const gchar ** icons)
349 {
350     return gtk_scale_button_new(min, max, step, icons);
351 }
352 #else
353 static inline void
ghb_image_set_from_icon_name(GtkImage * image,const gchar * name,GtkIconSize size)354 ghb_image_set_from_icon_name(GtkImage * image, const gchar * name,
355                              GtkIconSize size)
356 {
357     gtk_image_set_from_icon_name(image, name, size);
358 }
359 
360 static inline GtkWidget *
ghb_image_new_from_icon_name(const gchar * name,GtkIconSize size)361 ghb_image_new_from_icon_name(const gchar * name, GtkIconSize size)
362 {
363     return gtk_image_new_from_icon_name(name, size);
364 }
365 
366 static inline GtkWidget *
ghb_button_new_from_icon_name(const gchar * name)367 ghb_button_new_from_icon_name(const gchar * name)
368 {
369     return gtk_button_new_from_icon_name(name, GHB_ICON_SIZE_BUTTON);
370 }
371 
372 static inline GtkWidget *
ghb_scale_button_new(gdouble min,gdouble max,gdouble step,const gchar ** icons)373 ghb_scale_button_new(gdouble min, gdouble max, gdouble step,
374                      const gchar ** icons)
375 {
376     return gtk_scale_button_new(GHB_ICON_SIZE_BUTTON, min, max, step, icons);
377 }
378 #endif
379 
380 #if GTK_CHECK_VERSION(3, 90, 0)
ghb_drag_status(GdkDrop * ctx,GdkDragAction action,guint32 time)381 static inline void ghb_drag_status(GdkDrop * ctx, GdkDragAction action,
382                                    guint32 time)
383 {
384     gdk_drop_status(ctx, action);
385 }
386 #else
ghb_drag_status(GdkDragContext * ctx,GdkDragAction action,guint32 time)387 static inline void ghb_drag_status(GdkDragContext * ctx, GdkDragAction action,
388                                    guint32 time)
389 {
390     gdk_drag_status(ctx, action, time);
391 }
392 #endif
393 
394 #if GTK_CHECK_VERSION(3, 90, 0)
ghb_entry_set_width_chars(GtkEntry * entry,gint n_chars)395 static inline void ghb_entry_set_width_chars(GtkEntry * entry, gint n_chars)
396 {
397     gtk_editable_set_width_chars(GTK_EDITABLE(entry), n_chars);
398 }
399 #else
ghb_entry_set_width_chars(GtkEntry * entry,gint n_chars)400 static inline void ghb_entry_set_width_chars(GtkEntry * entry, gint n_chars)
401 {
402     gtk_entry_set_width_chars(entry, n_chars);
403 }
404 #endif
405 
406 #if GTK_CHECK_VERSION(3, 90, 0)
ghb_atom_string(const char * str)407 static inline GdkAtom ghb_atom_string(const char * str)
408 {
409     return g_intern_static_string(str);
410 }
411 #else
ghb_atom_string(const char * str)412 static inline GdkAtom ghb_atom_string(const char * str)
413 {
414     return gdk_atom_intern_static_string(str);
415 }
416 #endif
417 
418 #endif // _GHB_COMPAT_H_
419