diff --git a/src/bio-gio.c b/src/bio-gio.c
index fd6c754337a9fd833ed64313ee1033f033ac7486..5dd1c7151b5392471434517983be3e8c33199cb0 100644
--- a/src/bio-gio.c
+++ b/src/bio-gio.c
@@ -19,6 +19,7 @@
 #include <string.h>
 #include <glib.h>
 
+#include "spice-version.h"
 #include "spice-util.h"
 #include "bio-gio.h"
 
diff --git a/src/channel-cursor.h b/src/channel-cursor.h
index 442049c366233a0a50f8f5e815bbf6a0fcf995ee..e9293e85eebcd118d03735ea8e04b3cc9ef25bdc 100644
--- a/src/channel-cursor.h
+++ b/src/channel-cursor.h
@@ -96,8 +96,10 @@ struct _SpiceCursorChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType spice_cursor_channel_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_34
 GType spice_cursor_shape_get_type(void) G_GNUC_CONST;
 
 G_END_DECLS
diff --git a/src/channel-display.h b/src/channel-display.h
index 18fe8f29e3737a0f53af6d48454d2205addeca8a..7121c6e0a991cace9352b1accb219182448a2242 100644
--- a/src/channel-display.h
+++ b/src/channel-display.h
@@ -143,32 +143,41 @@ struct _SpiceDisplayChannelClass {
     /*< private >*/
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType	        spice_display_channel_get_type(void);
+SPICE_GTK_AVAILABLE_IN_0_35
 gboolean        spice_display_channel_get_primary(SpiceChannel *channel, guint32 surface_id,
                                                   SpiceDisplayPrimary *primary);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_display_channel_change_preferred_compression(SpiceChannel *channel, gint compression);
+SPICE_GTK_DEPRECATED_IN_0_38_FOR(spice_display_channel_change_preferred_video_codec_types)
 void spice_display_channel_change_preferred_video_codec_type(SpiceChannel *channel, gint codec_type);
+SPICE_GTK_AVAILABLE_IN_0_38
 gboolean spice_display_channel_change_preferred_video_codec_types(SpiceChannel *channel, const gint *codecs,
                                                                   gsize ncodecs, GError **err);
 
+SPICE_GTK_AVAILABLE_IN_0_31
 GType           spice_gl_scanout_get_type     (void) G_GNUC_CONST;
+SPICE_GTK_AVAILABLE_IN_0_31
 void            spice_gl_scanout_free         (SpiceGlScanout *scanout);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 const SpiceGlScanout* spice_display_channel_get_gl_scanout(SpiceDisplayChannel *channel);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_display_channel_gl_draw_done(SpiceDisplayChannel *channel);
 
 #ifndef SPICE_DISABLE_DEPRECATED
-G_DEPRECATED_FOR(spice_display_channel_change_preferred_compression)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_display_channel_change_preferred_compression)
 void spice_display_change_preferred_compression(SpiceChannel *channel, gint compression);
-G_DEPRECATED_FOR(spice_display_channel_change_preferred_video_codec_type)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_display_channel_change_preferred_video_codec_type)
 void spice_display_change_preferred_video_codec_type(SpiceChannel *channel, gint codec_type);
-G_DEPRECATED_FOR(spice_display_channel_get_gl_scanout)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_display_channel_get_gl_scanout)
 const SpiceGlScanout* spice_display_get_gl_scanout(SpiceDisplayChannel *channel);
-G_DEPRECATED_FOR(spice_display_channel_get_primary)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_display_channel_get_primary)
 gboolean spice_display_get_primary(SpiceChannel *channel, guint32 surface_id,
                                    SpiceDisplayPrimary *primary);
-G_DEPRECATED_FOR(spice_display_channel_gl_draw_done)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_display_channel_gl_draw_done)
 void spice_display_gl_draw_done(SpiceDisplayChannel *channel);
 #endif
 
diff --git a/src/channel-inputs.h b/src/channel-inputs.h
index bae87b58eedfe44d960d2db36fa5ec53f6ae046d..72d39e79c3f1cd8a2007798cdb5bad54dd9adcfa 100644
--- a/src/channel-inputs.h
+++ b/src/channel-inputs.h
@@ -80,36 +80,45 @@ struct _SpiceInputsChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType spice_inputs_channel_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_inputs_channel_motion(SpiceInputsChannel *channel, gint dx, gint dy, gint button_state);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_inputs_channel_position(SpiceInputsChannel *channel, gint x, gint y, gint display,
                                    gint button_state);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_inputs_channel_button_press(SpiceInputsChannel *channel, gint button, gint button_state);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_inputs_channel_button_release(SpiceInputsChannel *channel, gint button,
                                          gint button_state);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_inputs_channel_key_press(SpiceInputsChannel *channel, guint scancode);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_inputs_channel_key_release(SpiceInputsChannel *channel, guint scancode);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_inputs_channel_set_key_locks(SpiceInputsChannel *channel, guint locks);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_inputs_channel_key_press_and_release(SpiceInputsChannel *channel, guint scancode);
 
 #ifndef SPICE_DISABLE_DEPRECATED
-G_DEPRECATED_FOR(spice_inputs_channel_motion)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_inputs_channel_motion)
 void spice_inputs_motion(SpiceInputsChannel *channel, gint dx, gint dy, gint button_state);
-G_DEPRECATED_FOR(spice_inputs_channel_position)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_inputs_channel_position)
 void spice_inputs_position(SpiceInputsChannel *channel, gint x, gint y, gint display,
                            gint button_state);
-G_DEPRECATED_FOR(spice_inputs_channel_button_press)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_inputs_channel_button_press)
 void spice_inputs_button_press(SpiceInputsChannel *channel, gint button, gint button_state);
-G_DEPRECATED_FOR(spice_inputs_channel_button_release)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_inputs_channel_button_release)
 void spice_inputs_button_release(SpiceInputsChannel *channel, gint button, gint button_state);
-G_DEPRECATED_FOR(spice_inputs_channel_key_press)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_inputs_channel_key_press)
 void spice_inputs_key_press(SpiceInputsChannel *channel, guint scancode);
-G_DEPRECATED_FOR(spice_inputs_channel_key_release)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_inputs_channel_key_release)
 void spice_inputs_key_release(SpiceInputsChannel *channel, guint scancode);
-G_DEPRECATED_FOR(spice_inputs_channel_set_key_locks)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_inputs_channel_set_key_locks)
 void spice_inputs_set_key_locks(SpiceInputsChannel *channel, guint locks);
-G_DEPRECATED_FOR(spice_inputs_channel_key_press_and_release)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_inputs_channel_key_press_and_release)
 void spice_inputs_key_press_and_release(SpiceInputsChannel *channel, guint scancode);
 #endif
 
