<div dir="ltr"><div><div><div><div><div><div><div><div>Protocol documentation is produced directly from the xml currently. If it is merged with doxygen-produced comments then there will be duplication and possible confusion, so these header files must somehow be skipped when running doxygen.<br><br></div>That said, it may make sense to just use this and doxygen to produce the documentation, skipping all the docbook and xml conversions, and this would be part of such a patch. Positive reasons I can see:<br><br></div>- Eliminates the use of docbook. Current combination of docbook and doxygen is pretty confusing. Outside of gnu I can assure you that doxygen is vastly more popular and familiar to programmers.<br><br></div>- doxygen produces links easily, allowing the client and server api docs to refer to messages/events, and messages/event documentation to refer to functions in the client and server apis, with working cross-links. Descriptive chapters, if added, can easily link to the items in the documentation.<br><br></div><div>- Documentation is specific to a backend api, removing any ambiguity about how that backend translated messages and event descriptions. The documentation will list exactly what the user types into their software.<br><br></div></div>Problems I see:<br><br></div>- Unless a lot of \relates and pages comments are added, the C backend documentation will lose all the object-oriented aspects of the protocol. Doxygen is not really good at this and is heavily biased toward C++.<br><br></div>- It is a real pain to get Doxygen to produce introductory and instructional chapters that look remotely attractive. This may lead to running the doxygen output through docbook to add these, just like the current version does.<br><br></div>- Ambiguity may be a lot worse if somebody has to use the C documentation to figure out how to use their backend in a different language.<br><div><div><div><div><div><div><div><div><div><div><div><br></div></div></div></div></div></div></div></div></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Oct 28, 2015 at 6:48 PM, Peter Hutterer <span dir="ltr"><<a href="mailto:peter.hutterer@who-t.net" target="_blank">peter.hutterer@who-t.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This switches the scanner to generate doxygen-compatible tags for the<br>
generated protocol headers, and hooks up the doxygen build to generate server<br>
and client-side API documentation.<br>
<br>
For the wayland protocol, this generates a mainpage with the copyright<br>
information, all interfaces are separated by doxygen groups and thus listed in<br>
"Modules" in the generated output.<br>
<br>
Function, struct and #defines are documented in doxygen style and associated<br>
with the matching interface.<br>
---<br>
This is an RFC for now, we need to agree on whether we want to switch to<br>
doxygen style first. Other changes still missing here are:<br>
* afaict, the summary can be dropped for most entries, it doesn't seem<br>
  to add any value if a long description is there<br>
* currently parsing too many header files, we should only parse the protocol<br>
  ones for a cleaner documentation.<br>
* future work for wayland-protocols is to add the various protocols at the<br>
  @page level<br>
* a couple of things don't have the doxygen tag yet (mostly #defines)<br>
<br>
 doc/doxygen/Makefile.am        |  22 +++++-<br>
 doc/doxygen/<a href="http://wayland.doxygen.in" rel="noreferrer" target="_blank">wayland.doxygen.in</a> |   4 +-<br>
 src/scanner.c                  | 165 ++++++++++++++++++++++++++---------------<br>
 3 files changed, 130 insertions(+), 61 deletions(-)<br>
<br>
diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am<br>
index 5520d39..eaa6ce4 100644<br>
--- a/doc/doxygen/Makefile.am<br>
+++ b/doc/doxygen/Makefile.am<br>
@@ -1,7 +1,11 @@<br>
<br>
 .SUFFIXES = .gv .png .map<br>
<br>
-noinst_DATA = xml/Client/index.xml xml/Server/index.xml<br>
+noinst_DATA = \<br>
+              xml/Client/index.xml \<br>
+              xml/Server/index.xml \<br>
+              html/Client/index.html \<br>
+              html/Server/index.html<br>
 dist_noinst_DATA = <a href="http://wayland.doxygen.in" rel="noreferrer" target="_blank">wayland.doxygen.in</a><br>
<br>
 scanned_src_files_shared =                             \<br>
@@ -27,6 +31,12 @@ scanned_src_files_man =                                      \<br>
        $(top_srcdir)/src/wayland-client.h      \<br>
        $(top_srcdir)/src/wayland-client-core.h<br>
