summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--docs/reference/gtk/tmpl/gtkbuilder.sgml11
-rw-r--r--gtk/gtkbuilder.h1
-rw-r--r--gtk/gtkbuilderparser.c96
-rw-r--r--gtk/gtkbuilderprivate.h7
5 files changed, 120 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index d1522ee64d..c85d6b4cc6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2008-05-25 Tristan Van Berkom <tvb@gnome.org>
+
+ * gtk/gtkbuilderprivate.h, gtk/gtkbuilder.h, gtk/gtkbuilderparser.c:
+ Added support for parsing required toolkit versions (so that ui descriptions
+ can target specific versions of the backend widget libraries) bug 527612.
+
+ * gtk/docs/reference/gtk/tmpl/gtkbuilder.sgml: Added documentation
+ for the added xml tags to the ui description.
+
2008-05-25 Richard Hult <richard@imendio.com>
* gtk/gtkdnd-quartz.c: (gtk_drag_drop_finished): Run
diff --git a/docs/reference/gtk/tmpl/gtkbuilder.sgml b/docs/reference/gtk/tmpl/gtkbuilder.sgml
index 0677fc158f..f1e19a69e0 100644
--- a/docs/reference/gtk/tmpl/gtkbuilder.sgml
+++ b/docs/reference/gtk/tmpl/gtkbuilder.sgml
@@ -50,10 +50,11 @@ which are more limited in scope.
</para>
<para>
<programlisting><![CDATA[
-<!ELEMENT interface object* >
+<!ELEMENT interface (requires|object)* >
<!ELEMENT object (property|signal|child|ANY)* >
<!ELEMENT property PCDATA >
<!ELEMENT signal EMPTY >
+<!ELEMENT requires EMPTY >
<!ELEMENT child (object|ANY*) >
<!ATTLIST interface domain #IMPLIED >
@@ -61,6 +62,8 @@ which are more limited in scope.
class #REQUIRED
type-func #IMPLIED
constructor #IMPLIED >
+<!ATTLIST requires lib #REQUIRED
+ version #REQUIRED >
<!ATTLIST property name #REQUIRED
translatable #IMPLIED
comments #IMPLIED
@@ -88,6 +91,11 @@ elements, which describe child objects (most often widgets
inside a container, but also e.g. actions in an action group,
or columns in a tree model). A &lt;child&gt; element contains
an &lt;object&gt; element which describes the child object.
+The target toolkit version(s) are described by &lt;requires&gt;
+elements, the "lib" attribute specifies the widget library in
+question (currently the only supported value is "gtk+") and the "version"
+attribute specifies the target version in the form "&lt;major&gt;.&lt;minor&gt;".
+The builder will error out if the version requirements are not met.
</para>
<para>
Typically, the specific kind of object represented by an
@@ -258,6 +266,7 @@ respective objects, see
</para>
+@GTK_BUILDER_ERROR_VERSION_MISMATCH:
@GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION:
@GTK_BUILDER_ERROR_UNHANDLED_TAG:
@GTK_BUILDER_ERROR_MISSING_ATTRIBUTE:
diff --git a/gtk/gtkbuilder.h b/gtk/gtkbuilder.h
index 732acaa15e..eb82a61f7f 100644
--- a/gtk/gtkbuilder.h
+++ b/gtk/gtkbuilder.h
@@ -39,6 +39,7 @@ typedef struct _GtkBuilderPrivate GtkBuilderPrivate;
typedef enum
{
+ GTK_BUILDER_ERROR_VERSION_MISMATCH,
GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION,
GTK_BUILDER_ERROR_UNHANDLED_TAG,
GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index 15fbae3a3d..33b4f1bd88 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -28,6 +28,7 @@
#include "gtkbuilder.h"
#include "gtkbuildable.h"
#include "gtkdebug.h"
+#include "gtkversion.h"
#include "gtktypeutils.h"
#include "gtkintl.h"
#include "gtkalias.h"
@@ -225,6 +226,63 @@ _get_type_by_symbol (const gchar* symbol)
}
static void
+parse_requires (ParserData *data,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ GError **error)
+{
+ RequiresInfo *req_info;
+ const gchar *library = NULL;
+ const gchar *version = NULL;
+ gchar **split;
+ gint i, version_major = 0, version_minor = 0;
+ gint line_number, char_number;
+
+ g_markup_parse_context_get_position (data->ctx,
+ &line_number,
+ &char_number);
+
+ for (i = 0; names[i] != NULL; i++)
+ {
+ if (strcmp (names[i], "lib") == 0)
+ library = values[i];
+ else if (strcmp (names[i], "version") == 0)
+ version = values[i];
+ else
+ error_invalid_attribute (data, element_name, names[i], error);
+ }
+
+ if (!library || !version)
+ {
+ error_missing_attribute (data, element_name,
+ version ? "lib" : "version", error);
+ return;
+ }
+
+ if (!(split = g_strsplit (version, ".", 2)) || !split[0] || !split[1])
+ {
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_VALUE,
+ "%s:%d:%d <%s> attribute has malformed value \"%s\"",
+ data->filename,
+ line_number, char_number, "version", version);
+ return;
+ }
+ version_major = g_ascii_strtoll (split[0], NULL, 10);
+ version_minor = g_ascii_strtoll (split[1], NULL, 10);
+ g_strfreev (split);
+
+ req_info = g_slice_new0 (RequiresInfo);
+ req_info->library = g_strdup (library);
+ req_info->major = version_major;
+ req_info->minor = version_minor;
+ state_push (data, req_info);
+ req_info->tag.name = element_name;
+}
+
+static void
parse_object (ParserData *data,
const gchar *element_name,
const gchar **names,
@@ -521,6 +579,14 @@ _free_signal_info (SignalInfo *info,
g_slice_free (SignalInfo, info);
}
+void
+_free_requires_info (RequiresInfo *info,
+ gpointer user_data)
+{
+ g_free (info->library);
+ g_slice_free (RequiresInfo, info);
+}
+
static void
parse_interface (ParserData *data,
const gchar *element_name,
@@ -729,8 +795,10 @@ start_element (GMarkupParseContext *context,
if (!subparser_start (context, element_name, names, values,
data, error))
return;
-
- if (strcmp (element_name, "object") == 0)
+
+ if (strcmp (element_name, "requires") == 0)
+ parse_requires (data, element_name, names, values, error);
+ else if (strcmp (element_name, "object") == 0)
parse_object (data, element_name, names, values, error);
else if (strcmp (element_name, "child") == 0)
parse_child (data, element_name, names, values, error);
@@ -821,7 +889,27 @@ end_element (GMarkupParseContext *context,
return;
}
- if (strcmp (element_name, "object") == 0)
+ if (strcmp (element_name, "requires") == 0)
+ {
+ RequiresInfo *req_info = state_pop_info (data, RequiresInfo);
+
+ /* TODO: Allow third party widget developers to check thier
+ * required versions, possibly throw a signal allowing them
+ * to check thier library versions here.
+ */
+ if (!strcmp (req_info->library, "gtk+"))
+ {
+ if (!GTK_CHECK_VERSION (req_info->major, req_info->minor, 0))
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_VERSION_MISMATCH,
+ "%s: required %s version %d.%d, current version is %d.%d",
+ data->filename, req_info->library,
+ req_info->major, req_info->minor,
+ GTK_MAJOR_VERSION, GTK_MINOR_VERSION);
+ }
+ }
+ else if (strcmp (element_name, "object") == 0)
{
ObjectInfo *object_info = state_pop_info (data, ObjectInfo);
ChildInfo* child_info = state_peek_info (data, ChildInfo);
@@ -948,6 +1036,8 @@ free_info (CommonInfo *info)
free_property_info ((PropertyInfo *)info);
else if (strcmp (info->tag.name, "signal") == 0)
_free_signal_info ((SignalInfo *)info, NULL);
+ else if (strcmp (info->tag.name, "requires") == 0)
+ _free_requires_info ((RequiresInfo *)info, NULL);
else
g_assert_not_reached ();
}
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index a1d9eb41e3..ded6f238be 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -72,6 +72,13 @@ typedef struct {
} SignalInfo;
typedef struct {
+ TagInfo tag;
+ gchar *library;
+ gint major;
+ gint minor;
+} RequiresInfo;
+
+typedef struct {
GMarkupParser *parser;
gchar *tagname;
const gchar *start;