diff --git a/src/channel-main.h b/src/channel-main.h
index 2f8da62f4ab68253bed845605a1208c9ac5d7ae7..00de0b79f0f70adae6f83a50bf08b4a009394b38 100644
--- a/src/channel-main.h
+++ b/src/channel-main.h
@@ -68,26 +68,37 @@ struct _SpiceMainChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType spice_main_channel_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_39
 void spice_main_channel_update_display_mm(SpiceMainChannel *channel, int id,
                                           int width_mm, int height_mm, gboolean update);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_main_channel_update_display(SpiceMainChannel *channel, int id, int x, int y, int width,
                                        int height, gboolean update);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_main_channel_update_display_enabled(SpiceMainChannel *channel, int id, gboolean enabled,
                                                gboolean update);
+SPICE_GTK_AVAILABLE_IN_0_35
 gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_main_channel_clipboard_selection_grab(SpiceMainChannel *channel, guint selection,
                                                  guint32 *types, int ntypes);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_main_channel_clipboard_selection_release(SpiceMainChannel *channel, guint selection);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_main_channel_clipboard_selection_notify(SpiceMainChannel *channel, guint selection,
                                                    guint32 type, const guchar *data, size_t size);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_main_channel_clipboard_selection_request(SpiceMainChannel *channel, guint selection,
                                                     guint32 type);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 gboolean spice_main_channel_agent_test_capability(SpiceMainChannel *channel, guint32 cap);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_main_channel_file_copy_async(SpiceMainChannel *channel,
                                         GFile **sources,
                                         GFileCopyFlags flags,
@@ -97,56 +108,58 @@ void spice_main_channel_file_copy_async(SpiceMainChannel *channel,
                                         GAsyncReadyCallback callback,
                                         gpointer user_data);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 gboolean spice_main_channel_file_copy_finish(SpiceMainChannel *channel,
                                              GAsyncResult *result,
                                              GError **error);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_main_channel_request_mouse_mode(SpiceMainChannel *channel, int mode);
 
 #ifndef SPICE_DISABLE_DEPRECATED
-G_DEPRECATED_FOR(spice_main_channel_clipboard_selection_grab)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_clipboard_selection_grab)
 void spice_main_clipboard_grab(SpiceMainChannel *channel, guint32 *types, int ntypes);
-G_DEPRECATED_FOR(spice_main_channel_clipboard_selection_release)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_clipboard_selection_release)
 void spice_main_clipboard_release(SpiceMainChannel *channel);
-G_DEPRECATED_FOR(spice_main_channel_clipboard_selection_notify)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_clipboard_selection_notify)
 void spice_main_clipboard_notify(SpiceMainChannel *channel, guint32 type, const guchar *data, size_t size);
-G_DEPRECATED_FOR(spice_main_channel_clipboard_selection_request)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_clipboard_selection_request)
 void spice_main_clipboard_request(SpiceMainChannel *channel, guint32 type);
 
-G_DEPRECATED_FOR(spice_main_channel_update_display)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_update_display)
 void spice_main_set_display(SpiceMainChannel *channel, int id,int x, int y, int width, int height);
-G_DEPRECATED_FOR(spice_main_channel_update_display)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_update_display)
 void spice_main_update_display(SpiceMainChannel *channel, int id, int x, int y, int width,
                                int height, gboolean update);
-G_DEPRECATED_FOR(spice_main_channel_update_display_enabled)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_update_display_enabled)
 void spice_main_set_display_enabled(SpiceMainChannel *channel, int id, gboolean enabled);
-G_DEPRECATED_FOR(spice_main_channel_update_display_enabled)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_update_display_enabled)
 void spice_main_update_display_enabled(SpiceMainChannel *channel, int id, gboolean enabled,
                                        gboolean update);
-G_DEPRECATED_FOR(spice_main_channel_send_monitor_config)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_send_monitor_config)
 gboolean spice_main_send_monitor_config(SpiceMainChannel *channel);
-G_DEPRECATED_FOR(spice_main_channel_clipboard_selection_grab)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_clipboard_selection_grab)
 void spice_main_clipboard_selection_grab(SpiceMainChannel *channel, guint selection, guint32 *types,
                                          int ntypes);
-G_DEPRECATED_FOR(spice_main_channel_clipboard_selection_release)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_clipboard_selection_release)
 void spice_main_clipboard_selection_release(SpiceMainChannel *channel, guint selection);
-G_DEPRECATED_FOR(spice_main_channel_clipboard_selection_notify)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_clipboard_selection_notify)
 void spice_main_clipboard_selection_notify(SpiceMainChannel *channel, guint selection, guint32 type,
                                            const guchar *data, size_t size);
-G_DEPRECATED_FOR(spice_main_channel_clipboard_selection_request)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_clipboard_selection_request)
 void spice_main_clipboard_selection_request(SpiceMainChannel *channel, guint selection,
                                             guint32 type);
-G_DEPRECATED_FOR(spice_main_channel_agent_test_capability)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_agent_test_capability)
 gboolean spice_main_agent_test_capability(SpiceMainChannel *channel, guint32 cap);
-G_DEPRECATED_FOR(spice_main_channel_file_copy_async)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_file_copy_async)
 void spice_main_file_copy_async(SpiceMainChannel *channel, GFile **sources, GFileCopyFlags flags,
                                 GCancellable *cancellable, GFileProgressCallback progress_callback,
                                 gpointer progress_callback_data, GAsyncReadyCallback callback,
                                 gpointer user_data);
-G_DEPRECATED_FOR(spice_main_channel_file_copy_finish)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_file_copy_finish)
 gboolean spice_main_file_copy_finish(SpiceMainChannel *channel, GAsyncResult *result,
                                      GError **error);
-G_DEPRECATED_FOR(spice_main_channel_request_mouse_mode)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_main_channel_request_mouse_mode)
 void spice_main_request_mouse_mode(SpiceMainChannel *channel, int mode);
 #endif
 
diff --git a/src/channel-playback.h b/src/channel-playback.h
index 37b894bb0e6ce2e7e603f8eedcb8b8e565d5cb1c..e5b534f431903ec9f0de8ee9236cf8e0a007226e 100644
--- a/src/channel-playback.h
+++ b/src/channel-playback.h
@@ -71,7 +71,9 @@ struct _SpicePlaybackChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType           spice_playback_channel_get_type(void);
+SPICE_GTK_AVAILABLE_IN_0_4
 void            spice_playback_channel_set_delay(SpicePlaybackChannel *channel, guint32 delay_ms);
 
 G_END_DECLS
diff --git a/src/channel-port.h b/src/channel-port.h
index 5a86b8a4a66dfa47750fff0c715133f21d95b53c..accbbd225e1ee8098d207722a1f15b0cbcbf45d0 100644
--- a/src/channel-port.h
+++ b/src/channel-port.h
@@ -63,29 +63,33 @@ struct _SpicePortChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_0_15
 GType spice_port_channel_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_port_channel_write_async(SpicePortChannel *port,
                                     const void *buffer, gsize count,
                                     GCancellable *cancellable,
                                     GAsyncReadyCallback callback,
                                     gpointer user_data);