<br>
+extra_doxygen_Server = \<br>
+       $(top_builddir)/protocol/wayland-server-protocol.h<br>
+<br>
+extra_doxygen_Client = \<br>
+       $(top_builddir)/protocol/wayland-client-protocol.h<br>
+<br>
 diagramsdir := $(srcdir)/dot<br>
 diagramssrc := $(wildcard $(diagramsdir)/*.gv)<br>
 diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png))<br>
@@ -38,7 +48,7 @@ diagram_maps := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map))<br>
 dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n")<br>
<br>
 # Listing various directories that might need to be created.<br>
-alldirs := xml xml/Client xml/Server man/man3<br>
+alldirs := xml xml/Client xml/Server man/man3 html/Client html/Server<br>
<br>
 $(diagrams): $(diagramssrc)<br>
<br>
@@ -51,6 +61,13 @@ xml/%/index.xml: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_ma<br>
           echo "INPUT= $(scanned_src_files_$*)"; \<br>
           ) | $(DOXYGEN) -<br>
<br>
+html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | html/%<br>
+       $(AM_V_GEN)(cat wayland.doxygen; \<br>
+          echo "GENERATE_HTML=YES"; \<br>
+          echo "HTML_OUTPUT=html/$*"; \<br>
+          echo "INPUT= $(scanned_src_files_$*) $(extra_doxygen_$*)"; \<br>
+          ) | $(DOXYGEN) -<br>
+<br>
 man/man3/wl_display.3: $(scanned_src_files_man) wayland.doxygen | man/man3<br>
        $(AM_V_GEN)(cat wayland.doxygen; \<br>
           echo "GENERATE_MAN=YES"; \<br>
@@ -74,6 +91,7 @@ all-local: man/man3/wl_display.3<br>
<br>
 clean-local:<br>
        rm -rf xml/<br>
+       rm -rf html/<br>
        rm -rf man/<br>
<br>
 EXTRA_DIST = $(diagramssrc)<br>
diff --git a/doc/doxygen/<a href="http://wayland.doxygen.in" rel="noreferrer" target="_blank">wayland.doxygen.in</a> b/doc/doxygen/<a href="http://wayland.doxygen.in" rel="noreferrer" target="_blank">wayland.doxygen.in</a><br>
index fb76b12..9cd7a64 100644<br>
--- a/doc/doxygen/<a href="http://wayland.doxygen.in" rel="noreferrer" target="_blank">wayland.doxygen.in</a><br>
+++ b/doc/doxygen/<a href="http://wayland.doxygen.in" rel="noreferrer" target="_blank">wayland.doxygen.in</a><br>
@@ -13,4 +13,6 @@ MACRO_EXPANSION        = YES<br>
 EXPAND_ONLY_PREDEF     = YES<br>
 DOT_MULTI_TARGETS      = YES<br>
 ALIASES                += comment{1}="/* \1 *<!-- -->/"<br>
-GENERATE_HTML          = NO<br>
+OPTIMIZE_OUTPUT_FOR_C  = YES<br>
+EXTRACT_ALL            = YES<br>
+EXTRACT_STATIC         = YES<br>
diff --git a/src/scanner.c b/src/scanner.c<br>
index f456aa5..f7780d6 100644<br>
--- a/src/scanner.c<br>
+++ b/src/scanner.c<br>
@@ -762,9 +762,11 @@ emit_opcode_versions(struct wl_list *message_list, struct interface *interface)<br>
 {<br>
        struct message *m;<br>
<br>
-       wl_list_for_each(m, message_list, link)<br>
+       wl_list_for_each(m, message_list, link) {<br>
+               printf("/**\n * @ingroup iface_%s\n */\n", interface->name);<br>
                printf("#define %s_%s_SINCE_VERSION\t%d\n",<br>
                       interface->uppercase_name, m->uppercase_name, m->since);<br>
+       }<br>
<br>
        printf("\n");<br>
 }<br>
@@ -804,6 +806,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)<br>
        struct arg *a, *ret;<br>
        int has_destructor, has_destroy;<br>