+SPICE_GTK_AVAILABLE_IN_0_35
 gssize spice_port_channel_write_finish(SpicePortChannel *port,
                                        GAsyncResult *result, GError **error);
+SPICE_GTK_AVAILABLE_IN_0_35
 void spice_port_channel_event(SpicePortChannel *port, guint8 event);
 
 
 #ifndef SPICE_DISABLE_DEPRECATED
-G_DEPRECATED_FOR(spice_port_channel_write_async)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_port_channel_write_async)
 void spice_port_write_async(SpicePortChannel *port,
                             const void *buffer, gsize count,
                             GCancellable *cancellable,
                             GAsyncReadyCallback callback,
                             gpointer user_data);
-G_DEPRECATED_FOR(spice_port_channel_write_finish)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_port_channel_write_finish)
 gssize spice_port_write_finish(SpicePortChannel *port,
                                GAsyncResult *result, GError **error);
-G_DEPRECATED_FOR(spice_port_channel_event)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_port_channel_event)
 void spice_port_event(SpicePortChannel *port, guint8 event);
 #endif
 
diff --git a/src/channel-record.h b/src/channel-record.h
index afbb23dca98cce41e9309b321ea0a84780f6dabe..8c3df85612b429bb4701e5c90fb78e8300c9e3e9 100644
--- a/src/channel-record.h
+++ b/src/channel-record.h
@@ -71,12 +71,14 @@ struct _SpiceRecordChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType	        spice_record_channel_get_type(void);
+SPICE_GTK_AVAILABLE_IN_0_35
 void            spice_record_channel_send_data(SpiceRecordChannel *channel, gpointer data,
                                                gsize bytes, guint32 time);
 
 #ifndef SPICE_DISABLE_DEPRECATED
-G_DEPRECATED_FOR(spice_record_channel_send_data)
+SPICE_GTK_DEPRECATED_IN_0_35_FOR(spice_record_channel_send_data)
 void            spice_record_send_data(SpiceRecordChannel *channel, gpointer data,
                                        gsize bytes, guint32 time);
 #endif
diff --git a/src/channel-smartcard.h b/src/channel-smartcard.h
index 60ca9fef238ded5f050a0947b7cee64775619512..e9edbd5501093c741c3a00090c878bb91ed35e82 100644
--- a/src/channel-smartcard.h
+++ b/src/channel-smartcard.h
@@ -64,6 +64,7 @@ struct _SpiceSmartcardChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_0_7
 GType spice_smartcard_channel_get_type(void);
 
 G_END_DECLS
diff --git a/src/channel-usbredir.h b/src/channel-usbredir.h
index a430dfa2f48106b6f4ba52c875a832c0b4411188..c0eef5ccbb0fdb61e42500e373b0074605a7273f 100644
--- a/src/channel-usbredir.h
+++ b/src/channel-usbredir.h
@@ -67,6 +67,7 @@ struct _SpiceUsbredirChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_0_8
 GType spice_usbredir_channel_get_type(void);
 
 G_END_DECLS
diff --git a/src/channel-webdav.h b/src/channel-webdav.h
index fac877d78de68428b1d24f707127c0cee3f15d76..960cc47aa39e547541997cfe134900b0035b463e 100644
--- a/src/channel-webdav.h
+++ b/src/channel-webdav.h
@@ -64,6 +64,7 @@ struct _SpiceWebdavChannelClass {
     /* Do not add fields to this struct */
 };
 
+SPICE_GTK_AVAILABLE_IN_0_24
 GType spice_webdav_channel_get_type(void);
 
 G_END_DECLS
diff --git a/src/decode-glz.c b/src/decode-glz.c
index 3f3409877c214279cf0d87c000e241c047692823..9aa038ba31d7faa4d257a1e09bd64e0566167620 100644
--- a/src/decode-glz.c
+++ b/src/decode-glz.c
@@ -23,6 +23,7 @@
 #include <glib.h>
 
 #include "gio-coroutine.h"
+#include "spice-version.h"
 #include "spice-util.h"
 #include "decode.h"
 
diff --git a/src/get-type-declarations.h b/src/get-type-declarations.h
new file mode 100644
index 0000000000000000000000000000000000000000..864a1508babfd3d5d356389decc8557cc03cadee
--- /dev/null
+++ b/src/get-type-declarations.h
@@ -0,0 +1,16 @@
+#include "spice-common.h"
+
+SPICE_GTK_AVAILABLE_IN_ALL
+GType spice_inputs_lock_get_type(void) G_GNUC_CONST;
+
+SPICE_GTK_AVAILABLE_IN_ALL
+GType spice_channel_event_get_type(void) G_GNUC_CONST;
+
+SPICE_GTK_AVAILABLE_IN_ALL
+GType spice_session_verify_get_type(void) G_GNUC_CONST;
+
+SPICE_GTK_AVAILABLE_IN_ALL
+GType spice_session_migration_get_type(void) G_GNUC_CONST;
+
+SPICE_GTK_AVAILABLE_IN_ALL
+GType spice_display_key_event_get_type(void) G_GNUC_CONST;
diff --git a/src/meson.build b/src/meson.build
index 68fe7ab2154168c9612f4369d98113d155d5fa8d..c1f240fec4441092808c91a5516a053ea4c7c3ee 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -19,10 +19,54 @@ else
   endif
 endif
 
+script = ''
+# versions, [major, minimum_minor, maximum_minor]
+versions = [[ 0, 1, 43 ]]
+# build a long string to use for loops
+x = 'aaaaaaaaaa'
+x = x.replace('a', 'bbbbbbbbbb')
+
+# loop all versions, generate SPICE_GTK_VERSION_major_minor macros
+foreach version : versions
+  major = version[0]
+  minor = version[1]
+  max_minor = version[2]
+  foreach c : x.split('b')
+    script = '''@0@
+#define SPICE_GTK_VERSION_@1@_@2@ SPICE_GTK_ENCODE_VERSION(@1@, @2@)
+'''.format(script, major, minor)
+    minor += 1
+    if minor > max_minor
+      break
+    endif
+  endforeach
+endforeach
+
+versions = '''2 3 4 5 6 7 8 9 10 11 13 14 15 17 19
+   20 24 27 30 31 32 33 34 35 36 38 39 40'''.split()
+foreach version: versions
+  script = '''@2@
+#if SPICE_GTK_VERSION_MAX_ALLOWED < SPICE_GTK_VERSION_@0@_@1@
+# define SPICE_GTK_AVAILABLE_IN_@0@_@1@  G_UNAVAILABLE(@0@, @1@)
+#else
+# define SPICE_GTK_AVAILABLE_IN_@0@_@1@  SPICE_GTK_EXTERN
+#endif
+
+#if SPICE_GTK_VERSION_MIN_REQUIRED >= SPICE_GTK_VERSION_@0@_@1@
+# define SPICE_GTK_DEPRECATED_IN_@0@_@1@         G_DEPRECATED
+# define SPICE_GTK_DEPRECATED_IN_@0@_@1@_FOR(f)  G_DEPRECATED_FOR(f)
+#else
+# define SPICE_GTK_DEPRECATED_IN_@0@_@1@         SPICE_GTK_EXTERN
+# define SPICE_GTK_DEPRECATED_IN_@0@_@1@_FOR(f)  SPICE_GTK_EXTERN
+#endif
+'''.format('0', version, script)
+endforeach
+
 version_data = configuration_data()
 version_data.set('SPICE_GTK_MAJOR_VERSION', major)
 version_data.set('SPICE_GTK_MINOR_VERSION', minor)
 version_data.set('SPICE_GTK_MICRO_VERSION', micro)
+version_data.set('SPICE_VERSION_MACROS', script)
 spice_version_h = configure_file(input : 'spice-version.h.in',
                                  output : 'spice-version.h',
                                  configuration : version_data)
@@ -63,6 +107,7 @@ spice_marshals = gnome.genmarshal('spice-marshal', sources : 'spice-marshal.txt'
 spice_client_glib_enums = gnome.mkenums_simple('spice-glib-enums',
                                                sources : ['spice-channel.h', 'channel-inputs.h', 'spice-session.h'],
                                                install_header : true,
+                                               body_prefix: '#include "get-type-declarations.h"',
                                                install_dir : spice_gtk_includedir / 'spice-client-glib-2.0')
 
 spice_client_glib_introspection_sources = [
@@ -218,7 +263,8 @@ spice_client_glib_lib = library('spice-client-glib-2.0', spice_client_glib_sourc
                                 include_directories : spice_gtk_include,
                                 link_args : [spice_glib_version_script],
                                 link_depends : spice_client_glib_syms,
-                                dependencies : spice_glib_deps)
+                                dependencies : spice_glib_deps,
+                                gnu_symbol_visibility: 'hidden')
 
 spice_client_glib_dep = declare_dependency(sources : [spice_marshals[1], spice_client_glib_enums[1]],
                                            link_with : spice_client_glib_lib,
@@ -278,6 +324,7 @@ if spice_gtk_has_gtk
   spice_widget_enums = gnome.mkenums_simple('spice-widget-enums',
                                             sources : 'spice-widget.h',
                                             install_header : true,
+                                            body_prefix: '#include "get-type-declarations.h"',
                                             install_dir : spice_gtk_includedir / 'spice-client-gtk-3.0')
 
   spice_client_gtk_introspection_sources = [
@@ -399,7 +446,8 @@ if spice_gtk_has_gtk
                                  install : true,
                                  link_args : [spice_gtk_version_script],
                                  link_depends : spice_client_gtk_syms,
-                                 dependencies : [spice_client_glib_dep, spice_gtk_deps, spice_wayland_deps])
+                                 dependencies : [spice_client_glib_dep, spice_gtk_deps, spice_wayland_deps],
+                                 gnu_symbol_visibility: 'hidden')
 
   spice_client_gtk_dep = declare_dependency(sources : spice_widget_enums[1],
                                             link_with : spice_client_gtk_lib,
diff --git a/src/qmp-port.h b/src/qmp-port.h
index f05a5ec1b4249c316e62d9973ebb7c18c286d95d..352c0d06ac816cd2446d916ce90ebd660c751911 100644
--- a/src/qmp-port.h
+++ b/src/qmp-port.h
@@ -88,30 +88,39 @@ typedef struct _SpiceQmpStatus {
     gchar *status;
 } SpiceQmpStatus;
 
+SPICE_GTK_AVAILABLE_IN_0_36
 GType spice_qmp_port_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_36
 SpiceQmpPort *spice_qmp_port_get(SpicePortChannel *channel);
 
+SPICE_GTK_AVAILABLE_IN_0_36
 void spice_qmp_port_vm_action_async(SpiceQmpPort *self,
                                     SpiceQmpPortVmAction action,
                                     GCancellable *cancellable,
                                     GAsyncReadyCallback callback,
                                     gpointer user_data);
 
+SPICE_GTK_AVAILABLE_IN_0_36
 gboolean spice_qmp_port_vm_action_finish(SpiceQmpPort *self,
                                          GAsyncResult *result,
                                          GError **error);
 
+SPICE_GTK_AVAILABLE_IN_0_36
 GType spice_qmp_status_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_36
 SpiceQmpStatus *spice_qmp_status_ref(SpiceQmpStatus *status);
+SPICE_GTK_AVAILABLE_IN_0_36
 void spice_qmp_status_unref(SpiceQmpStatus *status);
 
+SPICE_GTK_AVAILABLE_IN_0_36
 void spice_qmp_port_query_status_async(SpiceQmpPort *self,
                                        GCancellable *cancellable,
                                        GAsyncReadyCallback callback,
                                        gpointer user_data);
 
+SPICE_GTK_AVAILABLE_IN_0_36
 SpiceQmpStatus *spice_qmp_port_query_status_finish(SpiceQmpPort *self,
                                                    GAsyncResult *result,
                                                    GError **error);
diff --git a/src/smartcard-manager.h b/src/smartcard-manager.h
index b7a8b25587dbeb46e1dfc34727000c070eb1d1ad..dccd63b967b8d057a2edf60bbd5e96f237d9a982 100644
--- a/src/smartcard-manager.h
+++ b/src/smartcard-manager.h
@@ -88,15 +88,24 @@ struct _SpiceSmartcardManagerClass
     gpointer _spice_reserved[10];
 };
 
+SPICE_GTK_AVAILABLE_IN_0_7
 GType spice_smartcard_manager_get_type(void);
+SPICE_GTK_AVAILABLE_IN_0_7
 GType spice_smartcard_reader_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_7
 SpiceSmartcardManager *spice_smartcard_manager_get(void);
+SPICE_GTK_AVAILABLE_IN_0_7
 gboolean spice_smartcard_manager_insert_card(SpiceSmartcardManager *manager);
+SPICE_GTK_AVAILABLE_IN_0_7
 gboolean spice_smartcard_manager_remove_card(SpiceSmartcardManager *manager);
+SPICE_GTK_AVAILABLE_IN_0_7
 gboolean spice_smartcard_reader_is_software(SpiceSmartcardReader *reader);
+SPICE_GTK_AVAILABLE_IN_0_20
 gboolean spice_smartcard_reader_insert_card(SpiceSmartcardReader *reader);
+SPICE_GTK_AVAILABLE_IN_0_20
 gboolean spice_smartcard_reader_remove_card(SpiceSmartcardReader *reader);
+SPICE_GTK_AVAILABLE_IN_0_20
 GList *spice_smartcard_manager_get_readers(SpiceSmartcardManager *manager);
 
 G_END_DECLS
diff --git a/src/spice-audio.h b/src/spice-audio.h
index d6ecf64267d8613a330ae66a3fdf55f32cef7014..ff737ea6dd172635e1f6548ca9831d180f3551b0 100644
--- a/src/spice-audio.h
+++ b/src/spice-audio.h
@@ -98,12 +98,14 @@ struct _SpiceAudioClass {
     gpointer _spice_reserved[6];
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType spice_audio_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_8
 SpiceAudio* spice_audio_get(SpiceSession *session, GMainContext *context);
 
 #ifndef SPICE_DISABLE_DEPRECATED
-G_DEPRECATED_FOR(spice_audio_get)
+SPICE_GTK_DEPRECATED_IN_0_8_FOR(spice_audio_get)
 SpiceAudio* spice_audio_new(SpiceSession *session, GMainContext *context, const char *name);
 #endif
 
diff --git a/src/spice-channel.h b/src/spice-channel.h
index 1e163ebc4f02c524d9eb07e7d14d6192a19b444a..c06b6d640463279275568a96bbe3c92e9adcd5dd 100644
--- a/src/spice-channel.h
+++ b/src/spice-channel.h
@@ -122,28 +122,40 @@ struct _SpiceChannelClass
     gpointer _spice_reserved[8];
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType spice_channel_get_type(void);
 
 typedef void (*spice_msg_handler)(SpiceChannel *channel, SpiceMsgIn *in);
 
+SPICE_GTK_AVAILABLE_IN_ALL
 SpiceChannel *spice_channel_new(SpiceSession *s, int type, int id);
+SPICE_GTK_AVAILABLE_IN_ALL
 gboolean spice_channel_connect(SpiceChannel *channel);
+SPICE_GTK_AVAILABLE_IN_0_2
 gboolean spice_channel_open_fd(SpiceChannel *channel, int fd);
+SPICE_GTK_AVAILABLE_IN_ALL
 void spice_channel_disconnect(SpiceChannel *channel, SpiceChannelEvent reason);
+SPICE_GTK_AVAILABLE_IN_ALL
 gboolean spice_channel_test_capability(SpiceChannel *channel, guint32 cap);
+SPICE_GTK_AVAILABLE_IN_0_6
 gboolean spice_channel_test_common_capability(SpiceChannel *channel, guint32 cap);
+SPICE_GTK_AVAILABLE_IN_0_15
 void spice_channel_flush_async(SpiceChannel *channel, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+SPICE_GTK_AVAILABLE_IN_0_15
 gboolean spice_channel_flush_finish(SpiceChannel *channel, GAsyncResult *result, GError **error);
 #ifndef SPICE_DISABLE_DEPRECATED
-G_DEPRECATED
+SPICE_GTK_DEPRECATED_IN_0_13
 void spice_channel_set_capability(SpiceChannel *channel, guint32 cap);
-G_DEPRECATED
+SPICE_GTK_DEPRECATED_IN_0_27
 void spice_channel_destroy(SpiceChannel *channel);
 #endif
 
+SPICE_GTK_AVAILABLE_IN_0_7
 const gchar* spice_channel_type_to_string(gint type);
+SPICE_GTK_AVAILABLE_IN_0_20
 gint spice_channel_string_to_type(const gchar *str);
 
+SPICE_GTK_AVAILABLE_IN_0_24
 const GError* spice_channel_get_error(SpiceChannel *channel);
 
 G_END_DECLS
diff --git a/src/spice-client.h b/src/spice-client.h
index bf95e936c04565db9ac10d71a986668de132276a..b753f6063c87ab00fc5170b7257e823f30485504 100644
--- a/src/spice-client.h
+++ b/src/spice-client.h
@@ -29,11 +29,11 @@
 
 /* spice/gtk */
 #include "spice-types.h"
+#include "spice-version.h"
 #include "spice-session.h"
 #include "spice-channel.h"
 #include "spice-option.h"
 #include "spice-uri.h"
-#include "spice-version.h"
 
 #include "channel-main.h"
 #include "channel-display.h"
@@ -89,6 +89,7 @@ typedef enum
 #define SPICE_CLIENT_USB_DEVICE_LOST SPICE_CLIENT_ERROR_USB_DEVICE_LOST
 #endif
 
+SPICE_GTK_AVAILABLE_IN_0_7
 GQuark spice_client_error_quark(void);
 
 G_END_DECLS
diff --git a/src/spice-common.h b/src/spice-common.h
index 52bedddd2716efc35dd7b0e4e594faaed6f8ab16..faa4cf817cc018df2bf0ef5b09d043d660be92fc 100644
--- a/src/spice-common.h
+++ b/src/spice-common.h
@@ -29,4 +29,5 @@
 #include "common/messages.h"
 #include "common/marshaller.h"
 
+#include "spice-version.h"
 #include "spice-util.h"
diff --git a/src/spice-file-transfer-task.h b/src/spice-file-transfer-task.h
index d04f0effe3ec0cceeda9362d24bb30e59d3afca9..f2e483a1405ef6e630b7605e7704a117a13d9add 100644
--- a/src/spice-file-transfer-task.h
+++ b/src/spice-file-transfer-task.h
@@ -39,12 +39,18 @@ G_BEGIN_DECLS
 typedef struct _SpiceFileTransferTask SpiceFileTransferTask;
 typedef struct _SpiceFileTransferTaskClass SpiceFileTransferTaskClass;
 
+SPICE_GTK_AVAILABLE_IN_0_31
 GType spice_file_transfer_task_get_type(void) G_GNUC_CONST;
 
+SPICE_GTK_AVAILABLE_IN_0_31
 char* spice_file_transfer_task_get_filename(SpiceFileTransferTask *self);
+SPICE_GTK_AVAILABLE_IN_0_31
 void spice_file_transfer_task_cancel(SpiceFileTransferTask *self);
+SPICE_GTK_AVAILABLE_IN_0_33
 guint64 spice_file_transfer_task_get_total_bytes(SpiceFileTransferTask *self);
+SPICE_GTK_AVAILABLE_IN_0_33
 guint64 spice_file_transfer_task_get_transferred_bytes(SpiceFileTransferTask *self);
+SPICE_GTK_AVAILABLE_IN_0_31
 double spice_file_transfer_task_get_progress(SpiceFileTransferTask *self);
 
 G_END_DECLS
diff --git a/src/spice-grabsequence.c b/src/spice-grabsequence.c
index dd454c9b31acc369bc79605d413ff19f6b1769f4..078bfa6df9a86583fc819cb7ef9f9c8d8218f032 100644
--- a/src/spice-grabsequence.c
+++ b/src/spice-grabsequence.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <gdk/gdk.h>
 
+#include "spice-version.h"
 #include "spice-grabsequence.h"
 #include "spice-grabsequence-priv.h"
 
diff --git a/src/spice-grabsequence.h b/src/spice-grabsequence.h
index 7f61ba16850c927a29dea8d8f66e504ed2b6c3b2..9b4d6c3ec5c21c2309cbcdf3036941d6d3fa80e2 100644
--- a/src/spice-grabsequence.h
+++ b/src/spice-grabsequence.h
@@ -40,12 +40,18 @@ G_BEGIN_DECLS
  **/
 typedef struct _SpiceGrabSequence SpiceGrabSequence;
 
+SPICE_GTK_AVAILABLE_IN_0_3
 GType spice_grab_sequence_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_3
 SpiceGrabSequence *spice_grab_sequence_new(guint nkeysyms, guint *keysyms);
+SPICE_GTK_AVAILABLE_IN_0_3
 SpiceGrabSequence *spice_grab_sequence_new_from_string(const gchar *str);
+SPICE_GTK_AVAILABLE_IN_0_3
 SpiceGrabSequence *spice_grab_sequence_copy(SpiceGrabSequence *sequence);
+SPICE_GTK_AVAILABLE_IN_0_3
 void spice_grab_sequence_free(SpiceGrabSequence *sequence);
+SPICE_GTK_AVAILABLE_IN_0_3
 gchar *spice_grab_sequence_as_string(SpiceGrabSequence *sequence);
 
 
diff --git a/src/spice-gtk-session.h b/src/spice-gtk-session.h
index e79475f863edc481371bc33d24759008b15fb5f0..33fbe5b1c63844e10e143dc273bd713d1b11a55a 100644
--- a/src/spice-gtk-session.h
+++ b/src/spice-gtk-session.h
@@ -46,10 +46,14 @@ typedef struct _SpiceGtkSession SpiceGtkSession;
  */
 typedef struct _SpiceGtkSessionClass SpiceGtkSessionClass;
 
+SPICE_GTK_AVAILABLE_IN_0_8
 GType spice_gtk_session_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_8
 SpiceGtkSession *spice_gtk_session_get(SpiceSession *session);
+SPICE_GTK_AVAILABLE_IN_0_8
 void spice_gtk_session_copy_to_guest(SpiceGtkSession *self);
+SPICE_GTK_AVAILABLE_IN_0_8
 void spice_gtk_session_paste_from_guest(SpiceGtkSession *self);
 
 G_END_DECLS
diff --git a/src/spice-option.c b/src/spice-option.c
index a1eacc38edc0777a1ca49496e62302f779b60c5b..abcaa1bf2b7be874069cbfbe582bba18e251aed6 100644
--- a/src/spice-option.c
+++ b/src/spice-option.c
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <glib-object.h>
 #include <glib/gi18n-lib.h>
+#include "spice-version.h"
 #include "spice-session.h"
 #include "spice-util.h"
 #include "spice-channel-priv.h"
diff --git a/src/spice-option.h b/src/spice-option.h
index 853c8c5558dd97598f71dabbda0fa62e86e607e6..9bb73c16abe66671ef1acfcf1244c67a753d75b9 100644
--- a/src/spice-option.h
+++ b/src/spice-option.h
@@ -26,7 +26,9 @@
 
 G_BEGIN_DECLS
 
+SPICE_GTK_AVAILABLE_IN_0_7
 GOptionGroup* spice_get_option_group(void);
+SPICE_GTK_AVAILABLE_IN_0_7
 void spice_set_session_option(SpiceSession *session);
 
 G_END_DECLS
diff --git a/src/spice-session.h b/src/spice-session.h
index d54ad410a8bb1d0b7fe65e9fda6ea62c95bfdcd6..855db6a82ed6f7330f313717986a344c278a88c7 100644
--- a/src/spice-session.h
+++ b/src/spice-session.h
@@ -104,16 +104,26 @@ struct _SpiceSessionClass
     gpointer  _spice_reserved[10];
 };
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType spice_session_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_ALL
 SpiceSession *spice_session_new(void);
+SPICE_GTK_AVAILABLE_IN_ALL
 gboolean spice_session_connect(SpiceSession *session);
+SPICE_GTK_AVAILABLE_IN_0_2
 gboolean spice_session_open_fd(SpiceSession *session, int fd);
+SPICE_GTK_AVAILABLE_IN_ALL
 void spice_session_disconnect(SpiceSession *session);
+SPICE_GTK_AVAILABLE_IN_ALL
 GList *spice_session_get_channels(SpiceSession *session);
+SPICE_GTK_AVAILABLE_IN_0_8
 gboolean spice_session_has_channel_type(SpiceSession *session, gint type);
+SPICE_GTK_AVAILABLE_IN_0_8
 gboolean spice_session_get_read_only(SpiceSession *session);
+SPICE_GTK_AVAILABLE_IN_0_24
 SpiceURI *spice_session_get_proxy_uri(SpiceSession *session);
+SPICE_GTK_AVAILABLE_IN_0_27
 gboolean spice_session_is_for_migration(SpiceSession *session);
 
 G_END_DECLS
diff --git a/src/spice-uri.h b/src/spice-uri.h
index ec4c983a07f3003284b189009f61b4d75d17e59a..c8166b943ffff457be8bad6fe062f31ba1beb574 100644
--- a/src/spice-uri.h
+++ b/src/spice-uri.h
@@ -48,18 +48,30 @@ typedef struct _SpiceURI SpiceURI;
 typedef struct _SpiceURIClass SpiceURIClass;
 typedef struct _SpiceURIPrivate SpiceURIPrivate;
 
+SPICE_GTK_AVAILABLE_IN_0_24
 GType spice_uri_get_type(void) G_GNUC_CONST;
 
+SPICE_GTK_AVAILABLE_IN_0_24
 const gchar* spice_uri_get_scheme(SpiceURI* uri);
+SPICE_GTK_AVAILABLE_IN_0_24
 void spice_uri_set_scheme(SpiceURI* uri, const gchar* scheme);
+SPICE_GTK_AVAILABLE_IN_0_24
 const gchar* spice_uri_get_hostname(SpiceURI* uri);
+SPICE_GTK_AVAILABLE_IN_0_24
 void spice_uri_set_hostname(SpiceURI* uri, const gchar* hostname);
+SPICE_GTK_AVAILABLE_IN_0_24
 guint spice_uri_get_port(SpiceURI* uri);
+SPICE_GTK_AVAILABLE_IN_0_24
 void spice_uri_set_port(SpiceURI* uri, guint port);
+SPICE_GTK_AVAILABLE_IN_0_24
 gchar *spice_uri_to_string(SpiceURI* uri);
+SPICE_GTK_AVAILABLE_IN_0_24
 const gchar* spice_uri_get_user(SpiceURI* uri);
+SPICE_GTK_AVAILABLE_IN_0_24
 void spice_uri_set_user(SpiceURI* uri, const gchar* user);
+SPICE_GTK_AVAILABLE_IN_0_24
 const gchar* spice_uri_get_password(SpiceURI* uri);
+SPICE_GTK_AVAILABLE_IN_0_24
 void spice_uri_set_password(SpiceURI* uri, const gchar* password);
 
 G_END_DECLS
diff --git a/src/spice-util.c b/src/spice-util.c
index 30d83c8d7bbab14014b591d4ec98c4c3c3de7063..aefe128483ef370b00e047f4c3152b9915724e05 100644
--- a/src/spice-util.c
+++ b/src/spice-util.c
@@ -22,9 +22,9 @@
 #include <string.h>
 #include <glib.h>
 #include <glib-object.h>
+#include "spice-version.h"
 #include "spice-util-priv.h"
 #include "spice-util.h"
-#include "spice-util-priv.h"
 
 /**
  * SECTION:spice-util
diff --git a/src/spice-util.h b/src/spice-util.h
index 421b4b08399e79d79b72daa8a422a37b3b57103a..c283b07eeb471203d57ad0a3a96a3ec0fa4751cb 100644
--- a/src/spice-util.h
+++ b/src/spice-util.h
@@ -21,14 +21,19 @@
 
 G_BEGIN_DECLS
 
+SPICE_GTK_AVAILABLE_IN_ALL
 void spice_util_set_debug(gboolean enabled);
+SPICE_GTK_AVAILABLE_IN_ALL
 gboolean spice_util_get_debug(void);
+SPICE_GTK_AVAILABLE_IN_ALL
 const gchar *spice_util_get_version_string(void);
+SPICE_GTK_AVAILABLE_IN_0_8
 gulong spice_g_signal_connect_object(gpointer instance,
                                      const gchar *detailed_signal,
                                      GCallback c_handler,
                                      gpointer gobject,
                                      GConnectFlags connect_flags);
+SPICE_GTK_AVAILABLE_IN_0_11
 gchar* spice_uuid_to_string(const guint8 uuid[16]);
 
 #define SPICE_DEBUG(fmt, ...)                                   \
diff --git a/src/spice-version.h.in b/src/spice-version.h.in
index ca9f55a2456384d2b6a91dce719edfbb261bea49..b847a22deadb4d4befea3f19d2476ecf4e31b771 100644
--- a/src/spice-version.h.in
+++ b/src/spice-version.h.in
@@ -71,5 +71,34 @@
          (SPICE_GTK_MAJOR_VERSION == (major) && SPICE_GTK_MINOR_VERSION == (minor) && \
           SPICE_GTK_MICRO_VERSION >= (micro)))
 
+#define SPICE_GTK_ENCODE_VERSION(major,minor)   ((major) << 16 | (minor) << 8)
 
+#define SPICE_GTK_VERSION_CURRENT \
+    SPICE_GTK_ENCODE_VERSION(SPICE_GTK_MAJOR_VERSION, SPICE_GTK_MINOR_VERSION)
+
+#if !defined (SPICE_GTK_VERSION_MIN_ALLOWED) || (SPICE_GTK_VERSION_MIN_ALLOWED == 0)
+# undef SPICE_GTK_VERSION_MIN_ALLOWED
+# define SPICE_GTK_VERSION_MIN_ALLOWED SPICE_GTK_VERSION_CURRENT
+#endif
+
+#if !defined (SPICE_GTK_VERSION_MAX_ALLOWED) || (SPICE_GTK_VERSION_MAX_ALLOWED == 0)
+# undef SPICE_GTK_VERSION_MAX_ALLOWED
+# define SPICE_GTK_VERSION_MAX_ALLOWED SPICE_GTK_VERSION_CURRENT
+#endif
+
+#if SPICE_GTK_VERSION_MIN_REQUIRED > SPICE_GTK_VERSION_CURRENT
+#error "SPICE_GTK_VERSION_MIN_REQUIRED must be <= SPICE_GTK_VERSION_CURRENT"
+#endif
+#if SPICE_GTK_VERSION_MAX_ALLOWED < SPICE_GTK_VERSION_MIN_REQUIRED
+#error "SPICE_GTK_VERSION_MAX_ALLOWED must be >= SPICE_GTK_VERSION_MIN_REQUIRED"
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define SPICE_GTK_EXTERN __attribute__ ((visibility ("default")))
+#else
+# define SPICE_GTK_EXTERN extern
+#endif
+
+#define SPICE_GTK_AVAILABLE_IN_ALL SPICE_GTK_EXTERN
+@SPICE_VERSION_MACROS@
 #endif /* __SPICE_VERSION_H__ */
diff --git a/src/spice-widget.h b/src/spice-widget.h
index 60a7514b65c16bf37a5e43e2afceba6eba170eed..778f75b5df2461a0c90c67497994e26ab3f03cf1 100644
--- a/src/spice-widget.h
+++ b/src/spice-widget.h
@@ -68,17 +68,26 @@ typedef enum
 	SPICE_DISPLAY_KEY_EVENT_CLICK = 3,
 } SpiceDisplayKeyEvent;
 
+SPICE_GTK_AVAILABLE_IN_ALL
 GType	        spice_display_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_ALL
 SpiceDisplay* spice_display_new(SpiceSession *session, int channel_id);
+SPICE_GTK_AVAILABLE_IN_0_13
 SpiceDisplay* spice_display_new_with_monitor(SpiceSession *session, gint channel_id, gint monitor_id);
 
+SPICE_GTK_AVAILABLE_IN_0_40
 void spice_display_keyboard_ungrab(SpiceDisplay *display);
+SPICE_GTK_AVAILABLE_IN_ALL
 void spice_display_mouse_ungrab(SpiceDisplay *display);
+SPICE_GTK_AVAILABLE_IN_ALL
 void spice_display_set_grab_keys(SpiceDisplay *display, SpiceGrabSequence *seq);
+SPICE_GTK_AVAILABLE_IN_ALL
 SpiceGrabSequence *spice_display_get_grab_keys(SpiceDisplay *display);
+SPICE_GTK_AVAILABLE_IN_ALL
 void spice_display_send_keys(SpiceDisplay *display, const guint *keyvals,
                              int nkeyvals, SpiceDisplayKeyEvent kind);
+SPICE_GTK_AVAILABLE_IN_ALL
 GdkPixbuf *spice_display_get_pixbuf(SpiceDisplay *display);
 
 G_END_DECLS
diff --git a/src/usb-backend.c b/src/usb-backend.c
index dd1ce99f0b55d5bd21b776b7716383e96d92c1f3..e6d1c3178607ebba0d96778ea8ba5d1d76ec5544 100644
--- a/src/usb-backend.c
+++ b/src/usb-backend.c
@@ -34,6 +34,7 @@
 #endif
 #include "usbredirhost.h"
 #include "usbredirparser.h"
+#include "spice-version.h"
 #include "spice-util.h"
 #include "usb-backend.h"
 #include "usb-emulation.h"
diff --git a/src/usb-device-manager.h b/src/usb-device-manager.h
index 1cebeb830832c10384d29aa48f6ea80c659c83f4..1bff418ca0dd7f60e3450d393c3d337721ea0fea 100644
--- a/src/usb-device-manager.h
+++ b/src/usb-device-manager.h
@@ -96,62 +96,79 @@ struct _SpiceUsbDeviceManagerClass
     gpointer _spice_reserved[10];
 };
 