<br>
+       printf("/** @ingroup iface_%s */\n", interface->name);<br>
        printf("static inline void\n"<br>
               "%s_set_user_data(struct %s *%s, void *user_data)\n"<br>
               "{\n"<br>
@@ -812,6 +815,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)<br>
               interface->name, interface->name, interface->name,<br>
               interface->name);<br>
<br>
+       printf("/** @ingroup iface_%s */\n", interface->name);<br>
        printf("static inline void *\n"<br>
               "%s_get_user_data(struct %s *%s)\n"<br>
               "{\n"<br>
@@ -838,6 +842,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)<br>
        }<br>
<br>
        if (!has_destroy && strcmp(interface->name, "wl_display") != 0)<br>
+               printf("/** @ingroup iface_%s */\n", interface->name);<br>
                printf("static inline void\n"<br>
                       "%s_destroy(struct %s *%s)\n"<br>
                       "{\n"<br>
@@ -865,6 +870,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)<br>
                                ret = a;<br>
                }<br>
<br>
+               printf("/** @ingroup iface_%s */\n", interface->name);<br>
                if (ret && ret->interface_name == NULL)<br>
                        printf("static inline void *\n");<br>
                else if (ret)<br>
@@ -950,6 +956,16 @@ emit_event_wrappers(struct wl_list *message_list, struct interface *interface)<br>
                return;<br>
<br>
        wl_list_for_each(m, message_list, link) {<br>
+               printf("/**\n"<br>
+                      " * @ingroup iface_%s\n"<br>
+                      " * Sends an %s event to the client owning the resource.\n",<br>
+                      interface->name,<br>
+                      m->name);<br>
+               wl_list_for_each(a, &m->arg_list, link) {<br>
+                       if (a->summary)<br>
+                               printf("@param %s %s\n", a->name, a->summary);<br>
+               }<br>
+               printf(" */\n");<br>
                printf("static inline void\n"<br>
                       "%s_send_%s(struct wl_resource *resource_",<br>
                       interface->name, m->name);<br>
@@ -981,6 +997,30 @@ emit_event_wrappers(struct wl_list *message_list, struct interface *interface)<br>
 }<br>
<br>
 static void<br>