+SPICE_GTK_AVAILABLE_IN_0_8
 GType spice_usb_device_get_type(void);
+SPICE_GTK_AVAILABLE_IN_0_8
 GType spice_usb_device_manager_get_type(void);
 
+SPICE_GTK_AVAILABLE_IN_0_8
 gchar *spice_usb_device_get_description(SpiceUsbDevice *device, const gchar *format);
+SPICE_GTK_AVAILABLE_IN_0_27
 gconstpointer spice_usb_device_get_libusb_device(const SpiceUsbDevice *device);
 
+SPICE_GTK_AVAILABLE_IN_0_8
 SpiceUsbDeviceManager *spice_usb_device_manager_get(SpiceSession *session,
                                                     GError **err);
 
+SPICE_GTK_AVAILABLE_IN_0_8
 GPtrArray *spice_usb_device_manager_get_devices(SpiceUsbDeviceManager *manager);
+SPICE_GTK_AVAILABLE_IN_0_20
 GPtrArray* spice_usb_device_manager_get_devices_with_filter(SpiceUsbDeviceManager *manager,
                                                             const gchar *filter);
 
+SPICE_GTK_AVAILABLE_IN_0_8
 gboolean spice_usb_device_manager_is_device_connected(SpiceUsbDeviceManager *manager,
                                                       SpiceUsbDevice *device);
+SPICE_GTK_AVAILABLE_IN_0_8
 void spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *manager,
                                                    SpiceUsbDevice *device,
                                                    GCancellable *cancellable,
                                                    GAsyncReadyCallback callback,
                                                    gpointer user_data);
 
+SPICE_GTK_AVAILABLE_IN_0_32
 void spice_usb_device_manager_disconnect_device_async(SpiceUsbDeviceManager *manager,
                                                       SpiceUsbDevice *device,
                                                       GCancellable *cancellable,
                                                       GAsyncReadyCallback callback,
                                                       gpointer user_data);
 
+SPICE_GTK_AVAILABLE_IN_0_8
 gboolean spice_usb_device_manager_connect_device_finish(SpiceUsbDeviceManager *manager,
                                                         GAsyncResult *res,
                                                         GError **err);
 
+SPICE_GTK_AVAILABLE_IN_0_32
 gboolean spice_usb_device_manager_disconnect_device_finish(SpiceUsbDeviceManager *manager,
                                                            GAsyncResult *res,
                                                            GError **err);
 
 #ifndef SPICE_DISABLE_DEPRECATED
-G_DEPRECATED_FOR(spice_usb_device_manager_disconnect_device_async)
+SPICE_GTK_DEPRECATED_IN_0_32_FOR(spice_usb_device_manager_disconnect_device_async)
 void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *manager,
                                                 SpiceUsbDevice *device);
 #endif
 