+format_text_to_comment(const char *text, bool standalone_comment)<br>
+{<br>
+       int bol = 1, start = 0, i;<br>
+<br>
+       for (i = 0; text[i]; i++) {<br>
+               if (bol && (text[i] == ' ' || text[i] == '\t')) {<br>
+                       continue;<br>
+               } else if (bol) {<br>
+                       bol = 0;<br>
+                       start = i;<br>
+               }<br>
+<br>
+               if (text[i] == '\n' || text[i] == '\0') {<br>
+                       printf("%s %.*s\n",<br>
+                              i == 0 && standalone_comment ? "/*" : " *",<br>
+                              i - start, text + start);<br>
+                       bol = 1;<br>
+               }<br>
+       }<br>
+       if (standalone_comment)<br>
+               printf(" */\n\n");<br>
+}<br>
+<br>
+static void<br>
 emit_enumerations(struct interface *interface)<br>
 {<br>
        struct enumeration *e;<br>
@@ -996,28 +1036,23 @@ emit_enumerations(struct interface *interface)<br>
<br>
                if (desc) {<br>
                        printf("/**\n");<br>
-                       desc_dump(desc->summary,<br>
-                                 " * %s_%s - ",<br>
-                                 interface->name, e->name);<br>
-                       wl_list_for_each(entry, &e->entry_list, link) {<br>
-                               desc_dump(entry->summary,<br>
-                                         " * @%s_%s_%s: ",<br>
-                                         interface->uppercase_name,<br>
-                                         e->uppercase_name,<br>
-                                         entry->uppercase_name);<br>
-                       }<br>
-                       if (desc->text) {<br>
-                               printf(" *\n");<br>
-                               desc_dump(desc->text, " * ");<br>
-                       }<br>
+                       printf(" * @ingroup iface_%s\n", interface->name);<br>
+                       format_text_to_comment(desc->summary, false);<br>
+                       if (desc->text)<br>
+                               format_text_to_comment(desc->text, false);<br>
                        printf(" */\n");<br>
                }<br>
                printf("enum %s_%s {\n", interface->name, e->name);<br>
-               wl_list_for_each(entry, &e->entry_list, link)<br>
+               wl_list_for_each(entry, &e->entry_list, link) {<br>
+                       if (entry->summary)<br>
+                               printf("\t/**\n"<br>
+                                      "\t * %s\n"<br>
+                                      "\t */\n", entry->summary);<br>
                        printf("\t%s_%s_%s = %s,\n",<br>
                               interface->uppercase_name,<br>
                               e->uppercase_name,<br>
                               entry->uppercase_name, entry->value);<br>
+               }<br>
                printf("};\n");<br>
                printf("#endif /* %s_%s_ENUM */\n\n",<br>
                       interface->uppercase_name, e->uppercase_name);<br>
@@ -1034,9 +1069,10 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid<br>
        if (wl_list_empty(message_list))<br>
                return;<br>
<br>
+       printf("/**\n");<br>
+#if 0<br>
        if (interface->description) {<br>
                struct description *desc = interface->description;<br>
-               printf("/**\n");<br>
                desc_dump(desc->summary, " * %s - ", interface->name);<br>
                wl_list_for_each(m, message_list, link) {<br>
                        struct description *mdesc = m->description;<br>
@@ -1046,8 +1082,12 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid<br>
                }<br>
                printf(" *\n");<br>
                desc_dump(desc->text, " * ");<br>
-               printf(" */\n");<br>
        }<br>
+#endif<br>
+       printf(" * @ingroup iface_%s\n", interface->name);<br>
+       printf(" * @struct %s_%s\n", interface->name,<br>
+              (side == SERVER) ? "interface" : "listener");<br>
+       printf(" */\n");<br>
        printf("struct %s_%s {\n", interface->name,<br>
               (side == SERVER) ? "interface" : "listener");<br>
<br>
@@ -1055,24 +1095,24 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid<br>
                struct description *mdesc = m->description;<br>
<br>
                printf("\t/**\n");<br>
-               desc_dump(mdesc ? mdesc->summary : "(none)",<br>
-                         "\t * %s - ", m->name);<br>
-               wl_list_for_each(a, &m->arg_list, link) {<br>
-                       if (side == SERVER && a->type == NEW_ID &&<br>
-                           a->interface_name == NULL)<br>
-                               printf("\t * @interface: name of the objects interface\n"<br>
-                                      "\t * @version: version of the objects interface\n");<br>
-<br>
-<br>
-                       desc_dump(a->summary ? a->summary : "(none)",<br>
-                                 "\t * @%s: ", a->name);<br>
-               }<br>
+               if (mdesc->summary)<br>
+                       printf("\t * %s\n", mdesc->summary);<br>
                if (mdesc) {<br>
                        printf("\t *\n");<br>
                        desc_dump(mdesc->text, "\t * ");<br>
                }<br>
+               wl_list_for_each(a, &m->arg_list, link) {<br>
+                       if (side == SERVER && a->type == NEW_ID &&<br>
+                           a->interface_name == NULL)<br>
+                               printf("\t * @param interface name of the objects interface\n"<br>
+                                      "\t * @param version version of the objects interface\n");<br>
+<br>
+                       if (a->summary)<br>
+                               printf("\t * @param %s %s\n", a->name,<br>
+                                      a->summary);<br>
+               }<br>
                if (m->since > 1) {<br>
-                       printf("\t * @since: %d\n", m->since);<br>
+                       printf("\t * @since %d\n", m->since);<br>
                }<br>
                printf("\t */\n");<br>
                printf("\tvoid (*%s)(", m->name);<br>
@@ -1112,6 +1152,9 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid<br>
        printf("};\n\n");<br>
<br>
        if (side == CLIENT) {<br>
+           printf("/**\n"<br>
+                  " * @ingroup %s_iface\n"<br>
+                  " */\n", interface->name);<br>
            printf("static inline int\n"<br>
                   "%s_add_listener(struct %s *%s,\n"<br>
                   "%sconst struct %s_listener *listener, void *data)\n"<br>
@@ -1128,29 +1171,6 @@ emit_structs(struct wl_list *message_list, struct interface *interface, enum sid<br>
 }<br>
<br>
 static void<br>
-format_copyright(const char *copyright)<br>
-{<br>
-       int bol = 1, start = 0, i;<br>
-<br>
-       for (i = 0; copyright[i]; i++) {<br>
-               if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {<br>
-                       continue;<br>
-               } else if (bol) {<br>
-                       bol = 0;<br>
-                       start = i;<br>
-               }<br>
-<br>
-               if (copyright[i] == '\n' || copyright[i] == '\0') {<br>
-                       printf("%s %.*s\n",<br>
-                              i == 0 ? "/*" : " *",<br>
-                              i - start, copyright + start);<br>
-                       bol = 1;<br>
-               }<br>
-       }<br>
-       printf(" */\n\n");<br>
-}<br>
-<br>
-static void<br>
 emit_types_forward_declarations(struct protocol *protocol,<br>
                                struct wl_list *message_list,<br>
                                struct wl_array *types)<br>
@@ -1203,6 +1223,31 @@ get_include_name(bool core, enum side side)<br>
 }<br>
<br>
 static void<br>
+emit_mainpage_blurb(const struct protocol *protocol, enum side side)<br>
+{<br>
+       printf("/**\n"<br>
+              " * @mainpage\n"<br>
+              " * Wayland protocol '%s' %s API documentation\n"<br>
+              " * For the list of available interfaces, please see the\n"<br>
+              " * <a href=\"modules.html\">modules</a> list.\n",<br>
+              protocol->name,<br>
+              (side == SERVER) ? "server" : "client");<br>
+<br>
+       if (protocol->description) {<br>
+               printf(" * @section description Description\n");<br>
+               format_text_to_comment(protocol->description->text, false);<br>
+       }<br>
+<br>
+       if (protocol->copyright) {<br>
+               printf(" * @section copyright Copyright\n");<br>
+               printf(" * <pre>\n");<br>
+               format_text_to_comment(protocol->copyright, false);<br>
+               printf(" * </pre>\n");<br>
+       }<br>
+       printf(" */\n");<br>
+}<br>
+<br>
+static void<br>
 emit_header(struct protocol *protocol, enum side side)<br>
 {<br>
        struct interface *i, *i_next;<br>
@@ -1210,9 +1255,6 @@ emit_header(struct protocol *protocol, enum side side)<br>
        const char *s = (side == SERVER) ? "SERVER" : "CLIENT";<br>
        char **p, *prev;<br>
<br>
-       if (protocol->copyright)<br>
-               format_copyright(protocol->copyright);<br>
-<br>
        printf("#ifndef %s_%s_PROTOCOL_H\n"<br>
               "#define %s_%s_PROTOCOL_H\n"<br>
               "\n"<br>
@@ -1229,6 +1271,8 @@ emit_header(struct protocol *protocol, enum side side)<br>
               protocol->uppercase_name, s,<br>
               get_include_name(protocol->core_headers, side));<br>
<br>
+       emit_mainpage_blurb(protocol, side);<br>
+<br>
        wl_array_init(&types);<br>
        wl_list_for_each(i, &protocol->interface_list, link) {<br>
                emit_types_forward_declarations(protocol, &i->request_list, &types);<br>
@@ -1252,6 +1296,11 @@ emit_header(struct protocol *protocol, enum side side)<br>
        printf("\n");<br>
<br>
        wl_list_for_each(i, &protocol->interface_list, link) {<br>
+               printf(" /**\n"<br>
+                      "  * @defgroup iface_%s The %s interface\n"<br>
+                      "  * API provided by the %s interface\n"<br>
+                      "  */\n",<br>
+                      i->name, i->name, i->name);<br>
                printf("extern const struct wl_interface "<br>
                       "%s_interface;\n", i->name);<br>
        }<br>
@@ -1395,7 +1444,7 @@ emit_code(struct protocol *protocol)<br>
        char **p, *prev;<br>
<br>
        if (protocol->copyright)<br>
-               format_copyright(protocol->copyright);<br>
+               format_text_to_comment(protocol->copyright, true);<br>
<br>
        printf("#include <stdlib.h>\n"<br>
               "#include <stdint.h>\n"<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.4.3<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" rel="noreferrer" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br></div>