+SPICE_GTK_AVAILABLE_IN_0_10
 gboolean
 spice_usb_device_manager_can_redirect_device(SpiceUsbDeviceManager *manager,
                                              SpiceUsbDevice *device,
                                              GError **err);
 
+SPICE_GTK_AVAILABLE_IN_0_32
 gboolean spice_usb_device_manager_is_redirecting(SpiceUsbDeviceManager *manager);
 
+SPICE_GTK_AVAILABLE_IN_0_38
 gboolean
 spice_usb_device_manager_create_shared_cd_device(SpiceUsbDeviceManager *manager,
                                                  gchar *filename,
                                                  GError **err);
+SPICE_GTK_AVAILABLE_IN_0_38
 gboolean
 spice_usb_device_manager_is_device_shared_cd(SpiceUsbDeviceManager *manager,
                                              SpiceUsbDevice *device);
 
+SPICE_GTK_AVAILABLE_IN_0_40
 SpiceUsbDevice *
 spice_usb_device_manager_allocate_device_for_file_descriptor(SpiceUsbDeviceManager *manager,
                                                              int file_descriptor,
diff --git a/src/usb-device-widget.h b/src/usb-device-widget.h
index c8befb7f6ca8cdcc8821e6132bc1687dec35f84b..d2c4518c0181f9aaed2b9ace017b3c87f431b057 100644
--- a/src/usb-device-widget.h
+++ b/src/usb-device-widget.h
@@ -50,7 +50,9 @@ typedef struct _SpiceUsbDeviceWidget SpiceUsbDeviceWidget;
 typedef struct _SpiceUsbDeviceWidgetClass SpiceUsbDeviceWidgetClass;
 typedef struct _SpiceUsbDeviceWidgetPrivate SpiceUsbDeviceWidgetPrivate;
 
+SPICE_GTK_AVAILABLE_IN_0_9
 GType spice_usb_device_widget_get_type(void);
+SPICE_GTK_AVAILABLE_IN_0_9
 GtkWidget *spice_usb_device_widget_new(SpiceSession    *session,
                                        const gchar     *device_format_string);
 
diff --git a/src/usbutil.c b/src/usbutil.c
index b34739e6c073d3a1b74fb5ae8dd99b55ca0ed7ac..b162d0c43b9f753f3c59566c9d03ddf94e1f1bd8 100644
--- a/src/usbutil.c
+++ b/src/usbutil.c
@@ -35,6 +35,7 @@
 #include <sys/stat.h>
 #endif
 #include "usbutil.h"
+#include "spice-version.h"
 #include "spice-util-priv.h"
 
 #define VENDOR_NAME_LEN (122 - sizeof(void *))
diff --git a/src/vmcstream.c b/src/vmcstream.c
index e26b939a8d8c9be8d45713230ab912647a0914a3..d5cc48e96f3e46339dc830276371b61fcc209dd4 100644
--- a/src/vmcstream.c
+++ b/src/vmcstream.c
@@ -18,6 +18,7 @@
 
 #include <string.h>
 
+#include "spice-version.h"
 #include "vmcstream.h"
 #include "spice-channel-priv.h"
 #include "gio-coroutine.h"
diff --git a/src/vncdisplaykeymap.c b/src/vncdisplaykeymap.c
index e09e33091434896a4f2c726d61d539954b0265e3..23766d9524c96a502c160ad1a75fab6673014e8f 100644
--- a/src/vncdisplaykeymap.c
+++ b/src/vncdisplaykeymap.c
@@ -14,7 +14,7 @@
 #include <gdk/gdkkeysyms.h>
 #include "vncdisplaykeymap.h"
 
-#include "spice-util.h"
+#include "spice-common.h"
 
 #undef G_LOG_DOMAIN
 #define G_LOG_DOMAIN "vnc-keymap"
diff --git a/tests/util.c b/tests/util.c
index fd753344cd6fc7db3ce8c7c2b760d0e1da744b61..a5e357cbafb3e8fbadbdc3e3daa85623e22d65a9 100644
--- a/tests/util.c
+++ b/tests/util.c
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 
 #define __SPICE_CLIENT_H_INSIDE__
+#include "spice-version.h"
 #include "spice-util-priv.h"
 
 enum {